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 }