You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

226 lines
4.2 KiB

package db
import (
"fmt"
"sort"
"sync"
)
func init() {
registerDBCreator(MemDBBackendStr, func(name string, dir string) (DB, error) {
return NewMemDB(), nil
}, false)
}
var _ DB = (*MemDB)(nil)
type MemDB struct {
mtx sync.Mutex
db map[string][]byte
}
func NewMemDB() *MemDB {
database := &MemDB{
db: make(map[string][]byte),
}
return database
}
func (db *MemDB) Get(key []byte) []byte {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
return db.db[string(key)]
}
func (db *MemDB) Has(key []byte) bool {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
_, ok := db.db[string(key)]
return ok
}
func (db *MemDB) Set(key []byte, value []byte) {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
db.SetNoLock(key, value)
}
func (db *MemDB) SetSync(key []byte, value []byte) {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
db.SetNoLock(key, value)
}
// NOTE: Implements atomicSetDeleter
func (db *MemDB) SetNoLock(key []byte, value []byte) {
if value == nil {
value = []byte{}
}
panicNilKey(key)
db.db[string(key)] = value
}
func (db *MemDB) Delete(key []byte) {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
delete(db.db, string(key))
}
func (db *MemDB) DeleteSync(key []byte) {
db.mtx.Lock()
defer db.mtx.Unlock()
panicNilKey(key)
delete(db.db, string(key))
}
// NOTE: Implements atomicSetDeleter
func (db *MemDB) DeleteNoLock(key []byte) {
panicNilKey(key)
delete(db.db, string(key))
}
func (db *MemDB) Close() {
// Close is a noop since for an in-memory
// database, we don't have a destination
// to flush contents to nor do we want
// any data loss on invoking Close()
// See the discussion in https://github.com/tendermint/tmlibs/pull/56
}
func (db *MemDB) Print() {
db.mtx.Lock()
defer db.mtx.Unlock()
for key, value := range db.db {
fmt.Printf("[%X]:\t[%X]\n", []byte(key), value)
}
}
func (db *MemDB) Stats() map[string]string {
db.mtx.Lock()
defer db.mtx.Unlock()
stats := make(map[string]string)
stats["database.type"] = "memDB"
stats["database.size"] = fmt.Sprintf("%d", len(db.db))
return stats
}
func (db *MemDB) NewBatch() Batch {
db.mtx.Lock()
defer db.mtx.Unlock()
return &memBatch{db, nil}
}
func (db *MemDB) Mutex() *sync.Mutex {
return &(db.mtx)
}
//----------------------------------------
func (db *MemDB) Iterator(start, end []byte) Iterator {
it := newMemDBIterator(db, start, end)
db.mtx.Lock()
defer db.mtx.Unlock()
// We need a copy of all of the keys.
// Not the best, but probably not a bottleneck depending.
it.keys = db.getSortedKeys(start, end)
return it
}
func (db *MemDB) ReverseIterator(start, end []byte) Iterator {
it := newMemDBIterator(db, start, end)
db.mtx.Lock()
defer db.mtx.Unlock()
// We need a copy of all of the keys.
// Not the best, but probably not a bottleneck depending.
it.keys = db.getSortedKeys(end, start)
// reverse the order
l := len(it.keys) - 1
for i, v := range it.keys {
it.keys[i] = it.keys[l-i]
it.keys[l-i] = v
}
return nil
}
func (db *MemDB) getSortedKeys(start, end []byte) []string {
keys := []string{}
for key, _ := range db.db {
if IsKeyInDomain(key, start, end) {
keys = append(keys, key)
}
}
sort.Strings(keys)
return keys
}
var _ Iterator = (*memDBIterator)(nil)
type memDBIterator struct {
cur int
keys []string
db DB
start, end []byte
}
func newMemDBIterator(db DB, start, end []byte) *memDBIterator {
return &memDBIterator{
db: db,
start: start,
end: end,
}
}
func (it *memDBIterator) Domain() ([]byte, []byte) {
return it.start, it.end
}
func (it *memDBIterator) Valid() bool {
return 0 <= it.cur && it.cur < len(it.keys)
}
func (it *memDBIterator) Next() {
if !it.Valid() {
panic("memDBIterator Next() called when invalid")
}
it.cur++
}
func (it *memDBIterator) Prev() {
if !it.Valid() {
panic("memDBIterator Next() called when invalid")
}
it.cur--
}
func (it *memDBIterator) Key() []byte {
if !it.Valid() {
panic("memDBIterator Key() called when invalid")
}
return []byte(it.keys[it.cur])
}
func (it *memDBIterator) Value() []byte {
if !it.Valid() {
panic("memDBIterator Value() called when invalid")
}
return it.db.Get(it.Key())
}
func (it *memDBIterator) Close() {
it.db = nil
it.keys = nil
}
func (it *memDBIterator) Release() {}