frostfs-node/pkg/local_object_storage/kvio/bbolt/bbolt.go
Alejandro Lopez 00c8712dc6 [#421] Create common interface for kv repositories
Signed-off-by: Alejandro Lopez <a.lopez@yadro.com>
2023-06-20 12:54:53 +03:00

105 lines
2.2 KiB
Go

// Package bbolt provides a kvio.Repository backed by bbolt.
package bbolt
import (
"errors"
"fmt"
"os"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/kvio"
"go.etcd.io/bbolt"
)
type impl struct {
db *bbolt.DB
}
type Options struct {
bbolt.Options
MaxBatchSize int
MaxBatchDelay time.Duration
}
var (
defaultBucket = []byte{0}
// ErrNoDefaultBucket is returned when the default bucket for objects is missing.
ErrNoDefaultBucket = errors.New("no default bucket")
)
func Open(path string, opts *Options) (kvio.Repository, error) {
db, err := bbolt.Open(path, os.ModePerm, &opts.Options)
if err != nil {
return nil, fmt.Errorf("could not open database: %w", err)
}
if opts.MaxBatchSize > 0 {
db.MaxBatchSize = opts.MaxBatchSize
}
if opts.MaxBatchDelay > 0 {
db.MaxBatchDelay = opts.MaxBatchDelay
}
if !opts.Options.ReadOnly {
err = db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(defaultBucket)
return err
})
if err != nil {
return nil, fmt.Errorf("could not create default bucket: %w", err)
}
}
return impl{db}, nil
}
func (r impl) Read(f func(kvio.ReadOnlyTx) error) error {
return r.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(defaultBucket)
if b == nil {
return ErrNoDefaultBucket
}
return f(txImpl{b, tx})
})
}
func (r impl) Write(f func(kvio.WriteOnlyTx) error) error {
return r.db.Batch(func(tx *bbolt.Tx) error {
b := tx.Bucket(defaultBucket)
if b == nil {
return ErrNoDefaultBucket
}
return f(txImpl{b, tx})
})
}
func (r impl) ReadWrite(f func(kvio.ReadWriteTx) error) error {
return r.db.Update(func(tx *bbolt.Tx) error {
b := tx.Bucket(defaultBucket)
if b == nil {
return ErrNoDefaultBucket
}
return f(txImpl{b, tx})
})
}
func (r impl) Stats() (kvio.Stats, error) {
var keyCount uint64
err := r.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(defaultBucket)
if b != nil {
keyCount = uint64(b.Stats().KeyN)
}
return nil
})
if err != nil {
return kvio.Stats{}, fmt.Errorf("could not read write-cache DB counter: %w", err)
}
return kvio.Stats{
KeyCount: keyCount,
}, nil
}
func (r impl) Close() error { return r.db.Close() }