Added CommitterLoader for IAVLStore

This commit is contained in:
Ethan Frey 2017-11-29 13:19:41 +01:00 committed by Jae Kwon
parent a2a1151a4f
commit 6a410607b8
2 changed files with 171 additions and 106 deletions

View File

@ -1,106 +1,106 @@
package store
import (
"encoding/binary"
// import (
// "encoding/binary"
sdk "github.com/cosmos/cosmos-sdk"
)
// sdk "github.com/cosmos/cosmos-sdk"
// )
var (
headKey = []byte("h")
tailKey = []byte("t")
dataKey = []byte("d")
)
// var (
// headKey = []byte("h")
// tailKey = []byte("t")
// dataKey = []byte("d")
// )
// QueueHeadKey gives us the key for the height at head of the queue
func QueueHeadKey() []byte {
return headKey
}
// // QueueHeadKey gives us the key for the height at head of the queue
// func QueueHeadKey() []byte {
// return headKey
// }
// QueueTailKey gives us the key for the height at tail of the queue
func QueueTailKey() []byte {
return tailKey
}
// // QueueTailKey gives us the key for the height at tail of the queue
// func QueueTailKey() []byte {
// return tailKey
// }
// QueueItemKey gives us the key to look up one item by sequence
func QueueItemKey(i uint64) []byte {
return makeKey(i)
}
// // QueueItemKey gives us the key to look up one item by sequence
// func QueueItemKey(i uint64) []byte {
// return makeKey(i)
// }
// Queue allows us to fill up a range of the db, and grab from either end
type Queue struct {
store sdk.KVStore
head uint64 // if Size() > 0, the first element is here
tail uint64 // this is the first empty slot to Push() to
}
// // Queue allows us to fill up a range of the db, and grab from either end
// type Queue struct {
// store sdk.KVStore
// head uint64 // if Size() > 0, the first element is here
// tail uint64 // this is the first empty slot to Push() to
// }
// NewQueue will load or initialize a queue in this state-space
//
// Generally, you will want to stack.PrefixStore() the space first
func NewQueue(store sdk.KVStore) *Queue {
q := &Queue{store: store}
q.head = q.getCount(headKey)
q.tail = q.getCount(tailKey)
return q
}
// // NewQueue will load or initialize a queue in this state-space
// //
// // Generally, you will want to stack.PrefixStore() the space first
// func NewQueue(store sdk.KVStore) *Queue {
// q := &Queue{store: store}
// q.head = q.getCount(headKey)
// q.tail = q.getCount(tailKey)
// return q
// }
// Tail returns the next slot that Push() will use
func (q *Queue) Tail() uint64 {
return q.tail
}
// // Tail returns the next slot that Push() will use
// func (q *Queue) Tail() uint64 {
// return q.tail
// }
// Size returns how many elements are in the queue
func (q *Queue) Size() int {
return int(q.tail - q.head)
}
// // Size returns how many elements are in the queue
// func (q *Queue) Size() int {
// return int(q.tail - q.head)
// }
// Push adds an element to the tail of the queue and returns it's location
func (q *Queue) Push(value []byte) uint64 {
key := makeKey(q.tail)
q.store.Set(key, value)
q.tail++
q.setCount(tailKey, q.tail)
return q.tail - 1
}
// // Push adds an element to the tail of the queue and returns it's location
// func (q *Queue) Push(value []byte) uint64 {
// key := makeKey(q.tail)
// q.store.Set(key, value)
// q.tail++
// q.setCount(tailKey, q.tail)
// return q.tail - 1
// }
// Pop gets an element from the end of the queue
func (q *Queue) Pop() []byte {
if q.Size() <= 0 {
return nil
}
key := makeKey(q.head)
value := q.store.Get(key)
q.head++
q.setCount(headKey, q.head)
return value
}
// // Pop gets an element from the end of the queue
// func (q *Queue) Pop() []byte {
// if q.Size() <= 0 {
// return nil
// }
// key := makeKey(q.head)
// value := q.store.Get(key)
// q.head++
// q.setCount(headKey, q.head)
// return value
// }
// Item looks at any element in the queue, without modifying anything
func (q *Queue) Item(seq uint64) []byte {
if seq >= q.tail || seq < q.head {
return nil
}
return q.store.Get(makeKey(seq))
}
// // Item looks at any element in the queue, without modifying anything
// func (q *Queue) Item(seq uint64) []byte {
// if seq >= q.tail || seq < q.head {
// return nil
// }
// return q.store.Get(makeKey(seq))
// }
func (q *Queue) setCount(key []byte, val uint64) {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, val)
q.store.Set(key, b)
}
// func (q *Queue) setCount(key []byte, val uint64) {
// b := make([]byte, 8)
// binary.BigEndian.PutUint64(b, val)
// q.store.Set(key, b)
// }
func (q *Queue) getCount(key []byte) (val uint64) {
b := q.store.Get(key)
if b != nil {
val = binary.BigEndian.Uint64(b)
}
return val
}
// func (q *Queue) getCount(key []byte) (val uint64) {
// b := q.store.Get(key)
// if b != nil {
// val = binary.BigEndian.Uint64(b)
// }
// return val
// }
// makeKey returns the key for a data point
func makeKey(val uint64) []byte {
b := make([]byte, 8+len(dataKey))
copy(b, dataKey)
binary.BigEndian.PutUint64(b[len(dataKey):], val)
return b
}
// // makeKey returns the key for a data point
// func makeKey(val uint64) []byte {
// b := make([]byte, 8+len(dataKey))
// copy(b, dataKey)
// binary.BigEndian.PutUint64(b[len(dataKey):], val)
// return b
// }

