Skip to content

Commit e933587

Browse files
dboehm-avalabsDarioush JalaliDan Laine
authored
Reduce allocations on insert and remove (#2201)
Signed-off-by: David Boehm <91908103+dboehm-avalabs@users.noreply.github.com> Signed-off-by: Dan Laine <daniel.laine@avalabs.org> Co-authored-by: Darioush Jalali <darioush.jalali@avalabs.org> Co-authored-by: Dan Laine <daniel.laine@avalabs.org>
1 parent 638000c commit e933587

File tree

3 files changed

+135
-178
lines changed

3 files changed

+135
-178
lines changed

x/merkledb/db.go

+6-11
Original file line numberDiff line numberDiff line change
@@ -474,19 +474,14 @@ func (db *merkleDB) PrefetchPath(key []byte) error {
474474
}
475475

476476
func (db *merkleDB) prefetchPath(view *trieView, keyBytes []byte) error {
477-
pathToKey, err := view.getPathTo(db.toKey(keyBytes))
478-
if err != nil {
479-
return err
480-
}
481-
for _, n := range pathToKey {
482-
if n.hasValue() {
483-
db.valueNodeDB.nodeCache.Put(n.key, n)
484-
} else if err := db.intermediateNodeDB.nodeCache.Put(n.key, n); err != nil {
485-
return err
477+
return view.visitPathToKey(db.toKey(keyBytes), func(n *node) error {
478+
if !n.hasValue() {
479+
return db.intermediateNodeDB.nodeCache.Put(n.key, n)
486480
}
487-
}
488481

489-
return nil
482+
db.valueNodeDB.nodeCache.Put(n.key, n)
483+
return nil
484+
})
490485
}
491486

492487
func (db *merkleDB) Get(key []byte) ([]byte, error) {

x/merkledb/trie_test.go

+54-38
Original file line numberDiff line numberDiff line change
@@ -23,40 +23,35 @@ func getNodeValue(t ReadOnlyTrie, key string) ([]byte, error) {
2323
}
2424

2525
func getNodeValueWithBranchFactor(t ReadOnlyTrie, key string, bf BranchFactor) ([]byte, error) {
26+
var view *trieView
2627
if asTrieView, ok := t.(*trieView); ok {
2728
if err := asTrieView.calculateNodeIDs(context.Background()); err != nil {
2829
return nil, err
2930
}
30-
path := ToKey([]byte(key), bf)
31-
nodePath, err := asTrieView.getPathTo(path)
32-
if err != nil {
33-
return nil, err
34-
}
35-
closestNode := nodePath[len(nodePath)-1]
36-
if closestNode.key != path || closestNode == nil {
37-
return nil, database.ErrNotFound
38-
}
39-
40-
return closestNode.value.Value(), nil
31+
view = asTrieView
4132
}
4233
if asDatabases, ok := t.(*merkleDB); ok {
43-
view, err := asDatabases.NewView(context.Background(), ViewChanges{})
34+
dbView, err := asDatabases.NewView(context.Background(), ViewChanges{})
4435
if err != nil {
4536
return nil, err
4637
}
47-
path := ToKey([]byte(key), bf)
48-
nodePath, err := view.(*trieView).getPathTo(path)
49-
if err != nil {
50-
return nil, err
51-
}
52-
closestNode := nodePath[len(nodePath)-1]
53-
if closestNode.key != path || closestNode == nil {
54-
return nil, database.ErrNotFound
55-
}
38+
view = dbView.(*trieView)
39+
}
5640

57-
return closestNode.value.Value(), nil
41+
path := ToKey([]byte(key), bf)
42+
var result *node
43+
err := view.visitPathToKey(path, func(n *node) error {
44+
result = n
45+
return nil
46+
})
47+
if err != nil {
48+
return nil, err
5849
}
59-
return nil, nil
50+
if result.key != path || result == nil {
51+
return nil, database.ErrNotFound
52+
}
53+
54+
return result.value.Value(), nil
6055
}
6156

6257
func Test_GetValue_Safety(t *testing.T) {
@@ -116,7 +111,7 @@ func Test_GetValues_Safety(t *testing.T) {
116111
require.Equal([]byte{0}, trieVals[0])
117112
}
118113

119-
func TestTrieViewGetPathTo(t *testing.T) {
114+
func TestTrieViewVisitPathToKey(t *testing.T) {
120115
require := require.New(t)
121116

122117
db, err := getBasicDB()
@@ -127,8 +122,11 @@ func TestTrieViewGetPathTo(t *testing.T) {
127122
require.IsType(&trieView{}, trieIntf)
128123
trie := trieIntf.(*trieView)
129124

130-
nodePath, err := trie.getPathTo(ToKey(nil, BranchFactor16))
131-
require.NoError(err)
125+
var nodePath []*node
126+
require.NoError(trie.visitPathToKey(ToKey(nil, BranchFactor16), func(n *node) error {
127+
nodePath = append(nodePath, n)
128+
return nil
129+
}))
132130

133131
// Just the root
134132
require.Len(nodePath, 1)
@@ -149,8 +147,11 @@ func TestTrieViewGetPathTo(t *testing.T) {
149147
trie = trieIntf.(*trieView)
150148
require.NoError(trie.calculateNodeIDs(context.Background()))
151149

152-
nodePath, err = trie.getPathTo(ToKey(key1, BranchFactor16))
153-
require.NoError(err)
150+
nodePath = make([]*node, 0, 2)
151+
require.NoError(trie.visitPathToKey(ToKey(key1, BranchFactor16), func(n *node) error {
152+
nodePath = append(nodePath, n)
153+
return nil
154+
}))
154155

155156
// Root and 1 value
156157
require.Len(nodePath, 2)
@@ -172,8 +173,11 @@ func TestTrieViewGetPathTo(t *testing.T) {
172173
trie = trieIntf.(*trieView)
173174
require.NoError(trie.calculateNodeIDs(context.Background()))
174175

175-
nodePath, err = trie.getPathTo(ToKey(key2, BranchFactor16))
176-
require.NoError(err)
176+
nodePath = make([]*node, 0, 3)
177+
require.NoError(trie.visitPathToKey(ToKey(key2, BranchFactor16), func(n *node) error {
178+
nodePath = append(nodePath, n)
179+
return nil
180+
}))
177181
require.Len(nodePath, 3)
178182
require.Equal(trie.root, nodePath[0])
179183
require.Equal(ToKey(key1, BranchFactor16), nodePath[1].key)
@@ -194,33 +198,45 @@ func TestTrieViewGetPathTo(t *testing.T) {
194198
trie = trieIntf.(*trieView)
195199
require.NoError(trie.calculateNodeIDs(context.Background()))
196200

197-
nodePath, err = trie.getPathTo(ToKey(key3, BranchFactor16))
198-
require.NoError(err)
201+
nodePath = make([]*node, 0, 2)
202+
require.NoError(trie.visitPathToKey(ToKey(key3, BranchFactor16), func(n *node) error {
203+
nodePath = append(nodePath, n)
204+
return nil
205+
}))
199206
require.Len(nodePath, 2)
200207
require.Equal(trie.root, nodePath[0])
201208
require.Equal(ToKey(key3, BranchFactor16), nodePath[1].key)
202209

203210
// Other key path not affected
204-
nodePath, err = trie.getPathTo(ToKey(key2, BranchFactor16))
205-
require.NoError(err)
211+
nodePath = make([]*node, 0, 3)
212+
require.NoError(trie.visitPathToKey(ToKey(key2, BranchFactor16), func(n *node) error {
213+
nodePath = append(nodePath, n)
214+
return nil
215+
}))
206216
require.Len(nodePath, 3)
207217
require.Equal(trie.root, nodePath[0])
208218
require.Equal(ToKey(key1, BranchFactor16), nodePath[1].key)
209219
require.Equal(ToKey(key2, BranchFactor16), nodePath[2].key)
210220

211221
// Gets closest node when key doesn't exist
212222
key4 := []byte{0, 1, 2}
213-
nodePath, err = trie.getPathTo(ToKey(key4, BranchFactor16))
214-
require.NoError(err)
223+
nodePath = make([]*node, 0, 3)
224+
require.NoError(trie.visitPathToKey(ToKey(key4, BranchFactor16), func(n *node) error {
225+
nodePath = append(nodePath, n)
226+
return nil
227+
}))
215228
require.Len(nodePath, 3)
216229
require.Equal(trie.root, nodePath[0])
217230
require.Equal(ToKey(key1, BranchFactor16), nodePath[1].key)
218231
require.Equal(ToKey(key2, BranchFactor16), nodePath[2].key)
219232

220233
// Gets just root when key doesn't exist and no key shares a prefix
221234
key5 := []byte{128}
222-
nodePath, err = trie.getPathTo(ToKey(key5, BranchFactor16))
223-
require.NoError(err)
235+
nodePath = make([]*node, 0, 1)
236+
require.NoError(trie.visitPathToKey(ToKey(key5, BranchFactor16), func(n *node) error {
237+
nodePath = append(nodePath, n)
238+
return nil
239+
}))
224240
require.Len(nodePath, 1)
225241
require.Equal(trie.root, nodePath[0])
226242
}

0 commit comments

Comments
 (0)