mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-03 17:44:29 +00:00
74 lines
1.7 KiB
Go
74 lines
1.7 KiB
Go
package dir
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/gofrs/flock"
|
|
"github.com/ledgerwatch/log/v3"
|
|
)
|
|
|
|
// Rw - type to represent Read-Write access to directory
|
|
// if some code accept this typ - it can be sure: dir exists, no other process now write there
|
|
// We have no specific Ro type, just use `string` for Ro directory path
|
|
type Rw struct {
|
|
dirLock *flock.Flock // prevents concurrent use of instance directory
|
|
Path string
|
|
}
|
|
|
|
func convertFileLockError(err error, dir string) error {
|
|
if errno, ok := err.(syscall.Errno); ok && dirInUseErrnos[uint(errno)] { //nolint
|
|
return fmt.Errorf("%w: %s", ErrDirUsed, dir)
|
|
}
|
|
return err
|
|
}
|
|
|
|
var dirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
|
|
|
|
var (
|
|
ErrDirUsed = errors.New("datadir already used by another process")
|
|
)
|
|
|
|
func OpenRw(dir string) (*Rw, error) {
|
|
MustExist(dir)
|
|
|
|
// Lock the instance directory to prevent concurrent use by another instance as well as
|
|
// accidental use of the instance directory as a database.
|
|
l := flock.New(filepath.Join(dir, "LOCK"))
|
|
locked, err := l.TryLock()
|
|
if err != nil {
|
|
return nil, convertFileLockError(err, dir)
|
|
}
|
|
if !locked {
|
|
return nil, fmt.Errorf("%w: %s", ErrDirUsed, dir)
|
|
}
|
|
return &Rw{dirLock: l, Path: dir}, nil
|
|
}
|
|
func (t *Rw) Close() {
|
|
// Release instance directory lock.
|
|
if t.dirLock != nil {
|
|
if err := t.dirLock.Unlock(); err != nil {
|
|
log.Error("Can't release snapshot dir lock", "err", err)
|
|
}
|
|
t.dirLock = nil
|
|
}
|
|
}
|
|
|
|
func MustExist(path string) {
|
|
const perm = 0764 // user rwx, group rw, other r
|
|
if err := os.MkdirAll(path, perm); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func Exist(path string) bool {
|
|
_, err := os.Stat(path)
|
|
if err != nil && os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|