View File

@ -1,47 +1,112 @@
package store
import (
"path"
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/tendermint/iavl"
dbm "github.com/tendermint/tmlibs/db"
)
// Implements IterKVStore
// NewIAVLLoader returns a CommitterLoader that returns
// an IAVLStore
func NewIAVLLoader(dbName string, cacheSize int, history uint64) CommitterLoader {
l := iavlLoader{
dbName: dbName,
cacheSize: cacheSize,
history: history,
}
return CommitterLoader(l.Load)
}
// IAVLStore Implements IterKVStore and Committer
type IAVLStore struct {
//
// we must store the last height here, as it is needed
// for saving the versioned tree
lastHeight uint64
// history is how many old versions we hold onto,
// uses a naive "hold last X versions" algorithm
history uint64
tree *iavl.VersionedTree
}
// XXX
func NewIAVLStore() {
// Commit writes another version to the
func (i *IAVLStore) Commit() CommitID {
// save a new version
i.lastHeight++
hash, err := i.tree.SaveVersion(i.lastHeight)
if err != nil {
// TODO: do we want to extend Commit to
// allow returning errors?
panic(err)
}
// release an old version
if i.history <= i.lastHeight {
release := i.lastHeight - i.history
i.tree.DeleteVersion(release)
}
return CommitID{
Version: i.lastHeight,
Hash: hash,
}
}
/*
// XXX GUT THIS AND TURN IT INTO AN IAVLSTORE LOADER, LoadIAVLStore()
func loadState(dbName string, cacheSize int) (*sm.State, error) {
// var _ IterKVStore = (*IAVLStore)(nil)
var _ KVStore = (*IAVLStore)(nil)
var _ Committer = (*IAVLStore)(nil)
// iavlLoader contains info on what store we want to load from
type iavlLoader struct {
dbName string
cacheSize int
history uint64
}
// Load implements CommitLoader type
func (l iavlLoader) Load(id CommitID) (Committer, error) {
// memory backed case, just for testing
if dbName == "" {
if l.dbName == "" {
tree := iavl.NewVersionedTree(0, dbm.NewMemDB())
return sm.NewState(tree), nil
store := &IAVLStore{
tree: tree,
history: l.history,
}
return store, nil
}
// Expand the path fully
dbPath, err := filepath.Abs(dbName)
dbPath, err := filepath.Abs(l.dbName)
if err != nil {
return nil, errors.ErrInternal("Invalid Database Name")
return nil, errors.New("Invalid Database Name")
}
// Some external calls accidently add a ".db", which is now removed
dbPath = strings.TrimSuffix(dbPath, path.Ext(dbPath))
// Split the database name into it's components (dir, name)
dir := path.Dir(dbPath)
name := path.Base(dbPath)
dir := filepath.Dir(dbPath)
name := filepath.Base(dbPath)
// Open database called "dir/name.db", if it doesn't exist it will be created
db := dbm.NewDB(name, dbm.LevelDBBackendStr, dir)
tree := iavl.NewVersionedTree(cacheSize, db)
tree := iavl.NewVersionedTree(l.cacheSize, db)
if err = tree.Load(); err != nil {
return nil, errors.ErrInternal("Loading tree: " + err.Error())
return nil, errors.New("Loading tree: " + err.Error())
}
return sm.NewState(tree), nil
// TODO: load the version stored in id
store := &IAVLStore{
tree: tree,
lastHeight: tree.LatestVersion(),
history: l.history,
}
return store, nil
}
*/