github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/ethdb/memorydb/memorydb.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package memorydb implements the key-value database layer based on memory maps. 18 package memorydb 19 20 import ( 21 "errors" 22 "sort" 23 "strings" 24 "sync" 25 26 "github.com/ethw3/go-ethereuma/common" 27 "github.com/ethw3/go-ethereuma/ethdb" 28 ) 29 30 var ( 31 // errMemorydbClosed is returned if a memory database was already closed at the 32 // invocation of a data access operation. 33 errMemorydbClosed = errors.New("database closed") 34 35 // errMemorydbNotFound is returned if a key is requested that is not found in 36 // the provided memory database. 37 errMemorydbNotFound = errors.New("not found") 38 39 // errSnapshotReleased is returned if callers want to retrieve data from a 40 // released snapshot. 41 errSnapshotReleased = errors.New("snapshot released") 42 ) 43 44 // Database is an ephemeral key-value store. Apart from basic data storage 45 // functionality it also supports batch writes and iterating over the keyspace in 46 // binary-alphabetical order. 47 type Database struct { 48 db map[string][]byte 49 lock sync.RWMutex 50 } 51 52 // New returns a wrapped map with all the required database interface methods 53 // implemented. 54 func New() *Database { 55 return &Database{ 56 db: make(map[string][]byte), 57 } 58 } 59 60 // NewWithCap returns a wrapped map pre-allocated to the provided capacity with 61 // all the required database interface methods implemented. 62 func NewWithCap(size int) *Database { 63 return &Database{ 64 db: make(map[string][]byte, size), 65 } 66 } 67 68 // Close deallocates the internal map and ensures any consecutive data access op 69 // fails with an error. 70 func (db *Database) Close() error { 71 db.lock.Lock() 72 defer db.lock.Unlock() 73 74 db.db = nil 75 return nil 76 } 77 78 // Has retrieves if a key is present in the key-value store. 79 func (db *Database) Has(key []byte) (bool, error) { 80 db.lock.RLock() 81 defer db.lock.RUnlock() 82 83 if db.db == nil { 84 return false, errMemorydbClosed 85 } 86 _, ok := db.db[string(key)] 87 return ok, nil 88 } 89 90 // Get retrieves the given key if it's present in the key-value store. 91 func (db *Database) Get(key []byte) ([]byte, error) { 92 db.lock.RLock() 93 defer db.lock.RUnlock() 94 95 if db.db == nil { 96 return nil, errMemorydbClosed 97 } 98 if entry, ok := db.db[string(key)]; ok { 99 return common.CopyBytes(entry), nil 100 } 101 return nil, errMemorydbNotFound 102 } 103 104 // Put inserts the given value into the key-value store. 105 func (db *Database) Put(key []byte, value []byte) error { 106 db.lock.Lock() 107 defer db.lock.Unlock() 108 109 if db.db == nil { 110 return errMemorydbClosed 111 } 112 db.db[string(key)] = common.CopyBytes(value) 113 return nil 114 } 115 116 // Delete removes the key from the key-value store. 117 func (db *Database) Delete(key []byte) error { 118 db.lock.Lock() 119 defer db.lock.Unlock() 120 121 if db.db == nil { 122 return errMemorydbClosed 123 } 124 delete(db.db, string(key)) 125 return nil 126 } 127 128 // NewBatch creates a write-only key-value store that buffers changes to its host 129 // database until a final write is called. 130 func (db *Database) NewBatch() ethdb.Batch { 131 return &batch{ 132 db: db, 133 } 134 } 135 136 // NewBatchWithSize creates a write-only database batch with pre-allocated buffer. 137 func (db *Database) NewBatchWithSize(size int) ethdb.Batch { 138 return &batch{ 139 db: db, 140 } 141 } 142 143 // NewIterator creates a binary-alphabetical iterator over a subset 144 // of database content with a particular key prefix, starting at a particular 145 // initial key (or after, if it does not exist). 146 func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { 147 db.lock.RLock() 148 defer db.lock.RUnlock() 149 150 var ( 151 pr = string(prefix) 152 st = string(append(prefix, start...)) 153 keys = make([]string, 0, len(db.db)) 154 values = make([][]byte, 0, len(db.db)) 155 ) 156 // Collect the keys from the memory database corresponding to the given prefix 157 // and start 158 for key := range db.db { 159 if !strings.HasPrefix(key, pr) { 160 continue 161 } 162 if key >= st { 163 keys = append(keys, key) 164 } 165 } 166 // Sort the items and retrieve the associated values 167 sort.Strings(keys) 168 for _, key := range keys { 169 values = append(values, db.db[key]) 170 } 171 return &iterator{ 172 index: -1, 173 keys: keys, 174 values: values, 175 } 176 } 177 178 // NewSnapshot creates a database snapshot based on the current state. 179 // The created snapshot will not be affected by all following mutations 180 // happened on the database. 181 func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { 182 return newSnapshot(db), nil 183 } 184 185 // Stat returns a particular internal stat of the database. 186 func (db *Database) Stat(property string) (string, error) { 187 return "", errors.New("unknown property") 188 } 189 190 // Compact is not supported on a memory database, but there's no need either as 191 // a memory database doesn't waste space anyway. 192 func (db *Database) Compact(start []byte, limit []byte) error { 193 return nil 194 } 195 196 // Len returns the number of entries currently present in the memory database. 197 // 198 // Note, this method is only used for testing (i.e. not public in general) and 199 // does not have explicit checks for closed-ness to allow simpler testing code. 200 func (db *Database) Len() int { 201 db.lock.RLock() 202 defer db.lock.RUnlock() 203 204 return len(db.db) 205 } 206 207 // keyvalue is a key-value tuple tagged with a deletion field to allow creating 208 // memory-database write batches. 209 type keyvalue struct { 210 key []byte 211 value []byte 212 delete bool 213 } 214 215 // batch is a write-only memory batch that commits changes to its host 216 // database when Write is called. A batch cannot be used concurrently. 217 type batch struct { 218 db *Database 219 writes []keyvalue 220 size int 221 } 222 223 // Put inserts the given value into the batch for later committing. 224 func (b *batch) Put(key, value []byte) error { 225 b.writes = append(b.writes, keyvalue{common.CopyBytes(key), common.CopyBytes(value), false}) 226 b.size += len(key) + len(value) 227 return nil 228 } 229 230 // Delete inserts the a key removal into the batch for later committing. 231 func (b *batch) Delete(key []byte) error { 232 b.writes = append(b.writes, keyvalue{common.CopyBytes(key), nil, true}) 233 b.size += len(key) 234 return nil 235 } 236 237 // ValueSize retrieves the amount of data queued up for writing. 238 func (b *batch) ValueSize() int { 239 return b.size 240 } 241 242 // Write flushes any accumulated data to the memory database. 243 func (b *batch) Write() error { 244 b.db.lock.Lock() 245 defer b.db.lock.Unlock() 246 247 for _, keyvalue := range b.writes { 248 if keyvalue.delete { 249 delete(b.db.db, string(keyvalue.key)) 250 continue 251 } 252 b.db.db[string(keyvalue.key)] = keyvalue.value 253 } 254 return nil 255 } 256 257 // Reset resets the batch for reuse. 258 func (b *batch) Reset() { 259 b.writes = b.writes[:0] 260 b.size = 0 261 } 262 263 // Replay replays the batch contents. 264 func (b *batch) Replay(w ethdb.KeyValueWriter) error { 265 for _, keyvalue := range b.writes { 266 if keyvalue.delete { 267 if err := w.Delete(keyvalue.key); err != nil { 268 return err 269 } 270 continue 271 } 272 if err := w.Put(keyvalue.key, keyvalue.value); err != nil { 273 return err 274 } 275 } 276 return nil 277 } 278 279 // iterator can walk over the (potentially partial) keyspace of a memory key 280 // value store. Internally it is a deep copy of the entire iterated state, 281 // sorted by keys. 282 type iterator struct { 283 index int 284 keys []string 285 values [][]byte 286 } 287 288 // Next moves the iterator to the next key/value pair. It returns whether the 289 // iterator is exhausted. 290 func (it *iterator) Next() bool { 291 // Short circuit if iterator is already exhausted in the forward direction. 292 if it.index >= len(it.keys) { 293 return false 294 } 295 it.index += 1 296 return it.index < len(it.keys) 297 } 298 299 // Error returns any accumulated error. Exhausting all the key/value pairs 300 // is not considered to be an error. A memory iterator cannot encounter errors. 301 func (it *iterator) Error() error { 302 return nil 303 } 304 305 // Key returns the key of the current key/value pair, or nil if done. The caller 306 // should not modify the contents of the returned slice, and its contents may 307 // change on the next call to Next. 308 func (it *iterator) Key() []byte { 309 // Short circuit if iterator is not in a valid position 310 if it.index < 0 || it.index >= len(it.keys) { 311 return nil 312 } 313 return []byte(it.keys[it.index]) 314 } 315 316 // Value returns the value of the current key/value pair, or nil if done. The 317 // caller should not modify the contents of the returned slice, and its contents 318 // may change on the next call to Next. 319 func (it *iterator) Value() []byte { 320 // Short circuit if iterator is not in a valid position 321 if it.index < 0 || it.index >= len(it.keys) { 322 return nil 323 } 324 return it.values[it.index] 325 } 326 327 // Release releases associated resources. Release should always succeed and can 328 // be called multiple times without causing error. 329 func (it *iterator) Release() { 330 it.index, it.keys, it.values = -1, nil, nil 331 } 332 333 // snapshot wraps a batch of key-value entries deep copied from the in-memory 334 // database for implementing the Snapshot interface. 335 type snapshot struct { 336 db map[string][]byte 337 lock sync.RWMutex 338 } 339 340 // newSnapshot initializes the snapshot with the given database instance. 341 func newSnapshot(db *Database) *snapshot { 342 db.lock.RLock() 343 defer db.lock.RUnlock() 344 345 copied := make(map[string][]byte) 346 for key, val := range db.db { 347 copied[key] = common.CopyBytes(val) 348 } 349 return &snapshot{db: copied} 350 } 351 352 // Has retrieves if a key is present in the snapshot backing by a key-value 353 // data store. 354 func (snap *snapshot) Has(key []byte) (bool, error) { 355 snap.lock.RLock() 356 defer snap.lock.RUnlock() 357 358 if snap.db == nil { 359 return false, errSnapshotReleased 360 } 361 _, ok := snap.db[string(key)] 362 return ok, nil 363 } 364 365 // Get retrieves the given key if it's present in the snapshot backing by 366 // key-value data store. 367 func (snap *snapshot) Get(key []byte) ([]byte, error) { 368 snap.lock.RLock() 369 defer snap.lock.RUnlock() 370 371 if snap.db == nil { 372 return nil, errSnapshotReleased 373 } 374 if entry, ok := snap.db[string(key)]; ok { 375 return common.CopyBytes(entry), nil 376 } 377 return nil, errMemorydbNotFound 378 } 379 380 // Release releases associated resources. Release should always succeed and can 381 // be called multiple times without causing error. 382 func (snap *snapshot) Release() { 383 snap.lock.Lock() 384 defer snap.lock.Unlock() 385 386 snap.db = nil 387 }