ipfs-cluster/cmd/ipfs-cluster-service/lock.go
Hector Sanjuan 0eef0ede89 Support a levelDB backend for cluster
Badger can take 1000x the amount of needed space if not GC'ed or compacted
(#1320), even for non heavy usage. Cluster has no provisions to run datastore
GC operations and while they could be added, they are not ensured to
help. Improvements on Badger v3 might help but would still need to GC
explicitally.

Cluster was however designed to support any go-datastore as backend.

This commit adds LevelDB support. LevelDB go-datastore wrapper is mature, does
not need GC and should work well for most cluster usecases, which are not
overly demanding.

A new `--datastore` flag has been added on init. The store backend is selected
based on the value in the configuration, similar to how raft/crdt is. The
default is set to leveldb. From now on it should be easier to add additional
backends, i.e. badgerv3.
2021-06-09 19:40:36 +02:00

72 lines
1.6 KiB
Go

package main
import (
"errors"
"fmt"
"io"
"path"
fslock "github.com/ipfs/go-fs-lock"
"github.com/ipfs/ipfs-cluster/cmdutils"
)
// lock logic heavily inspired by go-ipfs/repo/fsrepo/lock/lock.go
// The name of the file used for locking
const lockFileName = "cluster.lock"
var locker *lock
// lock helps to coordinate proceeds via a lock file
type lock struct {
lockCloser io.Closer
path string
}
func (l *lock) lock() {
if l.lockCloser != nil {
checkErr("", errors.New("cannot acquire lock twice"))
}
// we should have a config folder whenever we try to lock
cfgHelper := cmdutils.NewConfigHelper(configPath, identityPath, "", "")
cfgHelper.MakeConfigFolder()
// set the lock file within this function
logger.Debug("checking lock")
lk, err := fslock.Lock(l.path, lockFileName)
if err != nil {
logger.Debug(err)
l.lockCloser = nil
errStr := "%s. If no other "
errStr += "%s process is running, remove %s, or make sure "
errStr += "that the config folder is writable for the user "
errStr += "running %s."
errStr = fmt.Sprintf(
errStr,
err,
programName,
path.Join(l.path, lockFileName),
programName,
)
checkErr("obtaining execution lock", errors.New(errStr))
}
logger.Debugf("%s execution lock acquired", programName)
l.lockCloser = lk
}
func (l *lock) tryUnlock() error {
// Noop in the uninitialized case
if l.lockCloser == nil {
logger.Debug("locking not initialized, unlock is noop")
return nil
}
err := l.lockCloser.Close()
if err != nil {
return err
}
logger.Debug("successfully released execution lock")
l.lockCloser = nil
return nil
}