From a9772d785a9add019827e87aac23bbb02c4bba54 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 29 Nov 2023 01:38:25 -0600 Subject: [PATCH] Removed removal of root bookmark in test_mtree It turns out permanent root bookmark creates some rather interesting constraints on our mtree: 1. We can never delete all mids, since at least one mid needs to exist to represent the root's bookmark. 2. We can never revert to an inlined mdir after uninlining, since our root bookmark always exists to stop this. This is an unfortunate downside as it would be nice to be able to reinline mdirs, but not the end of the world. This restricts what operations are possible, and transitively, what we can test. This commit drops the removal of root bookmarks in test_mtree, which was a workaround to keep tests from early implementation running. This was preventing some minor optimizations. This required dropping some tests, but these tests tested operations that aren't really possible in practice. Dropping the removal of root bookmarks allowed for a minor optimization in lfsr_mdir_drop, and may lead to more in the future (or maybe just stricter asserts): code stack before: 31280 2648 after: 31208 (-0.2%) 2648 (+0.0%) --- lfs.c | 30 +- tests/test_mtree.toml | 896 ++++++++++-------------------------------- 2 files changed, 222 insertions(+), 704 deletions(-) diff --git a/lfs.c b/lfs.c index 0d886abf..fa8d2bd4 100644 --- a/lfs.c +++ b/lfs.c @@ -6278,30 +6278,16 @@ static int lfsr_mdir_drop(lfs_t *lfs, const lfsr_mdir_t *mdir) { return err; } -// TODO apply this -// // we should never drop a direct mdir, because we always have our -// // root bookmark -// LFS_ASSERT(!lfsr_mtree_ismptr(lfs)); - - // direct mdir? - if (lfsr_mtree_ismptr(lfs)) { - err = lfsr_mroot_commit(lfs, -1, 0, NULL, LFSR_ATTRS( - LFSR_ATTR(-1, - RM(WIDE(STRUCT)), 0, NULL()))); - if (err) { - return err; - } - - lfs->mtree = LFSR_MTREE_NULL(); + // we should never drop a direct mdir, because we always have our + // root bookmark + LFS_ASSERT(!lfsr_mtree_ismptr(lfs)); // update our mtree - } else { - err = lfsr_mtree_commit(lfs, LFSR_ATTRS( - LFSR_ATTR(lfsr_mdir_bid(lfs, mdir), - RM, -lfsr_mweight(lfs), NULL()))); - if (err) { - return err; - } + err = lfsr_mtree_commit(lfs, LFSR_ATTRS( + LFSR_ATTR(lfsr_mdir_bid(lfs, mdir), + RM, -lfsr_mweight(lfs), NULL()))); + if (err) { + return err; } // success? update in-device state, we must not error at this point diff --git a/tests/test_mtree.toml b/tests/test_mtree.toml index 7ffcb20e..5c158746 100644 --- a/tests/test_mtree.toml +++ b/tests/test_mtree.toml @@ -162,9 +162,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -175,7 +172,7 @@ code = ''' // create a large entry that needs to be uninlined (but not split!) memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -196,7 +193,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -220,7 +217,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -236,15 +233,12 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -263,7 +257,7 @@ code = ''' lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -287,7 +281,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -309,9 +303,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -321,7 +312,7 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -358,7 +349,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -386,7 +377,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -411,9 +402,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create entries lfsr_mdir_t mdir; @@ -422,6 +410,7 @@ code = ''' lfsr_mtree_weight(&lfs) - lfsr_mweight(&lfs), 0), &mdir) => 0; + mdir.mid += 1; for (lfs_size_t i = 0; i < N; i++) { // force a compaction? if (FORCE_COMPACTION) { @@ -452,6 +441,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -478,6 +472,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -503,9 +502,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -513,16 +509,17 @@ code = ''' uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random mid - lfs_ssize_t mid = (lfs_ssize_t)( - TEST_PRNG(&prng) % lfs_max32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs))); + lfs_ssize_t mid = TEST_PRNG(&prng) % lfs_max32( + lfsr_mtree_weight(&lfs), + lfsr_mweight(&lfs)); // fetch mdir lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; // limit our mid to our mdir's weight - mdir.mid = lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) - + (mdir.mid % (mdir.rbyd.weight+1)); + mdir.mid = lfs_max32( + lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) + + (mdir.mid % (mdir.rbyd.weight+1)), + 1); // force a compaction? if (FORCE_COMPACTION) { @@ -556,6 +553,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -586,6 +588,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -614,9 +621,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -626,27 +630,27 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); // remove the entry, forcing the mdir to be dropped lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(0, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -662,7 +666,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -683,9 +687,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -695,20 +696,20 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); // remove the entry, forcing the mdir to be dropped lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); // force mdir to compact while we're removing @@ -718,7 +719,7 @@ code = ''' LFSR_ATTR(0, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -734,7 +735,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -755,9 +756,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -767,139 +765,12 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; // remove the entry as we compact, forcing the mdir to be dropped - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - // assert that our attr is still in the mroot - lfsr_mdir_get(&lfs, &lfs.mroot, -1, LFSR_TAG_UATTR(1), - buffer, SIZE) => SIZE; - assert(memcmp(buffer, "a", 1) == 0); - - lfsr_unmount(&lfs) => 0; - - - // check things stay sane after remount - lfsr_mount(&lfs, CFG) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - // assert that our attr is still in the mroot - lfsr_mdir_get(&lfs, &lfs.mroot, -1, LFSR_TAG_UATTR(1), - buffer, SIZE) => SIZE; - assert(memcmp(buffer, "a", 1) == 0); - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_mtree_drop_uninline_split_l] -# this should be set so only one entry can fit in a metadata block -defines.SIZE = 'BLOCK_SIZE / 4' -in = 'lfs.c' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // create an mdir that needs to be split - uint8_t buffer[SIZE]; - memset(buffer, 'a', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; - - memset(buffer, 'b', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; - - // force mroot to compact - lfs.mroot.rbyd.eoff = -1; - - // remove the left entry as we compact, forcing the left - // mdir to be dropped - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - // assert that one entry is still in the mtree - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - assert(mdir.rbyd.weight == 1); - - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, SIZE) => SIZE; - assert(memcmp(buffer, "b", 1) == 0); - - lfsr_unmount(&lfs) => 0; - - - // check things stay sane after remount - lfsr_mount(&lfs, CFG) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - assert(mdir.rbyd.weight == 1); - - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, SIZE) => SIZE; - assert(memcmp(buffer, "b", 1) == 0); - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_mtree_drop_uninline_split_r] -# this should be set so only one entry can fit in a metadata block -defines.SIZE = 'BLOCK_SIZE / 4' -in = 'lfs.c' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // create an mdir that needs to be split - uint8_t buffer[SIZE]; - memset(buffer, 'a', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; - - memset(buffer, 'b', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; - - // force mroot to compact - lfs.mroot.rbyd.eoff = -1; - - // remove the right entry as we compact, forcing the right mdir - // to be dropped lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(1, RM, -1, NULL()))) => 0; @@ -908,12 +779,8 @@ code = ''' // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); - // assert that one entry is still in the mtree - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - assert(mdir.rbyd.weight == 1); - - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + // assert that our attr is still in the mroot + lfsr_mdir_get(&lfs, &lfs.mroot, -1, LFSR_TAG_UATTR(1), buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -928,67 +795,14 @@ code = ''' // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); - // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - assert(mdir.rbyd.weight == 1); - - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + // assert that our attr is still in the mroot + lfsr_mdir_get(&lfs, &lfs.mroot, -1, LFSR_TAG_UATTR(1), buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); lfsr_unmount(&lfs) => 0; ''' -[cases.test_mtree_drop_uninline_split_both] -# this should be set so only one entry can fit in a metadata block -defines.SIZE = 'BLOCK_SIZE / 4' -in = 'lfs.c' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // create an mdir that needs to be split - uint8_t buffer[SIZE]; - memset(buffer, 'a', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; - - memset(buffer, 'b', SIZE); - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; - - // force mroot to compact - lfs.mroot.rbyd.eoff = -1; - - // remove both entries as we compact, forcing both mdirs to be dropped - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()), - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - lfsr_unmount(&lfs) => 0; - - - // check things stay sane after remount - lfsr_mount(&lfs, CFG) => 0; - - // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); - // assert mroot has no entries - assert(lfs.mroot.rbyd.weight == 0); - - lfsr_unmount(&lfs) => 0; -''' - [cases.test_mtree_drop_split_l] # this should be set so only one entry can fit in a metadata block defines.SIZE = 'BLOCK_SIZE / 4' @@ -998,9 +812,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1010,20 +821,20 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); // now add another large entry to the mdir, forcing a split lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+1, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+1, &mdir) => 0; assert(mdir.rbyd.weight == 1); memset(buffer, 'c', SIZE); @@ -1035,12 +846,12 @@ code = ''' // remove the left entry as we compact, forcing the left // mdir to be dropped - mdir.mid = 0*lfsr_mweight(&lfs)+0; + mdir.mid = 1*lfsr_mweight(&lfs)+0; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1050,7 +861,7 @@ code = ''' assert(memcmp(buffer, "a", 1) == 0); // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, @@ -1064,7 +875,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1074,7 +885,7 @@ code = ''' assert(memcmp(buffer, "a", 1) == 0); // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, @@ -1093,9 +904,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1105,20 +913,20 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); // now add another large entry to the mdir, forcing a split lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+1, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+1, &mdir) => 0; assert(mdir.rbyd.weight == 1); memset(buffer, 'c', SIZE); @@ -1131,10 +939,10 @@ code = ''' // remove the right entry as we compact, forcing the right // mdir to be dropped lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(1, RM, -1, NULL()))) => 0; + LFSR_ATTR(mdir.mid, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1144,7 +952,7 @@ code = ''' assert(memcmp(buffer, "a", 1) == 0); // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, @@ -1158,7 +966,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1168,7 +976,7 @@ code = ''' assert(memcmp(buffer, "a", 1) == 0); // assert that one entry is still in the mtree - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, @@ -1187,9 +995,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -1206,13 +1011,13 @@ code = ''' lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); // now add another large entry to the mdir, forcing a split lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+1, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+1, &mdir) => 0; assert(mdir.rbyd.weight == 1); memset(buffer, 'c', SIZE); @@ -1223,12 +1028,13 @@ code = ''' mdir.rbyd.eoff = -1; // remove both entries as we compact, forcing both mdirs to be dropped + mdir.mid = 1*lfsr_mweight(&lfs)+0; lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()), - LFSR_ATTR(0, RM, -1, NULL()))) => 0; + LFSR_ATTR(mdir.mid, RM, -1, NULL()), + LFSR_ATTR(mdir.mid, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1244,7 +1050,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -1256,240 +1062,6 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -# try creating an mtree and then dropping mdirs -[cases.test_mtree_drop_many] -defines.N = [5, 10, 20, 40, 80, 160, 320] -# note we never drop all the way to zero, our mtree does not support this -defines.REMAINING = [20, 5, 1] -if = 'N > REMAINING' -defines.FORCE_COMPACTION = [false, true] -in = 'lfs.c' -code = ''' - const char *alphas = "abcdefghijklmnopqrstuvwxyz"; - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - // create entries - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, - lfs_smax32( - lfsr_mtree_weight(&lfs) - lfsr_mweight(&lfs), - 0), - &mdir) => 0; - for (lfs_size_t i = 0; i < N; i++) { - lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(mdir.mid, REG, +1, - BUF(&alphas[i % 26], 1)))) => 0; - - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - - mdir.mid += 1; - } - - // remove entries - for (lfs_size_t i = 0; i < N - REMAINING; i++) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, - 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - - // drop should make sure we never have empty mdirs - assert(lfsr_mtree_ismptr(&lfs) || mdir.rbyd.weight > 0); - - // force a compaction? - if (FORCE_COMPACTION) { - mdir.rbyd.eoff = -1; - lfs.mroot.rbyd.eoff = -1; - } - - lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - } - - // try looking up each entry - lfs_size_t i = N - REMAINING; - for (lfs_ssize_t mid = 0; - mid < lfs_smax32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs)); - mid += lfsr_mweight(&lfs)) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; - for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; - mdir.mid += 1) { - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - i += 1; - } - } - assert(i == N); - - lfsr_unmount(&lfs) => 0; - - - // check things stay sane after remount - lfsr_mount(&lfs, CFG) => 0; - - // try looking up each entry - i = N - REMAINING; - for (lfs_ssize_t mid = 0; - mid < lfs_smax32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs)); - mid += lfsr_mweight(&lfs)) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; - for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; - mdir.mid += 1) { - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - i += 1; - } - } - assert(i == N); - - lfsr_unmount(&lfs) => 0; -''' - -# this one has some pretty nasty corner cases -[cases.test_mtree_repeated_drop] -defines.N = [5, 10, 20, 40] -# note we never drop all the way to zero, our mtree does not support this -defines.REMAINING = 1 -defines.FORCE_COMPACTION = [false, true] -defines.CYCLES = 10 -in = 'lfs.c' -code = ''' - const char *alphas = "abcdefghijklmnopqrstuvwxyz"; - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - - for (lfs_size_t cycle = 0; cycle < CYCLES; cycle++) { - // create entries, note we may have leftovers from the previous cycle - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, - lfs_smax32( - lfsr_mtree_weight(&lfs) - lfsr_mweight(&lfs), - 0), - &mdir) => 0; - for (lfs_size_t i = 0; i < (cycle == 0 ? N : N-1); i++) { - lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(mdir.mid, REG, +1, - BUF(&alphas[i % 26], 1)))) => 0; - - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - - mdir.mid += 1; - } - - // try looking up each entry - lfs_size_t i = 0; - for (lfs_ssize_t mid = 0; - mid < lfs_smax32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs)); - mid += lfsr_mweight(&lfs)) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; - for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; - mdir.mid += 1) { - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - i += 1; - } - } - assert(i == N); - - // remove entries - for (lfs_size_t i = 0; i < N-1; i++) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, - 0*lfsr_mweight(&lfs)+0, &mdir) => 0; - - // drop should make sure we never have empty mdirs - assert(lfsr_mtree_ismptr(&lfs) || mdir.rbyd.weight > 0); - - // force a compaction? - if (FORCE_COMPACTION) { - mdir.rbyd.eoff = -1; - lfs.mroot.rbyd.eoff = -1; - } - - lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; - } - - // try looking up each entry - i = N - REMAINING; - for (lfs_ssize_t mid = 0; - mid < lfs_smax32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs)); - mid += lfsr_mweight(&lfs)) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; - for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; - mdir.mid += 1) { - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - i += 1; - } - } - assert(i == N); - } - - lfsr_unmount(&lfs) => 0; - - - // check things stay sane after remount - lfsr_mount(&lfs, CFG) => 0; - - // try looking up each entry - lfs_size_t i = N - REMAINING; - for (lfs_ssize_t mid = 0; - mid < lfs_smax32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs)); - mid += lfsr_mweight(&lfs)) { - lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; - for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; - mdir.mid += 1) { - uint8_t buffer[4]; - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, - buffer, 4) => 1; - assert(memcmp(buffer, &alphas[i % 26], 1) == 0); - i += 1; - } - } - assert(i == N); - - lfsr_unmount(&lfs) => 0; -''' - [cases.test_mtree_drop_fuzz] defines.N = [5, 10, 20, 40, 80, 160] defines.FORCE_COMPACTION = [false, true] @@ -1502,9 +1074,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -1512,16 +1081,17 @@ code = ''' uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random mid - lfs_ssize_t mid = (lfs_ssize_t)( - TEST_PRNG(&prng) % lfs_max32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs))); + lfs_ssize_t mid = TEST_PRNG(&prng) % lfs_max32( + lfsr_mtree_weight(&lfs), + lfsr_mweight(&lfs)); // fetch mdir lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; // limit our mid to our mdir's weight - mdir.mid = lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) - + (mdir.mid % (mdir.rbyd.weight+1)); + mdir.mid = lfs_max32( + lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) + + (mdir.mid % (mdir.rbyd.weight+1)), + 1); // choose to create or delete, note we make sure to never delete to zero uint8_t op = (lfsr_mdir_rid(&lfs, &mdir) == mdir.rbyd.weight || (lfsr_mdir_rid(&lfs, &mdir) == mdir.rbyd.weight-1 @@ -1575,6 +1145,11 @@ code = ''' for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -1609,6 +1184,11 @@ code = ''' for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -1639,9 +1219,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -1652,7 +1229,7 @@ code = ''' // create a large entry that needs to be uninlined (but not split!) memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -1675,7 +1252,7 @@ code = ''' mdir.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(mdir.mid, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // assert we relocated assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0); @@ -1689,7 +1266,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -1716,7 +1293,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -1734,15 +1311,12 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -1769,7 +1343,7 @@ code = ''' mdir.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(mdir.mid, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // assert we relocated assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0); @@ -1777,7 +1351,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -1804,7 +1378,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -1828,15 +1402,12 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -1871,7 +1442,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -1898,7 +1469,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -1922,9 +1493,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -1981,9 +1549,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -2039,9 +1604,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -2106,9 +1668,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -2119,7 +1678,7 @@ code = ''' // create a large entry that needs to be uninlined (but not split!) memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2147,7 +1706,7 @@ code = ''' mdir.rbyd.eoff = -1; memset(buffer, 'c', SIZE); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( - LFSR_ATTR(mdir.mid, REG, 0, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(mdir.mid, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // assert we relocated our mdir assert(lfsr_mdir_cmp(&old_mdir, &mdir) != 0); @@ -2164,7 +1723,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -2194,7 +1753,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "c", 1) == 0); @@ -2212,9 +1771,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2224,7 +1780,7 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -2269,7 +1825,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -2301,7 +1857,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -2325,9 +1881,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -2337,14 +1890,14 @@ code = ''' memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; lfsr_mdir_commit(&lfs, &lfs.mroot, NULL, 0) => 0; // assert mdir was unininlined correctly - assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 2*lfsr_mweight(&lfs)); // assert mroot now has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -2355,14 +1908,14 @@ code = ''' // remove the entry, forcing the mdir to be dropped lfsr_mdir_t mdir; - lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; + lfsr_mtree_lookup(&lfs, 1*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, RM, -1, NULL()))) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -2381,7 +1934,7 @@ code = ''' lfsr_mount(&lfs, CFG) => 0; // assert mdir was dropped - assert(lfsr_mtree_weight(&lfs) == 0*lfsr_mweight(&lfs)); + assert(lfsr_mtree_weight(&lfs) == 1*lfsr_mweight(&lfs)); // assert mroot still has no entries assert(lfs.mroot.rbyd.weight == 0); @@ -2407,9 +1960,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2425,7 +1975,7 @@ code = ''' // create a large entry that needs to be uninlined (but not split!) memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact, this should trigger a relocation lfsr_mdir_t old_mroot = lfs.mroot; @@ -2450,7 +2000,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -2477,7 +2027,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -2495,9 +2045,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // force mroot to compact once, so the second compact below will trigger // a relocation @@ -2508,7 +2055,7 @@ code = ''' uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -2531,7 +2078,7 @@ code = ''' lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -2558,7 +2105,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -2572,7 +2119,7 @@ code = ''' ''' # this fuzz covers a lot of configuratinos -[cases.test_mtree_relocating_fuzz] +[cases.test_mtree_relocate_fuzz] defines.N = [5, 10, 20, 40] defines.FORCE_COMPACTION = [false, true] defines.BLOCK_CYCLES = [5, 2, 1] @@ -2585,9 +2132,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -2595,16 +2139,17 @@ code = ''' uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random mid - lfs_ssize_t mid = (lfs_ssize_t)( - TEST_PRNG(&prng) % lfs_max32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs))); + lfs_ssize_t mid = TEST_PRNG(&prng) % lfs_max32( + lfsr_mtree_weight(&lfs), + lfsr_mweight(&lfs)); // fetch mdir lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; // limit our mid to our mdir's weight - mdir.mid = lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) - + (mdir.mid % (mdir.rbyd.weight+1)); + mdir.mid = lfs_max32( + lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) + + (mdir.mid % (mdir.rbyd.weight+1)), + 1); // choose to create or delete, note we make sure to never delete to zero uint8_t op = (lfsr_mdir_rid(&lfs, &mdir) == mdir.rbyd.weight || (lfsr_mdir_rid(&lfs, &mdir) == mdir.rbyd.weight-1 @@ -2671,6 +2216,11 @@ code = ''' for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -2705,6 +2255,11 @@ code = ''' for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -2730,41 +2285,38 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), - LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; + LFSR_ATTR(1, REG, +1, BUF("a", 1)), + LFSR_ATTR(2, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); lfsr_openedmdir_t left_neighbor = { - .mdir={.mid=0, .rbyd=lfs.mroot.rbyd}}; - lfsr_openedmdir_t right_neighbor = { .mdir={.mid=1, .rbyd=lfs.mroot.rbyd}}; + lfsr_openedmdir_t right_neighbor = { + .mdir={.mid=2, .rbyd=lfs.mroot.rbyd}}; lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &right_neighbor); // insert a new entry, this should update our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(1, REG, +1, BUF("c", 1)))) => 0; + LFSR_ATTR(2, REG, +1, BUF("c", 1)))) => 0; // assert that our entry is still in the mtree - assert(lfs.mroot.rbyd.weight == 3); + assert(lfs.mroot.rbyd.weight == 4); uint8_t buffer[1]; - lfsr_mdir_get(&lfs, &lfs.mroot, 1, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &lfs.mroot, 2, LFSR_TAG_REG, buffer, 1) => 1; assert(memcmp(buffer, "c", 1) == 0); // assert that our neighbors were updated correctly - assert(left_neighbor.mdir.mid == 0); + assert(left_neighbor.mdir.mid == 1); assert(memcmp(&left_neighbor.mdir.rbyd, &lfs.mroot.rbyd, sizeof(lfs.mroot.rbyd)) == 0); - assert(right_neighbor.mdir.mid == 2); + assert(right_neighbor.mdir.mid == 3); assert(memcmp(&right_neighbor.mdir.rbyd, &lfs.mroot.rbyd, sizeof(lfs.mroot.rbyd)) == 0); @@ -2780,34 +2332,31 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), - LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; + LFSR_ATTR(1, REG, +1, BUF("a", 1)), + LFSR_ATTR(2, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); lfsr_openedmdir_t left_neighbor = { - .mdir={.mid=0, .rbyd=lfs.mroot.rbyd}}; - lfsr_openedmdir_t right_neighbor = { .mdir={.mid=1, .rbyd=lfs.mroot.rbyd}}; + lfsr_openedmdir_t right_neighbor = { + .mdir={.mid=2, .rbyd=lfs.mroot.rbyd}}; lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &right_neighbor); // try removing our left entry lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; + LFSR_ATTR(1, RM, -1, NULL()))) => 0; // assert that an entry was removed - assert(lfs.mroot.rbyd.weight == 1); + assert(lfs.mroot.rbyd.weight == 2); // assert that our neighbors were updated correctly assert(left_neighbor.mdir.mid == -1); - assert(right_neighbor.mdir.mid == 0); + assert(right_neighbor.mdir.mid == 1); assert(memcmp(&right_neighbor.mdir.rbyd, &lfs.mroot.rbyd, sizeof(lfs.mroot.rbyd)) == 0); @@ -2823,33 +2372,30 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), - LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; + LFSR_ATTR(1, REG, +1, BUF("a", 1)), + LFSR_ATTR(2, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); lfsr_openedmdir_t left_neighbor = { - .mdir={.mid=0, .rbyd=lfs.mroot.rbyd}}; - lfsr_openedmdir_t right_neighbor = { .mdir={.mid=1, .rbyd=lfs.mroot.rbyd}}; + lfsr_openedmdir_t right_neighbor = { + .mdir={.mid=2, .rbyd=lfs.mroot.rbyd}}; lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &left_neighbor); lfsr_mdir_addopened(&lfs, LFS_TYPE_INTERNAL, &right_neighbor); - // try removing our left entry + // try removing our right entry lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(1, RM, -1, NULL()))) => 0; + LFSR_ATTR(2, RM, -1, NULL()))) => 0; // assert that an entry was removed - assert(lfs.mroot.rbyd.weight == 1); + assert(lfs.mroot.rbyd.weight == 2); // assert that our neighbors were updated correctly - assert(left_neighbor.mdir.mid == 0); + assert(left_neighbor.mdir.mid == 1); assert(memcmp(&left_neighbor.mdir.rbyd, &lfs.mroot.rbyd, sizeof(lfs.mroot.rbyd)) == 0); assert(right_neighbor.mdir.mid == -1); @@ -2868,13 +2414,10 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), + LFSR_ATTR(0, BOOKMARK, 0, BUF("a", 1)), LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); @@ -2948,13 +2491,10 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), + LFSR_ATTR(0, BOOKMARK, 0, BUF("a", 1)), LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); @@ -3023,9 +2563,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -3035,7 +2572,7 @@ code = ''' memset(buffer, 'd', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -3091,7 +2628,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+1, &mdir) => 0; assert(mdir.rbyd.weight == 2); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "d", 1) == 0); @@ -3127,13 +2664,10 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // setup our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)), + LFSR_ATTR(0, BOOKMARK, 0, BUF("a", 1)), LFSR_ATTR(1, REG, +1, BUF("b", 1)))) => 0; // this test only works if these all fit in the mroot assert(lfsr_mtree_ismptr(&lfs)); @@ -3193,9 +2727,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create an uninlined mdir uint8_t buffer[SIZE]; @@ -3205,7 +2736,7 @@ code = ''' memset(buffer, 'd', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -3288,9 +2819,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; //// create a situation where we have 3 mdirs in our tree @@ -3298,7 +2826,7 @@ code = ''' uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; @@ -3383,9 +2911,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; //// create a situation where we have 3 mdirs in our tree @@ -3393,7 +2918,7 @@ code = ''' uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( LFSR_ATTR(1, REG, +1, BUF(buffer, SIZE)))) => 0; @@ -3474,19 +2999,16 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // insert a new entry, this should update our neighbors lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF("a", 1)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF("a", 1)))) => 0; // assert that our entry is still in the mtree assert(lfs.mroot.rbyd.weight == 1); uint8_t buffer[1]; - lfsr_mdir_get(&lfs, &lfs.mroot, 0, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &lfs.mroot, 0, LFSR_TAG_BOOKMARK, buffer, 1) => 1; assert(memcmp(buffer, "a", 1) == 0); @@ -3551,7 +3073,7 @@ code = ''' // assert that our entry is still in the mtree assert(lfs.mroot.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &lfs.mroot, 0, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &lfs.mroot, 0, LFSR_TAG_BOOKMARK, buffer, 1) => 1; assert(memcmp(buffer, "a", 1) == 0); @@ -3568,9 +3090,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with a large attr so the next entry can not fit uint8_t buffer[SIZE]; @@ -3581,7 +3100,7 @@ code = ''' // create a large entry that needs to be uninlined (but not split!) memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; // force mroot to compact lfs.mroot.rbyd.eoff = -1; @@ -3602,7 +3121,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -3678,7 +3197,7 @@ code = ''' lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "b", 1) == 0); @@ -3695,15 +3214,12 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create 2 large entries that needs to be uninlined and split uint8_t buffer[SIZE]; memset(buffer, 'a', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, REG, +1, BUF(buffer, SIZE)))) => 0; + LFSR_ATTR(0, BOOKMARK, 0, BUF(buffer, SIZE)))) => 0; memset(buffer, 'b', SIZE); lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( @@ -3722,7 +3238,7 @@ code = ''' lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -3800,7 +3316,7 @@ code = ''' // assert that our entries are still in the mtree lfsr_mtree_lookup(&lfs, 0*lfsr_mweight(&lfs)+0, &mdir) => 0; assert(mdir.rbyd.weight == 1); - lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, + lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_BOOKMARK, buffer, SIZE) => SIZE; assert(memcmp(buffer, "a", 1) == 0); @@ -3826,9 +3342,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // prepare mroot with an attr uint8_t buffer[SIZE]; @@ -3935,9 +3448,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create entries lfsr_mdir_t mdir; @@ -3946,6 +3456,7 @@ code = ''' lfsr_mtree_weight(&lfs) - lfsr_mweight(&lfs), 0), &mdir) => 0; + mdir.mid += 1; for (lfs_size_t i = 0; i < N; i++) { // force a compaction? if (FORCE_COMPACTION) { @@ -3976,6 +3487,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -4054,6 +3570,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -4079,9 +3600,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // at least keep track of the number of entries we expect lfs_size_t count = 0; @@ -4089,16 +3607,17 @@ code = ''' uint32_t prng = SEED; for (lfs_size_t i = 0; i < N; i++) { // choose a pseudo-random mid - lfs_ssize_t mid = (lfs_ssize_t)( - TEST_PRNG(&prng) % lfs_max32( - lfsr_mtree_weight(&lfs), - lfsr_mweight(&lfs))); + lfs_ssize_t mid = TEST_PRNG(&prng) % lfs_max32( + lfsr_mtree_weight(&lfs), + lfsr_mweight(&lfs)); // fetch mdir lfsr_mdir_t mdir; lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; // limit our mid to our mdir's weight - mdir.mid = lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) - + (mdir.mid % (mdir.rbyd.weight+1)); + mdir.mid = lfs_max32( + lfsr_mdir_bid(&lfs, &mdir)-(lfsr_mweight(&lfs)-1) + + (mdir.mid % (mdir.rbyd.weight+1)), + 1); // force a compaction? if (FORCE_COMPACTION) { @@ -4132,6 +3651,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -4215,6 +3739,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1; @@ -4426,9 +3955,6 @@ code = ''' lfsr_format(&lfs, CFG) => 0; lfsr_mount(&lfs, CFG) => 0; lfs_alloc_ack(&lfs); - // remove root bookmark for now - lfsr_mdir_commit(&lfs, &lfs.mroot, LFSR_ATTRS( - LFSR_ATTR(0, RM, -1, NULL()))) => 0; // create entries lfsr_mdir_t mdir; @@ -4437,6 +3963,7 @@ code = ''' lfsr_mtree_weight(&lfs) - lfsr_mweight(&lfs), 0), &mdir) => 0; + mdir.mid += 1; for (lfs_size_t i = 0; i < N; i++) { lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( LFSR_ATTR(mdir.mid, REG, +1, @@ -4502,6 +4029,11 @@ code = ''' lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; for (; lfsr_mdir_rid(&lfs, &mdir) < mdir.rbyd.weight; mdir.mid += 1) { + // skip the root bookmark + if (mdir.mid == 0) { + continue; + } + uint8_t buffer[4]; lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG, buffer, 4) => 1;