gc: Also restart gc if lookahead + mutated/dirty

There is really no reason to continue lookahead traversals if our
filesystem has been mutated. Clearing the flag and restarting in this
case is more likely to make progress.

Note that it's worth continuing for all of the other current gc flags:

- LFS_GC_MKCONSISTENT - Except maybe for mkconsistent. We can't actually
  make progress, since we can't prove the filesystem is free of orphans,
  but it's beneficial to keep traversing and clearing orphans in case of
  other traversal flags that mutation would force a second traversal
  anyways.

  Continuing mkconsistent traversals also spreads out orphan cleanup a
  bit better, instead of just repeatedly cleaning up the first couple
  mdirs when under heavy contention.

  But to be honest, the chance of mutation that still leaves the
  filesystem with orphans is just so low that it's not worth doing
  anything. mkconsistent only needs to traverse the mtree anyways...

- LFS_GC_COMPACT - Like mkconsistent, compacting traversals are worth
  continuing for better mtree coverage under heavy contention.

  We will need a second pass to prove we compacted everything anyways,
  so might as well try to get as much mutation done as possible in the
  current traversal.

- LFS_GC_CKMETA/CKDATA - Continuing ckmeta/ckdata traversals provides
  better mtree coverage under heavy contention.

  This is much more important for CKMETA/CKDATA than the others, because
  _eventually_ checking every block for errors is more valuable than
  proving anything.

This adds some code, but the use of flags here is quite valuable for
expressing complex constraints like this cheaply:

           code          stack
  before: 36228           2680
  after:  36240 (+0.0%)   2680 (+0.0%)
This commit is contained in:
Christopher Haster
2024-07-19 02:08:54 -05:00
parent cb94fa4256
commit 15090e5dcf
2 changed files with 27 additions and 17 deletions
+21 -17
View File
@@ -13069,29 +13069,33 @@ int lfsr_fs_gc(lfs_t *lfs, lfs_soff_t steps, uint32_t flags) {
if (!lfsr_omdir_isopen(lfs, &lfs->gc.o.o)) {
lfs->gc = LFSR_TRAVERSAL(pending);
lfsr_omdir_open(lfs, &lfs->gc.o.o);
}
// existing traversal?
} else {
// mask flags, we can't trust existing traversals to make
// progress if flags change
lfs->gc.o.o.flags &= ~(
// mask flags, we can't trust existing traversals to make
// progress if flags change
lfs->gc.o.o.flags &= (
pending | ~(
LFS_GC_MKCONSISTENT
| LFS_GC_LOOKAHEAD
| LFS_GC_COMPACT
| LFS_GC_CKMETA
| LFS_GC_CKDATA
) | pending;
| LFS_GC_CKDATA));
// will this traversal still make progress? no? start over
if (!(lfs->gc.o.o.flags & (
LFS_GC_MKCONSISTENT
| LFS_GC_LOOKAHEAD
| LFS_GC_COMPACT
| LFS_GC_CKMETA
| LFS_GC_CKDATA))) {
lfsr_omdir_close(lfs, &lfs->gc.o.o);
continue;
}
// don't bother with lookahead if we've mutated
if (lfsr_f_isdirty(lfs->gc.o.o.flags)
|| lfsr_f_ismutated(lfs->gc.o.o.flags)) {
lfs->gc.o.o.flags &= ~LFS_GC_LOOKAHEAD;
}
// will this traversal still make progress? no? start over
if (!(lfs->gc.o.o.flags & (
LFS_GC_MKCONSISTENT
| LFS_GC_LOOKAHEAD
| LFS_GC_COMPACT
| LFS_GC_CKMETA
| LFS_GC_CKDATA))) {
lfsr_omdir_close(lfs, &lfs->gc.o.o);
continue;
}
// do we really need a full traversal?
+6
View File
@@ -80,6 +80,8 @@ defines.SIZE = [
'2*BLOCK_SIZE',
'8*BLOCK_SIZE',
]
# we need something to keep the traversal running
if = 'CKMETA || CKDATA'
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;
@@ -378,6 +380,8 @@ defines.SIZE = [
]
# set compact thresh to minimum
defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2'
# we need something to keep the traversal running
if = 'CKMETA || CKDATA'
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;
@@ -878,6 +882,8 @@ defines.SIZE = 'FILE_BUFFER_SIZE/2'
# <=2 => grm-able
# >2 => requires orphans
defines.ORPHANS = [3, 100]
# we need something to keep the traversal running
if = 'CKMETA || CKDATA'
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;