Skip to content
Merged
24 changes: 23 additions & 1 deletion cmd/utils/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"runtime"
"strings"
"syscall"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
Expand All @@ -40,7 +41,9 @@ import (
)

const (
importBatchSize = 2500
importBatchSize = 2500
freeDiskSpaceWarning = 1024 * 1024 * 1024
freeDiskSpaceCritical = 300 * 1024 * 1024
)

// Fatalf formats a message to standard error and exits the program.
Expand Down Expand Up @@ -71,6 +74,7 @@ func StartNode(stack *node.Node) {
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigc)
go monitorFreeDiskSpace(sigc, stack.InstanceDir())
<-sigc
log.Info("Got interrupt, shutting down...")
go stack.Close()
Expand All @@ -85,6 +89,24 @@ func StartNode(stack *node.Node) {
}()
}

func monitorFreeDiskSpace(sigc chan os.Signal, path string) {
for {
freeSpace, err := getFreeDiskSpace(path)
if err != nil {
log.Warn("Failed to get free disk space", "path", path, "err", err)
break
}
if freeSpace < freeDiskSpaceCritical {
log.Error("Low disk space. Gracefully shutting down Geth to prevent database corruption.", "available", freeSpace/1024/1024)
sigc <- syscall.SIGTERM
break
} else if freeSpace < freeDiskSpaceWarning {
log.Warn("Disk space is running low. Geth will shutdown if disk space runs below critical level.", "available", freeSpace/1024/1024, "critical_level", freeDiskSpaceCritical/1024/1024)
}
time.Sleep(5 * time.Second)
}
}

func ImportChain(chain *core.BlockChain, fn string) error {
// Watch for Ctrl-C while the import is running.
// If a signal is received, the import will stop at the next batch.
Expand Down
38 changes: 38 additions & 0 deletions cmd/utils/diskusage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// +build !windows

package utils

import (
"fmt"

"golang.org/x/sys/unix"
)

var stat unix.Statfs_t

func getFreeDiskSpace(path string) (uint64, error) {

err := unix.Statfs(path, &stat)
if err != nil {
return 0, fmt.Errorf("failed to call Statfs: %v", err)
}

// Available blocks * size per block = available space in bytes
return stat.Bavail * uint64(stat.Bsize), nil
}
38 changes: 38 additions & 0 deletions cmd/utils/diskusage_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package utils

import (
"fmt"

"golang.org/x/sys/windows"
)

func getFreeDiskSpace(path string) (uint64, error) {

cwd, err := windows.UTF16PtrFromString(path)
if err != nil {
return 0, fmt.Errorf("failed to call UTF16PtrFromString: %v", err)
}

var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
return 0, fmt.Errorf("failed to call GetDiskFreeSpaceEx: %v", err)
}

return freeBytesAvailableToCaller, nil
}