lnd.xprv/kvdb/etcd/bucket.go

132 lines
3.6 KiB
Go
Raw Permalink Normal View History

// +build kvdb_etcd
package etcd
import (
"crypto/sha256"
)
const (
bucketIDLength = 32
)
var (
valuePostfix = []byte{0x00}
bucketPostfix = []byte{0xFF}
sequencePrefix = []byte("$seq$")
)
// makeBucketID returns a deterministic key for the passed byte slice.
// Currently it returns the sha256 hash of the slice.
func makeBucketID(key []byte) [bucketIDLength]byte {
return sha256.Sum256(key)
}
// isValidBucketID checks if the passed slice is the required length to be a
// valid bucket id.
func isValidBucketID(s []byte) bool {
return len(s) == bucketIDLength
}
// makeKey concatenates parent, key and postfix into one byte slice.
// The postfix indicates the use of this key (whether bucket or value), while
// parent refers to the parent bucket.
func makeKey(parent, key, postfix []byte) []byte {
keyBuf := make([]byte, len(parent)+len(key)+len(postfix))
copy(keyBuf, parent)
copy(keyBuf[len(parent):], key)
copy(keyBuf[len(parent)+len(key):], postfix)
return keyBuf
}
// makeBucketKey returns a bucket key from the passed parent bucket id and
// the key.
func makeBucketKey(parent []byte, key []byte) []byte {
return makeKey(parent, key, bucketPostfix)
}
// makeValueKey returns a value key from the passed parent bucket id and
// the key.
func makeValueKey(parent []byte, key []byte) []byte {
return makeKey(parent, key, valuePostfix)
}
// makeSequenceKey returns a sequence key of the passed parent bucket id.
func makeSequenceKey(parent []byte) []byte {
keyBuf := make([]byte, len(sequencePrefix)+len(parent))
copy(keyBuf, sequencePrefix)
copy(keyBuf[len(sequencePrefix):], parent)
return keyBuf
}
// isBucketKey returns true if the passed key is a bucket key, meaning it
// keys a bucket name.
func isBucketKey(key string) bool {
if len(key) < bucketIDLength+1 {
return false
}
return key[len(key)-1] == bucketPostfix[0]
}
// getKey chops out the key from the raw key (by removing the bucket id
// prefixing the key and the postfix indicating whether it is a bucket or
// a value key)
func getKey(rawKey string) []byte {
return []byte(rawKey[bucketIDLength : len(rawKey)-1])
}
// getKeyVal chops out the key from the raw key (by removing the bucket id
// prefixing the key and the postfix indicating whether it is a bucket or
// a value key) and also returns the appropriate value for the key, which is
// nil in case of buckets (or the set value otherwise).
func getKeyVal(kv *KV) ([]byte, []byte) {
var val []byte
if !isBucketKey(kv.key) {
val = []byte(kv.val)
}
return getKey(kv.key), val
}
2021-07-06 17:31:24 +03:00
// BucketKey is a helper functon used in tests to create a bucket key from
// passed bucket list.
func BucketKey(buckets ...string) string {
var bucketKey []byte
rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
parent := rootID[:]
for _, bucketName := range buckets {
bucketKey = makeBucketKey(parent, []byte(bucketName))
id := makeBucketID(bucketKey)
parent = id[:]
}
return string(bucketKey)
}
// BucketVal is a helper function used in tests to create a bucket value (the
// value for a bucket key) from the passed bucket list.
func BucketVal(buckets ...string) string {
id := makeBucketID([]byte(BucketKey(buckets...)))
return string(id[:])
}
// ValueKey is a helper function used in tests to create a value key from the
// passed key and bucket list.
func ValueKey(key string, buckets ...string) string {
rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
bucket := rootID[:]
for _, bucketName := range buckets {
bucketKey := makeBucketKey(bucket, []byte(bucketName))
id := makeBucketID(bucketKey)
bucket = id[:]
}
return string(makeValueKey(bucket, []byte(key)))
}