Tweaked lfsr_bshrub_t representation to rely on LFSR_RBYD_ISSHRUB

D'oh, here I am trying to rely solely on our shrub.block == mdir.block
condition to tell bshrubs and btrees apart, when we already have
LFSR_RBYD_ISSHRUB as an explicit flag in the rbyd code!

Long story short, these are equivalent:

  bshrub.trunk & LFSR_RBYD_ISSHRUB => bshrub is shrub
  bshrub.block == mdir.block       => bshrub is shrub

But in theory flag checks are cheaper and require less things being
in-sync (i.e. fewer things can go wrong).

This also means we only need to look at bshrub.trunk to determine if
it's a bshrub, btree, or neither (trunk=0):

  bnull:               bshrub:              btree:
  .---+---+---+---. .. .---+---+---+---. .. .---+---+---+---.
  |    weight=0   |    |    weight>0   |    |    weight>0   |
  +---+---+---+---+    +---+---+---+---+    +---+---+---+---+
  |   block=mdir  |    |   block=mdir  |    |  block!=mdir  |
  +---+---+---+---+ .. +---+---+---+---+    +---+---+---+---+
  |    (unused)   |    |    (unused)   |    |    (unused)   |
  +---+---+---+---+    +---+---+---+---+    +---+---+---+---+
  |0|  trunk=0    |    |1|   trunk     |    |0|   trunk     |
  +---+---+---+---+    +---+---+---+---+ .. +---+---+---+---+
  |    (unused)   |    |    estimate   |    |p|   eoff      |
  +               +    +---+---+---+---+    +---+---+---+---+
  |               |    |    (unused)   |    |     cksum     |
  '---+---+---+---'    '---+---+---+---'    '---+---+---+---'

As a side-effect, lfsr_file_truncate/fruncate are back to dropping
zero-weight btrees even if they have erased-state (now handled in
lfsr_file_carve). On reflection this is the simpler approach, consistent
with LFS_O_TRUNC, uses fewer blocks, and if keeping erased-state turns
out to be more valuable we can always change this in the future.

Though we should at least add a test that we can read existing
zero-weight btrees and bshrubs...

---

This ended up highlighting that we were leaving dangling bshrub
references in lfsr_mtree_traverse_!

You may think these dangling references would've been fine with the
previous logic, but they could've created problems when the block
allocator makes a full circle. Not great!

Fortunately, relying on LFSR_RBYD_ISSHRUB is a lot safer, and lets us
catch issues like this with asserts in lfsr_mdir_commit.

---

Code savings were a bit disappointing, but any change that reduces
assumptions in the code is a good change:

           code          stack          ctx
  before: 36460           2608          640
  after:  36424 (-0.1%)   2608 (+0.0%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-02-02 17:24:45 -06:00
parent 475ca76cdf
commit 77a9ce3418
2 changed files with 74 additions and 82 deletions
+3 -6
View File
@@ -694,13 +694,10 @@ typedef struct lfsr_bptr {
} lfsr_bptr_t;
// the lfsr_bshrub_t struct represents the on-disk component of a file
//
// navigating this union is a bit tricky, and relies on the related
// mdir block:
// block==mdir.block, weight==0 => bnull
// block==mdir.block, weight!=0 => bshrub
// block!=mdir.block => btree
typedef struct lfsr_bshrub {
// weight=0 => no bshrub/btree
// sign(weight)=1 => bshrub
// sign(weight)=0 => btree
union {
lfs_size_t weight;
lfsr_shrub_t bshrub;