github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/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 // failes 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 keys: keys, 173 values: values, 174 } 175 } 176 177 // NewSnapshot creates a database snapshot based on the current state. 178 // The created snapshot will not be affected by all following mutations 179 // happened on the database. 180 func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { 181 return newSnapshot(db), nil 182 } 183 184 // Stat returns a particular internal stat of the database. 185 func (db *Database) Stat(property string) (string, error) { 186 return "", errors.New("unknown property") 187 } 188 189 // Compact is not supported on a memory database, but there's no need either as 190 // a memory database doesn't waste space anyway. 191 func (db *Database) Compact(start []byte, limit []byte) error { 192 return nil 193 } 194 195 // Len returns the number of entries currently present in the memory database. 196 // 197 // Note, this method is only used for testing (i.e. not public in general) and 198 // does not have explicit checks for closed-ness to allow simpler testing code. 199 func (db *Database) Len() int { 200 db.lock.RLock() 201 defer db.lock.RUnlock() 202 203 return len(db.db) 204 } 205 206 // keyvalue is a key-value tuple tagged with a deletion field to allow creating 207 // memory-database write batches. 208 type keyvalue struct { 209 key []byte 210 value []byte 211 delete bool 212 } 213 214 // batch is a write-only memory batch that commits changes to its host 215 // database when Write is called. A batch cannot be used concurrently. 216 type batch struct { 217 db *Database 218 writes []keyvalue 219 size int 220 } 221 222 // Put inserts the given value into the batch for later committing. 223 func (b *batch) Put(key, value []byte) error { 224 b.writes = append(b.writes, keyvalue{common.CopyBytes(key), common.CopyBytes(value), false}) 225 b.size += len(key) + len(value) 226 return nil 227 } 228 229 // Delete inserts the a key removal into the batch for later committing. 230 func (b *batch) Delete(key []byte) error { 231 b.writes = append(b.writes, keyvalue{common.CopyBytes(key), nil, true}) 232 b.size += len(key) 233 return nil 234 } 235 236 // ValueSize retrieves the amount of data queued up for writing. 237 func (b *batch) ValueSize() int { 238 return b.size 239 } 240 241 // Write flushes any accumulated data to the memory database. 242 func (b *batch) Write() error { 243 b.db.lock.Lock() 244 defer b.db.lock.Unlock() 245 246 for _, keyvalue := range b.writes { 247 if keyvalue.delete { 248 delete(b.db.db, string(keyvalue.key)) 249 continue 250 } 251 b.db.db[string(keyvalue.key)] = keyvalue.value 252 } 253 return nil 254 } 255 256 // Reset resets the batch for reuse. 257 func (b *batch) Reset() { 258 b.writes = b.writes[:0] 259 b.size = 0 260 } 261 262 // Replay replays the batch contents. 263 func (b *batch) Replay(w ethdb.KeyValueWriter) error { 264 for _, keyvalue := range b.writes { 265 if keyvalue.delete { 266 if err := w.Delete(keyvalue.key); err != nil { 267 return err 268 } 269 continue 270 } 271 if err := w.Put(keyvalue.key, keyvalue.value); err != nil { 272 return err 273 } 274 } 275 return nil 276 } 277 278 // iterator can walk over the (potentially partial) keyspace of a memory key 279 // value store. Internally it is a deep copy of the entire iterated state, 280 // sorted by keys. 281 type iterator struct { 282 inited bool 283 keys []string 284 values [][]byte 285 } 286 287 // Next moves the iterator to the next key/value pair. It returns whether the 288 // iterator is exhausted. 289 func (it *iterator) Next() bool { 290 // If the iterator was not yet initialized, do it now 291 if !it.inited { 292 it.inited = true 293 return len(it.keys) > 0 294 } 295 // Iterator already initialize, advance it 296 if len(it.keys) > 0 { 297 it.keys = it.keys[1:] 298 it.values = it.values[1:] 299 } 300 return len(it.keys) > 0 301 } 302 303 // Error returns any accumulated error. Exhausting all the key/value pairs 304 // is not considered to be an error. A memory iterator cannot encounter errors. 305 func (it *iterator) Error() error { 306 return nil 307 } 308 309 // Key returns the key of the current key/value pair, or nil if done. The caller 310 // should not modify the contents of the returned slice, and its contents may 311 // change on the next call to Next. 312 func (it *iterator) Key() []byte { 313 if len(it.keys) > 0 { 314 return []byte(it.keys[0]) 315 } 316 return nil 317 } 318 319 // Value returns the value of the current key/value pair, or nil if done. The 320 // caller should not modify the contents of the returned slice, and its contents 321 // may change on the next call to Next. 322 func (it *iterator) Value() []byte { 323 if len(it.values) > 0 { 324 return it.values[0] 325 } 326 return nil 327 } 328 329 // Release releases associated resources. Release should always succeed and can 330 // be called multiple times without causing error. 331 func (it *iterator) Release() { 332 it.keys, it.values = nil, nil 333 } 334 335 // snapshot wraps a batch of key-value entries deep copied from the in-memory 336 // database for implementing the Snapshot interface. 337 type snapshot struct { 338 db map[string][]byte 339 lock sync.RWMutex 340 } 341 342 // newSnapshot initializes the snapshot with the given database instance. 343 func newSnapshot(db *Database) *snapshot { 344 db.lock.RLock() 345 defer db.lock.RUnlock() 346 347 copied := make(map[string][]byte) 348 for key, val := range db.db { 349 copied[key] = common.CopyBytes(val) 350 } 351 return &snapshot{db: copied} 352 } 353 354 // Has retrieves if a key is present in the snapshot backing by a key-value 355 // data store. 356 func (snap *snapshot) Has(key []byte) (bool, error) { 357 snap.lock.RLock() 358 defer snap.lock.RUnlock() 359 360 if snap.db == nil { 361 return false, errSnapshotReleased 362 } 363 _, ok := snap.db[string(key)] 364 return ok, nil 365 } 366 367 // Get retrieves the given key if it's present in the snapshot backing by 368 // key-value data store. 369 func (snap *snapshot) Get(key []byte) ([]byte, error) { 370 snap.lock.RLock() 371 defer snap.lock.RUnlock() 372 373 if snap.db == nil { 374 return nil, errSnapshotReleased 375 } 376 if entry, ok := snap.db[string(key)]; ok { 377 return common.CopyBytes(entry), nil 378 } 379 return nil, errMemorydbNotFound 380 } 381 382 // Release releases associated resources. Release should always succeed and can 383 // be called multiple times without causing error. 384 func (snap *snapshot) Release() { 385 snap.lock.Lock() 386 defer snap.lock.Unlock() 387 388 snap.db = nil 389 }