kv: Added LFS3_KVONLY to opt-out of advanced file operations

One of the ideas behind the key-value API is that it is potentially much
cheaper than a full file API. With the key-value API, we get the
guarantee that all data must fit in RAM, and avoid headaches like
random reads/writes and needing to broadcast file state.

For an example of just how much complexity is avoided, the see the
difference between lfs3_file_flushonce_ vs the mess that is
lfs3_file_flush_ + lfs3_file_crystallize + lfs3_file_graft.

However, littlefs is designed around files, and a couple design
decisions hold back how much code saving is possible:

1. littlefs's shrubs are designed around being enrolled in the omdir
   linked-list, so internally we still have most of the file open/close
   code lumbering around.

2. Directories and traversals still exist, so we'd need the omdir
   linked-list anyways, and we still need to broadcast _some_ changes.

3. Despite being intended for small amounts of data, lfs3_set/get can
   still be used to create arbitrarily large files. So we still need all
   of the bshrub/btree logic.

   Which we still need for the mtree anyways, so this isn't really that
   much of a downside.

It also may be possible to save more code by aggressively rewriting the
_entire_ read/write path for lfs3_set/get, to not reuse any of the
existing file logic in LFS3_KVONLY mode. But I decided against this due
to concerns around maintainability.

The duplicate lfs3_file_read + lfs3_file_readonce and lfs3_file_flush_ +
lfs3_file_flushonce_ are already enough of a concern.

Anyways, here's LFS3_KVONLY:

                  code           stack           ctx
  default:       37824            2416           636
  kvonly:        30936 (-18.2%)   2168 (-10.3%)  636 (+0.0%)

LFS3_RDONLY + LFS3_KVONLY is also interesting:

                  code           stack           ctx
  rdonly:        10776             856           508
  rdonly+kvonly:  9904 (-8.1%)     888 (+3.7%)   508 (+0.0%)

---

This also added some noise to the default build's code, mainly due to
tweaks in lfs3_file_readnext to allow better reuse in LFS3_KVONLY:

           code          stack          ctx
  before: 37824           2416          636
  after:  37860 (+0.1%)   2416 (+0.0%)  636 (+0.0%)
This commit is contained in:
Christopher Haster
2025-06-24 13:52:20 -05:00
parent 213dba6f6d
commit 2c27c61f25
4 changed files with 329 additions and 48 deletions
+7
View File
@@ -827,6 +827,7 @@ code = '''
# test kv files can be read as normal files
[cases.test_kv_interop_reads]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -929,6 +930,7 @@ code = '''
# test normal files can be read a kv files
[cases.test_kv_interop_writes]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -981,6 +983,7 @@ code = '''
# test kv files broadcast sync updates
[cases.test_kv_interop_sync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -1068,6 +1071,7 @@ code = '''
# test kv files don't interfere with desync files
[cases.test_kv_interop_desync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -1159,6 +1163,7 @@ code = '''
# test kv files work with resyncing files
[cases.test_kv_interop_resync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -1269,6 +1274,7 @@ defines.SIZE = 4
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
@@ -1427,6 +1433,7 @@ defines.SIZE = 40000
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;