diff --git a/store/cachemultistore.go b/store/cachemultistore.go index ed6c9717e..001e05c4c 100644 --- a/store/cachemultistore.go +++ b/store/cachemultistore.go @@ -5,28 +5,24 @@ import dbm "github.com/tendermint/tmlibs/db" //---------------------------------------- // cacheMultiStore -type cwWriter interface { - Write() -} - -// cacheMultiStore holds many CacheWrap'd stores. +// cacheMultiStore holds many cache-wrapped stores. // Implements MultiStore. type cacheMultiStore struct { db dbm.DB version int64 lastCommitID CommitID - substores map[string]cwWriter + substores map[string]CacheWriter } func newCacheMultiStore(rs *rootMultiStore) cacheMultiStore { cms := cacheMultiStore{ - db: dbm.CacheWrap(), + db: dbm.CacheDB(), version: rs.curVersion, 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 { - cms.substores[name] = substore.CacheWrap().(cwWriter) + cms.substores[name] = substore.CacheWrap().(CacheWriter) } return cms } diff --git a/store/iavlstore.go b/store/iavlstore.go index de8cdfdf4..d36575394 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -22,7 +22,7 @@ func NewIAVLLoader(dbName string, cacheSize int, nHistoricalVersions uint64) Com return CommitterLoader(l.Load) } -var _ CacheWrappable = (*IAVLCommitter)(nil) +var _ CacheIterKVStore = (*IAVLCommitter)(nil) var _ Committer = (*IAVLCommitter)(nil) // IAVLCommitter Implements IterKVStore and Committer @@ -48,13 +48,13 @@ type IAVLCommitter struct { // that is ready to use as a IterKVStore func NewIAVLCommitter(tree *iavl.VersionedTree, lastHeight uint64, nHistoricalVersions uint64) *IAVLCommitter { - i := &IAVLCommitter{ + ic := &IAVLCommitter{ tree: tree, lastHeight: lastHeight, nHistoricalVersions: nHistoricalVersions, } - i.updateStore() - return i + ic.updateStore() + return ic } // 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() // save a new version - i.lastHeight++ - hash, err := i.tree.SaveVersion(i.lastHeight) + ic.lastHeight++ + hash, err := ic.tree.SaveVersion(ic.lastHeight) if err != nil { // TODO: do we want to extend Commit to // allow returning errors? @@ -73,23 +73,23 @@ func (i *IAVLCommitter) Commit() CommitID { } // now point working state to the new status - i.updateStore() + ic.updateStore() // release an old version of history - if i.nHistoricalVersions <= i.lastHeight { - release := i.lastHeight - i.nHistoricalVersions - i.tree.DeleteVersion(release) + if ic.nHistoricalVersions <= ic.lastHeight { + release := ic.lastHeight - ic.nHistoricalVersions + ic.tree.DeleteVersion(release) } return CommitID{ - Version: i.lastHeight, + Version: ic.lastHeight, Hash: hash, } } // store returns a wrapper around the current writable state -func (i *IAVLCommitter) updateStore() { - i.IAVLStore = IAVLStore{i.tree.Tree()} +func (ic *IAVLCommitter) updateStore() { + ic.IAVLStore = IAVLStore{ic.tree.Tree()} } // IAVLStore is the writable state (not history) and @@ -98,55 +98,60 @@ type IAVLStore struct { tree *iavl.Tree } -// CacheWrap returns a wrapper around the current writable state -func (i IAVLStore) CacheWrap() CacheWriter { - // TODO: add CacheWrap to IAVLTree using new db stuff +// CacheWrap implements IterKVStore. +func (is IAVLStore) CacheWrap() CacheWriter { + return is.CacheIterKVStore() +} + +// CacheIterKVStore implements IterKVStore. +func (is IAVLStore) CacheIterKVStore() CacheIterKVStore { + // TODO: Add CacheWrap to IAVLTree. return i } -// Set implements KVStore -func (i IAVLStore) Set(key, value []byte) (prev []byte) { - _, prev = i.tree.Get(key) - i.tree.Set(key, value) +// Set implements IterKVStore. +func (is IAVLStore) Set(key, value []byte) (prev []byte) { + _, prev = is.tree.Get(key) + is.tree.Set(key, value) return prev } -// Get implements KVStore -func (i IAVLStore) Get(key []byte) (value []byte, exists bool) { - _, v := i.tree.Get(key) +// Get implements IterKVStore. +func (is IAVLStore) Get(key []byte) (value []byte, exists bool) { + _, v := is.tree.Get(key) return v, (v != nil) } -// Has implements KVStore -func (i IAVLStore) Has(key []byte) (exists bool) { - return i.tree.Has(key) +// Has implements IterKVStore. +func (is IAVLStore) Has(key []byte) (exists bool) { + return is.tree.Has(key) } -// Remove implements KVStore -func (i IAVLStore) Remove(key []byte) (prev []byte, removed bool) { - return i.tree.Remove(key) +// Remove implements IterKVStore. +func (is IAVLStore) Remove(key []byte) (prev []byte, removed bool) { + return is.tree.Remove(key) } -// Iterator implements IterKVStore -func (i IAVLStore) Iterator(start, end []byte) Iterator { +// Iterator implements IterKVStore. +func (is IAVLStore) Iterator(start, end []byte) Iterator { // TODO: this needs changes to IAVL tree return nil } -// ReverseIterator implements IterKVStore -func (i IAVLStore) ReverseIterator(start, end []byte) Iterator { +// ReverseIterator implements IterKVStore. +func (is IAVLStore) ReverseIterator(start, end []byte) Iterator { // TODO return nil } -// First implements IterKVStore -func (i IAVLStore) First(start, end []byte) (kv KVPair, ok bool) { +// First implements IterKVStore. +func (is IAVLStore) First(start, end []byte) (kv KVPair, ok bool) { // TODO return KVPair{}, false } -// Last implements IterKVStore -func (i IAVLStore) Last(start, end []byte) (kv KVPair, ok bool) { +// Last implements IterKVStore. +func (is IAVLStore) Last(start, end []byte) (kv KVPair, ok bool) { // TODO return KVPair{}, false } @@ -163,7 +168,7 @@ var _ Iterator = (*iavlIterator)(nil) // // The start & end (exclusive) limits to iterate over. // 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 return nil, nil } @@ -171,7 +176,7 @@ func (i *iavlIterator) Domain() (start, end []byte) { // Valid implements Iterator // // Returns if the current position is valid. -func (i *iavlIterator) Valid() bool { +func (ii *iavlIterator) Valid() bool { // TODO return false } @@ -179,7 +184,7 @@ func (i *iavlIterator) Valid() bool { // Next implements Iterator // // Next moves the iterator to the next key/value pair. -func (i *iavlIterator) Next() { +func (ii *iavlIterator) Next() { // TODO } @@ -188,7 +193,7 @@ func (i *iavlIterator) Next() { // 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 // its contents may change after calling Next(). -func (i *iavlIterator) Key() []byte { +func (ii *iavlIterator) Key() []byte { // TODO 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. // The caller should not modify the contents of the returned slice, and // its contents may change after calling Next(). -func (i *iavlIterator) Value() []byte { +func (ii *iavlIterator) Value() []byte { // TODO return nil } @@ -206,7 +211,7 @@ func (i *iavlIterator) Value() []byte { // Release implements Iterator // // Releases any resources and iteration-locks -func (i *iavlIterator) Release() { +func (ii *iavlIterator) Release() { // TODO } @@ -218,16 +223,16 @@ type iavlLoader struct { } // 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 - if l.dbName == "" { + if il.dbName == "" { tree := iavl.NewVersionedTree(0, dbm.NewMemDB()) - store := NewIAVLCommitter(tree, 0, l.nHistoricalVersions) + store := NewIAVLCommitter(tree, 0, il.nHistoricalVersions) return store, nil } // Expand the path fully - dbPath, err := filepath.Abs(l.dbName) + dbPath, err := filepath.Abs(il.dbName) if err != nil { 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 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 { return nil, errors.New("Loading tree: " + err.Error()) } // TODO: load the version stored in id store := NewIAVLCommitter(tree, tree.LatestVersion(), - l.nHistoricalVersions) + il.nHistoricalVersions) return store, nil } diff --git a/store/multistore.go b/store/rootmultistore.go similarity index 80% rename from store/multistore.go rename to store/rootmultistore.go index f6c47c302..e6b7409dd 100644 --- a/store/multistore.go +++ b/store/rootmultistore.go @@ -14,35 +14,7 @@ const ( commitStateKeyFmt = "s/%d" // s/ ) -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 - - // 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. +// rootMultiStore is composed of many CommitStores. // Name contrasts with cacheMultiStore which is for cache-wrapping // other MultiStores. // Implements MultiStore. @@ -50,8 +22,8 @@ type rootMultiStore struct { db dbm.DB curVersion int64 lastHash []byte - storeLoaders map[string]CommitterLoader - substores map[string]Committer + storeLoaders map[string]CommitStoreLoader + substores map[string]CommitStore } func NewMultiStore(db dbm.DB) *rootMultiStore { @@ -59,19 +31,19 @@ func NewMultiStore(db dbm.DB) *rootMultiStore { db: db, curVersion: 0, lastHash: nil, - storeLoaders: make(map[string]CommitterLoader), - substores: make(map[string]Committer), + storeLoaders: make(map[string]CommitStoreLoader), + 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 { panic(fmt.Sprintf("rootMultiStore duplicate substore name " + name)) } 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 { ver := getLatestVersion(rs.db) rs.LoadVersion(ver) @@ -103,12 +75,12 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error { var state commitState = loadCommitState(rs.db, ver) // Load each Substore - var newSubstores = make(map[string]Committer) + var newSubstores = make(map[string]CommitStore) for _, store := range state.Substores { name, commitID := store.Name, store.CommitID storeLoader := rs.storeLoaders[name] 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) if err != nil { @@ -117,10 +89,10 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error { newSubstores[name] = store } - // If any CommitterLoaders were not used, return error. + // If any CommitStoreLoaders were not used, return error. for name := range rs.storeLoaders { 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 { version := rs.version @@ -190,7 +162,11 @@ func (rs *rootMultiStore) Commit() CommitID { Version: version, Hash: state.Hash(), } +} +// Implements CommitStore +func (rs *rootMultiStore) CacheWrap() CacheWriter { + return rs.CacheMultiStore() } // Get the last committed CommitID @@ -213,7 +189,7 @@ func (rs *rootMultiStore) CacheMultiStore() CacheMultiStore { } // Implements MultiStore -func (rs *rootMultiStore) GetCommitter(name string) Committer { +func (rs *rootMultiStore) GetCommitStore(name string) CommitStore { return rs.store[name] } diff --git a/store/types.go b/store/types.go index be1e863f3..12972005d 100644 --- a/store/types.go +++ b/store/types.go @@ -14,36 +14,39 @@ func (cid CommitID) IsZero() bool { } type Committer interface { - // Commit persists the state to disk. 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 -// write its cached changes to its parent -type CacheWriter interface { - // Write must write to the - Write() error -} + CacheWrap() should not return a Committer, since Commit() on + cache-wraps make no sense. It can return KVStore, IterKVStore, etc. -// CacheWrappable is anything that can be wrapped with a cache. -type CacheWrappable interface { + The returned object may or may not implement CacheWrap() as well. - // CacheWrap() wraps a thing with a cache. After calling - // .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. + NOTE: https://dave.cheney.net/2017/07/22/should-go-2-0-support-generics. + */ 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 type KVStore interface { Set(key, value []byte) (prev []byte) @@ -53,8 +56,11 @@ type KVStore interface { // CacheKVStore() wraps a thing with a cache. After // calling .Write() on the CacheKVStore, all previous - // CacheWraps on the object expire. + // cache-wraps on the object expire. CacheKVStore() CacheKVStore + + // CacheWrap() returns a CacheKVStore. + CacheWrap() CacheWriter } type CacheKVStore interface { @@ -75,8 +81,11 @@ type IterKVStore interface { // CacheIterKVStore() wraps a thing with a cache. // After calling .Write() on the CacheIterKVStore, all - // previous CacheWraps on the object expire. + // previous cache-wraps on the object expire. CacheIterKVStore() CacheIterKVStore + + // CacheWrap() returns a CacheIterKVStore. + CacheWrap() CacheWriter } type CacheIterKVStore interface { @@ -130,3 +139,32 @@ type Iterator interface { // Releases any resources and iteration-locks 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 +}