tendermint/db/prefix_db.go

264 lines
5.1 KiB
Go

package db
import (
"bytes"
"fmt"
"sync"
)
// IteratePrefix is a convenience function for iterating over a key domain
// restricted by prefix.
func IteratePrefix(db DB, prefix []byte) Iterator {
var start, end []byte
if len(prefix) == 0 {
start = nil
end = nil
} else {
start = cp(prefix)
end = cpIncr(prefix)
}
return db.Iterator(start, end)
}
/*
TODO: Make test, maybe rename.
// Like IteratePrefix but the iterator strips the prefix from the keys.
func IteratePrefixStripped(db DB, prefix []byte) Iterator {
return newUnprefixIterator(prefix, IteratePrefix(db, prefix))
}
*/
//----------------------------------------
// prefixDB
type prefixDB struct {
mtx sync.Mutex
prefix []byte
db DB
}
// NewPrefixDB lets you namespace multiple DBs within a single DB.
func NewPrefixDB(db DB, prefix []byte) *prefixDB {
return &prefixDB{
prefix: prefix,
db: db,
}
}
// Implements atomicSetDeleter.
func (pdb *prefixDB) Mutex() *sync.Mutex {
return &(pdb.mtx)
}
// Implements DB.
func (pdb *prefixDB) Get(key []byte) []byte {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
return pdb.db.Get(pdb.prefixed(key))
}
// Implements DB.
func (pdb *prefixDB) Has(key []byte) bool {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
return pdb.db.Has(pdb.prefixed(key))
}
// Implements DB.
func (pdb *prefixDB) Set(key []byte, value []byte) {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pdb.db.Set(pdb.prefixed(key), value)
}
// Implements DB.
func (pdb *prefixDB) SetSync(key []byte, value []byte) {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pdb.db.SetSync(pdb.prefixed(key), value)
}
// Implements atomicSetDeleter.
func (pdb *prefixDB) SetNoLock(key []byte, value []byte) {
pdb.db.Set(pdb.prefixed(key), value)
}
// Implements atomicSetDeleter.
func (pdb *prefixDB) SetNoLockSync(key []byte, value []byte) {
pdb.db.SetSync(pdb.prefixed(key), value)
}
// Implements DB.
func (pdb *prefixDB) Delete(key []byte) {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pdb.db.Delete(pdb.prefixed(key))
}
// Implements DB.
func (pdb *prefixDB) DeleteSync(key []byte) {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pdb.db.DeleteSync(pdb.prefixed(key))
}
// Implements atomicSetDeleter.
func (pdb *prefixDB) DeleteNoLock(key []byte) {
pdb.db.Delete(pdb.prefixed(key))
}
// Implements atomicSetDeleter.
func (pdb *prefixDB) DeleteNoLockSync(key []byte) {
pdb.db.DeleteSync(pdb.prefixed(key))
}
// Implements DB.
func (pdb *prefixDB) Iterator(start, end []byte) Iterator {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pstart := append(pdb.prefix, start...)
pend := []byte(nil)
if end != nil {
pend = append(pdb.prefix, end...)
}
return newUnprefixIterator(
pdb.prefix,
pdb.db.Iterator(
pstart,
pend,
),
)
}
// Implements DB.
func (pdb *prefixDB) ReverseIterator(start, end []byte) Iterator {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pstart := []byte(nil)
if start != nil {
pstart = append(pdb.prefix, start...)
}
pend := []byte(nil)
if end != nil {
pend = append(pdb.prefix, end...)
}
return newUnprefixIterator(
pdb.prefix,
pdb.db.ReverseIterator(
pstart,
pend,
),
)
}
// Implements DB.
func (pdb *prefixDB) NewBatch() Batch {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
return &memBatch{pdb, nil}
}
// Implements DB.
func (pdb *prefixDB) Close() {
pdb.mtx.Lock()
defer pdb.mtx.Unlock()
pdb.db.Close()
}
// Implements DB.
func (pdb *prefixDB) Print() {
fmt.Printf("prefix: %X\n", pdb.prefix)
itr := pdb.Iterator(nil, nil)
defer itr.Close()
for ; itr.Valid(); itr.Next() {
key := itr.Key()
value := itr.Value()
fmt.Printf("[%X]:\t[%X]\n", key, value)
}
}
// Implements DB.
func (pdb *prefixDB) Stats() map[string]string {
stats := make(map[string]string)
stats["prefixdb.prefix.string"] = string(pdb.prefix)
stats["prefixdb.prefix.hex"] = fmt.Sprintf("%X", pdb.prefix)
source := pdb.db.Stats()
for key, value := range source {
stats["prefixdb.source."+key] = value
}
return stats
}
func (pdb *prefixDB) prefixed(key []byte) []byte {
return append(pdb.prefix, key...)
}
//----------------------------------------
// Strips prefix while iterating from Iterator.
type unprefixIterator struct {
prefix []byte
source Iterator
}
func newUnprefixIterator(prefix []byte, source Iterator) unprefixIterator {
return unprefixIterator{
prefix: prefix,
source: source,
}
}
func (itr unprefixIterator) Domain() (start []byte, end []byte) {
start, end = itr.source.Domain()
if len(start) > 0 {
start = stripPrefix(start, itr.prefix)
}
if len(end) > 0 {
end = stripPrefix(end, itr.prefix)
}
return
}
func (itr unprefixIterator) Valid() bool {
return itr.source.Valid()
}
func (itr unprefixIterator) Next() {
itr.source.Next()
}
func (itr unprefixIterator) Key() (key []byte) {
return stripPrefix(itr.source.Key(), itr.prefix)
}
func (itr unprefixIterator) Value() (value []byte) {
return itr.source.Value()
}
func (itr unprefixIterator) Close() {
itr.source.Close()
}
//----------------------------------------
func stripPrefix(key []byte, prefix []byte) (stripped []byte) {
if len(key) < len(prefix) {
panic("should not happen")
}
if !bytes.Equal(key[:len(prefix)], prefix) {
panic("should not happne")
}
return key[len(prefix):]
}