-
Notifications
You must be signed in to change notification settings - Fork 807
Remove cached node bytes from merkle nodes #2393
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
Changes from 20 commits
e562467
6446181
48d7a07
ddace03
d66f8e7
2fa326e
67e5f39
1e9e189
603ca6c
07bec1f
7908bb5
b5a6dfa
d6c0774
4538d42
f3461fa
39cc53b
8462ead
a9ba3a1
b640a5a
3b23a4c
20df491
2a3b29c
2a3f2a2
4382155
9050a16
278abec
2d14a85
66b4498
ed026bc
1c1ced9
fd34f89
1f3363e
83892ed
20c6427
de890c5
40c9894
ebfba67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,6 @@ | |
package merkledb | ||
|
||
import ( | ||
"golang.org/x/exp/maps" | ||
"golang.org/x/exp/slices" | ||
|
||
"github.com/ava-labs/avalanchego/ids" | ||
|
@@ -17,7 +16,7 @@ const HashLength = 32 | |
// Representation of a node stored in the database. | ||
type dbNode struct { | ||
value maybe.Maybe[[]byte] | ||
children map[byte]child | ||
children map[byte]*child | ||
} | ||
|
||
type child struct { | ||
|
@@ -29,17 +28,15 @@ type child struct { | |
// node holds additional information on top of the dbNode that makes calculations easier to do | ||
type node struct { | ||
dbNode | ||
id ids.ID | ||
key Key | ||
nodeBytes []byte | ||
valueDigest maybe.Maybe[[]byte] | ||
} | ||
|
||
// Returns a new node with the given [key] and no value. | ||
func newNode(key Key) *node { | ||
return &node{ | ||
dbNode: dbNode{ | ||
children: make(map[byte]child, 2), | ||
children: make(map[byte]*child, 2), | ||
}, | ||
key: key, | ||
} | ||
|
@@ -52,9 +49,8 @@ func parseNode(key Key, nodeBytes []byte) (*node, error) { | |
return nil, err | ||
} | ||
result := &node{ | ||
dbNode: n, | ||
key: key, | ||
nodeBytes: nodeBytes, | ||
dbNode: n, | ||
key: key, | ||
} | ||
|
||
result.setValueDigest() | ||
|
@@ -68,34 +64,18 @@ func (n *node) hasValue() bool { | |
|
||
// Returns the byte representation of this node. | ||
func (n *node) bytes() []byte { | ||
if n.nodeBytes == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing this cached value means we'll have to reserialize the node before writing it. Are we concerned about the additional time that'll take? Seems to be a tradeoff between memory usage and CPU usage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. anything we are writing is something we edited so this would have always been nil |
||
n.nodeBytes = codec.encodeDBNode(&n.dbNode) | ||
} | ||
|
||
return n.nodeBytes | ||
} | ||
|
||
// clear the cached values that will need to be recalculated whenever the node changes | ||
// for example, node ID and byte representation | ||
func (n *node) onNodeChanged() { | ||
n.id = ids.Empty | ||
n.nodeBytes = nil | ||
return codec.encodeDBNode(&n.dbNode) | ||
} | ||
|
||
// Returns and caches the ID of this node. | ||
func (n *node) calculateID(metrics merkleMetrics) { | ||
if n.id != ids.Empty { | ||
return | ||
} | ||
|
||
func (n *node) calculateID(metrics merkleMetrics) ids.ID { | ||
metrics.HashCalculated() | ||
bytes := codec.encodeHashValues(n) | ||
n.id = hashing.ComputeHash256Array(bytes) | ||
return hashing.ComputeHash256Array(bytes) | ||
} | ||
|
||
// Set [n]'s value to [val]. | ||
func (n *node) setValue(val maybe.Maybe[[]byte]) { | ||
n.onNodeChanged() | ||
n.value = val | ||
n.setValueDigest() | ||
} | ||
|
@@ -114,23 +94,20 @@ func (n *node) setValueDigest() { | |
func (n *node) addChild(childNode *node, tokenSize int) { | ||
n.setChildEntry( | ||
childNode.key.Token(n.key.length, tokenSize), | ||
child{ | ||
&child{ | ||
compressedKey: childNode.key.Skip(n.key.length + tokenSize), | ||
id: childNode.id, | ||
hasValue: childNode.hasValue(), | ||
}, | ||
) | ||
} | ||
|
||
// Adds a child to [n] without a reference to the child node. | ||
func (n *node) setChildEntry(index byte, childEntry child) { | ||
n.onNodeChanged() | ||
func (n *node) setChildEntry(index byte, childEntry *child) { | ||
n.children[index] = childEntry | ||
} | ||
|
||
// Removes [child] from [n]'s children. | ||
func (n *node) removeChild(child *node, tokenSize int) { | ||
n.onNodeChanged() | ||
delete(n.children, child.key.Token(n.key.length, tokenSize)) | ||
} | ||
|
||
|
@@ -139,16 +116,22 @@ func (n *node) removeChild(child *node, tokenSize int) { | |
// if this ever changes, value will need to be copied as well | ||
// it is safe to clone all fields because they are only written/read while one or both of the db locks are held | ||
func (n *node) clone() *node { | ||
return &node{ | ||
id: n.id, | ||
result := &node{ | ||
key: n.key, | ||
dbNode: dbNode{ | ||
value: n.value, | ||
children: maps.Clone(n.children), | ||
children: make(map[byte]*child, len(n.children)), | ||
}, | ||
valueDigest: n.valueDigest, | ||
nodeBytes: n.nodeBytes, | ||
} | ||
for key, existing := range n.children { | ||
result.children[key] = &child{ | ||
compressedKey: existing.compressedKey, | ||
id: existing.id, | ||
hasValue: existing.hasValue, | ||
} | ||
} | ||
return result | ||
} | ||
|
||
// Returns the ProofNode representation of this node. | ||
|
Uh oh!
There was an error while loading. Please reload this page.