Skip to content

Commit d3021d4

Browse files
authored
Merge PR #2143: Speedup IAVL iterator by removing defers when unneeded.
2 parents 5ed1775 + 2c3a4fc commit d3021d4

File tree

4 files changed

+73
-39
lines changed

4 files changed

+73
-39
lines changed

Gopkg.lock

Lines changed: 27 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PENDING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ IMPROVEMENTS
6363
* SDK
6464
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
6565
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
66+
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
6667
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
6768

6869
* Tendermint

store/iavlstore.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -332,39 +332,42 @@ func (iter *iavlIterator) Domain() (start, end []byte) {
332332
func (iter *iavlIterator) Valid() bool {
333333
iter.waitInit()
334334
iter.mtx.Lock()
335-
defer iter.mtx.Unlock()
336335

337-
return !iter.invalid
336+
validity := !iter.invalid
337+
iter.mtx.Unlock()
338+
return validity
338339
}
339340

340341
// Implements Iterator.
341342
func (iter *iavlIterator) Next() {
342343
iter.waitInit()
343344
iter.mtx.Lock()
344-
defer iter.mtx.Unlock()
345-
iter.assertIsValid()
345+
iter.assertIsValid(true)
346346

347347
iter.receiveNext()
348+
iter.mtx.Unlock()
348349
}
349350

350351
// Implements Iterator.
351352
func (iter *iavlIterator) Key() []byte {
352353
iter.waitInit()
353354
iter.mtx.Lock()
354-
defer iter.mtx.Unlock()
355-
iter.assertIsValid()
355+
iter.assertIsValid(true)
356356

357-
return iter.key
357+
key := iter.key
358+
iter.mtx.Unlock()
359+
return key
358360
}
359361

360362
// Implements Iterator.
361363
func (iter *iavlIterator) Value() []byte {
362364
iter.waitInit()
363365
iter.mtx.Lock()
364-
defer iter.mtx.Unlock()
365-
iter.assertIsValid()
366+
iter.assertIsValid(true)
366367

367-
return iter.value
368+
val := iter.value
369+
iter.mtx.Unlock()
370+
return val
368371
}
369372

370373
// Implements Iterator.
@@ -375,14 +378,14 @@ func (iter *iavlIterator) Close() {
375378
//----------------------------------------
376379

377380
func (iter *iavlIterator) setNext(key, value []byte) {
378-
iter.assertIsValid()
381+
iter.assertIsValid(false)
379382

380383
iter.key = key
381384
iter.value = value
382385
}
383386

384387
func (iter *iavlIterator) setInvalid() {
385-
iter.assertIsValid()
388+
iter.assertIsValid(false)
386389

387390
iter.invalid = true
388391
}
@@ -400,8 +403,14 @@ func (iter *iavlIterator) receiveNext() {
400403
}
401404
}
402405

403-
func (iter *iavlIterator) assertIsValid() {
406+
// assertIsValid panics if the iterator is invalid. If unlockMutex is true,
407+
// it also unlocks the mutex before panicing, to prevent deadlocks in code that
408+
// recovers from panics
409+
func (iter *iavlIterator) assertIsValid(unlockMutex bool) {
404410
if iter.invalid {
411+
if unlockMutex {
412+
iter.mtx.Unlock()
413+
}
405414
panic("invalid iterator")
406415
}
407416
}

store/iavlstore_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,3 +464,26 @@ func TestIAVLStoreQuery(t *testing.T) {
464464
require.Equal(t, uint32(sdk.CodeOK), qres.Code)
465465
require.Equal(t, v1, qres.Value)
466466
}
467+
468+
func BenchmarkIAVLIteratorNext(b *testing.B) {
469+
db := dbm.NewMemDB()
470+
treeSize := 1000
471+
tree := iavl.NewVersionedTree(db, cacheSize)
472+
for i := 0; i < treeSize; i++ {
473+
key := cmn.RandBytes(4)
474+
value := cmn.RandBytes(50)
475+
tree.Set(key, value)
476+
}
477+
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
478+
iterators := make([]Iterator, b.N/treeSize)
479+
for i := 0; i < len(iterators); i++ {
480+
iterators[i] = iavlStore.Iterator([]byte{0}, []byte{255, 255, 255, 255, 255})
481+
}
482+
b.ResetTimer()
483+
for i := 0; i < len(iterators); i++ {
484+
iter := iterators[i]
485+
for j := 0; j < treeSize; j++ {
486+
iter.Next()
487+
}
488+
}
489+
}

0 commit comments

Comments
 (0)