Skip to content

Commit 9b6be30

Browse files
authored
cherry optional fastnode (#562)
1 parent 1244f6b commit 9b6be30

19 files changed

+423
-208
lines changed

basic_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,15 +472,15 @@ func TestPersistence(t *testing.T) {
472472
}
473473

474474
// Construct some tree and save it
475-
t1, err := NewMutableTree(db, 0)
475+
t1, err := NewMutableTree(db, 0, false)
476476
require.NoError(t, err)
477477
for key, value := range records {
478478
t1.Set([]byte(key), []byte(value))
479479
}
480480
t1.SaveVersion()
481481

482482
// Load a tree
483-
t2, err := NewMutableTree(db, 0)
483+
t2, err := NewMutableTree(db, 0, false)
484484
require.NoError(t, err)
485485
t2.Load()
486486
for key, value := range records {
@@ -527,7 +527,7 @@ func TestProof(t *testing.T) {
527527

528528
func TestTreeProof(t *testing.T) {
529529
db := db.NewMemDB()
530-
tree, err := NewMutableTree(db, 100)
530+
tree, err := NewMutableTree(db, 100, false)
531531
require.NoError(t, err)
532532
hash, err := tree.Hash()
533533
require.NoError(t, err)

benchmarks/bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func randBytes(length int) []byte {
2424
}
2525

2626
func prepareTree(b *testing.B, db db.DB, size, keyLen, dataLen int) (*iavl.MutableTree, [][]byte) {
27-
t, err := iavl.NewMutableTreeWithOpts(db, size, nil)
27+
t, err := iavl.NewMutableTreeWithOpts(db, size, nil, false)
2828
require.NoError(b, err)
2929
keys := make([][]byte, size)
3030

benchmarks/cosmos-exim/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func runExport(dbPath string) (int64, map[string][]*iavl.ExportNode, error) {
9191
if err != nil {
9292
return 0, nil, err
9393
}
94-
tree, err := iavl.NewMutableTree(tmdb.NewPrefixDB(ldb, []byte("s/k:main/")), 0)
94+
tree, err := iavl.NewMutableTree(tmdb.NewPrefixDB(ldb, []byte("s/k:main/")), 0, false)
9595
if err != nil {
9696
return 0, nil, err
9797
}
@@ -106,7 +106,7 @@ func runExport(dbPath string) (int64, map[string][]*iavl.ExportNode, error) {
106106
totalStats := Stats{}
107107
for _, name := range stores {
108108
db := tmdb.NewPrefixDB(ldb, []byte("s/k:"+name+"/"))
109-
tree, err := iavl.NewMutableTree(db, 0)
109+
tree, err := iavl.NewMutableTree(db, 0, false)
110110
if err != nil {
111111
return 0, nil, err
112112
}
@@ -171,7 +171,7 @@ func runImport(version int64, exports map[string][]*iavl.ExportNode) error {
171171
if err != nil {
172172
return err
173173
}
174-
newTree, err := iavl.NewMutableTree(newDB, 0)
174+
newTree, err := iavl.NewMutableTree(newDB, 0, false)
175175
if err != nil {
176176
return err
177177
}

cmd/iaviewer/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func ReadTree(dir string, version int, prefix []byte) (*iavl.MutableTree, error)
120120
db = dbm.NewPrefixDB(db, prefix)
121121
}
122122

123-
tree, err := iavl.NewMutableTree(db, DefaultCacheSize)
123+
tree, err := iavl.NewMutableTree(db, DefaultCacheSize, false)
124124
if err != nil {
125125
return nil, err
126126
}

export_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
// setupExportTreeBasic sets up a basic tree with a handful of
1515
// create/update/delete operations over a few versions.
1616
func setupExportTreeBasic(t require.TestingT) *ImmutableTree {
17-
tree, err := NewMutableTree(db.NewMemDB(), 0)
17+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
1818
require.NoError(t, err)
1919

2020
tree.Set([]byte("x"), []byte{255})
@@ -59,7 +59,7 @@ func setupExportTreeRandom(t *testing.T) *ImmutableTree {
5959
)
6060

6161
r := rand.New(rand.NewSource(randSeed))
62-
tree, err := NewMutableTree(db.NewMemDB(), 0)
62+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
6363
require.NoError(t, err)
6464

6565
var version int64
@@ -119,7 +119,7 @@ func setupExportTreeSized(t require.TestingT, treeSize int) *ImmutableTree {
119119
)
120120

121121
r := rand.New(rand.NewSource(randSeed))
122-
tree, err := NewMutableTree(db.NewMemDB(), 0)
122+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
123123
require.NoError(t, err)
124124

125125
for i := 0; i < treeSize; i++ {
@@ -176,7 +176,7 @@ func TestExporter(t *testing.T) {
176176

177177
func TestExporter_Import(t *testing.T) {
178178
testcases := map[string]*ImmutableTree{
179-
"empty tree": NewImmutableTree(db.NewMemDB(), 0),
179+
"empty tree": NewImmutableTree(db.NewMemDB(), 0, false),
180180
"basic tree": setupExportTreeBasic(t),
181181
}
182182
if !testing.Short() {
@@ -192,7 +192,7 @@ func TestExporter_Import(t *testing.T) {
192192
exporter := tree.Export()
193193
defer exporter.Close()
194194

195-
newTree, err := NewMutableTree(db.NewMemDB(), 0)
195+
newTree, err := NewMutableTree(db.NewMemDB(), 0, false)
196196
require.NoError(t, err)
197197
importer, err := newTree.Import(tree.Version())
198198
require.NoError(t, err)
@@ -256,7 +256,7 @@ func TestExporter_Close(t *testing.T) {
256256
}
257257

258258
func TestExporter_DeleteVersionErrors(t *testing.T) {
259-
tree, err := NewMutableTree(db.NewMemDB(), 0)
259+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
260260
require.NoError(t, err)
261261

262262
tree.Set([]byte("a"), []byte{1})

immutable_tree.go

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,31 @@ import (
1414
// Returned key/value byte slices must not be modified, since they may point to data located inside
1515
// IAVL which would also be modified.
1616
type ImmutableTree struct {
17-
root *Node
18-
ndb *nodeDB
19-
version int64
17+
root *Node
18+
ndb *nodeDB
19+
version int64
20+
skipFastStorageUpgrade bool
2021
}
2122

2223
// NewImmutableTree creates both in-memory and persistent instances
23-
func NewImmutableTree(db dbm.DB, cacheSize int) *ImmutableTree {
24+
func NewImmutableTree(db dbm.DB, cacheSize int, skipFastStorageUpgrade bool) *ImmutableTree {
2425
if db == nil {
2526
// In-memory Tree.
2627
return &ImmutableTree{}
2728
}
2829
return &ImmutableTree{
2930
// NodeDB-backed Tree.
30-
ndb: newNodeDB(db, cacheSize, nil),
31+
ndb: newNodeDB(db, cacheSize, nil),
32+
skipFastStorageUpgrade: skipFastStorageUpgrade,
3133
}
3234
}
3335

3436
// NewImmutableTreeWithOpts creates an ImmutableTree with the given options.
35-
func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options) *ImmutableTree {
37+
func NewImmutableTreeWithOpts(db dbm.DB, cacheSize int, opts *Options, skipFastStorageUpgrade bool) *ImmutableTree {
3638
return &ImmutableTree{
3739
// NodeDB-backed Tree.
38-
ndb: newNodeDB(db, cacheSize, opts),
40+
ndb: newNodeDB(db, cacheSize, opts),
41+
skipFastStorageUpgrade: skipFastStorageUpgrade,
3942
}
4043
}
4144

@@ -172,36 +175,40 @@ func (t *ImmutableTree) GetWithIndex(key []byte) (int64, []byte, error) {
172175
// Get returns the value of the specified key if it exists, or nil.
173176
// The returned value must not be modified, since it may point to data stored within IAVL.
174177
// Get potentially employs a more performant strategy than GetWithIndex for retrieving the value.
178+
// If tree.skipFastStorageUpgrade is true, this will work almost the same as GetWithIndex.
175179
func (t *ImmutableTree) Get(key []byte) ([]byte, error) {
176180
if t.root == nil {
177181
return nil, nil
178182
}
179183

180-
// attempt to get a FastNode directly from db/cache.
181-
// if call fails, fall back to the original IAVL logic in place.
182-
fastNode, err := t.ndb.GetFastNode(key)
183-
if err != nil {
184-
_, result, err := t.root.get(t, key)
185-
return result, err
186-
}
187-
188-
if fastNode == nil {
189-
// If the tree is of the latest version and fast node is not in the tree
190-
// then the regular node is not in the tree either because fast node
191-
// represents live state.
192-
if t.version == t.ndb.latestVersion {
193-
return nil, nil
184+
if !t.skipFastStorageUpgrade {
185+
// attempt to get a FastNode directly from db/cache.
186+
// if call fails, fall back to the original IAVL logic in place.
187+
fastNode, err := t.ndb.GetFastNode(key)
188+
if err != nil {
189+
_, result, err := t.root.get(t, key)
190+
return result, err
194191
}
195192

196-
_, result, err := t.root.get(t, key)
197-
return result, err
198-
}
193+
if fastNode == nil {
194+
// If the tree is of the latest version and fast node is not in the tree
195+
// then the regular node is not in the tree either because fast node
196+
// represents live state.
197+
if t.version == t.ndb.latestVersion {
198+
return nil, nil
199+
}
199200

200-
if fastNode.versionLastUpdatedAt <= t.version {
201-
return fastNode.value, nil
201+
_, result, err := t.root.get(t, key)
202+
return result, err
203+
}
204+
205+
if fastNode.versionLastUpdatedAt <= t.version {
206+
return fastNode.value, nil
207+
}
202208
}
203209

204-
// Otherwise the cached node was updated later than the current tree. In this case,
210+
// otherwise skipFastStorageUpgrade is true or
211+
// the cached node was updated later than the current tree. In this case,
205212
// we need to use the regular stategy for reading from the current tree to avoid staleness.
206213
_, result, err := t.root.get(t, key)
207214
return result, err
@@ -239,13 +246,15 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (bool, e
239246

240247
// Iterator returns an iterator over the immutable tree.
241248
func (t *ImmutableTree) Iterator(start, end []byte, ascending bool) (dbm.Iterator, error) {
242-
isFastCacheEnabled, err := t.IsFastCacheEnabled()
243-
if err != nil {
244-
return nil, err
245-
}
249+
if !t.skipFastStorageUpgrade {
250+
isFastCacheEnabled, err := t.IsFastCacheEnabled()
251+
if err != nil {
252+
return nil, err
253+
}
246254

247-
if isFastCacheEnabled {
248-
return NewFastIterator(start, end, ascending, t.ndb), nil
255+
if isFastCacheEnabled {
256+
return NewFastIterator(start, end, ascending, t.ndb), nil
257+
}
249258
}
250259
return NewIterator(start, end, ascending, t), nil
251260
}
@@ -311,6 +320,7 @@ func (t *ImmutableTree) clone() *ImmutableTree {
311320
}
312321

313322
// nodeSize is like Size, but includes inner nodes too.
323+
//
314324
//nolint:unused
315325
func (t *ImmutableTree) nodeSize() int {
316326
size := 0

import_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
func ExampleImporter() {
13-
tree, err := NewMutableTree(db.NewMemDB(), 0)
13+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
1414
if err != nil {
1515
// handle err
1616
}
@@ -41,7 +41,7 @@ func ExampleImporter() {
4141
exported = append(exported, node)
4242
}
4343

44-
newTree, err := NewMutableTree(db.NewMemDB(), 0)
44+
newTree, err := NewMutableTree(db.NewMemDB(), 0, false)
4545
if err != nil {
4646
// handle err
4747
}
@@ -63,14 +63,14 @@ func ExampleImporter() {
6363
}
6464

6565
func TestImporter_NegativeVersion(t *testing.T) {
66-
tree, err := NewMutableTree(db.NewMemDB(), 0)
66+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
6767
require.NoError(t, err)
6868
_, err = tree.Import(-1)
6969
require.Error(t, err)
7070
}
7171

7272
func TestImporter_NotEmpty(t *testing.T) {
73-
tree, err := NewMutableTree(db.NewMemDB(), 0)
73+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
7474
require.NoError(t, err)
7575
tree.Set([]byte("a"), []byte{1})
7676
_, _, err = tree.SaveVersion()
@@ -83,13 +83,13 @@ func TestImporter_NotEmpty(t *testing.T) {
8383
func TestImporter_NotEmptyDatabase(t *testing.T) {
8484
db := db.NewMemDB()
8585

86-
tree, err := NewMutableTree(db, 0)
86+
tree, err := NewMutableTree(db, 0, false)
8787
require.NoError(t, err)
8888
tree.Set([]byte("a"), []byte{1})
8989
_, _, err = tree.SaveVersion()
9090
require.NoError(t, err)
9191

92-
tree, err = NewMutableTree(db, 0)
92+
tree, err = NewMutableTree(db, 0, false)
9393
require.NoError(t, err)
9494
_, err = tree.Load()
9595
require.NoError(t, err)
@@ -99,7 +99,7 @@ func TestImporter_NotEmptyDatabase(t *testing.T) {
9999
}
100100

101101
func TestImporter_NotEmptyUnsaved(t *testing.T) {
102-
tree, err := NewMutableTree(db.NewMemDB(), 0)
102+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
103103
require.NoError(t, err)
104104
tree.Set([]byte("a"), []byte{1})
105105

@@ -126,7 +126,7 @@ func TestImporter_Add(t *testing.T) {
126126
for desc, tc := range testcases {
127127
tc := tc // appease scopelint
128128
t.Run(desc, func(t *testing.T) {
129-
tree, err := NewMutableTree(db.NewMemDB(), 0)
129+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
130130
require.NoError(t, err)
131131
importer, err := tree.Import(1)
132132
require.NoError(t, err)
@@ -143,7 +143,7 @@ func TestImporter_Add(t *testing.T) {
143143
}
144144

145145
func TestImporter_Add_Closed(t *testing.T) {
146-
tree, err := NewMutableTree(db.NewMemDB(), 0)
146+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
147147
require.NoError(t, err)
148148
importer, err := tree.Import(1)
149149
require.NoError(t, err)
@@ -155,7 +155,7 @@ func TestImporter_Add_Closed(t *testing.T) {
155155
}
156156

157157
func TestImporter_Close(t *testing.T) {
158-
tree, err := NewMutableTree(db.NewMemDB(), 0)
158+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
159159
require.NoError(t, err)
160160
importer, err := tree.Import(1)
161161
require.NoError(t, err)
@@ -172,7 +172,7 @@ func TestImporter_Close(t *testing.T) {
172172
}
173173

174174
func TestImporter_Commit(t *testing.T) {
175-
tree, err := NewMutableTree(db.NewMemDB(), 0)
175+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
176176
require.NoError(t, err)
177177
importer, err := tree.Import(1)
178178
require.NoError(t, err)
@@ -188,7 +188,7 @@ func TestImporter_Commit(t *testing.T) {
188188
}
189189

190190
func TestImporter_Commit_Closed(t *testing.T) {
191-
tree, err := NewMutableTree(db.NewMemDB(), 0)
191+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
192192
require.NoError(t, err)
193193
importer, err := tree.Import(1)
194194
require.NoError(t, err)
@@ -203,7 +203,7 @@ func TestImporter_Commit_Closed(t *testing.T) {
203203
}
204204

205205
func TestImporter_Commit_Empty(t *testing.T) {
206-
tree, err := NewMutableTree(db.NewMemDB(), 0)
206+
tree, err := NewMutableTree(db.NewMemDB(), 0, false)
207207
require.NoError(t, err)
208208
importer, err := tree.Import(3)
209209
require.NoError(t, err)
@@ -232,7 +232,7 @@ func BenchmarkImport(b *testing.B) {
232232
b.StartTimer()
233233

234234
for n := 0; n < b.N; n++ {
235-
newTree, err := NewMutableTree(db.NewMemDB(), 0)
235+
newTree, err := NewMutableTree(db.NewMemDB(), 0, false)
236236
require.NoError(b, err)
237237
importer, err := newTree.Import(tree.Version())
238238
require.NoError(b, err)

0 commit comments

Comments
 (0)