cosmos-sdk/store/iavlstore.go

386 lines
8.6 KiB
Go
Raw Normal View History

2017-11-29 03:08:32 -08:00
package store
import (
"fmt"
2017-12-10 00:24:55 -08:00
"sync"
2017-11-29 04:19:41 -08:00
"github.com/tendermint/go-amino"
2017-11-29 03:08:32 -08:00
"github.com/tendermint/iavl"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
2017-11-29 03:08:32 -08:00
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
defaultIAVLCacheSize = 10000
2018-06-26 16:26:24 -07:00
defaultIAVLNumRecent = 100
2018-06-26 13:01:45 -07:00
defaultIAVLStoreEvery = 10000
)
2017-11-29 04:19:41 -08:00
2018-04-18 21:49:24 -07:00
// load the iavl store
func LoadIAVLStore(db dbm.DB, id CommitID) (CommitStore, error) {
tree := iavl.NewVersionedTree(db, defaultIAVLCacheSize)
2018-03-22 21:32:57 -07:00
_, err := tree.LoadVersion(id.Version)
if err != nil {
return nil, err
}
2018-06-26 13:01:45 -07:00
store := newIAVLStore(tree, defaultIAVLNumRecent, defaultIAVLStoreEvery)
return store, nil
}
//----------------------------------------
var _ KVStore = (*iavlStore)(nil)
2017-12-09 12:35:51 -08:00
var _ CommitStore = (*iavlStore)(nil)
2018-01-30 10:37:03 -08:00
var _ Queryable = (*iavlStore)(nil)
2017-11-29 04:19:41 -08:00
// iavlStore Implements KVStore and CommitStore.
2017-12-09 12:35:51 -08:00
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.
2018-07-02 15:17:45 -07:00
// A value of 0 means keep no recent states
2018-06-26 13:01:45 -07:00
numRecent int64
2018-07-02 15:17:45 -07:00
// Distance between state-sync waypoint states to be stored
// See https://github.com/tendermint/tendermint/issues/828
// A value of 1 means store every state
// A value of 0 means store no waypoints (node cannot assist in state-sync)
// By default this value should be set the same across all nodes,
// so that nodes can know the waypoints their peers store
// TODO if set to non-default, signal to peers that the node is not suitable as a state sync source
2018-06-26 13:01:45 -07:00
storeEvery int64
2017-11-29 04:19:41 -08:00
}
2017-12-09 12:35:51 -08:00
// CONTRACT: tree should be fully loaded.
2018-06-26 13:01:45 -07:00
func newIAVLStore(tree *iavl.VersionedTree, numRecent int64, storeEvery int64) *iavlStore {
2017-12-09 12:35:51 -08:00
st := &iavlStore{
tree: tree,
2018-06-26 13:01:45 -07:00
numRecent: numRecent,
storeEvery: storeEvery,
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
}
// Implements Committer.
2017-12-09 12:35:51 -08:00
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)
}
2018-06-26 13:01:45 -07:00
// Release an old version of history, if not a sync waypoint
2018-07-02 15:17:45 -07:00
previous := version - 1
if st.numRecent < previous {
toRelease := previous - st.numRecent
if st.storeEvery == 0 || toRelease%st.storeEvery != 0 {
2018-06-26 13:01:45 -07:00
err := st.tree.DeleteVersion(toRelease)
if err != nil {
panic(err)
}
}
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
}
// Implements Committer.
func (st *iavlStore) LastCommitID() CommitID {
return CommitID{
Version: st.tree.Version64(),
Hash: st.tree.Hash(),
}
}
2018-06-26 16:26:24 -07:00
// VersionExists returns whether or not a given version is stored
func (st *iavlStore) VersionExists(version int64) bool {
return st.tree.VersionExists(version)
}
// Implements Store.
func (st *iavlStore) GetStoreType() StoreType {
return sdk.StoreTypeIAVL
}
// Implements Store.
2017-12-10 00:24:55 -08:00
func (st *iavlStore) CacheWrap() CacheWrap {
return NewCacheKVStore(st)
2017-12-10 00:24:55 -08:00
}
// Implements KVStore.
2017-12-11 23:30:44 -08:00
func (st *iavlStore) Set(key, value []byte) {
2017-12-09 12:35:51 -08:00
st.tree.Set(key, value)
2017-11-29 05:07:39 -08:00
}
// Implements KVStore.
2017-12-11 23:30:44 -08:00
func (st *iavlStore) Get(key []byte) (value []byte) {
2017-12-09 12:35:51 -08:00
_, v := st.tree.Get(key)
2017-12-11 23:30:44 -08:00
return v
2017-11-29 05:07:39 -08:00
}
// Implements KVStore.
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
}
// Implements KVStore.
func (st *iavlStore) Delete(key []byte) {
2017-12-11 23:30:44 -08:00
st.tree.Remove(key)
2017-11-29 05:07:39 -08:00
}
// Implements KVStore
func (st *iavlStore) Prefix(prefix []byte) KVStore {
return prefixStore{st, prefix}
}
// Implements KVStore.
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)
}
2018-04-01 09:00:28 -07:00
// Implements KVStore.
func (st *iavlStore) ReverseIterator(start, end []byte) Iterator {
return newIAVLIterator(st.tree.Tree(), start, end, false)
}
2018-01-30 10:37:03 -08:00
// Query implements ABCI interface, allows queries
//
// by default we will return from (latest height -1),
// as we will have merkle proofs immediately (header height = data height + 1)
// If latest-1 is not present, use latest (which must be present)
// if you care to have the latest data to see a tx results, you must
// explicitly set the height you want to see
func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
if len(req.Data) == 0 {
msg := "Query cannot be zero length"
return sdk.ErrTxDecode(msg).QueryResult()
2018-01-30 10:37:03 -08:00
}
tree := st.tree
height := req.Height
if height == 0 {
latest := tree.Version64()
if tree.VersionExists(latest - 1) {
height = latest - 1
} else {
height = latest
}
}
// store the height we chose in the response
res.Height = height
switch req.Path {
case "/store", "/key": // Get by key
key := req.Data // Data holds the key bytes
res.Key = key
if req.Prove {
value, proof, err := tree.GetVersionedWithProof(key, height)
if err != nil {
res.Log = err.Error()
break
}
res.Value = value
cdc := amino.NewCodec()
p, err := cdc.MarshalBinary(proof)
if err != nil {
res.Log = err.Error()
break
}
res.Proof = p
2018-01-30 10:37:03 -08:00
} else {
_, res.Value = tree.GetVersioned(key, height)
}
case "/subspace":
subspace := req.Data
res.Key = subspace
2018-05-09 15:24:51 -07:00
var KVs []KVPair
2018-05-26 18:00:39 -07:00
iterator := sdk.KVStorePrefixIterator(st, subspace)
for ; iterator.Valid(); iterator.Next() {
2018-05-09 15:24:51 -07:00
KVs = append(KVs, KVPair{iterator.Key(), iterator.Value()})
}
iterator.Close()
res.Value = cdc.MustMarshalBinary(KVs)
2018-01-30 10:37:03 -08:00
default:
msg := fmt.Sprintf("Unexpected Query path: %v", req.Path)
return sdk.ErrUnknownRequest(msg).QueryResult()
2018-01-30 10:37:03 -08:00
}
return
}
2017-12-09 12:35:51 -08:00
//----------------------------------------
// Implements Iterator.
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.
2017-12-17 18:09:39 -08:00
iterCh chan cmn.KVPair
2017-12-10 00:24:55 -08:00
// 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.
2017-12-11 23:30:44 -08:00
func newIAVLIterator(tree *iavl.Tree, start, end []byte, ascending bool) *iavlIterator {
iter := &iavlIterator{
tree: tree,
2017-12-10 00:24:55 -08:00
start: cp(start),
end: cp(end),
ascending: ascending,
2017-12-17 18:09:39 -08:00
iterCh: make(chan cmn.KVPair, 0), // Set capacity > 0?
2017-12-10 00:24:55 -08:00
quitCh: make(chan struct{}),
initCh: make(chan struct{}),
}
2017-12-11 23:30:44 -08:00
go iter.iterateRoutine()
go iter.initRoutine()
return iter
2017-12-10 00:24:55 -08:00
}
// Run this to funnel items from the tree to iterCh.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) iterateRoutine() {
iter.tree.IterateRange(
iter.start, iter.end, iter.ascending,
2017-12-10 00:24:55 -08:00
func(key, value []byte) bool {
select {
2017-12-11 23:30:44 -08:00
case <-iter.quitCh:
2017-12-10 00:24:55 -08:00
return true // done with iteration.
2017-12-17 18:09:39 -08:00
case iter.iterCh <- cmn.KVPair{key, value}:
2017-12-10 00:24:55 -08:00
return false // yay.
}
},
)
2017-12-11 23:30:44 -08:00
close(iter.iterCh) // done.
2017-12-10 00:24:55 -08:00
}
// Run this to fetch the first item.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) initRoutine() {
iter.receiveNext()
close(iter.initCh)
2017-12-10 00:24:55 -08:00
}
// Implements Iterator.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) Domain() (start, end []byte) {
return iter.start, iter.end
}
// Implements Iterator.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) Valid() bool {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
return !iter.invalid
}
// Implements Iterator.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) Next() {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
iter.receiveNext()
}
// Implements Iterator.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) Key() []byte {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
return iter.key
}
// Implements Iterator.
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) Value() []byte {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
return iter.value
}
// Implements Iterator.
func (iter *iavlIterator) Close() {
2017-12-11 23:30:44 -08:00
close(iter.quitCh)
2017-12-10 00:24:55 -08:00
}
//----------------------------------------
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) setNext(key, value []byte) {
iter.assertIsValid()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
iter.key = key
iter.value = value
2017-12-10 00:24:55 -08:00
}
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) setInvalid() {
iter.assertIsValid()
2017-12-10 00:24:55 -08:00
2017-12-11 23:30:44 -08:00
iter.invalid = true
2017-12-10 00:24:55 -08:00
}
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) waitInit() {
<-iter.initCh
2017-12-10 00:24:55 -08:00
}
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) receiveNext() {
kvPair, ok := <-iter.iterCh
2017-12-10 00:24:55 -08:00
if ok {
2017-12-11 23:30:44 -08:00
iter.setNext(kvPair.Key, kvPair.Value)
2017-12-10 00:24:55 -08:00
} else {
2017-12-11 23:30:44 -08:00
iter.setInvalid()
2017-12-10 00:24:55 -08:00
}
}
2017-12-11 23:30:44 -08:00
func (iter *iavlIterator) assertIsValid() {
if iter.invalid {
2017-12-10 00:24:55 -08:00
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-10 00:24:55 -08:00
func cp(bz []byte) (ret []byte) {
2018-03-31 15:26:00 -07:00
if bz == nil {
return nil
}
2017-12-10 00:24:55 -08:00
ret = make([]byte, len(bz))
copy(ret, bz)
return ret
}