cosmos-sdk/state/kvstore.go

144 lines
2.9 KiB
Go
Raw Normal View History

2017-07-06 05:23:38 -07:00
package state
2016-05-01 13:52:08 -07:00
import (
"sort"
2016-05-02 14:48:29 -07:00
2017-07-25 21:06:12 -07:00
"github.com/tendermint/go-wire/data"
2016-05-01 13:52:08 -07:00
)
// KVStore is a simple interface to get/set data
2016-05-01 13:52:08 -07:00
type KVStore interface {
Set(key, value []byte)
Get(key []byte) (value []byte)
}
//----------------------------------------
// Model grabs together key and value to allow easier return values
2017-07-25 21:06:12 -07:00
type Model struct {
Key data.Bytes
Value data.Bytes
}
// SimpleDB allows us to do some basic range queries on a db
2017-07-25 21:06:12 -07:00
type SimpleDB interface {
KVStore
Has(key []byte) (has bool)
Remove(key []byte) (value []byte) // returns old value if there was one
// Start is inclusive, End is exclusive...
// Thus List ([]byte{12, 13}, []byte{12, 14}) will return anything with
// the prefix []byte{12, 13}
2017-07-25 21:06:12 -07:00
List(start, end []byte, limit int) []Model
First(start, end []byte) Model
Last(start, end []byte) Model
// // Checkpoint returns the same state, but where writes
// // are buffered and don't affect the parent
// Checkpoint() SimpleDB
2017-07-25 21:06:12 -07:00
// // Commit will take all changes from the checkpoint and write
// // them to the parent.
// // Returns an error if this is not a child of this one
// Commit(SimpleDB) error
2017-07-25 21:06:12 -07:00
// Discard will remove reference to this
Discard()
}
//----------------------------------------
2016-05-01 13:52:08 -07:00
type MemKVStore struct {
m map[string][]byte
}
var _ SimpleDB = NewMemKVStore()
2016-05-01 13:52:08 -07:00
func NewMemKVStore() *MemKVStore {
return &MemKVStore{
m: make(map[string][]byte, 0),
}
}
func (mkv *MemKVStore) Set(key []byte, value []byte) {
mkv.m[string(key)] = value
}
func (mkv *MemKVStore) Get(key []byte) (value []byte) {
return mkv.m[string(key)]
}
func (mkv *MemKVStore) Has(key []byte) (has bool) {
_, ok := mkv.m[string(key)]
return ok
2016-05-01 13:52:08 -07:00
}
func (mkv *MemKVStore) Remove(key []byte) (value []byte) {
val := mkv.m[string(key)]
delete(mkv.m, string(key))
return val
2016-05-01 13:52:08 -07:00
}
func (mkv *MemKVStore) List(start, end []byte, limit int) []Model {
keys := mkv.keysInRange(start, end)
sort.Strings(keys)
keys = keys[:limit]
2017-01-29 18:42:25 -08:00
res := make([]Model, len(keys))
for i, k := range keys {
res[i] = Model{
Key: []byte(k),
Value: mkv.m[k],
}
}
return res
2016-05-01 13:52:08 -07:00
}
// First iterates through all keys to find the one that matches
func (mkv *MemKVStore) First(start, end []byte) Model {
key := ""
for _, k := range mkv.keysInRange(start, end) {
if key == "" || k < key {
key = k
}
2017-01-29 18:42:25 -08:00
}
if key == "" {
return Model{}
}
return Model{
Key: []byte(key),
Value: mkv.m[key],
2016-05-01 13:52:08 -07:00
}
}
func (mkv *MemKVStore) Last(start, end []byte) Model {
key := ""
for _, k := range mkv.keysInRange(start, end) {
if key == "" || k > key {
key = k
2017-01-29 18:42:25 -08:00
}
2016-05-02 14:48:29 -07:00
}
if key == "" {
return Model{}
}
return Model{
Key: []byte(key),
Value: mkv.m[key],
2016-05-01 13:52:08 -07:00
}
}
2016-05-02 14:48:29 -07:00
func (mkv *MemKVStore) Discard() {
mkv.m = make(map[string][]byte, 0)
}
2016-05-02 14:48:29 -07:00
func (mkv *MemKVStore) keysInRange(start, end []byte) (res []string) {
s, e := string(start), string(end)
for k := range mkv.m {
if k >= s && k < e {
res = append(res, k)
2016-05-02 14:48:29 -07:00
}
}
return
2016-05-02 14:48:29 -07:00
}