btree: Reworked btree traversal to leverage leaf caches
This comes from an observation that we never actually use the leaf cache
during traversals, and there is surprisingly little risk of a lookup
creating a conflict in the future.
Btree traversal fall into two categories:
1. Full traversals, where we traverse a full btree all at once. These
are unlikely to have lookup conflicts because everything is
usually self-contained in one chunk of logic.
2. Incremental traversals. These _are_ at risk, but in our current
design limited to lfs3_trv_t, which already creates a fully
bshrub/btree copy for tracking purposes.
This copy unintentionally, but conveniently, protects against lookup
conflicts.
So, why not reuse the btree leaf cache to hold the rbyd state during
traversals? In theory this makes lfs3_btree_traverse the same cost and
lfs3_btree_lookupnext, drops the need for lfs3_btrv_t, and simplifies
the internal API.
The only extra bit of state we need is the current target bid, which is
now expected as a caller-incremented argument similar to
lfs3_btree_lookupnext iteration.
There was a bit of futzing around with bid=-1 being necessary to
initialize traversal (to avoid conflicts with bid=-1 => 0 caused by
empty btrees). But the end result is a btree traversal that only needs
one extra word of state.
---
Unfortunately, in practice, the savings were not as great as expected:
code stack ctx
before: 36792 2400 684
after: 36876 (+0.2%) 2384 (-0.7%) 684 (+0.0%)
This does claw back some stack, but less than a full rbyd due to the
union with the mtortoise in lfs3_trv_t. The mtortoise now dominates. It
might be possible to union the mtortoise and the bshrub/btree state
better (both are not needed at the same time), but strict aliasing rules
in C make this tricky.
The new lfs3_btree_traverse is also a bit more complicated in terms of
code cost. In theory this would be offset by the simpler traversal setup
logic, but we only actually call lfs3_btree_traverse twice:
1. In lfs3_mtree_traverse
2. In lfs3_file_ck
Still, some stack savings + a simpler internal API makes this worthwhile
for now. lfs3_trv_t is also due for a revisit, and hopefully it's
possible to better union things with btree leaf caches somehow.
This commit is contained in:
@@ -6313,49 +6313,64 @@ static lfs3_scmp_t lfs3_btree_namelookup(lfs3_t *lfs3, lfs3_btree_t *btree,
|
|||||||
|
|
||||||
// incremental btree traversal
|
// incremental btree traversal
|
||||||
//
|
//
|
||||||
// note this is different from iteration, iteration should use
|
// when bid is initialized to -1, incrementally traverses all btree
|
||||||
// lfs3_btree_lookupnext, traversal includes inner btree nodes
|
// nodes using the leaf rbyd to keep track of state
|
||||||
|
//
|
||||||
|
// unlike lfs3_btree_lookupnext, this includes inner btree nodes
|
||||||
|
//
|
||||||
|
// just don't call lfs3_btree_lookupnext/lookup/commit or anything else
|
||||||
|
// that uses the leaf rbyd mid-traversal or things will break!
|
||||||
#ifndef LFS3_2BONLY
|
#ifndef LFS3_2BONLY
|
||||||
static void lfs3_btrv_init(lfs3_btrv_t *btrv) {
|
static lfs3_stag_t lfs3_btree_traverse(lfs3_t *lfs3, lfs3_btree_t *btree,
|
||||||
btrv->bid = 0;
|
lfs3_sbid_t bid,
|
||||||
btrv->branch = NULL;
|
lfs3_sbid_t *bid_, lfs3_bid_t *weight_, lfs3_data_t *data_) {
|
||||||
btrv->rid = 0;
|
// restart from the root?
|
||||||
}
|
if (bid == -1 || btree->leaf.rbyd.weight == 0) {
|
||||||
#endif
|
// end of traversal?
|
||||||
|
if (bid >= (lfs3_sbid_t)btree->r.weight) {
|
||||||
|
return LFS3_ERR_NOENT;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef LFS3_2BONLY
|
// restart from the root
|
||||||
static lfs3_stag_t lfs3_btree_traverse(lfs3_t *lfs3, const lfs3_btree_t *btree,
|
btree->leaf.bid = btree->r.weight-1;
|
||||||
lfs3_btrv_t *btrv,
|
btree->leaf.rbyd = btree->r;
|
||||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_data_t *data_) {
|
|
||||||
// explicitly traverse the root even if weight=0
|
|
||||||
if (!btrv->branch) {
|
|
||||||
btrv->branch = &btree->r;
|
|
||||||
btrv->rid = btrv->bid;
|
|
||||||
|
|
||||||
// traverse the root
|
// explicitly traverse the root even if weight=0
|
||||||
if (btrv->bid == 0
|
if (bid == -1) {
|
||||||
// unless we don't even have a root yet
|
// unless we don't even have a root yet
|
||||||
&& lfs3_rbyd_trunk(&btree->r) != 0
|
if (lfs3_rbyd_trunk(&btree->r) != 0
|
||||||
// or are a shrub
|
// or are a shrub
|
||||||
&& !lfs3_rbyd_isshrub(&btree->r)) {
|
&& !lfs3_rbyd_isshrub(&btree->r)) {
|
||||||
if (bid_) {
|
if (bid_) {
|
||||||
*bid_ = btree->r.weight-1;
|
*bid_ = btree->r.weight-1;
|
||||||
|
}
|
||||||
|
if (weight_) {
|
||||||
|
*weight_ = btree->r.weight;
|
||||||
|
}
|
||||||
|
if (data_) {
|
||||||
|
// note we point data_ at the actual root here! this
|
||||||
|
// avoids redundant fetches if the traversal fetches
|
||||||
|
// btree nodes
|
||||||
|
data_->u.buffer = (const uint8_t*)&btree->r;
|
||||||
|
}
|
||||||
|
return LFS3_TAG_BRANCH;
|
||||||
}
|
}
|
||||||
if (weight_) {
|
|
||||||
*weight_ = btree->r.weight;
|
bid = btree->leaf.bid+1;
|
||||||
}
|
|
||||||
if (data_) {
|
|
||||||
data_->u.buffer = (const uint8_t*)btrv->branch;
|
|
||||||
}
|
|
||||||
return LFS3_TAG_BRANCH;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to restart from the root?
|
// did someone mess with the leaf rbyd?
|
||||||
if (btrv->rid >= (lfs3_srid_t)btrv->branch->weight) {
|
LFS3_ASSERT(bid >= (lfs3_sbid_t)(
|
||||||
btrv->branch = &btree->r;
|
btree->leaf.bid-(btree->leaf.rbyd.weight-1))
|
||||||
btrv->rid = btrv->bid;
|
&& bid <= (lfs3_sbid_t)(
|
||||||
|
btree->leaf.bid+1));
|
||||||
|
|
||||||
|
// the user increments bid to move the traversal forward, but if we
|
||||||
|
// were at a btree inner node we remap this to descending down the
|
||||||
|
// tree
|
||||||
|
if (bid == (lfs3_sbid_t)(btree->leaf.bid+1)) {
|
||||||
|
bid = btree->leaf.bid-(btree->leaf.rbyd.weight-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// descend down the tree
|
// descend down the tree
|
||||||
@@ -6363,8 +6378,8 @@ static lfs3_stag_t lfs3_btree_traverse(lfs3_t *lfs3, const lfs3_btree_t *btree,
|
|||||||
lfs3_srid_t rid__;
|
lfs3_srid_t rid__;
|
||||||
lfs3_rid_t weight__;
|
lfs3_rid_t weight__;
|
||||||
lfs3_data_t data__;
|
lfs3_data_t data__;
|
||||||
lfs3_stag_t tag__ = lfs3_rbyd_lookupnext(lfs3, btrv->branch,
|
lfs3_stag_t tag__ = lfs3_rbyd_lookupnext(lfs3, &btree->leaf.rbyd,
|
||||||
btrv->rid, 0,
|
bid - (btree->leaf.bid-(btree->leaf.rbyd.weight-1)), 0,
|
||||||
&rid__, &weight__, &data__);
|
&rid__, &weight__, &data__);
|
||||||
if (tag__ < 0) {
|
if (tag__ < 0) {
|
||||||
return tag__;
|
return tag__;
|
||||||
@@ -6372,7 +6387,8 @@ static lfs3_stag_t lfs3_btree_traverse(lfs3_t *lfs3, const lfs3_btree_t *btree,
|
|||||||
|
|
||||||
// if we found a bname, lookup the branch
|
// if we found a bname, lookup the branch
|
||||||
if (tag__ == LFS3_TAG_BNAME) {
|
if (tag__ == LFS3_TAG_BNAME) {
|
||||||
tag__ = lfs3_rbyd_lookup(lfs3, btrv->branch, rid__, LFS3_TAG_BRANCH,
|
tag__ = lfs3_rbyd_lookup(lfs3, &btree->leaf.rbyd,
|
||||||
|
rid__, LFS3_TAG_BRANCH,
|
||||||
&data__);
|
&data__);
|
||||||
if (tag__ < 0) {
|
if (tag__ < 0) {
|
||||||
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
LFS3_ASSERT(tag__ != LFS3_ERR_NOENT);
|
||||||
@@ -6380,43 +6396,49 @@ static lfs3_stag_t lfs3_btree_traverse(lfs3_t *lfs3, const lfs3_btree_t *btree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adjust bid__ with subtree's weight
|
||||||
|
lfs3_bid_t bid__ = (btree->leaf.bid-(btree->leaf.rbyd.weight-1))
|
||||||
|
+ rid__;
|
||||||
|
|
||||||
// found another branch
|
// found another branch
|
||||||
if (tag__ == LFS3_TAG_BRANCH) {
|
if (tag__ == LFS3_TAG_BRANCH) {
|
||||||
// adjust rid with subtree's weight
|
|
||||||
btrv->rid -= (rid__ - (weight__-1));
|
|
||||||
|
|
||||||
// fetch the next branch
|
// fetch the next branch
|
||||||
|
lfs3_rbyd_t rbyd__;
|
||||||
int err = lfs3_data_fetchbranch(lfs3, &data__, weight__,
|
int err = lfs3_data_fetchbranch(lfs3, &data__, weight__,
|
||||||
&btrv->rbyd);
|
&rbyd__);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
btrv->branch = &btrv->rbyd;
|
btree->leaf.bid = bid__;
|
||||||
|
btree->leaf.rbyd = rbyd__;
|
||||||
|
|
||||||
// return inner btree nodes if this is the first time we've
|
// return inner btree nodes if this is the first time we've
|
||||||
// seen them
|
// seen them
|
||||||
if (btrv->rid == 0) {
|
if (bid - (btree->leaf.bid-(btree->leaf.rbyd.weight-1)) == 0) {
|
||||||
if (bid_) {
|
if (bid_) {
|
||||||
*bid_ = btrv->bid + (rid__ - btrv->rid);
|
*bid_ = btree->leaf.bid;
|
||||||
}
|
}
|
||||||
if (weight_) {
|
if (weight_) {
|
||||||
*weight_ = weight__;
|
*weight_ = btree->leaf.rbyd.weight;
|
||||||
}
|
}
|
||||||
if (data_) {
|
if (data_) {
|
||||||
data_->u.buffer = (const uint8_t*)btrv->branch;
|
data_->u.buffer = (const uint8_t*)&btree->leaf.rbyd;
|
||||||
}
|
}
|
||||||
return LFS3_TAG_BRANCH;
|
return LFS3_TAG_BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found our bid
|
// found our bid
|
||||||
} else {
|
} else {
|
||||||
// move on to the next rid
|
// discard the leaf when we're done with it to restart from
|
||||||
|
// the root on the next call
|
||||||
|
if (rid__ == (lfs3_srid_t)(btree->leaf.rbyd.weight-1)) {
|
||||||
|
lfs3_btree_discardleaf(btree);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we let the user increment bid to step through
|
||||||
|
// the full leaf
|
||||||
//
|
//
|
||||||
// note this effectively traverses a full leaf without redoing
|
// this + leaf caching avoids redoing the full btree walk
|
||||||
// the btree walk
|
|
||||||
lfs3_bid_t bid__ = btrv->bid + (rid__ - btrv->rid);
|
|
||||||
btrv->bid = bid__ + 1;
|
|
||||||
btrv->rid = rid__ + 1;
|
|
||||||
|
|
||||||
if (bid_) {
|
if (bid_) {
|
||||||
*bid_ = bid__;
|
*bid_ = bid__;
|
||||||
@@ -6783,11 +6805,10 @@ static lfs3_stag_t lfs3_bshrub_lookup(lfs3_t *lfs3, lfs3_bshrub_t *bshrub,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_2BONLY
|
#ifndef LFS3_2BONLY
|
||||||
static lfs3_stag_t lfs3_bshrub_traverse(lfs3_t *lfs3,
|
static lfs3_stag_t lfs3_bshrub_traverse(lfs3_t *lfs3, lfs3_bshrub_t *bshrub,
|
||||||
const lfs3_bshrub_t *bshrub,
|
lfs3_sbid_t bid,
|
||||||
lfs3_btrv_t *btrv,
|
lfs3_sbid_t *bid_, lfs3_bid_t *weight_, lfs3_data_t *data_) {
|
||||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_data_t *data_) {
|
return lfs3_btree_traverse(lfs3, &bshrub->shrub, bid,
|
||||||
return lfs3_btree_traverse(lfs3, &bshrub->shrub, btrv,
|
|
||||||
bid_, weight_, data_);
|
bid_, weight_, data_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -9871,7 +9892,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transition to traversing the mtree
|
// transition to traversing the mtree
|
||||||
lfs3_btrv_init(&trv->u.btrv);
|
trv->u.bid = -2;
|
||||||
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_MTREE);
|
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_MTREE);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -9927,7 +9948,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
|||||||
// here, lfs3_bshrub_fetch ignores these for us
|
// here, lfs3_bshrub_fetch ignores these for us
|
||||||
if (err != LFS3_ERR_NOENT) {
|
if (err != LFS3_ERR_NOENT) {
|
||||||
// start traversing
|
// start traversing
|
||||||
lfs3_btrv_init(&trv->u.btrv);
|
trv->u.bid = -2;
|
||||||
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_BTREE);
|
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_BTREE);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -9972,7 +9993,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
|||||||
// transition to traversing the file
|
// transition to traversing the file
|
||||||
const lfs3_file_t *file = (const lfs3_file_t*)trv->htrv;
|
const lfs3_file_t *file = (const lfs3_file_t*)trv->htrv;
|
||||||
trv->b.shrub = file->b.shrub;
|
trv->b.shrub = file->b.shrub;
|
||||||
lfs3_btrv_init(&trv->u.btrv);
|
trv->u.bid = -2;
|
||||||
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_OBTREE);
|
lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_OBTREE);
|
||||||
continue;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
@@ -9984,8 +10005,8 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
|||||||
case LFS3_TSTATE_BTREE:;
|
case LFS3_TSTATE_BTREE:;
|
||||||
case LFS3_TSTATE_OBTREE:;
|
case LFS3_TSTATE_OBTREE:;
|
||||||
// traverse through our bshrub/btree
|
// traverse through our bshrub/btree
|
||||||
tag = lfs3_bshrub_traverse(lfs3, &trv->b, &trv->u.btrv,
|
tag = lfs3_bshrub_traverse(lfs3, &trv->b, trv->u.bid+1,
|
||||||
NULL, NULL, &data);
|
&trv->u.bid, NULL, &data);
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
// clear the bshrub state
|
// clear the bshrub state
|
||||||
@@ -11671,8 +11692,7 @@ static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file);
|
|||||||
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const lfs3_name_t *name);
|
const lfs3_name_t *name);
|
||||||
#endif
|
#endif
|
||||||
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_ck(lfs3_t *lfs3, lfs3_file_t *file, uint32_t flags);
|
||||||
uint32_t flags);
|
|
||||||
|
|
||||||
int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const char *path, uint32_t flags,
|
const char *path, uint32_t flags,
|
||||||
@@ -14085,15 +14105,13 @@ failed:;
|
|||||||
// file check functions
|
// file check functions
|
||||||
|
|
||||||
#if !defined(LFS3_KVONLY) && !defined(LFS3_2BONLY)
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_2BONLY)
|
||||||
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_ck(lfs3_t *lfs3, lfs3_file_t *file, uint32_t flags) {
|
||||||
uint32_t flags) {
|
|
||||||
// traverse the file's bshrub/btree
|
// traverse the file's bshrub/btree
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
while (true) {
|
while (true) {
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
lfs3_stag_t tag = lfs3_bshrub_traverse(lfs3, &file->b, &btrv,
|
lfs3_stag_t tag = lfs3_bshrub_traverse(lfs3, &file->b, bid+1,
|
||||||
NULL, NULL, &data);
|
&bid, NULL, &data);
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -768,13 +768,6 @@ typedef struct lfs3_dir {
|
|||||||
lfs3_off_t pos;
|
lfs3_off_t pos;
|
||||||
} lfs3_dir_t;
|
} lfs3_dir_t;
|
||||||
|
|
||||||
typedef struct lfs3_btrv {
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
const lfs3_rbyd_t *branch;
|
|
||||||
lfs3_srid_t rid;
|
|
||||||
lfs3_rbyd_t rbyd;
|
|
||||||
} lfs3_btrv_t;
|
|
||||||
|
|
||||||
// littlefs traversal type
|
// littlefs traversal type
|
||||||
typedef struct lfs3_trv {
|
typedef struct lfs3_trv {
|
||||||
// mdir/bshrub/btree state, this also includes our traversal
|
// mdir/bshrub/btree state, this also includes our traversal
|
||||||
@@ -790,7 +783,7 @@ typedef struct lfs3_trv {
|
|||||||
uint8_t power;
|
uint8_t power;
|
||||||
} mtortoise;
|
} mtortoise;
|
||||||
// btree traversal state
|
// btree traversal state
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
// recalculate gcksum when traversing with ckmeta
|
// recalculate gcksum when traversing with ckmeta
|
||||||
|
|||||||
@@ -4281,17 +4281,15 @@ code = '''
|
|||||||
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
|
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
|
||||||
memset(seen, 0, (BLOCK_COUNT+7)/8);
|
memset(seen, 0, (BLOCK_COUNT+7)/8);
|
||||||
|
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i <= 2*N);
|
assert(i <= 2*N);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_btree_traverse(&lfs3, &btree, &btrv,
|
tag = lfs3_btree_traverse(&lfs3, &btree, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -4439,17 +4437,15 @@ code = '''
|
|||||||
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
|
uint8_t *seen = malloc((BLOCK_COUNT+7)/8);
|
||||||
memset(seen, 0, (BLOCK_COUNT+7)/8);
|
memset(seen, 0, (BLOCK_COUNT+7)/8);
|
||||||
|
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i <= 2*N);
|
assert(i <= 2*N);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_btree_traverse(&lfs3, &btree, &btrv,
|
tag = lfs3_btree_traverse(&lfs3, &btree, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
|
|||||||
+20
-40
@@ -183,17 +183,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -331,17 +329,15 @@ code = '''
|
|||||||
lfs3_block_t blocks = 0;
|
lfs3_block_t blocks = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -597,17 +593,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -760,17 +754,15 @@ code = '''
|
|||||||
lfs3_block_t blocks = 0;
|
lfs3_block_t blocks = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -2088,17 +2080,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -2240,17 +2230,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -2539,17 +2527,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -2706,17 +2692,15 @@ code = '''
|
|||||||
lfs3_block_t blocks = 0;
|
lfs3_block_t blocks = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -2999,17 +2983,15 @@ code = '''
|
|||||||
lfs3_size_t fragments = 0;
|
lfs3_size_t fragments = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
@@ -3170,17 +3152,15 @@ code = '''
|
|||||||
lfs3_block_t blocks = 0;
|
lfs3_block_t blocks = 0;
|
||||||
|
|
||||||
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
lfs3_file_open(&lfs3, &file, "hello", LFS3_O_RDONLY) => 0;
|
||||||
lfs3_btrv_t btrv;
|
lfs3_sbid_t bid = -2;
|
||||||
lfs3_btrv_init(&btrv);
|
|
||||||
for (lfs3_block_t i = 0;; i++) {
|
for (lfs3_block_t i = 0;; i++) {
|
||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i < 2*BLOCK_COUNT);
|
assert(i < 2*BLOCK_COUNT);
|
||||||
|
|
||||||
lfs3_bid_t bid;
|
|
||||||
lfs3_stag_t tag;
|
lfs3_stag_t tag;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_data_t data;
|
lfs3_data_t data;
|
||||||
tag = lfs3_bshrub_traverse(&lfs3, &file.b, &btrv,
|
tag = lfs3_bshrub_traverse(&lfs3, &file.b, bid+1,
|
||||||
&bid, &weight, &data);
|
&bid, &weight, &data);
|
||||||
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
assert(tag >= 0 || tag == LFS3_ERR_NOENT);
|
||||||
if (tag == LFS3_ERR_NOENT) {
|
if (tag == LFS3_ERR_NOENT) {
|
||||||
|
|||||||
Reference in New Issue
Block a user