From 1a28c4b89c3235d4cdf4e060c23f88b19dd99e6b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 12 Dec 2017 02:36:50 -0500 Subject: [PATCH] store: add some tests, fix deadlocks (#297) --- store/iavlstore.go | 44 ++++++++---------- store/iavlstore_test.go | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 store/iavlstore_test.go diff --git a/store/iavlstore.go b/store/iavlstore.go index a90941462670..bd1cc22fd980 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -7,6 +7,13 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) +// iavlStoreLoader contains info on what store we want to load from +type iavlStoreLoader struct { + db dbm.DB + cacheSize int + numHistory int64 +} + // NewIAVLStoreLoader returns a CommitStoreLoader that returns an iavlStore func NewIAVLStoreLoader(db dbm.DB, cacheSize int, numHistory int64) CommitStoreLoader { l := iavlStoreLoader{ @@ -17,6 +24,19 @@ func NewIAVLStoreLoader(db dbm.DB, cacheSize int, numHistory int64) CommitStoreL return l.Load } +// Load implements CommitLoader. +func (isl iavlStoreLoader) Load(id CommitID) (CommitStore, error) { + tree := iavl.NewVersionedTree(isl.db, isl.cacheSize) + err := tree.Load() + if err != nil { + return nil, err + } + store := newIAVLStore(tree, isl.numHistory) + return store, nil +} + +//---------------------------------------- + var _ IterKVStore = (*iavlStore)(nil) var _ CommitStore = (*iavlStore)(nil) @@ -243,8 +263,6 @@ func (iter *iavlIterator) Release() { //---------------------------------------- func (iter *iavlIterator) setNext(key, value []byte) { - iter.mtx.Lock() - defer iter.mtx.Unlock() iter.assertIsValid() iter.key = key @@ -252,8 +270,6 @@ func (iter *iavlIterator) setNext(key, value []byte) { } func (iter *iavlIterator) setInvalid() { - iter.mtx.Lock() - defer iter.mtx.Unlock() iter.assertIsValid() iter.invalid = true @@ -280,26 +296,6 @@ func (iter *iavlIterator) assertIsValid() { //---------------------------------------- -// iavlStoreLoader contains info on what store we want to load from -type iavlStoreLoader struct { - db dbm.DB - cacheSize int - numHistory int64 -} - -// Load implements CommitLoader. -func (isl iavlStoreLoader) Load(id CommitID) (CommitStore, error) { - tree := iavl.NewVersionedTree(isl.db, isl.cacheSize) - err := tree.Load() - if err != nil { - return nil, err - } - store := newIAVLStore(tree, isl.numHistory) - return store, nil -} - -//---------------------------------------- - func cp(bz []byte) (ret []byte) { ret = make([]byte, len(bz)) copy(ret, bz) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go new file mode 100644 index 000000000000..5ed1a1a29f06 --- /dev/null +++ b/store/iavlstore_test.go @@ -0,0 +1,100 @@ +package store + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + + "github.com/tendermint/iavl" +) + +var ( + cacheSize = 100 + numHistory int64 = 5 +) + +var ( + treeData = map[string]string{ + "hello": "goodbye", + "aloha": "shalom", + } + nMoreData = 0 +) + +// make a tree and save it +func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) { + tree := iavl.NewVersionedTree(db, cacheSize) + for k, v := range treeData { + tree.Set([]byte(k), []byte(v)) + } + for i := 0; i < nMoreData; i++ { + key := cmn.RandBytes(12) + value := cmn.RandBytes(50) + tree.Set(key, value) + } + hash, ver, err := tree.SaveVersion() + assert.Nil(t, err) + return tree, CommitID{ver, hash} +} + +func TestIAVLStoreLoader(t *testing.T) { + db := dbm.NewMemDB() + _, id := newTree(t, db) + + iavlLoader := NewIAVLStoreLoader(db, cacheSize, numHistory) + commitStore, err := iavlLoader(id) + assert.Nil(t, err) + + id2 := commitStore.Commit() + + assert.Equal(t, id.Hash, id2.Hash) + assert.Equal(t, id.Version+1, id2.Version) +} + +func TestIAVLStoreGetSetHasRemove(t *testing.T) { + db := dbm.NewMemDB() + tree, _ := newTree(t, db) + iavlStore := newIAVLStore(tree, numHistory) + + key := "hello" + + exists := iavlStore.Has([]byte(key)) + assert.True(t, exists) + + value, exists := iavlStore.Get([]byte(key)) + assert.True(t, exists) + assert.EqualValues(t, value, treeData[key]) + + value2 := "notgoodbye" + prev := iavlStore.Set([]byte(key), []byte(value2)) + assert.EqualValues(t, value, prev) + + value, exists = iavlStore.Get([]byte(key)) + assert.True(t, exists) + assert.EqualValues(t, value, value2) + + prev, removed := iavlStore.Remove([]byte(key)) + assert.True(t, removed) + assert.EqualValues(t, value2, prev) + + exists = iavlStore.Has([]byte(key)) + assert.False(t, exists) +} + +func TestIAVLIterator(t *testing.T) { + db := dbm.NewMemDB() + tree, _ := newTree(t, db) + iavlStore := newIAVLStore(tree, numHistory) + iter := iavlStore.Iterator([]byte("aloha"), []byte("hellz")) + expected := []string{"aloha", "hello"} + for i := 0; iter.Valid(); iter.Next() { + expectedKey := expected[i] + key, value := iter.Key(), iter.Value() + assert.EqualValues(t, key, expectedKey) + assert.EqualValues(t, value, treeData[expectedKey]) + i += 1 + } +}