From 5ecdc8b4f732d3cd4da69cdf8c5675e56a3d7f1b Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 17 Aug 2023 17:52:59 -0500 Subject: [PATCH] More btree tweaks, now with better handling of degenerate parents Normally, in btrees, the height of the btree only decreases when nodes are merged. But not in our btree! Thanks again to lazy merging, btree nodes can be dropped instead of merged. We don't have enough information to decrease the height of the btree exactly when we drop a btree node, since we don't know how many siblings the original node had, but we can at least decrease the height of the btree if we notice this condition during normal commits. --- lfs.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lfs.c b/lfs.c index 4ffa591d..30329c6b 100644 --- a/lfs.c +++ b/lfs.c @@ -3962,7 +3962,7 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, goto compact; } - goto commit_recurse; + goto commit; compact:; // can't commit, try to compact @@ -4099,7 +4099,9 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, return err; } - commit_recurse:; + goto commit; + + commit:; // done? if (rid == -1) { LFS_ASSERT(bid == 0); @@ -4107,15 +4109,19 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, return 0; } + // is our parent the root and is the root degenerate? + if (rbyd.weight == lfsr_btree_weight(btree)) { + // collapse the root, decreasing the height of the tree + btree->u.r.rbyd = rbyd_; + return 0; + } + lfs_ssize_t scratch_dsize = lfsr_branch_todisk(lfs, &rbyd_, scratch_buf); if (scratch_dsize < 0) { return scratch_dsize; } - // TODO can split and merge both end up with zero weight rbyds - // as well? do our tests cover this? - // prepare commit to parent, tail recursing upwards // // note that since we defer merges to compaction time, we can @@ -4207,7 +4213,7 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, if (rbyd_.weight == 0) { rbyd_ = sibling; } - goto commit_recurse; + goto commit; } // lookup first name in sibling to use as the split name @@ -4336,11 +4342,11 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, return err; } - // TODO we should also do this when dropping no? - // we must have a parent at this point, but is our parent degenerate? + // we must have a parent at this point, but is our parent the root + // and is the root degenerate? LFS_ASSERT(rid != -1); if (rbyd.weight+sibling.weight == lfsr_btree_weight(btree)) { - // collapse our parent, decreasing the height of the tree + // collapse the root, decreasing the height of the tree btree->u.r.rbyd = rbyd__; return 0; }