171 lines
3.7 KiB
Go
171 lines
3.7 KiB
Go
package storm
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
bolt "go.etcd.io/bbolt"
|
|
)
|
|
|
|
// KeyValueStore can store and fetch values by key
|
|
type KeyValueStore interface {
|
|
// Get a value from a bucket
|
|
Get(bucketName string, key interface{}, to interface{}) error
|
|
// Set a key/value pair into a bucket
|
|
Set(bucketName string, key interface{}, value interface{}) error
|
|
// Delete deletes a key from a bucket
|
|
Delete(bucketName string, key interface{}) error
|
|
// GetBytes gets a raw value from a bucket.
|
|
GetBytes(bucketName string, key interface{}) ([]byte, error)
|
|
// SetBytes sets a raw value into a bucket.
|
|
SetBytes(bucketName string, key interface{}, value []byte) error
|
|
// KeyExists reports the presence of a key in a bucket.
|
|
KeyExists(bucketName string, key interface{}) (bool, error)
|
|
}
|
|
|
|
// GetBytes gets a raw value from a bucket.
|
|
func (n *node) GetBytes(bucketName string, key interface{}) ([]byte, error) {
|
|
id, err := toBytes(key, n.codec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var val []byte
|
|
return val, n.readTx(func(tx *bolt.Tx) error {
|
|
raw, err := n.getBytes(tx, bucketName, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
val = make([]byte, len(raw))
|
|
copy(val, raw)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// GetBytes gets a raw value from a bucket.
|
|
func (n *node) getBytes(tx *bolt.Tx, bucketName string, id []byte) ([]byte, error) {
|
|
bucket := n.GetBucket(tx, bucketName)
|
|
if bucket == nil {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
raw := bucket.Get(id)
|
|
if raw == nil {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
return raw, nil
|
|
}
|
|
|
|
// SetBytes sets a raw value into a bucket.
|
|
func (n *node) SetBytes(bucketName string, key interface{}, value []byte) error {
|
|
if key == nil {
|
|
return ErrNilParam
|
|
}
|
|
|
|
id, err := toBytes(key, n.codec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return n.readWriteTx(func(tx *bolt.Tx) error {
|
|
return n.setBytes(tx, bucketName, id, value)
|
|
})
|
|
}
|
|
|
|
func (n *node) setBytes(tx *bolt.Tx, bucketName string, id, data []byte) error {
|
|
bucket, err := n.CreateBucketIfNotExists(tx, bucketName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// save node configuration in the bucket
|
|
_, err = newMeta(bucket, n)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return bucket.Put(id, data)
|
|
}
|
|
|
|
// Get a value from a bucket
|
|
func (n *node) Get(bucketName string, key interface{}, to interface{}) error {
|
|
ref := reflect.ValueOf(to)
|
|
|
|
if !ref.IsValid() || ref.Kind() != reflect.Ptr {
|
|
return ErrPtrNeeded
|
|
}
|
|
|
|
id, err := toBytes(key, n.codec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return n.readTx(func(tx *bolt.Tx) error {
|
|
raw, err := n.getBytes(tx, bucketName, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return n.codec.Unmarshal(raw, to)
|
|
})
|
|
}
|
|
|
|
// Set a key/value pair into a bucket
|
|
func (n *node) Set(bucketName string, key interface{}, value interface{}) error {
|
|
var data []byte
|
|
var err error
|
|
if value != nil {
|
|
data, err = n.codec.Marshal(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return n.SetBytes(bucketName, key, data)
|
|
}
|
|
|
|
// Delete deletes a key from a bucket
|
|
func (n *node) Delete(bucketName string, key interface{}) error {
|
|
id, err := toBytes(key, n.codec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return n.readWriteTx(func(tx *bolt.Tx) error {
|
|
return n.delete(tx, bucketName, id)
|
|
})
|
|
}
|
|
|
|
func (n *node) delete(tx *bolt.Tx, bucketName string, id []byte) error {
|
|
bucket := n.GetBucket(tx, bucketName)
|
|
if bucket == nil {
|
|
return ErrNotFound
|
|
}
|
|
|
|
return bucket.Delete(id)
|
|
}
|
|
|
|
// KeyExists reports the presence of a key in a bucket.
|
|
func (n *node) KeyExists(bucketName string, key interface{}) (bool, error) {
|
|
id, err := toBytes(key, n.codec)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
var exists bool
|
|
return exists, n.readTx(func(tx *bolt.Tx) error {
|
|
bucket := n.GetBucket(tx, bucketName)
|
|
if bucket == nil {
|
|
return ErrNotFound
|
|
}
|
|
|
|
v := bucket.Get(id)
|
|
if v != nil {
|
|
exists = true
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|