Skip to content

Commit

Permalink
Improve rootkey cache in pruning: Reduce 4 rootkey fetches to 1 (back…
Browse files Browse the repository at this point in the history
…port #1029) (#1031)

Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
  • Loading branch information
mergify[bot] and ValarDragon authored Jan 2, 2025
1 parent 19a6276 commit 1170299
Showing 1 changed file with 32 additions and 10 deletions.
42 changes: 32 additions & 10 deletions nodedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,22 @@ func (ndb *nodeDB) saveNodeFromPruning(node *Node) error {
return ndb.batch.Set(ndb.nodeKey(node.GetKey()), buf.Bytes())
}

// rootkey cache of two elements, attempting to mimic a direct-mapped cache.
type rootkeyCache struct {
version int64
rootKey []byte
// initial value is set to {-1, -1}, which is an invalid version for a getrootkey call.
versions [2]int64
rootKeys [2][]byte
next int
}

func (rkc *rootkeyCache) getRootKey(ndb *nodeDB, version int64) ([]byte, error) {
if rkc.version == version {
return rkc.rootKey, nil
// Check both cache entries
for i := 0; i < 2; i++ {
if rkc.versions[i] == version {
return rkc.rootKeys[i], nil
}
}

rootKey, err := ndb.GetRoot(version)
if err != nil {
return nil, err
Expand All @@ -435,8 +442,18 @@ func (rkc *rootkeyCache) getRootKey(ndb *nodeDB, version int64) ([]byte, error)
}

func (rkc *rootkeyCache) setRootKey(version int64, rootKey []byte) {
rkc.version = version
rkc.rootKey = rootKey
// Store in next available slot, cycling between 0 and 1
rkc.versions[rkc.next] = version
rkc.rootKeys[rkc.next] = rootKey
rkc.next = (rkc.next + 1) % 2
}

func newRootkeyCache() *rootkeyCache {
return &rootkeyCache{
versions: [2]int64{-1, -1},
rootKeys: [2][]byte{},
next: 0,
}
}

// deleteVersion deletes a tree version from disk.
Expand All @@ -447,7 +464,7 @@ func (ndb *nodeDB) deleteVersion(version int64, cache *rootkeyCache) error {
return err
}

if err := ndb.traverseOrphans(version, version+1, func(orphan *Node) error {
if err := ndb.traverseOrphansWithRootkeyCache(cache, version, version+1, func(orphan *Node) error {
if orphan.nodeKey.nonce == 0 && !orphan.isLegacy {
// if the orphan is a reformatted root, it can be a legacy root
// so it should be removed from the pruning process.
Expand Down Expand Up @@ -707,7 +724,7 @@ func (ndb *nodeDB) deleteVersionsTo(toVersion int64) error {
ndb.resetLegacyLatestVersion(-1)
}

rootkeyCache := &rootkeyCache{}
rootkeyCache := newRootkeyCache()
for version := first; version <= toVersion; version++ {
if err := ndb.deleteVersion(version, rootkeyCache); err != nil {
return err
Expand Down Expand Up @@ -1096,7 +1113,12 @@ func isReferenceRoot(bz []byte) (bool, int) {
// traverseOrphans traverses orphans which removed by the updates of the curVersion in the prevVersion.
// NOTE: it is used for both legacy and new nodes.
func (ndb *nodeDB) traverseOrphans(prevVersion, curVersion int64, fn func(*Node) error) error {
curKey, err := ndb.GetRoot(curVersion)
cache := newRootkeyCache()
return ndb.traverseOrphansWithRootkeyCache(cache, prevVersion, curVersion, fn)
}

func (ndb *nodeDB) traverseOrphansWithRootkeyCache(cache *rootkeyCache, prevVersion, curVersion int64, fn func(*Node) error) error {
curKey, err := cache.getRootKey(ndb, curVersion)
if err != nil {
return err
}
Expand All @@ -1106,7 +1128,7 @@ func (ndb *nodeDB) traverseOrphans(prevVersion, curVersion int64, fn func(*Node)
return err
}

prevKey, err := ndb.GetRoot(prevVersion)
prevKey, err := cache.getRootKey(ndb, prevVersion)
if err != nil {
return err
}
Expand Down

0 comments on commit 1170299

Please sign in to comment.