This commit is contained in:
Steven Roose 2025-03-20 04:18:24 -07:00 committed by GitHub
commit 2681c6b6ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 89 additions and 0 deletions

View file

@ -62,6 +62,11 @@ const (
// the database was attempted against a read-only transaction.
ErrTxNotWritable
// ErrAvailableDiskSpace indicates that the user is running out of
// disk space. The database preventively decided to not allow the
// transaction to prevent causing hard-to-detect problems.
ErrAvailableDiskSpace
// **************************************
// Errors related to metadata operations.
// **************************************
@ -143,6 +148,7 @@ var errorCodeStrings = map[ErrorCode]string{
ErrCorruption: "ErrCorruption",
ErrTxClosed: "ErrTxClosed",
ErrTxNotWritable: "ErrTxNotWritable",
ErrAvailableDiskSpace: "ErrAvailableDiskSpace",
ErrBucketNotFound: "ErrBucketNotFound",
ErrBucketExists: "ErrBucketExists",
ErrBucketNameRequired: "ErrBucketNameRequired",

View file

@ -27,6 +27,7 @@ func TestErrorCodeStringer(t *testing.T) {
{database.ErrCorruption, "ErrCorruption"},
{database.ErrTxClosed, "ErrTxClosed"},
{database.ErrTxNotWritable, "ErrTxNotWritable"},
{database.ErrAvailableDiskSpace, "ErrAvailableDiskSpace"},
{database.ErrBucketNotFound, "ErrBucketNotFound"},
{database.ErrBucketExists, "ErrBucketExists"},
{database.ErrBucketNameRequired, "ErrBucketNameRequired"},

View file

@ -43,6 +43,13 @@ const (
// The serialized block index row format is:
// <blocklocation><blockheader>
blockHdrOffset = blockLocSize
// bytesMiB is the number of bytes in a mebibyte.
bytesMiB = 1024 * 1024
// minAvailableSpaceUpdate is the minimum space available (in bytes) to
// allow a write transaction. The value is 25 MiB.
minAvailableSpaceUpdate = 25 * bytesMiB
)
var (
@ -1885,6 +1892,22 @@ func (db *db) Type() string {
// which is used by the managed transaction code while the database method
// returns the interface.
func (db *db) begin(writable bool) (*transaction, error) {
// Make sure there is enough available disk space so we can inform the
// user of the problem instead of causing a db failure.
if writable {
freeSpace, err := getAvailableDiskSpace()
if err != nil {
return nil, makeDbErr(database.ErrDriverSpecific,
"failed to inspect available disk space", err)
}
if freeSpace < minAvailableSpaceUpdate {
errMsg := fmt.Sprintf("available disk space too low: "+
"%.1f MiB", float64(freeSpace)/float64(bytesMiB))
return nil, makeDbErr(database.ErrAvailableDiskSpace,
errMsg, nil)
}
}
// Whenever a new writable transaction is started, grab the write lock
// to ensure only a single write transaction can be active at the same
// time. This lock will not be released until the transaction is

View file

@ -0,0 +1,26 @@
// +build !windows
// Copyright (c) 2013-2018 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ffldb
import (
"os"
"syscall"
)
// getAvailableDiskSpace returns the number of bytes of available disk space.
func getAvailableDiskSpace() (uint64, error) {
var stat syscall.Statfs_t
wd, err := os.Getwd()
if err != nil {
return 0, err
}
syscall.Statfs(wd, &stat)
return stat.Bavail * uint64(stat.Bsize), nil
}

View file

@ -0,0 +1,33 @@
// +build windows
// Copyright (c) 2013-2018 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package ffldb
import (
"os"
"syscall"
"unsafe"
)
// getAvailableDiskSpace returns the number of bytes of available disk space.
func getAvailableDiskSpace() (uint64, error) {
wd, err := os.Getwd()
if err != nil {
return 0, err
}
h := syscall.MustLoadDLL("kernel32.dll")
c := h.MustFindProc("GetDiskFreeSpaceExW")
var freeBytes int64
_, _, err := c.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(wd))),
uintptr(unsafe.Pointer(&freeBytes)), nil, nil)
if err != nil {
return 0, err
}
return uint64(freeBytes), nil
}