cosmos-sdk/store/iavlstore.go

333 lines
6.9 KiB
Go
Raw Normal View History

2017-11-29 03:08:32 -08:00
package store
import (
2017-12-10 00:24:55 -08:00
"bytes"
"sync"
2017-11-29 04:19:41 -08:00
2017-11-29 03:08:32 -08:00
"github.com/tendermint/iavl"
2017-11-29 04:19:41 -08:00
dbm "github.com/tendermint/tmlibs/db"
2017-11-29 03:08:32 -08:00
)
2017-12-09 12:35:51 -08:00
// NewIAVLStoreLoader returns a CommitStoreLoader that returns an iavlStore
2017-12-10 00:24:55 -08:00
func NewIAVLStoreLoader(db dbm.DB, cacheSize int, numHistory int64) CommitStoreLoader {
2017-12-09 12:35:51 -08:00
l := iavlStoreLoader{
2017-12-10 00:24:55 -08:00
db: db,
2017-12-09 12:35:51 -08:00
cacheSize: cacheSize,
numHistory: numHistory,
2017-11-29 04:19:41 -08:00
}
2017-12-09 12:35:51 -08:00
return l.Load
2017-11-29 04:19:41 -08:00
}
2017-12-09 12:35:51 -08:00
var _ IterKVStore = (*iavlStore)(nil)
var _ CommitStore = (*iavlStore)(nil)
2017-11-29 04:19:41 -08:00
2017-12-09 12:35:51 -08:00
// iavlStore Implements IterKVStore and CommitStore.
type iavlStore struct {
2017-11-29 04:19:41 -08:00
2017-12-09 12:35:51 -08:00
// The underlying tree.
2017-11-29 04:19:41 -08:00
tree *iavl.VersionedTree
2017-11-29 05:07:39 -08:00
2017-12-09 12:35:51 -08:00
// How many old versions we hold onto.
numHistory int64
2017-11-29 04:19:41 -08:00
}
2017-12-09 12:35:51 -08:00
// CONTRACT: tree should be fully loaded.
func newIAVLStore(tree *iavl.VersionedTree, numHistory int64) *iavlStore {
st := &iavlStore{
tree: tree,
numHistory: numHistory,
2017-11-29 05:07:39 -08:00
}
2017-12-09 12:35:51 -08:00
return st
2017-11-29 05:07:39 -08:00
}
2017-12-09 12:35:51 -08:00
// Commit persists the store.
func (st *iavlStore) Commit() CommitID {
2017-11-29 05:07:39 -08:00
2017-12-09 12:35:51 -08:00
// Save a new version.
hash, version, err := st.tree.SaveVersion()
2017-11-29 04:19:41 -08:00
if err != nil {
2017-12-09 12:35:51 -08:00
// TODO: Do we want to extend Commit to allow returning errors?
2017-11-29 04:19:41 -08:00
panic(err)
}
2017-12-09 12:35:51 -08:00
// Release an old version of history
2017-12-10 00:24:55 -08:00
if st.numHistory < st.tree.Version64() {
2017-12-09 12:35:51 -08:00
toRelease := version - st.numHistory
st.tree.DeleteVersion(toRelease)
2017-11-29 04:19:41 -08:00
}
return CommitID{
2017-12-09 12:35:51 -08:00
Version: version,
2017-11-29 04:19:41 -08:00
Hash: hash,
}
2017-11-29 03:08:32 -08:00
}
2017-12-03 22:55:15 -08:00
// CacheWrap implements IterKVStore.
2017-12-10 00:24:55 -08:00
func (st *iavlStore) CacheWrap() CacheWrap {
return st.CacheIterKVStore()
}
// CacheKVStore implements IterKVStore.
func (st *iavlStore) CacheKVStore() CacheKVStore {
2017-12-09 12:35:51 -08:00
return st.CacheIterKVStore()
2017-12-03 22:55:15 -08:00
}
// CacheIterKVStore implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) CacheIterKVStore() CacheIterKVStore {
// XXX Create generic IterKVStore wrapper.
return nil
2017-11-29 05:07:39 -08:00
}
2017-12-03 22:55:15 -08:00
// Set implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) Set(key, value []byte) (prev []byte) {
_, prev = st.tree.Get(key)
st.tree.Set(key, value)
2017-11-29 05:07:39 -08:00
return prev
}
2017-12-03 22:55:15 -08:00
// Get implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) Get(key []byte) (value []byte, exists bool) {
_, v := st.tree.Get(key)
2017-11-29 05:07:39 -08:00
return v, (v != nil)
}
2017-12-03 22:55:15 -08:00
// Has implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) Has(key []byte) (exists bool) {
return st.tree.Has(key)
2017-11-29 05:07:39 -08:00
}
2017-12-03 22:55:15 -08:00
// Remove implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) Remove(key []byte) (prev []byte, removed bool) {
return st.tree.Remove(key)
2017-11-29 05:07:39 -08:00
}
2017-12-03 22:55:15 -08:00
// Iterator implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) Iterator(start, end []byte) Iterator {
2017-12-10 00:24:55 -08:00
return newIAVLIterator(st.tree.Tree(), start, end, true)
}
2017-12-03 22:55:15 -08:00
// ReverseIterator implements IterKVStore.
2017-12-09 12:35:51 -08:00
func (st *iavlStore) ReverseIterator(start, end []byte) Iterator {
2017-12-10 00:24:55 -08:00
return newIAVLIterator(st.tree.Tree(), start, end, false)
}
2017-12-03 22:55:15 -08:00
// First implements IterKVStore.
2017-12-10 00:24:55 -08:00
func (st *iavlStore) First(start, end []byte) (kv KVPair, ok bool) {
iter := st.Iterator(start, end)
if !iter.Valid() {
return kv, false
}
defer iter.Release()
return KVPair{iter.Key(), iter.Value()}, true
}
2017-12-03 22:55:15 -08:00
// Last implements IterKVStore.
2017-12-10 00:24:55 -08:00
func (st *iavlStore) Last(start, end []byte) (kv KVPair, ok bool) {
iter := st.ReverseIterator(end, start)
if !iter.Valid() {
if v, ok := st.Get(start); ok {
return KVPair{cp(start), cp(v)}, true
} else {
return kv, false
}
}
defer iter.Release()
if bytes.Equal(iter.Key(), end) {
// Skip this one, end is exclusive.
iter.Next()
if !iter.Valid() {
return kv, false
}
}
return KVPair{iter.Key(), iter.Value()}, true
}
2017-12-09 12:35:51 -08:00
//----------------------------------------
type iavlIterator struct {
2017-12-10 00:24:55 -08:00
// Underlying store
tree *iavl.Tree
// Domain
start, end []byte
// Iteration order
ascending bool
// Channel to push iteration values.
iterCh chan KVPair
// Close this to release goroutine.
quitCh chan struct{}
// Close this to signal that state is initialized.
initCh chan struct{}
//----------------------------------------
// What follows are mutable state.
mtx sync.Mutex
invalid bool // True once, true forever
key []byte // The current key
value []byte // The current value
}
var _ Iterator = (*iavlIterator)(nil)
2017-12-10 00:24:55 -08:00
// newIAVLIterator will create a new iavlIterator.
// CONTRACT: Caller must release the iavlIterator, as each one creates a new
// goroutine.
func newIAVLIterator(t *iavl.Tree, start, end []byte, ascending bool) *iavlIterator {
itr := &iavlIterator{
tree: t,
start: cp(start),
end: cp(end),
ascending: ascending,
iterCh: make(chan KVPair, 0), // Set capacity > 0?
quitCh: make(chan struct{}),
initCh: make(chan struct{}),
}
go itr.iterateRoutine()
go itr.initRoutine()
return itr
}
// Run this to funnel items from the tree to iterCh.
func (ii *iavlIterator) iterateRoutine() {
ii.tree.IterateRange(
ii.start, ii.end, ii.ascending,
func(key, value []byte) bool {
select {
case <-ii.quitCh:
return true // done with iteration.
case ii.iterCh <- KVPair{key, value}:
return false // yay.
}
},
)
close(ii.iterCh) // done.
}
// Run this to fetch the first item.
func (ii *iavlIterator) initRoutine() {
ii.receiveNext()
close(ii.initCh)
}
// Domain implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Domain() (start, end []byte) {
2017-12-10 00:24:55 -08:00
return ii.start, ii.end
}
// Valid implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Valid() bool {
2017-12-10 00:24:55 -08:00
ii.waitInit()
ii.mtx.Lock()
defer ii.mtx.Unlock()
return !ii.invalid
}
// Next implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Next() {
2017-12-10 00:24:55 -08:00
ii.waitInit()
ii.mtx.Lock()
defer ii.mtx.Unlock()
ii.assertIsValid()
ii.receiveNext()
}
// Key implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Key() []byte {
2017-12-10 00:24:55 -08:00
ii.waitInit()
ii.mtx.Lock()
defer ii.mtx.Unlock()
ii.assertIsValid()
return ii.key
}
// Value implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Value() []byte {
2017-12-10 00:24:55 -08:00
ii.waitInit()
ii.mtx.Lock()
defer ii.mtx.Unlock()
ii.assertIsValid()
return ii.value
}
// Release implements Iterator
2017-12-03 22:55:15 -08:00
func (ii *iavlIterator) Release() {
2017-12-10 00:24:55 -08:00
close(ii.quitCh)
}
//----------------------------------------
func (ii *iavlIterator) setNext(key, value []byte) {
ii.mtx.Lock()
defer ii.mtx.Unlock()
ii.assertIsValid()
ii.key = key
ii.value = value
}
func (ii *iavlIterator) setInvalid() {
ii.mtx.Lock()
defer ii.mtx.Unlock()
ii.assertIsValid()
ii.invalid = true
}
func (ii *iavlIterator) waitInit() {
<-ii.initCh
}
func (ii *iavlIterator) receiveNext() {
kvPair, ok := <-ii.iterCh
if ok {
ii.setNext(kvPair.Key, kvPair.Value)
} else {
ii.setInvalid()
}
}
func (ii *iavlIterator) assertIsValid() {
if ii.invalid {
panic("invalid iterator")
}
}
2017-11-29 04:19:41 -08:00
2017-12-09 12:35:51 -08:00
//----------------------------------------
2017-12-01 14:08:37 -08:00
2017-12-09 12:35:51 -08:00
// iavlStoreLoader contains info on what store we want to load from
type iavlStoreLoader struct {
db dbm.DB
cacheSize int
numHistory int64
}
2017-11-29 03:08:32 -08:00
2017-12-09 12:35:51 -08:00
// Load implements CommitLoader.
2017-12-10 00:24:55 -08:00
func (isl iavlStoreLoader) Load(id CommitID) (CommitStore, error) {
2017-12-09 12:35:51 -08:00
tree := iavl.NewVersionedTree(isl.db, isl.cacheSize)
err := tree.Load()
2017-11-29 03:08:32 -08:00
if err != nil {
2017-12-09 12:35:51 -08:00
return nil, err
2017-11-29 03:08:32 -08:00
}
2017-12-09 12:35:51 -08:00
store := newIAVLStore(tree, isl.numHistory)
2017-11-29 04:19:41 -08:00
return store, nil
2017-11-29 03:08:32 -08:00
}
2017-12-10 00:24:55 -08:00
//----------------------------------------
func cp(bz []byte) (ret []byte) {
ret = make([]byte, len(bz))
copy(ret, bz)
return ret
}