Skip to content

Commit

Permalink
Speedup IAVL iterator by removing defers when unneeded.
Browse files Browse the repository at this point in the history
Note each defer occurs a 30ish ns overhead here, which is significant
for IAVL iteration. We were previously using around 3-4 defers. (2 in
next, one in Valid, one in Key, one in Value) This slows down the entire
application quite significantly, as we require fast iteration.
  • Loading branch information
ValarDragon committed Aug 24, 2018
1 parent c5d44bc commit f6cb4d4
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 39 deletions.
53 changes: 27 additions & 26 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ IMPROVEMENTS
* SDK
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)

* Tendermint

Expand Down
35 changes: 22 additions & 13 deletions store/iavlstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,39 +332,42 @@ func (iter *iavlIterator) Domain() (start, end []byte) {
func (iter *iavlIterator) Valid() bool {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()

return !iter.invalid
validity := !iter.invalid
iter.mtx.Unlock()
return validity
}

// Implements Iterator.
func (iter *iavlIterator) Next() {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
iter.assertIsValid(true)

iter.receiveNext()
iter.mtx.Unlock()
}

// Implements Iterator.
func (iter *iavlIterator) Key() []byte {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
iter.assertIsValid(true)

return iter.key
key := iter.key
iter.mtx.Unlock()
return key
}

// Implements Iterator.
func (iter *iavlIterator) Value() []byte {
iter.waitInit()
iter.mtx.Lock()
defer iter.mtx.Unlock()
iter.assertIsValid()
iter.assertIsValid(true)

return iter.value
val := iter.value
iter.mtx.Unlock()
return val
}

// Implements Iterator.
Expand All @@ -375,14 +378,14 @@ func (iter *iavlIterator) Close() {
//----------------------------------------

func (iter *iavlIterator) setNext(key, value []byte) {
iter.assertIsValid()
iter.assertIsValid(false)

iter.key = key
iter.value = value
}

func (iter *iavlIterator) setInvalid() {
iter.assertIsValid()
iter.assertIsValid(false)

iter.invalid = true
}
Expand All @@ -400,8 +403,14 @@ func (iter *iavlIterator) receiveNext() {
}
}

func (iter *iavlIterator) assertIsValid() {
// assertIsValid panics if the iterator is invalid. If unlockMutex is true,
// it also unlocks the mutex before panicing, to prevent deadlocks in code that
// recovers from panics
func (iter *iavlIterator) assertIsValid(unlockMutex bool) {
if iter.invalid {
if unlockMutex {
iter.mtx.Unlock()
}
panic("invalid iterator")
}
}
Expand Down
23 changes: 23 additions & 0 deletions store/iavlstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,26 @@ func TestIAVLStoreQuery(t *testing.T) {
require.Equal(t, uint32(sdk.CodeOK), qres.Code)
require.Equal(t, v1, qres.Value)
}

func BenchmarkIAVLIteratorNext(b *testing.B) {
db := dbm.NewMemDB()
treeSize := 1000
tree := iavl.NewVersionedTree(db, cacheSize)
for i := 0; i < treeSize; i++ {
key := cmn.RandBytes(4)
value := cmn.RandBytes(50)
tree.Set(key, value)
}
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
iterators := make([]Iterator, b.N/treeSize)
for i := 0; i < len(iterators); i++ {
iterators[i] = iavlStore.Iterator([]byte{0}, []byte{255, 255, 255, 255, 255})
}
b.ResetTimer()
for i := 0; i < len(iterators); i++ {
iter := iterators[i]
for j := 0; j < treeSize; j++ {
iter.Next()
}
}
}

0 comments on commit f6cb4d4

Please sign in to comment.