github.com/decred/dcrlnd@v0.7.6/kvdb/etcd/bucket.go (about)

     1  //go:build kvdb_etcd
     2  // +build kvdb_etcd
     3  
     4  package etcd
     5  
     6  import (
     7  	"crypto/sha256"
     8  )
     9  
    10  const (
    11  	bucketIDLength = 32
    12  )
    13  
    14  var (
    15  	valuePostfix   = []byte{0x00}
    16  	bucketPostfix  = []byte{0xFF}
    17  	sequencePrefix = []byte("$seq$")
    18  )
    19  
    20  // makeBucketID returns a deterministic key for the passed byte slice.
    21  // Currently it returns the sha256 hash of the slice.
    22  func makeBucketID(key []byte) [bucketIDLength]byte {
    23  	return sha256.Sum256(key)
    24  }
    25  
    26  // isValidBucketID checks if the passed slice is the required length to be a
    27  // valid bucket id.
    28  func isValidBucketID(s []byte) bool {
    29  	return len(s) == bucketIDLength
    30  }
    31  
    32  // makeKey concatenates parent, key and postfix into one byte slice.
    33  // The postfix indicates the use of this key (whether bucket or value), while
    34  // parent refers to the parent bucket.
    35  func makeKey(parent, key, postfix []byte) []byte {
    36  	keyBuf := make([]byte, len(parent)+len(key)+len(postfix))
    37  	copy(keyBuf, parent)
    38  	copy(keyBuf[len(parent):], key)
    39  	copy(keyBuf[len(parent)+len(key):], postfix)
    40  
    41  	return keyBuf
    42  }
    43  
    44  // makeBucketKey returns a bucket key from the passed parent bucket id and
    45  // the key.
    46  func makeBucketKey(parent []byte, key []byte) []byte {
    47  	return makeKey(parent, key, bucketPostfix)
    48  }
    49  
    50  // makeValueKey returns a value key from the passed parent bucket id and
    51  // the key.
    52  func makeValueKey(parent []byte, key []byte) []byte {
    53  	return makeKey(parent, key, valuePostfix)
    54  }
    55  
    56  // makeSequenceKey returns a sequence key of the passed parent bucket id.
    57  func makeSequenceKey(parent []byte) []byte {
    58  	keyBuf := make([]byte, len(sequencePrefix)+len(parent))
    59  	copy(keyBuf, sequencePrefix)
    60  	copy(keyBuf[len(sequencePrefix):], parent)
    61  	return keyBuf
    62  }
    63  
    64  // isBucketKey returns true if the passed key is a bucket key, meaning it
    65  // keys a bucket name.
    66  func isBucketKey(key string) bool {
    67  	if len(key) < bucketIDLength+1 {
    68  		return false
    69  	}
    70  
    71  	return key[len(key)-1] == bucketPostfix[0]
    72  }
    73  
    74  // getKey chops out the key from the raw key (by removing the bucket id
    75  // prefixing the key and the postfix indicating whether it is a bucket or
    76  // a value key)
    77  func getKey(rawKey string) []byte {
    78  	return []byte(rawKey[bucketIDLength : len(rawKey)-1])
    79  }
    80  
    81  // getKeyVal chops out the key from the raw key (by removing the bucket id
    82  // prefixing the key and the postfix indicating whether it is a bucket or
    83  // a value key) and also returns the appropriate value for the key, which is
    84  // nil in case of buckets (or the set value otherwise).
    85  func getKeyVal(kv *KV) ([]byte, []byte) {
    86  	var val []byte
    87  
    88  	if !isBucketKey(kv.key) {
    89  		val = []byte(kv.val)
    90  	}
    91  
    92  	return getKey(kv.key), val
    93  }
    94  
    95  // BucketKey is a helper functon used in tests to create a bucket key from
    96  // passed bucket list.
    97  func BucketKey(buckets ...string) string {
    98  	var bucketKey []byte
    99  
   100  	rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
   101  	parent := rootID[:]
   102  
   103  	for _, bucketName := range buckets {
   104  		bucketKey = makeBucketKey(parent, []byte(bucketName))
   105  		id := makeBucketID(bucketKey)
   106  		parent = id[:]
   107  	}
   108  
   109  	return string(bucketKey)
   110  }
   111  
   112  // BucketVal is a helper function used in tests to create a bucket value (the
   113  // value for a bucket key) from the passed bucket list.
   114  func BucketVal(buckets ...string) string {
   115  	id := makeBucketID([]byte(BucketKey(buckets...)))
   116  	return string(id[:])
   117  }
   118  
   119  // ValueKey is a helper function used in tests to create a value key from the
   120  // passed key and bucket list.
   121  func ValueKey(key string, buckets ...string) string {
   122  	rootID := makeBucketID([]byte(etcdDefaultRootBucketId))
   123  	bucket := rootID[:]
   124  
   125  	for _, bucketName := range buckets {
   126  		bucketKey := makeBucketKey(bucket, []byte(bucketName))
   127  		id := makeBucketID(bucketKey)
   128  		bucket = id[:]
   129  	}
   130  
   131  	return string(makeValueKey(bucket, []byte(key)))
   132  }