Committer -> CommitStore; CacheWrap()

This commit is contained in:
Jae Kwon 2017-12-03 22:55:15 -08:00
parent 51f522f8d8
commit 8db15fe3ef
4 changed files with 136 additions and 121 deletions

View File

@ -5,28 +5,24 @@ import dbm "github.com/tendermint/tmlibs/db"
//---------------------------------------- //----------------------------------------
// cacheMultiStore // cacheMultiStore
type cwWriter interface { // cacheMultiStore holds many cache-wrapped stores.
Write()
}
// cacheMultiStore holds many CacheWrap'd stores.
// Implements MultiStore. // Implements MultiStore.
type cacheMultiStore struct { type cacheMultiStore struct {
db dbm.DB db dbm.DB
version int64 version int64
lastCommitID CommitID lastCommitID CommitID
substores map[string]cwWriter substores map[string]CacheWriter
} }
func newCacheMultiStore(rs *rootMultiStore) cacheMultiStore { func newCacheMultiStore(rs *rootMultiStore) cacheMultiStore {
cms := cacheMultiStore{ cms := cacheMultiStore{
db: dbm.CacheWrap(), db: dbm.CacheDB(),
version: rs.curVersion, version: rs.curVersion,
lastCommitID: rs.lastCommitID, lastCommitID: rs.lastCommitID,
substores: make(map[string]cwWriter, len(rs.substores)), substores: make(map[string]CacheWriter, len(rs.substores)),
} }
for name, substore := range rs.substores { for name, substore := range rs.substores {
cms.substores[name] = substore.CacheWrap().(cwWriter) cms.substores[name] = substore.CacheWrap().(CacheWriter)
} }
return cms return cms
} }

View File

