github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/kv/utils.go (about) 1 package kv 2 3 import ( 4 "bytes" 5 "context" 6 7 bolt "go.etcd.io/bbolt" 8 "go.opencensus.io/trace" 9 ) 10 11 // lookupValuesForIndices takes in a list of indices and looks up 12 // their corresponding values in the DB, returning a list of 13 // roots which can then be used for batch lookups of their corresponding 14 // objects from the DB. For example, if we are fetching 15 // attestations and we have an index `[]byte("5")` under the shard indices bucket, 16 // we might find roots `0x23` and `0x45` stored under that index. We can then 17 // do a batch read for attestations corresponding to those roots. 18 func lookupValuesForIndices(ctx context.Context, indicesByBucket map[string][]byte, tx *bolt.Tx) [][][]byte { 19 ctx, span := trace.StartSpan(ctx, "BeaconDB.lookupValuesForIndices") 20 defer span.End() 21 values := make([][][]byte, 0, len(indicesByBucket)) 22 for k, v := range indicesByBucket { 23 bkt := tx.Bucket([]byte(k)) 24 roots := bkt.Get(v) 25 splitRoots := make([][]byte, 0, len(roots)/32) 26 for i := 0; i < len(roots); i += 32 { 27 splitRoots = append(splitRoots, roots[i:i+32]) 28 } 29 values = append(values, splitRoots) 30 } 31 return values 32 } 33 34 // updateValueForIndices updates the value for each index by appending it to the previous 35 // values stored at said index. Typically, indices are roots of data that can then 36 // be used for reads or batch reads from the DB. 37 func updateValueForIndices(ctx context.Context, indicesByBucket map[string][]byte, root []byte, tx *bolt.Tx) error { 38 ctx, span := trace.StartSpan(ctx, "BeaconDB.updateValueForIndices") 39 defer span.End() 40 for k, idx := range indicesByBucket { 41 bkt := tx.Bucket([]byte(k)) 42 valuesAtIndex := bkt.Get(idx) 43 if valuesAtIndex == nil { 44 if err := bkt.Put(idx, root); err != nil { 45 return err 46 } 47 } else { 48 // Do not save duplication in indices bucket 49 for i := 0; i < len(valuesAtIndex); i += 32 { 50 if bytes.Equal(valuesAtIndex[i:i+32], root) { 51 return nil 52 } 53 } 54 if err := bkt.Put(idx, append(valuesAtIndex, root...)); err != nil { 55 return err 56 } 57 } 58 } 59 return nil 60 } 61 62 // deleteValueForIndices clears a root stored at each index. 63 func deleteValueForIndices(ctx context.Context, indicesByBucket map[string][]byte, root []byte, tx *bolt.Tx) error { 64 ctx, span := trace.StartSpan(ctx, "BeaconDB.deleteValueForIndices") 65 defer span.End() 66 for k, idx := range indicesByBucket { 67 bkt := tx.Bucket([]byte(k)) 68 valuesAtIndex := bkt.Get(idx) 69 if valuesAtIndex != nil { 70 start := bytes.Index(valuesAtIndex, root) 71 // If the root was not found inside the values at index slice, we continue. 72 // Root must be correctly aligned to avoid matching to subsequences of adjacent values. 73 if start == -1 || start%len(root) != 0 { 74 continue 75 } 76 // We clear out the root from the values at index slice. For example, 77 // If we had [0x32, 0x33, 0x45] and we wanted to clear out 0x33, the code below 78 // updates the slice to [0x32, 0x45]. 79 80 valuesStart := make([]byte, len(valuesAtIndex[:start])) 81 copy(valuesStart, valuesAtIndex[:start]) 82 83 valuesEnd := make([]byte, len(valuesAtIndex[start+len(root):])) 84 copy(valuesEnd, valuesAtIndex[start+len(root):]) 85 86 valuesAtIndex = append(valuesStart, valuesEnd...) 87 88 // If this removes the last value, delete the whole key/value entry. 89 if len(valuesAtIndex) == 0 { 90 if err := bkt.Delete(idx); err != nil { 91 return err 92 } 93 continue 94 } 95 if err := bkt.Put(idx, valuesAtIndex); err != nil { 96 return err 97 } 98 } 99 } 100 return nil 101 }