github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/db/memdb/mem_db.go (about)

     1  package memdb
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  
     8  	dbm "github.com/gnolang/gno/tm2/pkg/db"
     9  	"github.com/gnolang/gno/tm2/pkg/db/internal"
    10  	"github.com/gnolang/gno/tm2/pkg/strings"
    11  )
    12  
    13  func init() {
    14  	dbm.InternalRegisterDBCreator(dbm.MemDBBackend, func(name, dir string) (dbm.DB, error) {
    15  		return NewMemDB(), nil
    16  	}, false)
    17  }
    18  
    19  var _ dbm.DB = (*MemDB)(nil)
    20  
    21  type MemDB struct {
    22  	mtx sync.Mutex
    23  	db  map[string][]byte
    24  }
    25  
    26  func NewMemDB() *MemDB {
    27  	database := &MemDB{
    28  		db: make(map[string][]byte),
    29  	}
    30  	return database
    31  }
    32  
    33  // Implements internal.AtomicSetDeleter.
    34  func (db *MemDB) Mutex() *sync.Mutex {
    35  	return &(db.mtx)
    36  }
    37  
    38  // Implements DB.
    39  func (db *MemDB) Get(key []byte) []byte {
    40  	db.mtx.Lock()
    41  	defer db.mtx.Unlock()
    42  	key = internal.NonNilBytes(key)
    43  
    44  	value := db.db[string(key)]
    45  	return value
    46  }
    47  
    48  // Implements DB.
    49  func (db *MemDB) Has(key []byte) bool {
    50  	db.mtx.Lock()
    51  	defer db.mtx.Unlock()
    52  	key = internal.NonNilBytes(key)
    53  
    54  	_, ok := db.db[string(key)]
    55  	return ok
    56  }
    57  
    58  // Implements DB.
    59  func (db *MemDB) Set(key []byte, value []byte) {
    60  	db.mtx.Lock()
    61  	defer db.mtx.Unlock()
    62  
    63  	db.SetNoLock(key, value)
    64  }
    65  
    66  // Implements DB.
    67  func (db *MemDB) SetSync(key []byte, value []byte) {
    68  	db.mtx.Lock()
    69  	defer db.mtx.Unlock()
    70  
    71  	db.SetNoLock(key, value)
    72  }
    73  
    74  // Implements internal.AtomicSetDeleter.
    75  func (db *MemDB) SetNoLock(key []byte, value []byte) {
    76  	db.SetNoLockSync(key, value)
    77  }
    78  
    79  // Implements internal.AtomicSetDeleter.
    80  func (db *MemDB) SetNoLockSync(key []byte, value []byte) {
    81  	key = internal.NonNilBytes(key)
    82  	value = internal.NonNilBytes(value)
    83  
    84  	db.db[string(key)] = value
    85  }
    86  
    87  // Implements DB.
    88  func (db *MemDB) Delete(key []byte) {
    89  	db.mtx.Lock()
    90  	defer db.mtx.Unlock()
    91  
    92  	db.DeleteNoLock(key)
    93  }
    94  
    95  // Implements DB.
    96  func (db *MemDB) DeleteSync(key []byte) {
    97  	db.mtx.Lock()
    98  	defer db.mtx.Unlock()
    99  
   100  	db.DeleteNoLock(key)
   101  }
   102  
   103  // Implements internal.AtomicSetDeleter.
   104  func (db *MemDB) DeleteNoLock(key []byte) {
   105  	db.DeleteNoLockSync(key)
   106  }
   107  
   108  // Implements internal.AtomicSetDeleter.
   109  func (db *MemDB) DeleteNoLockSync(key []byte) {
   110  	key = internal.NonNilBytes(key)
   111  
   112  	delete(db.db, string(key))
   113  }
   114  
   115  // Implements DB.
   116  func (db *MemDB) Close() {
   117  	// Close is a noop since for an in-memory
   118  	// database, we don't have a destination
   119  	// to flush contents to nor do we want
   120  	// any data loss on invoking Close()
   121  	// See the discussion in https://github.com/tendermint/classic/libs/pull/56
   122  }
   123  
   124  // Implements DB.
   125  func (db *MemDB) Print() {
   126  	db.mtx.Lock()
   127  	defer db.mtx.Unlock()
   128  
   129  	for key, value := range db.db {
   130  		var keystr, valstr string
   131  		if strings.IsASCIIText(key) {
   132  			keystr = key
   133  		} else {
   134  			keystr = fmt.Sprintf("0x%X", []byte(key))
   135  		}
   136  		if strings.IsASCIIText(string(value)) {
   137  			valstr = string(value)
   138  		} else {
   139  			valstr = fmt.Sprintf("0x%X", value)
   140  		}
   141  		fmt.Printf("%s:\t%s\n", keystr, valstr)
   142  	}
   143  }
   144  
   145  // Implements DB.
   146  func (db *MemDB) Stats() map[string]string {
   147  	db.mtx.Lock()
   148  	defer db.mtx.Unlock()
   149  
   150  	stats := make(map[string]string)
   151  	stats["database.type"] = "memDB"
   152  	stats["database.size"] = fmt.Sprintf("%d", len(db.db))
   153  	return stats
   154  }
   155  
   156  // Implements DB.
   157  func (db *MemDB) NewBatch() dbm.Batch {
   158  	db.mtx.Lock()
   159  	defer db.mtx.Unlock()
   160  
   161  	return &internal.MemBatch{db, nil}
   162  }
   163  
   164  // ----------------------------------------
   165  // Iterator
   166  
   167  // Implements DB.
   168  func (db *MemDB) Iterator(start, end []byte) dbm.Iterator {
   169  	db.mtx.Lock()
   170  	defer db.mtx.Unlock()
   171  
   172  	keys := db.getSortedKeys(start, end, false)
   173  	return internal.NewMemIterator(db, keys, start, end)
   174  }
   175  
   176  // Implements DB.
   177  func (db *MemDB) ReverseIterator(start, end []byte) dbm.Iterator {
   178  	db.mtx.Lock()
   179  	defer db.mtx.Unlock()
   180  
   181  	keys := db.getSortedKeys(start, end, true)
   182  	return internal.NewMemIterator(db, keys, start, end)
   183  }
   184  
   185  // ----------------------------------------
   186  // Misc.
   187  
   188  func (db *MemDB) getSortedKeys(start, end []byte, reverse bool) []string {
   189  	keys := []string{}
   190  	for key := range db.db {
   191  		inDomain := dbm.IsKeyInDomain([]byte(key), start, end)
   192  		if inDomain {
   193  			keys = append(keys, key)
   194  		}
   195  	}
   196  	sort.Strings(keys)
   197  	if reverse {
   198  		nkeys := len(keys)
   199  		for i := 0; i < nkeys/2; i++ {
   200  			temp := keys[i]
   201  			keys[i] = keys[nkeys-i-1]
   202  			keys[nkeys-i-1] = temp
   203  		}
   204  	}
   205  	return keys
   206  }