@ -22,7 +22,7 @@ func NewIAVLLoader(dbName string, cacheSize int, nHistoricalVersions uint64) Com
return CommitterLoader(l.Load) return CommitterLoader(l.Load)
} }
var _ CacheWrappable = (*IAVLCommitter)(nil) var _ CacheIterKVStore = (*IAVLCommitter)(nil)
var _ Committer = (*IAVLCommitter)(nil) var _ Committer = (*IAVLCommitter)(nil)
// IAVLCommitter Implements IterKVStore and Committer // IAVLCommitter Implements IterKVStore and Committer
@ -48,13 +48,13 @@ type IAVLCommitter struct {
// that is ready to use as a IterKVStore // that is ready to use as a IterKVStore
func NewIAVLCommitter(tree *iavl.VersionedTree, func NewIAVLCommitter(tree *iavl.VersionedTree,
lastHeight uint64, nHistoricalVersions uint64) *IAVLCommitter { lastHeight uint64, nHistoricalVersions uint64) *IAVLCommitter {
i := &IAVLCommitter{ ic := &IAVLCommitter{
tree: tree, tree: tree,
lastHeight: lastHeight, lastHeight: lastHeight,
nHistoricalVersions: nHistoricalVersions, nHistoricalVersions: nHistoricalVersions,
} }
i.updateStore() ic.updateStore()
return i return ic
} }
// Commit syncs the working state and // Commit syncs the working state and
@ -64,8 +64,8 @@ func (i *IAVLCommitter) Commit() CommitID {
// I think this is done already just by writing to tree.Tree() // I think this is done already just by writing to tree.Tree()
// save a new version // save a new version
i.lastHeight++ ic.lastHeight++
hash, err := i.tree.SaveVersion(i.lastHeight) hash, err := ic.tree.SaveVersion(ic.lastHeight)
if err != nil { if err != nil {
// TODO: do we want to extend Commit to // TODO: do we want to extend Commit to
// allow returning errors? // allow returning errors?
@ -73,23 +73,23 @@ func (i *IAVLCommitter) Commit() CommitID {
} }
// now point working state to the new status // now point working state to the new status
i.updateStore() ic.updateStore()
// release an old version of history // release an old version of history
if i.nHistoricalVersions <= i.lastHeight { if ic.nHistoricalVersions <= ic.lastHeight {
release := i.lastHeight - i.nHistoricalVersions release := ic.lastHeight - ic.nHistoricalVersions
i.tree.DeleteVersion(release) ic.tree.DeleteVersion(release)
} }
return CommitID{ return CommitID{
Version: i.lastHeight, Version: ic.lastHeight,
Hash: hash, Hash: hash,
} }
} }
// store returns a wrapper around the current writable state // store returns a wrapper around the current writable state
func (i *IAVLCommitter) updateStore() { func (ic *IAVLCommitter) updateStore() {
i.IAVLStore = IAVLStore{i.tree.Tree()} ic.IAVLStore = IAVLStore{ic.tree.Tree()}
} }
// IAVLStore is the writable state (not history) and // IAVLStore is the writable state (not history) and
@ -98,55 +98,60 @@ type IAVLStore struct {
tree *iavl.Tree tree *iavl.Tree
} }
// CacheWrap returns a wrapper around the current writable state // CacheWrap implements IterKVStore.
func (i IAVLStore) CacheWrap() CacheWriter { func (is IAVLStore) CacheWrap() CacheWriter {
// TODO: add CacheWrap to IAVLTree using new db stuff return is.CacheIterKVStore()
}
// CacheIterKVStore implements IterKVStore.
func (is IAVLStore) CacheIterKVStore() CacheIterKVStore {
// TODO: Add CacheWrap to IAVLTree.
return i return i
} }
// Set implements KVStore // Set implements IterKVStore.
func (i IAVLStore) Set(key, value []byte) (prev []byte) { func (is IAVLStore) Set(key, value []byte) (prev []byte) {
_, prev = i.tree.Get(key) _, prev = is.tree.Get(key)
i.tree.Set(key, value) is.tree.Set(key, value)
return prev return prev
} }
// Get implements KVStore // Get implements IterKVStore.
func (i IAVLStore) Get(key []byte) (value []byte, exists bool) { func (is IAVLStore) Get(key []byte) (value []byte, exists bool) {
_, v := i.tree.Get(key) _, v := is.tree.Get(key)
return v, (v != nil) return v, (v != nil)
} }
// Has implements KVStore // Has implements IterKVStore.
func (i IAVLStore) Has(key []byte) (exists bool) { func (is IAVLStore) Has(key []byte) (exists bool) {
return i.tree.Has(key) return is.tree.Has(key)
} }
// Remove implements KVStore // Remove implements IterKVStore.
func (i IAVLStore) Remove(key []byte) (prev []byte, removed bool) { func (is IAVLStore) Remove(key []byte) (prev []byte, removed bool) {
return i.tree.Remove(key) return is.tree.Remove(key)
} }
// Iterator implements IterKVStore // Iterator implements IterKVStore.
func (i IAVLStore) Iterator(start, end []byte) Iterator { func (is IAVLStore) Iterator(start, end []byte) Iterator {
// TODO: this needs changes to IAVL tree // TODO: this needs changes to IAVL tree
return nil return nil
} }
// ReverseIterator implements IterKVStore // ReverseIterator implements IterKVStore.
func (i IAVLStore) ReverseIterator(start, end []byte) Iterator { func (is IAVLStore) ReverseIterator(start, end []byte) Iterator {
// TODO // TODO
return nil return nil
} }
// First implements IterKVStore // First implements IterKVStore.
func (i IAVLStore) First(start, end []byte) (kv KVPair, ok bool) { func (is IAVLStore) First(start, end []byte) (kv KVPair, ok bool) {
// TODO // TODO
return KVPair{}, false return KVPair{}, false
} }
// Last implements IterKVStore // Last implements IterKVStore.
func (i IAVLStore) Last(start, end []byte) (kv KVPair, ok bool) { func (is IAVLStore) Last(start, end []byte) (kv KVPair, ok bool) {
// TODO // TODO
return KVPair{}, false return KVPair{}, false
} }
@ -163,7 +168,7 @@ var _ Iterator = (*iavlIterator)(nil)
// //
// The start & end (exclusive) limits to iterate over. // The start & end (exclusive) limits to iterate over.
// If end < start, then the Iterator goes in reverse order. // If end < start, then the Iterator goes in reverse order.
func (i *iavlIterator) Domain() (start, end []byte) { func (ii *iavlIterator) Domain() (start, end []byte) {
// TODO // TODO
return nil, nil return nil, nil
} }
@ -171,7 +176,7 @@ func (i *iavlIterator) Domain() (start, end []byte) {
// Valid implements Iterator // Valid implements Iterator
// //
// Returns if the current position is valid. // Returns if the current position is valid.
func (i *iavlIterator) Valid() bool { func (ii *iavlIterator) Valid() bool {
// TODO // TODO
return false return false
} }
@ -179,7 +184,7 @@ func (i *iavlIterator) Valid() bool {
// Next implements Iterator // Next implements Iterator
// //
// Next moves the iterator to the next key/value pair. // Next moves the iterator to the next key/value pair.
func (i *iavlIterator) Next() { func (ii *iavlIterator) Next() {
// TODO // TODO
} }
@ -188,7 +193,7 @@ func (i *iavlIterator) Next() {
// Key returns the key of the current key/value pair, or nil if done. // Key returns the key of the current key/value pair, or nil if done.
// The caller should not modify the contents of the returned slice, and // The caller should not modify the contents of the returned slice, and
// its contents may change after calling Next(). // its contents may change after calling Next().
func (i *iavlIterator) Key() []byte { func (ii *iavlIterator) Key() []byte {
// TODO // TODO
return nil return nil
} }
@ -198,7 +203,7 @@ func (i *iavlIterator) Key() []byte {
// Value returns the key of the current key/value pair, or nil if done. // Value returns the key of the current key/value pair, or nil if done.
// The caller should not modify the contents of the returned slice, and // The caller should not modify the contents of the returned slice, and
// its contents may change after calling Next(). // its contents may change after calling Next().
func (i *iavlIterator) Value() []byte { func (ii *iavlIterator) Value() []byte {
// TODO // TODO
return nil return nil
} }
@ -206,7 +211,7 @@ func (i *iavlIterator) Value() []byte {
// Release implements Iterator // Release implements Iterator
// //
// Releases any resources and iteration-locks // Releases any resources and iteration-locks
func (i *iavlIterator) Release() { func (ii *iavlIterator) Release() {
// TODO // TODO
} }
@ -218,16 +223,16 @@ type iavlLoader struct {
} }
// Load implements CommitLoader type // Load implements CommitLoader type
func (l iavlLoader) Load(id CommitID) (Committer, error) { func (il iavlLoader) Load(id CommitID) (Committer, error) {
// memory backed case, just for testing // memory backed case, just for testing
if l.dbName == "" { if il.dbName == "" {
tree := iavl.NewVersionedTree(0, dbm.NewMemDB()) tree := iavl.NewVersionedTree(0, dbm.NewMemDB())
store := NewIAVLCommitter(tree, 0, l.nHistoricalVersions) store := NewIAVLCommitter(tree, 0, il.nHistoricalVersions)
return store, nil return store, nil
} }
// Expand the path fully // Expand the path fully
dbPath, err := filepath.Abs(l.dbName) dbPath, err := filepath.Abs(il.dbName)
if err != nil { if err != nil {
return nil, errors.New("Invalid Database Name") return nil, errors.New("Invalid Database Name")
} }
@ -241,13 +246,13 @@ func (l iavlLoader) Load(id CommitID) (Committer, error) {
// Open database called "dir/name.db", if it doesn't exist it will be created // Open database called "dir/name.db", if it doesn't exist it will be created
db := dbm.NewDB(name, dbm.LevelDBBackendStr, dir) db := dbm.NewDB(name, dbm.LevelDBBackendStr, dir)
tree := iavl.NewVersionedTree(l.cacheSize, db) tree := iavl.NewVersionedTree(il.cacheSize, db)
if err = tree.Load(); err != nil { if err = tree.Load(); err != nil {
return nil, errors.New("Loading tree: " + err.Error()) return nil, errors.New("Loading tree: " + err.Error())
} }
// TODO: load the version stored in id // TODO: load the version stored in id
store := NewIAVLCommitter(tree, tree.LatestVersion(), store := NewIAVLCommitter(tree, tree.LatestVersion(),
l.nHistoricalVersions) il.nHistoricalVersions)
return store, nil return store, nil
} }

View File

@ -14,35 +14,7 @@ const (
commitStateKeyFmt = "s/%d" // s/<version> commitStateKeyFmt = "s/%d" // s/<version>
) )
type MultiStore interface { // rootMultiStore is composed of many CommitStores.
// Last commit, or the zero CommitID.
// If not zero, CommitID.Version is CurrentVersion()-1.
LastCommitID() CommitID
// Current version being worked on now, not yet committed.
// Should be greater than 0.
CurrentVersion() int64
// Cache wrap MultiStore.
// NOTE: Caller should probably not call .Write() on each, but
// call CacheMultiStore.Write().
CacheMultiStore() CacheMultiStore
// Convenience
GetStore(name string) interface{}
GetKVStore(name string) KVStore
GetIterKVStore(name string) IterKVStore
}
type CacheMultiStore interface {
MultiStore
Write() // Writes operations to underlying KVStore
}
//----------------------------------------
// rootMultiStore is composed of many Committers.
// Name contrasts with cacheMultiStore which is for cache-wrapping // Name contrasts with cacheMultiStore which is for cache-wrapping
// other MultiStores. // other MultiStores.
// Implements MultiStore. // Implements MultiStore.
@ -50,8 +22,8 @@ type rootMultiStore struct {
db dbm.DB db dbm.DB
curVersion int64 curVersion int64
lastHash []byte lastHash []byte
storeLoaders map[string]CommitterLoader storeLoaders map[string]CommitStoreLoader
substores map[string]Committer substores map[string]CommitStore
} }
func NewMultiStore(db dbm.DB) *rootMultiStore { func NewMultiStore(db dbm.DB) *rootMultiStore {
@ -59,19 +31,19 @@ func NewMultiStore(db dbm.DB) *rootMultiStore {
db: db, db: db,
curVersion: 0, curVersion: 0,
lastHash: nil, lastHash: nil,
storeLoaders: make(map[string]CommitterLoader), storeLoaders: make(map[string]CommitStoreLoader),
substores: make(map[string]Committer), substores: make(map[string]CommitStore),
} }
} }
func (rs *rootMultiStore) SetCommitterLoader(name string, loader CommitterLoader) { func (rs *rootMultiStore) SetCommitStoreLoader(name string, loader CommitStoreLoader) {
if _, ok := rs.storeLoaders[name]; ok { if _, ok := rs.storeLoaders[name]; ok {
panic(fmt.Sprintf("rootMultiStore duplicate substore name " + name)) panic(fmt.Sprintf("rootMultiStore duplicate substore name " + name))
} }
rs.storeLoaders[name] = loader rs.storeLoaders[name] = loader
} }
// Call once after all calls to SetCommitterLoader are complete. // Call once after all calls to SetCommitStoreLoader are complete.
func (rs *rootMultiStore) LoadLatestVersion() error { func (rs *rootMultiStore) LoadLatestVersion() error {
ver := getLatestVersion(rs.db) ver := getLatestVersion(rs.db)
rs.LoadVersion(ver) rs.LoadVersion(ver)
@ -103,12 +75,12 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
var state commitState = loadCommitState(rs.db, ver) var state commitState = loadCommitState(rs.db, ver)
// Load each Substore // Load each Substore
var newSubstores = make(map[string]Committer) var newSubstores = make(map[string]CommitStore)
for _, store := range state.Substores { for _, store := range state.Substores {
name, commitID := store.Name, store.CommitID name, commitID := store.Name, store.CommitID
storeLoader := rs.storeLoaders[name] storeLoader := rs.storeLoaders[name]
if storeLoader == nil { if storeLoader == nil {
return fmt.Errorf("Failed to loadrootMultiStore: CommitterLoader missing for %v", name) return fmt.Errorf("Failed to loadrootMultiStore: CommitStoreLoader missing for %v", name)
} }
store, err := storeLoader(commitID) store, err := storeLoader(commitID)
if err != nil { if err != nil {
@ -117,10 +89,10 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
newSubstores[name] = store newSubstores[name] = store
} }
// If any CommitterLoaders were not used, return error. // If any CommitStoreLoaders were not used, return error.
for name := range rs.storeLoaders { for name := range rs.storeLoaders {
if _, ok := rs.substores[name]; !ok { if _, ok := rs.substores[name]; !ok {
return fmt.Errorf("Unused CommitterLoader: %v", name) return fmt.Errorf("Unused CommitStoreLoader: %v", name)
} }
} }
@ -162,7 +134,7 @@ func (rs *rootMultiStore) doCommit() commitState {
//---------------------------------------- //----------------------------------------
// Implements Committer // Implements CommitStore
func (rs *rootMultiStore) Commit() CommitID { func (rs *rootMultiStore) Commit() CommitID {
version := rs.version version := rs.version
@ -190,7 +162,11 @@ func (rs *rootMultiStore) Commit() CommitID {
Version: version, Version: version,
Hash: state.Hash(), Hash: state.Hash(),
} }
}
// Implements CommitStore
func (rs *rootMultiStore) CacheWrap() CacheWriter {
return rs.CacheMultiStore()
} }
// Get the last committed CommitID // Get the last committed CommitID
@ -213,7 +189,7 @@ func (rs *rootMultiStore) CacheMultiStore() CacheMultiStore {
} }
// Implements MultiStore // Implements MultiStore
func (rs *rootMultiStore) GetCommitter(name string) Committer { func (rs *rootMultiStore) GetCommitStore(name string) CommitStore {
return rs.store[name] return rs.store[name]
} }

View File

@ -14,36 +14,39 @@ func (cid CommitID) IsZero() bool {
} }
type Committer interface { type Committer interface {
// Commit persists the state to disk. // Commit persists the state to disk.
Commit() CommitID Commit() CommitID
} }
type CommitterLoader func(id CommitID) (Committer, error) type CacheWrapper interface {
/*
CacheWrap() makes the most appropriate cache-wrap. For example,
IAVLStore.CacheWrap() returns a CacheIterKVStore. After call to
.Write() on the cache-wrap, all previous cache-wraps on the object
expire.
// CacheWriter is returned from CacheWrap and knows how to CacheWrap() should not return a Committer, since Commit() on
// write its cached changes to its parent cache-wraps make no sense. It can return KVStore, IterKVStore, etc.
type CacheWriter interface {
// Write must write to the
Write() error
}
// CacheWrappable is anything that can be wrapped with a cache. The returned object may or may not implement CacheWrap() as well.
type CacheWrappable interface {
// CacheWrap() wraps a thing with a cache. After calling NOTE: https://dave.cheney.net/2017/07/22/should-go-2-0-support-generics.
// .Write() on the CacheWrap, all previous CacheWraps on the */
// object expire.
//
// CacheWrap() should not return a Committer, since Commit() on
// CacheWraps make no sense. It can return KVStore, IterKVStore,
// etc.
//
// NOTE: https://dave.cheney.net/2017/07/22/should-go-2-0-support-generics.
// The returned object may or may not implement CacheWrap() as well.
CacheWrap() CacheWriter CacheWrap() CacheWriter
} }
// CacheWriter.Write syncs with the underlying store.
type CacheWriter interface {
Write()
}
type CommitStore interface {
Committer
CacheWrapper
}
type CommitStoreLoader func(id CommitID) (CommitStore, error)
// KVStore is a simple interface to get/set data // KVStore is a simple interface to get/set data
type KVStore interface { type KVStore interface {
Set(key, value []byte) (prev []byte) Set(key, value []byte) (prev []byte)
@ -53,8 +56,11 @@ type KVStore interface {
// CacheKVStore() wraps a thing with a cache. After // CacheKVStore() wraps a thing with a cache. After
// calling .Write() on the CacheKVStore, all previous // calling .Write() on the CacheKVStore, all previous
// CacheWraps on the object expire. // cache-wraps on the object expire.
CacheKVStore() CacheKVStore CacheKVStore() CacheKVStore
// CacheWrap() returns a CacheKVStore.
CacheWrap() CacheWriter
} }
type CacheKVStore interface { type CacheKVStore interface {
@ -75,8 +81,11 @@ type IterKVStore interface {
// CacheIterKVStore() wraps a thing with a cache. // CacheIterKVStore() wraps a thing with a cache.
// After calling .Write() on the CacheIterKVStore, all // After calling .Write() on the CacheIterKVStore, all
// previous CacheWraps on the object expire. // previous cache-wraps on the object expire.
CacheIterKVStore() CacheIterKVStore CacheIterKVStore() CacheIterKVStore
// CacheWrap() returns a CacheIterKVStore.
CacheWrap() CacheWriter
} }
type CacheIterKVStore interface { type CacheIterKVStore interface {
@ -130,3 +139,32 @@ type Iterator interface {
// Releases any resources and iteration-locks // Releases any resources and iteration-locks
Release() Release()
} }
type MultiStore interface {
// Last commit, or the zero CommitID.
// If not zero, CommitID.Version is CurrentVersion()-1.
LastCommitID() CommitID
// Current version being worked on now, not yet committed.
// Should be greater than 0.
CurrentVersion() int64
// Cache wrap MultiStore.
// NOTE: Caller should probably not call .Write() on each, but
// call CacheMultiStore.Write().
CacheMultiStore() CacheMultiStore
// CacheWrap returns a CacheMultiStore.
CacheWrap() CacheWriter
// Convenience
GetStore(name string) interface{}
GetKVStore(name string) KVStore
GetIterKVStore(name string) IterKVStore
}
type CacheMultiStore interface {
MultiStore
Write() // Writes operations to underlying KVStore
}