diff --git a/_attic/store/queue.go b/_attic/store/queue.go index a1512dc505..eacd815ca4 100644 --- a/_attic/store/queue.go +++ b/_attic/store/queue.go @@ -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 +// } diff --git a/store/iavlstore.go b/store/iavlstore.go index 324a3958ab..606ecd0ca5 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -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 } -*/