package boltdb import ( "io/ioutil" "log" "os" "path" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/bucket" "github.com/pkg/errors" "github.com/spf13/viper" "go.etcd.io/bbolt" ) type ( boltBucket struct { db *bbolt.DB name []byte } // Options groups the BoltDB bucket's options. Options struct { bbolt.Options Name []byte Path string Perm os.FileMode } ) const defaultFilePermission = 0777 var errEmptyPath = errors.New("database empty path") const Name = "boltdb" func makeCopy(val []byte) []byte { tmp := make([]byte, len(val)) copy(tmp, val) return tmp } // NewOptions prepares options for badger instance. func NewOptions(prefix string, v *viper.Viper) (opts Options, err error) { prefix = prefix + "." + Name opts = Options{ Options: bbolt.Options{ // set defaults: Timeout: bbolt.DefaultOptions.Timeout, FreelistType: bbolt.DefaultOptions.FreelistType, // set config options: NoSync: v.GetBool(prefix + ".no_sync"), ReadOnly: v.GetBool(prefix + ".read_only"), NoGrowSync: v.GetBool(prefix + ".no_grow_sync"), NoFreelistSync: v.GetBool(prefix + ".no_freelist_sync"), PageSize: v.GetInt(prefix + ".page_size"), MmapFlags: v.GetInt(prefix + ".mmap_flags"), InitialMmapSize: v.GetInt(prefix + ".initial_mmap_size"), }, Name: []byte(Name), Perm: defaultFilePermission, Path: v.GetString(prefix + ".path"), } if opts.Path == "" { return opts, errEmptyPath } if tmp := v.GetDuration(prefix + ".lock_timeout"); tmp > 0 { opts.Timeout = tmp } if perm := v.GetUint32(prefix + ".perm"); perm != 0 { opts.Perm = os.FileMode(perm) } base := path.Dir(opts.Path) if err := os.MkdirAll(base, opts.Perm); err != nil { return opts, errors.Wrapf(err, "could not use `%s` dir", base) } return opts, nil } // NewBucket creates badger-bucket instance. func NewBucket(opts *Options) (bucket.Bucket, error) { log.SetOutput(ioutil.Discard) // disable default logger db, err := bbolt.Open(opts.Path, opts.Perm, &opts.Options) if err != nil { return nil, err } err = db.Update(func(tx *bbolt.Tx) error { _, err := tx.CreateBucketIfNotExists(opts.Name) return err }) if err != nil { return nil, err } return &boltBucket{db: db, name: opts.Name}, nil }