diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b94354bfd7..84bb578a1307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (store) [#10218](https://github.com/cosmos/cosmos-sdk/pull/10218) Charge gas even when there are no entries while seeking. * (store) [#10247](https://github.com/cosmos/cosmos-sdk/pull/10247) Charge gas for the key length in gas meter. +### Improvements + +* (store) [\#10741](https://github.com/cosmos/cosmos-sdk/pull/10741) Significantly speedup iterator creation after delete heavy workloads. Significantly improves IBC migration times. + ## [v0.44.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.5) - 2021-12-02 ### Improvements diff --git a/store/cachekv/bench_helper_test.go b/store/cachekv/bench_helper_test.go index be7fec4b3a7b..fe5be27fabc9 100644 --- a/store/cachekv/bench_helper_test.go +++ b/store/cachekv/bench_helper_test.go @@ -34,7 +34,7 @@ func generateSequentialKeys(startKey []byte, numKeys int) [][]byte { } // Generate many random, unsorted keys -func generateRandomKeys(keySize, numKeys int) [][]byte { +func generateRandomKeys(keySize int, numKeys int) [][]byte { toReturn := make([][]byte, 0, numKeys) for i := 0; i < numKeys; i++ { newKey := randSlice(keySize) diff --git a/store/cachekv/store_bench_test.go b/store/cachekv/store_bench_test.go index 96e9e3101cfc..c3d93fd5de2c 100644 --- a/store/cachekv/store_bench_test.go +++ b/store/cachekv/store_bench_test.go @@ -14,8 +14,7 @@ const defaultValueSizeBz = 1 << 12 // This benchmark measures the time of iterator.Next() when the parent store is blank func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) { - b.Helper() - mem := dbadapter.Store{DB: coretesting.NewMemDB()} + mem := dbadapter.Store{DB: dbm.NewMemDB()} kvstore := cachekv.NewStore(mem) // Use a singleton for value, to not waste time computing it value := randSlice(defaultValueSizeBz) @@ -35,8 +34,7 @@ func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) { iter := kvstore.Iterator(keys[0], keys[b.N]) defer iter.Close() - for ; iter.Valid(); iter.Next() { - _ = iter.Key() + for _ = iter.Key(); iter.Valid(); iter.Next() { // deadcode elimination stub sink = iter } @@ -44,8 +42,7 @@ func benchmarkBlankParentIteratorNext(b *testing.B, keysize int) { // Benchmark setting New keys to a store, where the new keys are in sequence. func benchmarkBlankParentAppend(b *testing.B, keysize int) { - b.Helper() - mem := dbadapter.Store{DB: coretesting.NewMemDB()} + mem := dbadapter.Store{DB: dbm.NewMemDB()} kvstore := cachekv.NewStore(mem) // Use a singleton for value, to not waste time computing it @@ -67,14 +64,12 @@ func benchmarkBlankParentAppend(b *testing.B, keysize int) { // Benchmark setting New keys to a store, where the new keys are random. // the speed of this function does not depend on the values in the parent store func benchmarkRandomSet(b *testing.B, keysize int) { - b.Helper() - mem := dbadapter.Store{DB: coretesting.NewMemDB()} + mem := dbadapter.Store{DB: dbm.NewMemDB()} kvstore := cachekv.NewStore(mem) // Use a singleton for value, to not waste time computing it value := randSlice(defaultValueSizeBz) - // Add 1 to avoid issues when b.N = 1 - keys := generateRandomKeys(keysize, b.N+1) + keys := generateRandomKeys(keysize, b.N) b.ReportAllocs() b.ResetTimer() @@ -86,8 +81,7 @@ func benchmarkRandomSet(b *testing.B, keysize int) { iter := kvstore.Iterator(keys[0], keys[b.N]) defer iter.Close() - for ; iter.Valid(); iter.Next() { - _ = iter.Key() + for _ = iter.Key(); iter.Valid(); iter.Next() { // deadcode elimination stub sink = iter } @@ -98,16 +92,14 @@ func benchmarkRandomSet(b *testing.B, keysize int) { // We essentially are benchmarking the cacheKV iterator creation & iteration times // with the number of entries deleted in the parent. func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) { - b.Helper() - mem := dbadapter.Store{DB: coretesting.NewMemDB()} + mem := dbadapter.Store{DB: dbm.NewMemDB()} // Use a singleton for value, to not waste time computing it value := randSlice(32) // Use simple values for keys, pick a random start, // and take next D keys sequentially after. startKey := randSlice(32) - // Add 1 to avoid issues when numDeletes = 1 - keys := generateSequentialKeys(startKey, numDeletes+1) + keys := generateSequentialKeys(startKey, numDeletes) // setup parent db with D keys. for _, k := range keys { mem.Set(k, value) @@ -125,11 +117,10 @@ func benchmarkIteratorOnParentWithManyDeletes(b *testing.B, numDeletes int) { b.ReportAllocs() b.ResetTimer() - iter := kvstore.Iterator(keys[0], keys[numDeletes]) + iter := kvstore.Iterator(keys[0], keys[b.N]) defer iter.Close() - for ; iter.Valid(); iter.Next() { - _ = iter.Key() + for _ = iter.Key(); iter.Valid(); iter.Next() { // deadcode elimination stub sink = iter }