bmap: Changing direction, store bmap mode in wcompat flags

The idea behind separate ctrled+unctrled airspaces was to try to avoid
multiple interpretations of the on-disk bmap, but I'm starting to think
this adds more complexity than it solves.

The main conflict is the meaning of "in-flight" blocks. When using the
"uncontrolled" bmap algorithm, in-flight blocks need to be
double-checked by traversing the filesystem. But in the "controlled"
bmap algorithm, blocks are only marked as "in-flight" while they are
truly in-flight (in-use in RAM, but not yet in use on disk).
Representing these both with the same "in-flight" state risks
incompatible algorithms misinterpreting the bmap across different
mounts.

In theory the separate airspaces solve this, but now all the algorithms
need to know how to convert the bmap from different modes, adding
complexity and code cost.

Well, in theory at least. I'm unsure separate airspaces actually solves
this due to subtleties between what "in-flight" means in the different
algorithms (note both in-use and free blocks are "in-flight" in the
unknown airspace!). It really depends on how the "controlled" algorithm
actually works, which isn't implemented/fully designed yet.

---

Long story short, due to a time crunch, I'm ripping this out for now and
just storing the current algorithm in the wcompat flags:

  LFS3_WCOMPAT_GBMAP       0x00006000  Global block-map in use
  LFS3_WCOMPAT_GBMAPNONE   0x00000000  Gbmap not in use
  LFS3_WCOMPAT_GBMAPCACHE  0x00002000  Gbmap in cache mode
  LFS3_WCOMPAT_GBMAPVFR    0x00004000  Gbmap in VFR mode
  LFS3_WCOMPAT_GBMAPIFR    0x00006000  Gbmap in IFR mode

Note GBMAPVFR/IFR != BMAPSLOW/FAST! At least BMAPSLOW/FAST can share
bmap representations:

- GBMAPVFR => Uncontrolled airspace, i.e. in-flight blocks may or may
  not be in use, need to traverse open files.

- GBMAPIFR => Controlled airspace, i.e. in-flight blocks are in use,
  at least until powerloss, no traversal needed, but requires more bmap
  writes.

- BMAPSLOW => Treediff by checking what blocks are in B but not in A,
  and what blocks are in A but not in B, O(n^2), but minimizes bmap
  updates.

  Can be optimized with a bloom filter.

- BMAPFAST => Treediff by clearing all blocks in A, and then setting all
  blocks in B, O(n), but also writes all blocks to the bmap twice even
  on small changes.

  Can be optimized with a sliding bitmap window (or a block hashtable,
  though a bitmap converges to the same thing in both algorithms when
  >=disk_size).

It will probably be worth unifying the bmap representation later (the
more algorithm-specific flags there are, the harder interop becomes for
users, but for now this opens a path to implementing/experimenting with
bmap algorithms without dealing with this headache.
This commit is contained in:
Christopher Haster
2025-07-27 16:41:30 -05:00
parent beb1f1346a
commit ebae43898e
7 changed files with 156 additions and 185 deletions
+13 -11
View File
@@ -87,22 +87,24 @@
#define LFS3_BMAP
#endif
// TODO is this the best way to structure this?
// LFS3_BMAP mappings
//
// LFS3_YES_BMAP => LFS3_YES_BMAPFAST
#ifdef LFS3_YES_BMAP
#ifndef LFS3_YES_BMAPFAST
#define LFS3_YES_BMAPFAST
#endif
#endif
// TODO eventually allow runtime flags
//
// LFS3_YES_BMAP* => LFS3_BMAP
#if defined(LFS3_YES_BMAPFAST) \
|| defined(LFS3_YES_BMAPSLOW) \
|| defined(LFS3_YES_BMAPCACHE) \
|| defined(LFS3_YES_BMAPNONE)
#if defined(LFS3_YES_BMAPCACHE) \
|| defined(LFS3_YES_BMAPVFR) \
|| defined(LFS3_YES_BMAPIFR)
#define LFS3_BMAP
#endif
// TODO figure out the best default bmap mode
// if LFS3_BMAP but no algorithm defined, default to LFS3_YES_BMAPCACHE
#if defined(LFS3_BMAP) \
&& !defined(LFS3_BMAPCACHE) \
&& !defined(LFS3_BMAPVFR) \
&& !defined(LFS3_BMAPIFR)
#define LFS3_YES_BMAPCACHE
#endif
// LFS3_NO_LOG disables all logging macros
#ifdef LFS3_NO_LOG