github.com/iotexproject/iotex-core@v1.14.1-rc1/db/range_index.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package db 7 8 import ( 9 "github.com/pkg/errors" 10 ) 11 12 var ( 13 // MaxKey is the special key such that bytes.Compare(MaxUint64, MaxKey) = -1 14 MaxKey = []byte{255, 255, 255, 255, 255, 255, 255, 255, 0} 15 // NotExist is the empty byte slice to indicate a key does not exist (as a result of calling Purge()) 16 NotExist = []byte{} 17 ) 18 19 type ( 20 // RangeIndex is a bucket of sparse <k, v> pair, where k consists of 8-byte value 21 // and all keys that falls in 2 consecutive k have the same v 22 // for example, given 3 entries in the bucket: 23 // 24 // k = 0x0000000000000004 ==> v1 25 // k = 0x0000000000000123 ==> v2 26 // k = 0x0000000000005678 ==> v3 27 // 28 // we have: 29 // for all key 0x0 <= k < 0x4, value[k] = initial value 30 // for all key 0x4 <= k < 0x123, value[k] = v1 31 // for all key 0x123 <= k < 0x5678, value[k] = v2 32 // for all key k >= 0x5678, value[k] = v3 33 // 34 RangeIndex interface { 35 // Insert inserts a value into the index 36 Insert(uint64, []byte) error 37 // Get returns value by the key 38 Get(uint64) ([]byte, error) 39 // Delete deletes an existing key 40 Delete(uint64) error 41 // Purge deletes an existing key and all keys before it 42 Purge(uint64) error 43 // Close makes the index not usable 44 Close() 45 } 46 47 // rangeIndex is RangeIndex implementation based on bolt DB 48 rangeIndex struct { 49 kvStore KVStoreForRangeIndex 50 bucket []byte 51 } 52 ) 53 54 // NewRangeIndex creates a new instance of rangeIndex 55 func NewRangeIndex(kv KVStore, name, init []byte) (RangeIndex, error) { 56 if kv == nil { 57 return nil, errors.Wrap(ErrInvalid, "KVStore object is nil") 58 } 59 kvRange, ok := kv.(KVStoreForRangeIndex) 60 if !ok { 61 return nil, errors.Wrap(ErrInvalid, "range index can only be created from KVStoreForRangeIndex") 62 } 63 if len(name) == 0 { 64 return nil, errors.Wrap(ErrInvalid, "bucket name is nil") 65 } 66 // check whether init value exist or not 67 v, err := kv.Get(string(name), MaxKey) 68 if errors.Cause(err) == ErrNotExist || v == nil { 69 // write the initial value 70 if err := kv.Put(string(name), MaxKey, init); err != nil { 71 return nil, errors.Wrapf(err, "failed to create range index %x", name) 72 } 73 } 74 75 bucket := make([]byte, len(name)) 76 copy(bucket, name) 77 78 return &rangeIndex{ 79 kvStore: kvRange, 80 bucket: bucket, 81 }, nil 82 } 83 84 // Insert inserts a value into the index 85 func (r *rangeIndex) Insert(key uint64, value []byte) error { 86 if key == 0 { 87 // by definition, Get(0) = initial value 88 // so insert 0 is not allowed 89 return errors.New("cannot insert 0 for range index") 90 } 91 return r.kvStore.Insert(r.bucket, key, value) 92 } 93 94 // Get returns value by the key 95 func (r *rangeIndex) Get(key uint64) ([]byte, error) { 96 return r.kvStore.SeekNext(r.bucket, key) 97 } 98 99 // Delete deletes an existing key 100 func (r *rangeIndex) Delete(key uint64) error { 101 return r.kvStore.Remove(r.bucket, key) 102 } 103 104 // Purge deletes an existing key and all keys before it 105 func (r *rangeIndex) Purge(key uint64) error { 106 return r.kvStore.Purge(r.bucket, key) 107 } 108 109 // Close makes the index not usable 110 func (r *rangeIndex) Close() { 111 // frees reference to db, the db object itself will be closed/freed by its owner, not here 112 r.kvStore = nil 113 r.bucket = nil 114 }