github.com/tendermint/tmlibs@v0.9.0/db/mem_db.go (about)

     1  package db
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  )
     8  
     9  func init() {
    10  	registerDBCreator(MemDBBackend, func(name string, dir string) (DB, error) {
    11  		return NewMemDB(), nil
    12  	}, false)
    13  }
    14  
    15  var _ DB = (*MemDB)(nil)
    16  
    17  type MemDB struct {
    18  	mtx sync.Mutex
    19  	db  map[string][]byte
    20  }
    21  
    22  func NewMemDB() *MemDB {
    23  	database := &MemDB{
    24  		db: make(map[string][]byte),
    25  	}
    26  	return database
    27  }
    28  
    29  // Implements atomicSetDeleter.
    30  func (db *MemDB) Mutex() *sync.Mutex {
    31  	return &(db.mtx)
    32  }
    33  
    34  // Implements DB.
    35  func (db *MemDB) Get(key []byte) []byte {
    36  	db.mtx.Lock()
    37  	defer db.mtx.Unlock()
    38  	key = nonNilBytes(key)
    39  
    40  	value := db.db[string(key)]
    41  	return value
    42  }
    43  
    44  // Implements DB.
    45  func (db *MemDB) Has(key []byte) bool {
    46  	db.mtx.Lock()
    47  	defer db.mtx.Unlock()
    48  	key = nonNilBytes(key)
    49  
    50  	_, ok := db.db[string(key)]
    51  	return ok
    52  }
    53  
    54  // Implements DB.
    55  func (db *MemDB) Set(key []byte, value []byte) {
    56  	db.mtx.Lock()
    57  	defer db.mtx.Unlock()
    58  
    59  	db.SetNoLock(key, value)
    60  }
    61  
    62  // Implements DB.
    63  func (db *MemDB) SetSync(key []byte, value []byte) {
    64  	db.mtx.Lock()
    65  	defer db.mtx.Unlock()
    66  
    67  	db.SetNoLock(key, value)
    68  }
    69  
    70  // Implements atomicSetDeleter.
    71  func (db *MemDB) SetNoLock(key []byte, value []byte) {
    72  	db.SetNoLockSync(key, value)
    73  }
    74  
    75  // Implements atomicSetDeleter.
    76  func (db *MemDB) SetNoLockSync(key []byte, value []byte) {
    77  	key = nonNilBytes(key)
    78  	value = nonNilBytes(value)
    79  
    80  	db.db[string(key)] = value
    81  }
    82  
    83  // Implements DB.
    84  func (db *MemDB) Delete(key []byte) {
    85  	db.mtx.Lock()
    86  	defer db.mtx.Unlock()
    87  
    88  	db.DeleteNoLock(key)
    89  }
    90  
    91  // Implements DB.
    92  func (db *MemDB) DeleteSync(key []byte) {
    93  	db.mtx.Lock()
    94  	defer db.mtx.Unlock()
    95  
    96  	db.DeleteNoLock(key)
    97  }
    98  
    99  // Implements atomicSetDeleter.
   100  func (db *MemDB) DeleteNoLock(key []byte) {
   101  	db.DeleteNoLockSync(key)
   102  }
   103  
   104  // Implements atomicSetDeleter.
   105  func (db *MemDB) DeleteNoLockSync(key []byte) {
   106  	key = nonNilBytes(key)
   107  
   108  	delete(db.db, string(key))
   109  }
   110  
   111  // Implements DB.
   112  func (db *MemDB) Close() {
   113  	// Close is a noop since for an in-memory
   114  	// database, we don't have a destination
   115  	// to flush contents to nor do we want
   116  	// any data loss on invoking Close()
   117  	// See the discussion in https://github.com/tendermint/tmlibs/pull/56
   118  }
   119  
   120  // Implements DB.
   121  func (db *MemDB) Print() {
   122  	db.mtx.Lock()
   123  	defer db.mtx.Unlock()
   124  
   125  	for key, value := range db.db {
   126  		fmt.Printf("[%X]:\t[%X]\n", []byte(key), value)
   127  	}
   128  }
   129  
   130  // Implements DB.
   131  func (db *MemDB) Stats() map[string]string {
   132  	db.mtx.Lock()
   133  	defer db.mtx.Unlock()
   134  
   135  	stats := make(map[string]string)
   136  	stats["database.type"] = "memDB"
   137  	stats["database.size"] = fmt.Sprintf("%d", len(db.db))
   138  	return stats
   139  }
   140  
   141  // Implements DB.
   142  func (db *MemDB) NewBatch() Batch {
   143  	db.mtx.Lock()
   144  	defer db.mtx.Unlock()
   145  
   146  	return &memBatch{db, nil}
   147  }
   148  
   149  //----------------------------------------
   150  // Iterator
   151  
   152  // Implements DB.
   153  func (db *MemDB) Iterator(start, end []byte) Iterator {
   154  	db.mtx.Lock()
   155  	defer db.mtx.Unlock()
   156  
   157  	keys := db.getSortedKeys(start, end, false)
   158  	return newMemDBIterator(db, keys, start, end)
   159  }
   160  
   161  // Implements DB.
   162  func (db *MemDB) ReverseIterator(start, end []byte) Iterator {
   163  	db.mtx.Lock()
   164  	defer db.mtx.Unlock()
   165  
   166  	keys := db.getSortedKeys(start, end, true)
   167  	return newMemDBIterator(db, keys, start, end)
   168  }
   169  
   170  // We need a copy of all of the keys.
   171  // Not the best, but probably not a bottleneck depending.
   172  type memDBIterator struct {
   173  	db    DB
   174  	cur   int
   175  	keys  []string
   176  	start []byte
   177  	end   []byte
   178  }
   179  
   180  var _ Iterator = (*memDBIterator)(nil)
   181  
   182  // Keys is expected to be in reverse order for reverse iterators.
   183  func newMemDBIterator(db DB, keys []string, start, end []byte) *memDBIterator {
   184  	return &memDBIterator{
   185  		db:    db,
   186  		cur:   0,
   187  		keys:  keys,
   188  		start: start,
   189  		end:   end,
   190  	}
   191  }
   192  
   193  // Implements Iterator.
   194  func (itr *memDBIterator) Domain() ([]byte, []byte) {
   195  	return itr.start, itr.end
   196  }
   197  
   198  // Implements Iterator.
   199  func (itr *memDBIterator) Valid() bool {
   200  	return 0 <= itr.cur && itr.cur < len(itr.keys)
   201  }
   202  
   203  // Implements Iterator.
   204  func (itr *memDBIterator) Next() {
   205  	itr.assertIsValid()
   206  	itr.cur++
   207  }
   208  
   209  // Implements Iterator.
   210  func (itr *memDBIterator) Key() []byte {
   211  	itr.assertIsValid()
   212  	return []byte(itr.keys[itr.cur])
   213  }
   214  
   215  // Implements Iterator.
   216  func (itr *memDBIterator) Value() []byte {
   217  	itr.assertIsValid()
   218  	key := []byte(itr.keys[itr.cur])
   219  	return itr.db.Get(key)
   220  }
   221  
   222  // Implements Iterator.
   223  func (itr *memDBIterator) Close() {
   224  	itr.keys = nil
   225  	itr.db = nil
   226  }
   227  
   228  func (itr *memDBIterator) assertIsValid() {
   229  	if !itr.Valid() {
   230  		panic("memDBIterator is invalid")
   231  	}
   232  }
   233  
   234  //----------------------------------------
   235  // Misc.
   236  
   237  func (db *MemDB) getSortedKeys(start, end []byte, reverse bool) []string {
   238  	keys := []string{}
   239  	for key := range db.db {
   240  		inDomain := IsKeyInDomain([]byte(key), start, end, reverse)
   241  		if inDomain {
   242  			keys = append(keys, key)
   243  		}
   244  	}
   245  	sort.Strings(keys)
   246  	if reverse {
   247  		nkeys := len(keys)
   248  		for i := 0; i < nkeys/2; i++ {
   249  			temp := keys[i]
   250  			keys[i] = keys[nkeys-i-1]
   251  			keys[nkeys-i-1] = temp
   252  		}
   253  	}
   254  	return keys
   255  }