Simplified lfsr_bshrub_t representation

Now that we don't use bmoss or bsprouts anymore, we can drop the
LFSR_BSHRUB_ISNULLORBMOSSORBPTR flag and simplify our lfsr_bshrub_t
struct quite a bit.

However, we do still need a bnull representation, which is surprisingly
tricky... And annoying...

Current solution: Bnulls are bshrubs with weight=0. This works, but
unfortunately does mean we need to update bnull blocks on mdir
relocation/compaction, and risks bnull blocks falling out-of-sync, which
is a really weird thing to worry about:

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

Note we can't just assume all weight=0 files are bnulls, or else we
won't use erased-state in empty btree roots. This risks thrashing in
files oscillating around weight=0.

Technically, weight=0 bshrubs _are_ slightly different than bnulls (
bshrubs point to a null tag, while bnulls simply have no tree), but
unlike btrees, there's no reason to keep weight=0 bshrubs around. Any
bshrub erased-state can still be used by the mdir.

This change also makes LFS_O_TRUNC and lfsr_file_truncate/fruncate
behave slightly differently, with LFS_O_TRUNC unconditionally reverting
to a bnull, while lfsr_file_truncate/fruncate tries to keep the btree
root around. This may be worth revisiting...

---

Despite the awkward encoding, this simplification still ends up saving a
nice bit of code and stack:

           code          stack          ctx
  before: 36668           2616          640
  after:  36460 (-0.6%)   2608 (-0.3%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-02-01 15:47:54 -06:00
parent a2b50d2463
commit 475ca76cdf
2 changed files with 131 additions and 194 deletions
+7 -12
View File
@@ -694,20 +694,15 @@ 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 {
// navigating this union is a bit tricky, and relies on the related
// mdir's block:
//
// sign(size)=1, data.size==0 => bnull
// sign(size)=1, data.block==mdir.block => bmoss
// sign(size)=1, data.block!=mdir.block => bptr
// sign(size)=0, data.block==mdir.block => bshrub
// sign(size)=0, data.block!=mdir.block => btree
//
union {
lfs_off_t size;
lfsr_data_t bmoss;
lfsr_bptr_t bsprout;
lfs_size_t weight;
lfsr_shrub_t bshrub;
lfsr_btree_t btree;
} u;