Added a bit of fuzz testing over mtree splits

This isn't the greatest coverage as we don't have a verifiable simulation.
Simulating the splitting-bucket-tree that is the mtree is tricky.

So right now this mostly just checks there's no internal assert failures and
if we have the expected number of entries afterwards.
This commit is contained in:
Christopher Haster
2023-05-10 11:31:20 -05:00
parent 3625882343
commit ea28413eb2
2 changed files with 86 additions and 8 deletions
+1 -6
View File
@@ -4523,12 +4523,7 @@ static inline int lfsr_mtree_isinlined(lfs_t *lfs) {
}
static inline lfs_ssize_t lfsr_mtree_weight(lfs_t *lfs) {
// inlined mdir?
if (lfsr_mtree_isinlined(lfs)) {
return lfs->mroot.rbyd.weight;
} else {
return lfsr_btree_weight(&lfs->mtree);
}
return lfsr_btree_weight(&lfs->mtree);
}
static int lfsr_mtree_lookup(lfs_t *lfs, lfs_ssize_t mid, lfsr_mdir_t *mdir_) {
+85 -2
View File
@@ -63,7 +63,7 @@ code = '''
# TODO test many mroots
# try creating a range of entries that may or may not split our mtree
[cases.test_mtree_splitting]
[cases.test_mtree_split]
defines.N = [5, 10, 20, 40, 80, 160, 320]
in = 'lfs.c'
code = '''
@@ -71,6 +71,7 @@ code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
// create entries
lfsr_mount(&lfs, cfg) => 0;
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0;
@@ -88,6 +89,7 @@ code = '''
}
lfsr_unmount(&lfs) => 0;
// try looking up each entry
lfsr_mount(&lfs, cfg) => 0;
lfs_ssize_t mid = -1;
rid = 0;
@@ -112,7 +114,7 @@ code = '''
# create a range of entries, and commit to the mroot several times,
# this makes it more likely to force uninlining without necessarily
# splitting
[cases.test_mtree_uninlining]
[cases.test_mtree_uninline]
defines.N = [5, 10, 20, 40, 80, 160, 320]
defines.M = [5, 5000]
in = 'lfs.c'
@@ -121,6 +123,7 @@ code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
// create entries
lfsr_mount(&lfs, cfg) => 0;
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, lfsr_mtree_weight(&lfs)-1, &mdir) => 0;
@@ -137,6 +140,8 @@ code = '''
rid += 1;
}
// also append a bunch of fs-level attributes, if the mdir should be
// uninlined this will force it to happen
for (lfs_size_t i = 0; i < M; i++) {
lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS(
LFSR_ATTR(-1, UATTR(1), 0, &alphas[i % 26], 1))) => 0;
@@ -148,6 +153,7 @@ code = '''
}
lfsr_unmount(&lfs) => 0;
// try looking up each entry
lfsr_mount(&lfs, cfg) => 0;
lfs_ssize_t mid = -1;
rid = 0;
@@ -174,3 +180,80 @@ code = '''
lfsr_unmount(&lfs) => 0;
'''
# create random entries
[cases.test_mtree_split_fuzz]
defines.N = [5, 10, 20, 40, 80, 160, 320]
defines.SAMPLES = 10
# -1 => all pseudo-random seeds
# n => reproduce a specific seed
defines.SEED = -1
in = 'lfs.c'
code = '''
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
// iterate through severals seeds that we can reproduce easily
for (uint32_t seed = (SEED == -1 ? 1 : SEED);
(SEED == -1 ? seed < SAMPLES+1 : seed == SEED);
seed++) {
printf("--- seed: %d ---\n", seed);
// create lfs here since we need to reset each iteration, we're
// space constrained and we can't expect gc to work at this point
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// at least keep track of the number of entries we expect
lfs_size_t count = 0;
uint32_t prng = seed;
for (lfs_size_t i = 0; i < N; i++) {
// choose a pseudo-random mid
lfs_ssize_t mid = lfsr_mtree_weight(&lfs) == 0
? -1
: (lfs_ssize_t)(TEST_PRNG(&prng) % lfsr_mtree_weight(&lfs));
// fetch mdir
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
// choose a pseudo-random rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (mdir.rbyd.weight+1);
// add to rbyd, potentially splitting the mdir
lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS(
LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0;
// make sure we can look up the new entry
uint8_t buffer[4];
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1;
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
count += 1;
}
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// try looking up each entry
lfs_size_t count_ = 0;
for (lfs_ssize_t mid = (lfsr_mtree_isinlined(&lfs) ? -1 : 0);
mid < lfsr_mtree_weight(&lfs);
mid++) {
lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
for (lfs_ssize_t rid = 0;
rid < (lfs_ssize_t)mdir.rbyd.weight;
rid++) {
uint8_t buffer[4];
lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED,
buffer, 4) => 1;
count_ += 1;
}
}
// the mtree is a bit difficult to simulate, but we can at least test
// we ended up with the right number of entries
assert(count_ == count);
lfsr_unmount(&lfs) => 0;
}
'''