Typedefed lfsr_shrub_t -> lfsr_rbyd_t, replacing lfsr_bshrub_t union

The lfsr_shrub_t/lfsr_btree_t union was _technically_ not undefined
behavior, because the relevant fields were all a part of the "common
initial sequence", but collapsing these to the same type certainly does
simplify things.

The only weirdness is that we now store shrub.estimate in shrub.eoff.

We could add a union here, but the extra noise is just not worth the
slighty better name. The shrub.estimate is a sort of "simulated
shrub.eoff" anyways.

---

This makes it so all of these types alias to the same core lfsr_rbyd_t
type, which I suppose actually reflects the on-disk format quite well:

  lfsr_shrub_t  => lfsr_rbyd_t
  lfsr_bshrub_t
  lfsr_btree_t

Code cost more-or-less unaffected:

           code          stack          ctx
  before: 36432           2608          640
  after:  36436 (+0.0%)   2608 (+0.0%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-02-03 02:17:52 -06:00
parent 192c58318f
commit 7c17be4dbe
3 changed files with 91 additions and 107 deletions
+78 -82
View File
@@ -4627,7 +4627,7 @@ static int lfsr_rbyd_appendshrub(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// compact our shrub // compact our shrub
int err = lfsr_rbyd_appendcompactrbyd(lfs, rbyd, int err = lfsr_rbyd_appendcompactrbyd(lfs, rbyd,
(const lfsr_rbyd_t*)shrub, -1, -1); shrub, -1, -1);
if (err) { if (err) {
return err; return err;
} }
@@ -5954,24 +5954,22 @@ static void lfsr_shrub_init(lfsr_shrub_t *shrub, lfs_block_t block) {
shrub->blocks[0] = block; shrub->blocks[0] = block;
shrub->trunk = LFSR_RBYD_ISSHRUB | 0; shrub->trunk = LFSR_RBYD_ISSHRUB | 0;
// force estimate recalculation // force estimate recalculation
shrub->estimate = -1; shrub->eoff = -1;
} }
// helper functions // helper functions
static inline bool lfsr_shrub_isshrub(const lfsr_shrub_t *shrub) { static inline bool lfsr_shrub_isshrub(const lfsr_shrub_t *shrub) {
return lfsr_rbyd_isshrub((const lfsr_rbyd_t*)shrub); return lfsr_rbyd_isshrub(shrub);
} }
static inline lfs_size_t lfsr_shrub_trunk(const lfsr_shrub_t *shrub) { static inline lfs_size_t lfsr_shrub_trunk(const lfsr_shrub_t *shrub) {
return lfsr_rbyd_trunk((const lfsr_rbyd_t*)shrub); return lfsr_rbyd_trunk(shrub);
} }
static inline int lfsr_shrub_cmp( static inline int lfsr_shrub_cmp(
const lfsr_shrub_t *a, const lfsr_shrub_t *a,
const lfsr_shrub_t *b) { const lfsr_shrub_t *b) {
return lfsr_rbyd_cmp( return lfsr_rbyd_cmp(a, b);
(const lfsr_rbyd_t*)a,
(const lfsr_rbyd_t*)b);
} }
// shrub on-disk encoding // shrub on-disk encoding
@@ -6021,7 +6019,7 @@ static int lfsr_data_readshrub(lfs_t *lfs, lfsr_data_t *data,
// copy the mdir block // copy the mdir block
shrub->blocks[0] = mdir->rbyd.blocks[0]; shrub->blocks[0] = mdir->rbyd.blocks[0];
// force estimate recalculation if we write to this shrub // force estimate recalculation if we write to this shrub
shrub->estimate = -1; shrub->eoff = -1;
int err = lfsr_data_readleb128(lfs, data, &shrub->weight); int err = lfsr_data_readleb128(lfs, data, &shrub->weight);
if (err) { if (err) {
@@ -6051,16 +6049,16 @@ static lfs_ssize_t lfsr_shrub_estimate(lfs_t *lfs,
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) { for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
if (lfsr_o_isbshrub(o->flags) if (lfsr_o_isbshrub(o->flags)
&& lfsr_shrub_cmp( && lfsr_shrub_cmp(
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub, &((lfsr_obshrub_t*)o)->bshrub,
shrub) == 0) { shrub) == 0) {
last = &((lfsr_obshrub_t*)o)->bshrub.u.bshrub; last = &((lfsr_obshrub_t*)o)->bshrub;
} }
} }
if (last && shrub != last) { if (last && shrub != last) {
return 0; return 0;
} }
return lfsr_rbyd_estimate(lfs, (const lfsr_rbyd_t*)shrub, -1, -1, return lfsr_rbyd_estimate(lfs, shrub, -1, -1,
NULL); NULL);
} }
@@ -6083,11 +6081,11 @@ static int lfsr_shrub_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) { for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
if (lfsr_o_isbshrub(o->flags) if (lfsr_o_isbshrub(o->flags)
&& lfsr_shrub_cmp( && lfsr_shrub_cmp(
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub, &((lfsr_obshrub_t*)o)->bshrub,
shrub) == 0) { shrub) == 0) {
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0] = rbyd_->blocks[0]; ((lfsr_obshrub_t*)o)->bshrub_.blocks[0] = rbyd_->blocks[0];
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.trunk = rbyd_->trunk; ((lfsr_obshrub_t*)o)->bshrub_.trunk = rbyd_->trunk;
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.weight = rbyd_->weight; ((lfsr_obshrub_t*)o)->bshrub_.weight = rbyd_->weight;
} }
} }
@@ -6141,20 +6139,20 @@ static int lfsr_shrub_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
// create a non-existant bshrub // create a non-existant bshrub
static void lfsr_bshrub_init(lfsr_bshrub_t *bshrub) { static void lfsr_bshrub_init(lfsr_bshrub_t *bshrub) {
bshrub->u.bshrub.weight = 0; bshrub->weight = 0;
bshrub->u.bshrub.trunk = 0; bshrub->trunk = 0;
} }
static inline bool lfsr_bshrub_isbnull(const lfsr_bshrub_t *bshrub) { static inline bool lfsr_bshrub_isbnull(const lfsr_bshrub_t *bshrub) {
return !bshrub->u.bshrub.trunk; return !bshrub->trunk;
} }
static inline bool lfsr_bshrub_isbshrub(const lfsr_bshrub_t *bshrub) { static inline bool lfsr_bshrub_isbshrub(const lfsr_bshrub_t *bshrub) {
return lfsr_shrub_isshrub(&bshrub->u.bshrub); return lfsr_rbyd_isshrub(bshrub);
} }
static inline bool lfsr_bshrub_isbtree(const lfsr_bshrub_t *bshrub) { static inline bool lfsr_bshrub_isbtree(const lfsr_bshrub_t *bshrub) {
return !lfsr_shrub_isshrub(&bshrub->u.bshrub); return !lfsr_rbyd_isshrub(bshrub);
} }
// needed in lfsr_bshrub_estimate // needed in lfsr_bshrub_estimate
@@ -6201,7 +6199,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
&& lfsr_bshrub_isbshrub( && lfsr_bshrub_isbshrub(
&((lfsr_obshrub_t*)o)->bshrub)) { &((lfsr_obshrub_t*)o)->bshrub)) {
lfs_ssize_t dsize = lfsr_shrub_estimate(lfs, lfs_ssize_t dsize = lfsr_shrub_estimate(lfs,
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub); &((lfsr_obshrub_t*)o)->bshrub);
if (dsize < 0) { if (dsize < 0) {
return dsize; return dsize;
} }
@@ -6219,7 +6217,7 @@ static int lfsr_bshrub_lookupnext(lfs_t *lfs,
lfsr_bptr_t *bptr_) { lfsr_bptr_t *bptr_) {
(void)mdir; (void)mdir;
// out of bounds? // out of bounds?
if (bid >= bshrub->u.weight) { if (bid >= bshrub->weight) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
@@ -6230,7 +6228,7 @@ static int lfsr_bshrub_lookupnext(lfs_t *lfs,
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_bid_t weight; lfsr_bid_t weight;
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_btree_lookupnext_(lfs, &bshrub->u.btree, bid, int err = lfsr_btree_lookupnext_(lfs, bshrub, bid,
&bid__, &rbyd, &rid, &tag, &weight, &data); &bid__, &rbyd, &rid, &tag, &weight, &data);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -6270,7 +6268,7 @@ static int lfsr_bshrub_traverse(lfs_t *lfs,
(void)mdir; (void)mdir;
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_btree_traverse(lfs, &bshrub->u.btree, bt, int err = lfsr_btree_traverse(lfs, bshrub, bt,
bid_, &tag, &data); bid_, &tag, &data);
if (err) { if (err) {
return err; return err;
@@ -6310,17 +6308,17 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
if (lfsr_o_isbshrub(o->flags) if (lfsr_o_isbshrub(o->flags)
&& &((lfsr_obshrub_t*)o)->bshrub != bshrub && &((lfsr_obshrub_t*)o)->bshrub != bshrub
&& lfsr_btree_cmp( && lfsr_btree_cmp(
&((lfsr_obshrub_t*)o)->bshrub.u.btree, &((lfsr_obshrub_t*)o)->bshrub,
&bshrub->u.btree) == 0) { bshrub) == 0) {
// mark as unerased // mark as unerased
((lfsr_obshrub_t*)o)->bshrub.u.btree.eoff = -1; ((lfsr_obshrub_t*)o)->bshrub.eoff = -1;
} }
} }
} }
// try to commit to the btree // try to commit to the btree
lfsr_bscratch_t bscratch; lfsr_bscratch_t bscratch;
int err = lfsr_btree_commit__(lfs, &bshrub->u.btree, &bscratch, int err = lfsr_btree_commit__(lfs, bshrub, &bscratch,
&bid, rbyd, rid, &rats, &rat_count); &bid, rbyd, rid, &rats, &rat_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
@@ -6354,9 +6352,7 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
// does our estimate exceed our shrub_size? need to recalculate an // does our estimate exceed our shrub_size? need to recalculate an
// accurate estimate // accurate estimate
lfs_ssize_t estimate = (alloc) lfs_ssize_t estimate = (alloc) ? (lfs_size_t)-1 : bshrub->eoff;
? (lfs_size_t)-1
: bshrub->u.bshrub.estimate;
// this double condition avoids overflow issues // this double condition avoids overflow issues
if ((lfs_size_t)estimate > lfs->cfg->shrub_size if ((lfs_size_t)estimate > lfs->cfg->shrub_size
|| estimate + commit_estimate > lfs->cfg->shrub_size) { || estimate + commit_estimate > lfs->cfg->shrub_size) {
@@ -6386,11 +6382,11 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
int err = lfsr_mdir_commit(lfs, mdir, LFSR_RATS( int err = lfsr_mdir_commit(lfs, mdir, LFSR_RATS(
LFSR_RAT_SHRUBCOMMIT( LFSR_RAT_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0, LFSR_TAG_SHRUBCOMMIT, 0,
&bshrub->u.bshrub, bid, rats, rat_count))); bshrub, bid, rats, rat_count)));
if (err) { if (err) {
return err; return err;
} }
LFS_ASSERT(bshrub->u.bshrub.blocks[0] == mdir->rbyd.blocks[0]); LFS_ASSERT(bshrub->blocks[0] == mdir->rbyd.blocks[0]);
// update _all_ shrubs with the new estimate // update _all_ shrubs with the new estimate
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) { for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
@@ -6398,13 +6394,13 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
&& o->mdir.mid == mdir->mid && o->mdir.mid == mdir->mid
&& lfsr_bshrub_isbshrub( && lfsr_bshrub_isbshrub(
&((lfsr_obshrub_t*)o)->bshrub)) { &((lfsr_obshrub_t*)o)->bshrub)) {
((lfsr_obshrub_t*)o)->bshrub.u.bshrub.estimate = estimate; ((lfsr_obshrub_t*)o)->bshrub.eoff = estimate;
} }
} }
LFS_ASSERT(bshrub->u.bshrub.estimate == (lfs_size_t)estimate); LFS_ASSERT(bshrub->eoff == (lfs_size_t)estimate);
} }
LFS_ASSERT(lfsr_shrub_trunk(&bshrub->u.bshrub)); LFS_ASSERT(lfsr_shrub_trunk(bshrub));
#ifdef LFS_DEBUGBTREECOMMITS #ifdef LFS_DEBUGBTREECOMMITS
if (lfsr_bshrub_isbshrub(mdir, bshrub)) { if (lfsr_bshrub_isbshrub(mdir, bshrub)) {
LFS_DEBUG("Committed bshrub " LFS_DEBUG("Committed bshrub "
@@ -6432,7 +6428,7 @@ relocate:;
// note this may be a new root // note this may be a new root
if (!alloc) { if (!alloc) {
err = lfsr_rbyd_compact(lfs, &rbyd_, &bshrub->u.btree, -1, -1); err = lfsr_rbyd_compact(lfs, &rbyd_, bshrub, -1, -1);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
// bad prog? try another block // bad prog? try another block
@@ -6453,9 +6449,9 @@ relocate:;
return err; return err;
} }
bshrub->u.btree = rbyd_; *bshrub = rbyd_;
LFS_ASSERT(lfsr_rbyd_trunk(&bshrub->u.btree)); LFS_ASSERT(lfsr_rbyd_trunk(bshrub));
#ifdef LFS_DEBUGBTREECOMMITS #ifdef LFS_DEBUGBTREECOMMITS
LFS_DEBUG("Committed btree 0x%"PRIx32".%"PRIx32" w%"PRId32", " LFS_DEBUG("Committed btree 0x%"PRIx32".%"PRIx32" w%"PRId32", "
"cksum %"PRIx32, "cksum %"PRIx32,
@@ -7434,7 +7430,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
const lfsr_shrubcommit_t *shrubcommit = rats[i].cat; const lfsr_shrubcommit_t *shrubcommit = rats[i].cat;
// find the staging shrub // find the staging shrub
lfsr_shrub_t *shrub = shrubcommit->shrub; lfsr_shrub_t *shrub = shrubcommit->shrub;
lfsr_shrub_t *shrub_ = &((lfsr_bshrub_t*)shrub + 1)->u.bshrub; lfsr_shrub_t *shrub_ = shrub + 1;
// reset shrub if it doesn't live in our block, this happens // reset shrub if it doesn't live in our block, this happens
// when converting from a btree // when converting from a btree
@@ -7459,7 +7455,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
} else if (lfsr_tag_key(rats[i].tag) == LFSR_TAG_SHRUBTRUNK) { } else if (lfsr_tag_key(rats[i].tag) == LFSR_TAG_SHRUBTRUNK) {
// find the staging shrub // find the staging shrub
lfsr_shrub_t *shrub = (lfsr_shrub_t*)rats[i].cat; lfsr_shrub_t *shrub = (lfsr_shrub_t*)rats[i].cat;
lfsr_shrub_t *shrub_ = &((lfsr_bshrub_t*)shrub + 1)->u.bshrub; lfsr_shrub_t *shrub_ = shrub + 1;
uint8_t shrub_buf[LFSR_SHRUB_DSIZE]; uint8_t shrub_buf[LFSR_SHRUB_DSIZE];
int err = lfsr_rbyd_appendrat(lfs, &mdir->rbyd, int err = lfsr_rbyd_appendrat(lfs, &mdir->rbyd,
@@ -7544,11 +7540,11 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
&((lfsr_obshrub_t*)o)->bshrub) &((lfsr_obshrub_t*)o)->bshrub)
// only compact once, first compact should // only compact once, first compact should
// stage the new block // stage the new block
&& ((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0] && ((lfsr_obshrub_t*)o)->bshrub_.blocks[0]
!= mdir->rbyd.blocks[0]) { != mdir->rbyd.blocks[0]) {
int err = lfsr_shrub_compact(lfs, &mdir->rbyd, int err = lfsr_shrub_compact(lfs, &mdir->rbyd,
&((lfsr_obshrub_t*)o)->bshrub_.u.bshrub, &((lfsr_obshrub_t*)o)->bshrub_,
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub); &((lfsr_obshrub_t*)o)->bshrub);
if (err) { if (err) {
return err; return err;
} }
@@ -7770,7 +7766,7 @@ static lfs_ssize_t lfsr_mdir_estimate__(lfs_t *lfs, const lfsr_mdir_t *mdir,
&& lfsr_bshrub_isbshrub( && lfsr_bshrub_isbshrub(
&((lfsr_obshrub_t*)o)->bshrub)) { &((lfsr_obshrub_t*)o)->bshrub)) {
lfs_ssize_t dsize__ = lfsr_shrub_estimate(lfs, lfs_ssize_t dsize__ = lfsr_shrub_estimate(lfs,
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub); &((lfsr_obshrub_t*)o)->bshrub);
if (dsize__ < 0) { if (dsize__ < 0) {
return dsize__; return dsize__;
} }
@@ -7896,11 +7892,11 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
&((lfsr_obshrub_t*)o)->bshrub) &((lfsr_obshrub_t*)o)->bshrub)
// only compact once, first compact should // only compact once, first compact should
// stage the new block // stage the new block
&& ((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0] && ((lfsr_obshrub_t*)o)->bshrub_.blocks[0]
!= mdir_->rbyd.blocks[0]) { != mdir_->rbyd.blocks[0]) {
int err = lfsr_shrub_compact(lfs, &mdir_->rbyd, int err = lfsr_shrub_compact(lfs, &mdir_->rbyd,
&((lfsr_obshrub_t*)o)->bshrub_.u.bshrub, &((lfsr_obshrub_t*)o)->bshrub_,
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub); &((lfsr_obshrub_t*)o)->bshrub);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
@@ -8141,7 +8137,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// a bshrub outside of its mdir means something has gone // a bshrub outside of its mdir means something has gone
// horribly wrong // horribly wrong
LFS_ASSERT(!lfsr_bshrub_isbshrub(&((lfsr_obshrub_t*)o)->bshrub) LFS_ASSERT(!lfsr_bshrub_isbshrub(&((lfsr_obshrub_t*)o)->bshrub)
|| ((lfsr_obshrub_t*)o)->bshrub.u.bshrub.blocks[0] || ((lfsr_obshrub_t*)o)->bshrub.blocks[0]
== o->mdir.rbyd.blocks[0]); == o->mdir.rbyd.blocks[0]);
((lfsr_obshrub_t*)o)->bshrub_ = ((lfsr_obshrub_t*)o)->bshrub; ((lfsr_obshrub_t*)o)->bshrub_ = ((lfsr_obshrub_t*)o)->bshrub;
} }
@@ -9127,7 +9123,7 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_traversal_t *t,
} else if (tag == LFSR_TAG_MTREE) { } else if (tag == LFSR_TAG_MTREE) {
// fetch the root of the mtree // fetch the root of the mtree
err = lfsr_data_fetchbtree(lfs, &data, err = lfsr_data_fetchbtree(lfs, &data,
&t->o.bshrub.u.btree); &t->o.bshrub);
if (err) { if (err) {
return err; return err;
} }
@@ -9193,7 +9189,7 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_traversal_t *t,
// found a bshrub (inlined btree)? // found a bshrub (inlined btree)?
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) { if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
err = lfsr_data_readshrub(lfs, &data, &t->o.o.mdir, err = lfsr_data_readshrub(lfs, &data, &t->o.o.mdir,
&t->o.bshrub.u.bshrub); &t->o.bshrub);
if (err) { if (err) {
return err; return err;
} }
@@ -9201,7 +9197,7 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_traversal_t *t,
// found a btree? // found a btree?
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BTREE) { } else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BTREE) {
err = lfsr_data_fetchbtree(lfs, &data, err = lfsr_data_fetchbtree(lfs, &data,
&t->o.bshrub.u.btree); &t->o.bshrub);
if (err) { if (err) {
return err; return err;
} }
@@ -10797,7 +10793,7 @@ static inline lfs_size_t lfsr_file_inlinesize(lfs_t *lfs,
static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) { static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) {
return lfs_max( return lfs_max(
file->buffer.pos + file->buffer.size, file->buffer.pos + file->buffer.size,
file->o.bshrub.u.weight); file->o.bshrub.weight);
} }
// file operations // file operations
@@ -10830,7 +10826,7 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
// may be a bshrub (inlined btree) // may be a bshrub (inlined btree)
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) { if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
err = lfsr_data_readshrub(lfs, &data, &file->o.o.mdir, err = lfsr_data_readshrub(lfs, &data, &file->o.o.mdir,
&file->o.bshrub_.u.bshrub); &file->o.bshrub_);
if (err) { if (err) {
return err; return err;
} }
@@ -10838,7 +10834,7 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
// or a btree // or a btree
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BTREE) { } else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BTREE) {
err = lfsr_data_fetchbtree(lfs, &data, err = lfsr_data_fetchbtree(lfs, &data,
&file->o.bshrub_.u.btree); &file->o.bshrub_);
if (err) { if (err) {
return err; return err;
} }
@@ -11240,7 +11236,7 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
} }
// any data in our btree? // any data in our btree?
if (pos_ < file->o.bshrub.u.weight) { if (pos_ < file->o.bshrub.weight) {
// bypass buffer? // bypass buffer?
if ((lfs_size_t)d >= lfsr_file_buffersize(lfs, file)) { if ((lfs_size_t)d >= lfsr_file_buffersize(lfs, file)) {
lfs_ssize_t d_ = lfsr_file_readnext(lfs, file, lfs_ssize_t d_ = lfsr_file_readnext(lfs, file,
@@ -11327,14 +11323,14 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
// carving the entire tree? revert to no bshrub/btree // carving the entire tree? revert to no bshrub/btree
if (pos == 0 if (pos == 0
&& weight >= file->o.bshrub.u.weight && weight >= file->o.bshrub.weight
&& rat.weight == -(lfs_soff_t)weight) { && rat.weight == -(lfs_soff_t)weight) {
lfsr_bshrub_init(&file->o.bshrub); lfsr_bshrub_init(&file->o.bshrub);
return 0; return 0;
} }
// try to merge commits where possible // try to merge commits where possible
lfsr_bid_t bid = file->o.bshrub.u.weight; lfsr_bid_t bid = file->o.bshrub.weight;
lfsr_rat_t rats[5]; lfsr_rat_t rats[5];
lfs_size_t rat_count = 0; lfs_size_t rat_count = 0;
union { union {
@@ -11347,26 +11343,26 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
} right; } right;
// need a hole? // need a hole?
if (pos > file->o.bshrub.u.weight) { if (pos > file->o.bshrub.weight) {
// can we coalesce? // can we coalesce?
if (file->o.bshrub.u.weight > 0) { if (file->o.bshrub.weight > 0) {
bid = lfs_min(bid, file->o.bshrub.u.weight-1); bid = lfs_min(bid, file->o.bshrub.weight-1);
rats[rat_count++] = LFSR_RAT( rats[rat_count++] = LFSR_RAT(
LFSR_TAG_GROW, +(pos - file->o.bshrub.u.weight), LFSR_TAG_GROW, +(pos - file->o.bshrub.weight),
LFSR_DATA_NULL()); LFSR_DATA_NULL());
// new hole // new hole
} else { } else {
bid = lfs_min(bid, file->o.bshrub.u.weight); bid = lfs_min(bid, file->o.bshrub.weight);
rats[rat_count++] = LFSR_RAT( rats[rat_count++] = LFSR_RAT(
LFSR_TAG_DATA, +(pos - file->o.bshrub.u.weight), LFSR_TAG_DATA, +(pos - file->o.bshrub.weight),
LFSR_DATA_NULL()); LFSR_DATA_NULL());
} }
} }
// try to carve any existing data // try to carve any existing data
lfsr_rat_t right_rat_ = {.tag=0}; lfsr_rat_t right_rat_ = {.tag=0};
while (pos < file->o.bshrub.u.weight) { while (pos < file->o.bshrub.weight) {
lfsr_tag_t tag_; lfsr_tag_t tag_;
lfsr_bid_t weight_; lfsr_bid_t weight_;
lfsr_bptr_t bptr_; lfsr_bptr_t bptr_;
@@ -11556,21 +11552,21 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
if (weight + rat.weight > 0) { if (weight + rat.weight > 0) {
// can we coalesce a hole? // can we coalesce a hole?
if (lfsr_rat_size(rat) == 0 && pos > 0) { if (lfsr_rat_size(rat) == 0 && pos > 0) {
bid = lfs_min(bid, file->o.bshrub.u.weight-1); bid = lfs_min(bid, file->o.bshrub.weight-1);
rats[rat_count++] = LFSR_RAT( rats[rat_count++] = LFSR_RAT(
LFSR_TAG_GROW, +(weight + rat.weight), LFSR_TAG_GROW, +(weight + rat.weight),
LFSR_DATA_NULL()); LFSR_DATA_NULL());
// need a new hole? // need a new hole?
} else if (lfsr_rat_size(rat) == 0) { } else if (lfsr_rat_size(rat) == 0) {
bid = lfs_min(bid, file->o.bshrub.u.weight); bid = lfs_min(bid, file->o.bshrub.weight);
rats[rat_count++] = LFSR_RAT( rats[rat_count++] = LFSR_RAT(
LFSR_TAG_DATA, +(weight + rat.weight), LFSR_TAG_DATA, +(weight + rat.weight),
LFSR_DATA_NULL()); LFSR_DATA_NULL());
// append new fragment/bptr? // append new fragment/bptr?
} else { } else {
bid = lfs_min(bid, file->o.bshrub.u.weight); bid = lfs_min(bid, file->o.bshrub.weight);
rats[rat_count++] = LFSR_RAT_( rats[rat_count++] = LFSR_RAT_(
rat.tag, +(weight + rat.weight), rat.tag, +(weight + rat.weight),
rat.cat, rat.count); rat.cat, rat.count);
@@ -11620,8 +11616,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
if (pos > 0 if (pos > 0
&& lfs->cfg->crystal_thresh > 0 && lfs->cfg->crystal_thresh > 0
&& (lfs_soff_t)(pos - (lfs->cfg->crystal_thresh-1)) && (lfs_soff_t)(pos - (lfs->cfg->crystal_thresh-1))
< (lfs_soff_t)file->o.bshrub.u.weight < (lfs_soff_t)file->o.bshrub.weight
&& file->o.bshrub.u.weight > 0 && file->o.bshrub.weight > 0
// don't bother to lookup left after the first block // don't bother to lookup left after the first block
&& !aligned) { && !aligned) {
lfsr_bid_t bid; lfsr_bid_t bid;
@@ -11674,14 +11670,14 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
// if we haven't already exceeded our crystallization threshold, // if we haven't already exceeded our crystallization threshold,
// find right crystal neighbor // find right crystal neighbor
if (crystal_end - crystal_start < lfs->cfg->crystal_thresh if (crystal_end - crystal_start < lfs->cfg->crystal_thresh
&& file->o.bshrub.u.weight > 0) { && file->o.bshrub.weight > 0) {
lfsr_bid_t bid; lfsr_bid_t bid;
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_bid_t weight; lfsr_bid_t weight;
int err = lfsr_file_lookupnext(lfs, file, int err = lfsr_file_lookupnext(lfs, file,
lfs_min( lfs_min(
crystal_start + (lfs->cfg->crystal_thresh-1), crystal_start + (lfs->cfg->crystal_thresh-1),
file->o.bshrub.u.weight-1), file->o.bshrub.weight-1),
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -11717,7 +11713,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
// crystal for this // crystal for this
block_start = crystal_start; block_start = crystal_start;
if (crystal_start > 0 if (crystal_start > 0
&& file->o.bshrub.u.weight > 0 && file->o.bshrub.weight > 0
// don't bother to lookup left after the first block // don't bother to lookup left after the first block
&& !aligned) { && !aligned) {
lfsr_bid_t bid; lfsr_bid_t bid;
@@ -11726,7 +11722,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
int err = lfsr_file_lookupnext(lfs, file, int err = lfsr_file_lookupnext(lfs, file,
lfs_min( lfs_min(
crystal_start-1, crystal_start-1,
file->o.bshrub.u.weight-1), file->o.bshrub.weight-1),
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -11793,14 +11789,14 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
+ (lfs->cfg->block_size - bptr.data.u.disk.off), + (lfs->cfg->block_size - bptr.data.u.disk.off),
lfs_max( lfs_max(
pos + size, pos + size,
file->o.bshrub.u.weight))) { file->o.bshrub.weight))) {
// keep track of the next highest priority data offset // keep track of the next highest priority data offset
lfs_ssize_t d = lfs_min( lfs_ssize_t d = lfs_min(
block_start block_start
+ (lfs->cfg->block_size - bptr.data.u.disk.off), + (lfs->cfg->block_size - bptr.data.u.disk.off),
lfs_max( lfs_max(
pos + size, pos + size,
file->o.bshrub.u.weight)) - pos_; file->o.bshrub.weight)) - pos_;
// any data in our buffer? // any data in our buffer?
if (pos_ < pos + size && size > 0) { if (pos_ < pos + size && size > 0) {
@@ -11835,7 +11831,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
// any data on disk? // any data on disk?
if (pos_ < file->o.bshrub.u.weight) { if (pos_ < file->o.bshrub.weight) {
lfsr_bid_t bid_; lfsr_bid_t bid_;
lfsr_tag_t tag_; lfsr_tag_t tag_;
lfsr_bid_t weight_; lfsr_bid_t weight_;
@@ -12005,7 +12001,7 @@ fragment:;
// do we have a left sibling? // do we have a left sibling?
if (fragment_start > 0 if (fragment_start > 0
&& file->o.bshrub.u.weight >= fragment_start && file->o.bshrub.weight >= fragment_start
// don't bother to lookup left after first fragment // don't bother to lookup left after first fragment
&& !aligned) { && !aligned) {
lfsr_bid_t bid; lfsr_bid_t bid;
@@ -12053,7 +12049,7 @@ fragment:;
// do we have a right sibling? // do we have a right sibling?
// //
// note this may the same as our left sibling // note this may the same as our left sibling
if (fragment_end < file->o.bshrub.u.weight if (fragment_end < file->o.bshrub.weight
// don't bother to lookup right if fragment is already full // don't bother to lookup right if fragment is already full
&& fragment_end - fragment_start < lfs->cfg->fragment_size) { && fragment_end - fragment_start < lfs->cfg->fragment_size) {
lfsr_bid_t bid; lfsr_bid_t bid;
@@ -12360,7 +12356,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
} }
// zero size files should have no bshrub/btree // zero size files should have no bshrub/btree
LFS_ASSERT(file->o.bshrub.u.weight > 0 LFS_ASSERT(file->o.bshrub.weight > 0
|| lfsr_bshrub_isbnull(&file->o.bshrub)); || lfsr_bshrub_isbnull(&file->o.bshrub));
// no bshrub/btree? // no bshrub/btree?
@@ -12372,12 +12368,12 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
} else if (lfsr_bshrub_isbshrub(&file->o.bshrub)) { } else if (lfsr_bshrub_isbshrub(&file->o.bshrub)) {
rats[rat_count++] = LFSR_RAT_SHRUBTRUNK( rats[rat_count++] = LFSR_RAT_SHRUBTRUNK(
LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0, LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0,
&file->o.bshrub.u.bshrub); &file->o.bshrub);
// btree? // btree?
} else if (lfsr_bshrub_isbtree(&file->o.bshrub)) { } else if (lfsr_bshrub_isbtree(&file->o.bshrub)) {
rats[rat_count++] = LFSR_RAT( rats[rat_count++] = LFSR_RAT(
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0, LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
LFSR_DATA_BTREE(&file->o.bshrub.u.btree, buf)); LFSR_DATA_BTREE(&file->o.bshrub, buf));
} else { } else {
LFS_UNREACHABLE(); LFS_UNREACHABLE();
} }
+6 -18
View File
@@ -605,14 +605,7 @@ typedef struct lfsr_rbyd {
typedef lfsr_rbyd_t lfsr_btree_t; typedef lfsr_rbyd_t lfsr_btree_t;
// a shrub is a secondary trunk in an mdir // a shrub is a secondary trunk in an mdir
typedef struct { typedef lfsr_rbyd_t lfsr_shrub_t;
// this mostly lines up with lfsr_rbyd_t
lfsr_rid_t weight;
lfs_block_t blocks[2];
lfs_size_t trunk;
// except for shrub estimate, which takes the place of eoff, etc
lfs_size_t estimate;
} lfsr_shrub_t;
typedef struct lfsr_mdir { typedef struct lfsr_mdir {
lfsr_smid_t mid; lfsr_smid_t mid;
@@ -694,16 +687,11 @@ typedef struct lfsr_bptr {
} lfsr_bptr_t; } lfsr_bptr_t;
// the lfsr_bshrub_t struct represents the on-disk component of a file // the lfsr_bshrub_t struct represents the on-disk component of a file
typedef struct lfsr_bshrub { //
// weight=0 => no bshrub/btree // weight=0 => no bshrub/btree
// sign(weight)=1 => bshrub // sign(weight)=1 => bshrub
// sign(weight)=0 => btree // sign(weight)=0 => btree
union { typedef lfsr_rbyd_t lfsr_bshrub_t;
lfs_size_t weight;
lfsr_shrub_t bshrub;
lfsr_btree_t btree;
} u;
} lfsr_bshrub_t;
typedef struct lfsr_obshrub { typedef struct lfsr_obshrub {
// bshrubs need to be tracked for commits to work // bshrubs need to be tracked for commits to work
+7 -7
View File
@@ -1097,19 +1097,19 @@ code = '''
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS( lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBCOMMIT( LFSR_RAT_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0, LFSR_TAG_SHRUBCOMMIT, 0,
&file.o.bshrub.u.bshrub, 0, ((lfsr_rat_t[]){ &file.o.bshrub, 0, ((lfsr_rat_t[]){
LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1))}), LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1))}),
1))) => 0; 1))) => 0;
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS( lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBCOMMIT( LFSR_RAT_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0, LFSR_TAG_SHRUBCOMMIT, 0,
&file.o.bshrub.u.bshrub, 0, ((lfsr_rat_t[]){ &file.o.bshrub, 0, ((lfsr_rat_t[]){
LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL())}), LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL())}),
1))) => 0; 1))) => 0;
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS( lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
LFSR_RAT_SHRUBTRUNK( LFSR_RAT_SHRUBTRUNK(
LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0, LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0,
&file.o.bshrub.u.bshrub))) => 0; &file.o.bshrub))) => 0;
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
@@ -1224,16 +1224,16 @@ code = '''
// create an empty btree // create an empty btree
lfs_alloc_ckpoint(&lfs); lfs_alloc_ckpoint(&lfs);
lfsr_rbyd_alloc(&lfs, &file.o.bshrub.u.btree) => 0; lfsr_rbyd_alloc(&lfs, &file.o.bshrub) => 0;
lfsr_rbyd_commit(&lfs, &file.o.bshrub.u.btree, 0, LFSR_RATS( lfsr_rbyd_commit(&lfs, &file.o.bshrub, 0, LFSR_RATS(
LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1)))) => 0; LFSR_RAT(LFSR_TAG_DATA, +1, LFSR_DATA_BUF("?", 1)))) => 0;
lfsr_rbyd_commit(&lfs, &file.o.bshrub.u.btree, 0, LFSR_RATS( lfsr_rbyd_commit(&lfs, &file.o.bshrub, 0, LFSR_RATS(
LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; LFSR_RAT(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0;
uint8_t buf[LFSR_BTREE_DSIZE]; uint8_t buf[LFSR_BTREE_DSIZE];
lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS( lfsr_mdir_commit(&lfs, &file.o.o.mdir, LFSR_RATS(
LFSR_RAT( LFSR_RAT(
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0, LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
LFSR_DATA_BTREE(&file.o.bshrub.u.btree, buf)))) => 0; LFSR_DATA_BTREE(&file.o.bshrub, buf)))) => 0;
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;