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
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
}

View File

@ -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
}

View File

@ -14,35 +14,7 @@ const (
commitStateKeyFmt = "s/%d" // s/<version>
)
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]
}

View File

@ -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
}