btree: Dropped reliance on leaf cache during traversals

Brings back lfs3_btrv_t, but keeps some of the btree internal changes.

I think the biggest one is dropping the internal branch pointer, now
instead of internally pointing to the root rbyd, we just unconditionally
sync the rbyd state anytime the rbyd matches the root's weight. This is
necessary to avoid out-of-sync state when traversing bshrubs under
mutation.

Also after refactoring I think the current btree traversal logic is
easier to read.

---

This is in preparation for removing the leaf cache, or at least making
it opt-in.

It adds a chunk of stack, but in theory we can reclaim this by allowing
leaf caches to be disabled:

           code          stack          ctx
  before: 37160           2352          688
  after:  37088 (-0.2%)   2384 (+1.4%)  688 (+0.0%)
This commit is contained in:
Christopher Haster
2025-10-25 16:48:04 -05:00
parent 5d905e6da4
commit 39a265ce90
4 changed files with 103 additions and 85 deletions
+40 -20
View File
@@ -183,15 +183,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -329,15 +331,17 @@ code = '''
lfs3_block_t blocks = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -593,15 +597,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -754,15 +760,17 @@ code = '''
lfs3_block_t blocks = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -2080,15 +2088,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -2230,15 +2240,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -2527,15 +2539,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -2692,15 +2706,17 @@ code = '''
lfs3_block_t blocks = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -2983,15 +2999,17 @@ code = '''
lfs3_size_t fragments = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {
@@ -3152,15 +3170,17 @@ code = '''
lfs3_block_t blocks = 0;
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
lfs3_sbid_t bid = -2;
lfs3_btrv_t btrv;
lfs3_btrv_init(&btrv);
for (lfs3_block_t i = 0;; i++) {
// a bit hacky, but this catches infinite loops
assert(i < 2*BLOCK_COUNT);
lfs3_stag_t tag;
lfs3_sbid_t bid;
lfs3_bid_t weight;
lfs3_data_t data;
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
&bid, &weight, &data);
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
if (tag == LFS3_ERR_NOENT) {