github.com/iotexproject/iotex-core@v1.14.1-rc1/db/kvstore_impl.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 "context" 10 11 "github.com/pkg/errors" 12 13 "github.com/iotexproject/go-pkgs/cache" 14 "github.com/iotexproject/iotex-core/db/batch" 15 "github.com/iotexproject/iotex-core/pkg/util/byteutil" 16 ) 17 18 var ( 19 // ErrBucketNotExist indicates certain bucket does not exist in db 20 ErrBucketNotExist = errors.New("bucket not exist in DB") 21 // ErrNotExist indicates certain item does not exist in Blockchain database 22 ErrNotExist = errors.New("not exist in DB") 23 // ErrIO indicates the generic error of DB I/O operation 24 ErrIO = errors.New("DB I/O operation error") 25 // ErrNotSupported indicates that api is not supported 26 ErrNotSupported = errors.New("not supported") 27 ) 28 29 const ( 30 _keyDelimiter = "." 31 ) 32 33 // memKVStore is the in-memory implementation of KVStore for testing purpose 34 type memKVStore struct { 35 data cache.LRUCache 36 bucket cache.LRUCache 37 } 38 39 // NewMemKVStore instantiates an in-memory KV store 40 func NewMemKVStore() KVStoreForRangeIndex { 41 return &memKVStore{ 42 bucket: cache.NewThreadSafeLruCache(0), 43 data: cache.NewThreadSafeLruCache(0), 44 } 45 } 46 47 func (m *memKVStore) Start(_ context.Context) error { return nil } 48 49 func (m *memKVStore) Stop(_ context.Context) error { return nil } 50 51 // Put inserts a <key, value> record 52 func (m *memKVStore) Put(namespace string, key, value []byte) error { 53 if _, ok := m.bucket.Get(namespace); !ok { 54 m.bucket.Add(namespace, struct{}{}) 55 } 56 m.data.Add(namespace+_keyDelimiter+string(key), value) 57 return nil 58 } 59 60 func (m *memKVStore) Insert(name []byte, key uint64, value []byte) error { 61 return ErrNotSupported 62 } 63 64 func (m *memKVStore) Purge(name []byte, key uint64) error { 65 return ErrNotSupported 66 } 67 68 func (m *memKVStore) Remove(name []byte, key uint64) error { 69 return ErrNotSupported 70 } 71 72 func (m *memKVStore) SeekPrev(name []byte, key uint64) ([]byte, error) { 73 return nil, ErrNotSupported 74 } 75 76 func (m *memKVStore) SeekNext(name []byte, key uint64) ([]byte, error) { 77 return nil, ErrNotSupported 78 } 79 80 // Get retrieves a record 81 func (m *memKVStore) Get(namespace string, key []byte) ([]byte, error) { 82 if _, ok := m.bucket.Get(namespace); !ok { 83 return nil, errors.Wrapf(ErrNotExist, "namespace = %x doesn't exist", []byte(namespace)) 84 } 85 value, _ := m.data.Get(namespace + _keyDelimiter + string(key)) 86 if value != nil { 87 return value.([]byte), nil 88 } 89 return nil, errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key) 90 } 91 92 // Get retrieves a record 93 func (m *memKVStore) Range(namespace string, key []byte, count uint64) ([][]byte, error) { 94 if _, ok := m.bucket.Get(namespace); !ok { 95 return nil, errors.Wrapf(ErrNotExist, "namespace = %s doesn't exist", namespace) 96 } 97 value := make([][]byte, count) 98 start := byteutil.BytesToUint64BigEndian(key) 99 for i := uint64(0); i < count; i++ { 100 key = byteutil.Uint64ToBytesBigEndian(start + i) 101 v, _ := m.data.Get(namespace + _keyDelimiter + string(key)) 102 if v == nil { 103 return nil, errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key) 104 } 105 value[i] = make([]byte, len(v.([]byte))) 106 copy(value[i], v.([]byte)) 107 } 108 return value, nil 109 } 110 111 // Delete deletes a record 112 func (m *memKVStore) Delete(namespace string, key []byte) error { 113 m.data.Remove(namespace + _keyDelimiter + string(key)) 114 return nil 115 } 116 117 // Filter returns <k, v> pair in a bucket that meet the condition 118 func (m *memKVStore) Filter(namespace string, c Condition, minKey, maxKey []byte) ([][]byte, [][]byte, error) { 119 // TODO: implement filter for memKVStore 120 return nil, nil, errors.New("in-memory KVStore does not support Filter()") 121 } 122 123 // WriteBatch commits a batch 124 func (m *memKVStore) WriteBatch(b batch.KVStoreBatch) (e error) { 125 succeed := false 126 b.Lock() 127 defer func() { 128 if succeed { 129 // clear the batch if commit succeeds 130 b.ClearAndUnlock() 131 } else { 132 b.Unlock() 133 } 134 }() 135 for i := 0; i < b.Size(); i++ { 136 write, err := b.Entry(i) 137 if err != nil { 138 return err 139 } 140 switch write.WriteType() { 141 case batch.Put: 142 if err := m.Put(write.Namespace(), write.Key(), write.Value()); err != nil { 143 e = err 144 } 145 case batch.Delete: 146 if err := m.Delete(write.Namespace(), write.Key()); err != nil { 147 e = err 148 } 149 } 150 if e != nil { 151 break 152 } 153 } 154 if e == nil { 155 succeed = true 156 } 157 158 return e 159 } 160 161 // GetBucketByPrefix retrieves all bucket those with const namespace prefix 162 func (m *memKVStore) GetBucketByPrefix(namespace []byte) ([][]byte, error) { 163 return nil, ErrNotSupported 164 } 165 166 // GetKeyByPrefix retrieves all keys those with const prefix 167 func (m *memKVStore) GetKeyByPrefix(namespace, prefix []byte) ([][]byte, error) { 168 return nil, ErrNotSupported 169 }