Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast Cache - Downgrade - reupgrade protection and other improvements #12

Merged
merged 27 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6350dc8
add leaf hash to fast node and unit test
p0mvn Jan 26, 2022
5f579c5
refactor get with index and get by index, fix migration in load versi…
p0mvn Jan 26, 2022
f6ebabb
use Get in GetVersioned of mutable tree
p0mvn Jan 27, 2022
89633f7
refactor non membership proof to use fast storage if available
p0mvn Jan 27, 2022
75d9f81
bench non-membership proof
p0mvn Jan 27, 2022
19ee7d3
fix bench tests to work with the new changes
p0mvn Jan 28, 2022
cbf2f41
add downgrade-reupgrade protection and unit test
p0mvn Jan 28, 2022
96208dc
remove leaf hash from fast node
p0mvn Jan 28, 2022
5217e71
resolve multithreading bug related to iterators not being closed
p0mvn Jan 28, 2022
ea072a6
clean up
p0mvn Jan 28, 2022
806b1a0
use correct tree in bench tests
p0mvn Jan 29, 2022
3f24e71
add cache to tree used to bench non membership proofs
p0mvn Jan 29, 2022
0cb480e
add benc tests for GetWithIndex and GetByIndex
p0mvn Jan 29, 2022
ee1ab84
revert GetWithIndex and GetByIndex
p0mvn Jan 29, 2022
2edb8cc
remove unused import
p0mvn Jan 29, 2022
9712e87
unit test re-upgrade protection and fix small issues
p0mvn Jan 30, 2022
eea8cfd
remove redundant setStorageVersion method
p0mvn Jan 31, 2022
cd0a61c
fix bug with appending to live stage version to storage version and n…
p0mvn Jan 31, 2022
8586d10
add comment for setFastStorageVersionToBatch
p0mvn Jan 31, 2022
c293938
refactor and improve unit tests for reupgrade protection
p0mvn Jan 31, 2022
eae9425
rename ndb's isFastStorageEnabled to hasUpgradedToFastStorage and add…
p0mvn Jan 31, 2022
2241204
comment out new implementation for GetNonMembershipProof
p0mvn Jan 31, 2022
31710b3
update comments in nodedb to reflect the difference between hasUpgrad…
p0mvn Jan 31, 2022
c0e4776
refactor nodedb tests
p0mvn Jan 31, 2022
51b6c2f
downgrade tendermint to 0.34.14 - osmosis's latest cosmos sdk does no…
p0mvn Feb 3, 2022
a7e7fb2
fix bug where fast storage was not enabled when version 0 was attempt…
p0mvn Feb 7, 2022
f78896b
implement unsaved fast iterator to be used in mutable tree (#16)
p0mvn Feb 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions benchmarks/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func commitTree(b *testing.B, t *iavl.MutableTree) {

// queries random keys against live state. Keys are almost certainly not in the tree.
func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) {
require.True(b, t.IsFastCacheEnabled())
for i := 0; i < b.N; i++ {
q := randBytes(keyLen)
t.Get(q)
Expand All @@ -67,6 +68,7 @@ func runQueriesFast(b *testing.B, t *iavl.MutableTree, keyLen int) {

// queries keys that are known to be in state
func runKnownQueriesFast(b *testing.B, t *iavl.MutableTree, keys [][]byte) {
require.True(b, t.IsFastCacheEnabled()) // to ensure fast storage is enabled
l := int32(len(keys))
for i := 0; i < b.N; i++ {
q := keys[rand.Int31n(l)]
Expand All @@ -75,22 +77,43 @@ func runKnownQueriesFast(b *testing.B, t *iavl.MutableTree, keys [][]byte) {
}

func runQueriesSlow(b *testing.B, t *iavl.MutableTree, keyLen int) {
b.StopTimer()
// Save version to get an old immutable tree to query against,
// Fast storage is not enabled on old tree versions, allowing us to bench the desired behavior.
_, version, err := t.SaveVersion()
require.NoError(b, err)

itree, err := t.GetImmutable(version - 1)
require.NoError(b, err)
require.False(b, itree.IsFastCacheEnabled()) // to ensure fast storage is not enabled

b.StartTimer()
for i := 0; i < b.N; i++ {
q := randBytes(keyLen)
t.GetWithIndex(q)
itree.GetWithIndex(q)
}
}

func runKnownQueriesSlow(b *testing.B, t *iavl.MutableTree, keys [][]byte) {
b.StopTimer()
// Save version to get an old immutable tree to query against,
// Fast storage is not enabled on old tree versions, allowing us to bench the desired behavior.
_, version, err := t.SaveVersion()
require.NoError(b, err)

itree, err := t.GetImmutable(version - 1)
require.NoError(b, err)
require.False(b, itree.IsFastCacheEnabled()) // to ensure fast storage is not enabled
b.StartTimer()
l := int32(len(keys))
for i := 0; i < b.N; i++ {
q := keys[rand.Int31n(l)]
t.GetWithIndex(q)
itree.GetWithIndex(q)
}
}

func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) {
require.True(b, t.IsFastCacheEnabled()) // to ensure that fast iterator is returned.
require.True(b, t.IsFastCacheEnabled()) // to ensure fast storage is enabled
for i := 0; i < b.N; i++ {
itr := t.ImmutableTree.Iterator(nil, nil, false)
iterate(b, itr, expectedSize)
Expand All @@ -100,7 +123,7 @@ func runIterationFast(b *testing.B, t *iavl.MutableTree, expectedSize int) {

func runIterationSlow(b *testing.B, t *iavl.MutableTree, expectedSize int) {
for i := 0; i < b.N; i++ {
itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree)
itr := iavl.NewIterator(nil, nil, false, t.ImmutableTree) // create slow iterator directly
iterate(b, itr, expectedSize)
itr.Close()
}
Expand Down
4 changes: 2 additions & 2 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func setupExportTreeRandom(t *testing.T) *ImmutableTree {
keySize = 16
valueSize = 16

versions = 32 // number of versions to generate
versionOps = 4096 // number of operations (create/update/delete) per version
versions = 8 // number of versions to generate
versionOps = 1024 // number of operations (create/update/delete) per version
updateRatio = 0.4 // ratio of updates out of all operations
deleteRatio = 0.2 // ratio of deletes out of all operations
)
Expand Down
5 changes: 2 additions & 3 deletions fast_iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,11 @@ func (iter *FastIterator) Next() {

// Close implements dbm.Iterator
func (iter *FastIterator) Close() error {
iter.fastIterator = nil
iter.valid = false

if iter.fastIterator != nil {
iter.err = iter.fastIterator.Close()
}
iter.valid = false
iter.fastIterator = nil
return iter.err
}

Expand Down
3 changes: 1 addition & 2 deletions fast_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ type FastNode struct {
key []byte
versionLastUpdatedAt int64
value []byte
// leafHash []byte // TODO: Look into if this would help with proof stuff.
}

// NewFastNode returns a new fast node from a value and version.
Expand All @@ -34,7 +33,7 @@ func DeserializeFastNode(key []byte, buf []byte) (*FastNode, error) {

val, _, cause := decodeBytes(buf)
if cause != nil {
return nil, errors.Wrap(cause, "decoding node.value")
return nil, errors.Wrap(cause, "decoding fastnode.value")
}

fastNode := &FastNode{
Expand Down
58 changes: 58 additions & 0 deletions fast_node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package iavl

import (
"bytes"
"encoding/hex"
"testing"

"github.com/stretchr/testify/require"
)

func TestFastNode_encodedSize(t *testing.T) {
fastNode := &FastNode{
key: randBytes(10),
versionLastUpdatedAt: 1,
value: randBytes(20),
}

expectedSize := 1 + len(fastNode.value) + 1

require.Equal(t, expectedSize, fastNode.encodedSize())
}

func TestFastNode_encode_decode(t *testing.T) {
testcases := map[string]struct {
node *FastNode
expectHex string
expectError bool
}{
"nil": {nil, "", true},
"empty": {&FastNode{}, "0000", false},
"inner": {&FastNode{
key: []byte{0x4},
versionLastUpdatedAt: 1,
value: []byte{0x2},
}, "020102", false},
}
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
var buf bytes.Buffer
err := tc.node.writeBytes(&buf)
if tc.expectError {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectHex, hex.EncodeToString(buf.Bytes()))

node, err := DeserializeFastNode(tc.node.key, buf.Bytes())
require.NoError(t, err)
// since value and leafHash are always decoded to []byte{} we augment the expected struct here
if tc.node.value == nil {
tc.node.value = []byte{}
}
require.Equal(t, tc.node, node)
})
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
github.com/tendermint/tendermint v0.35.0
github.com/tendermint/tendermint v0.34.14
github.com/tendermint/tm-db v0.6.4
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4
Expand Down
Loading