Dropped bmoss/bsprout support completely
Similar to msprouts/mshrubs, this drops all of the logic necessary for
reading and maintaining bmoss/bshrubs, while clearing/reserving the
LFSR_RCOMPAT_BMOSS/BSPROUT flags in case we want to re-explore these in
the future.
---
Wait, wait, dropping bmosses? Inlined files? Aren't inlined files pretty
fundamental to littlefs?
bmoss: bsprout: bshrub: btree:
.--------. .--------. .--------. .--------.
.| mdir | .| mdir | .| mdir | .| mdir |
|| name | || name | || name | || config |
|| data | || bptr | || bshrub -. || btree |
|| | || | | || data <' || | |
|'--------' |'---|----' |'--------' |'---|----'
'--------' '----|---' '--------' '----|---'
v v
.--------. .--------.
| data | | btree |
| | | data |
| | | |
| | | |
'--------' '--------'
Yep! And that's why they stuck around for so long. I never really
expected something to replace the simplicity of inlined files.
But bmoss/inlined files' simplicity is deceptive. They're actually a big
pain-in-the-ass when you realize:
1. littlefs's file snapshot semantics means you somehow need to keep
track of bmoss/inlined files that are no longer in the mdir tree.
2. You actually can't rely on bmoss/inlined files always fitting in RAM,
in cases where the filesystem is shared between different drivers
with different configurations.
This has been a pretty big pain point upstream, and results in tricky
edge cases that are difficult to test.
Bshrubs just sort of side-step these problems...
Well, we _do_ still need quite a bit of logic to keep track of detached
bshrubs across mdir compactions, but we'd need that logic for bshrubs
anyways. And why pay for two piles of logic if we can get away with one?
The only difference between inlined bmoss and inlined bshrubs is the
trunk pointer (<=9 bytes) and extra data tag (<=10 bytes), adding at
most 19 extra bytes per file.
But these extra 19 bytes per file save us a big chunk of code:
code stack ctx
before: 37652 2616 640
after: 36668 (-2.6%) 2616 (+0.0%) 640 (+0.0%)
---
There _is_ an argument for keeping bmoss around: In cases where you have
a shitton of tiny files, these extra 19 bytes may add up.
But I think this is a micro-optimization for a very specific use case
that is out-of-scope for littlefs. We should always trade disk usage for
code size when possible.
This commit is contained in:
@@ -6000,79 +6000,6 @@ static inline lfs_off_t lfsr_bshrub_size(const lfsr_bshrub_t *bshrub) {
|
||||
}
|
||||
|
||||
|
||||
// moss things
|
||||
|
||||
static inline int lfsr_moss_cmp(
|
||||
const lfsr_data_t *a,
|
||||
const lfsr_data_t *b) {
|
||||
// big assumption for mosses, we convert straight to bshrubs,
|
||||
// and never leave sliced mosses in our files, so we don't need
|
||||
// to compare the size
|
||||
LFS_ASSERT(a->u.disk.block != b->u.disk.block
|
||||
|| a->u.disk.off != b->u.disk.off
|
||||
|| lfsr_data_size(*a) == lfsr_data_size(*b));
|
||||
if (a->u.disk.block != b->u.disk.block) {
|
||||
return a->u.disk.block - b->u.disk.block;
|
||||
} else {
|
||||
return a->u.disk.off - b->u.disk.off;
|
||||
}
|
||||
}
|
||||
|
||||
// needed in lfsr_moss_estimate
|
||||
static inline bool lfsr_o_isbshrub(uint32_t flags);
|
||||
|
||||
// these are used in mdir compaction
|
||||
static lfs_ssize_t lfsr_moss_estimate(lfs_t *lfs,
|
||||
const lfsr_data_t *moss) {
|
||||
// only include the last reference
|
||||
const lfsr_data_t *last = NULL;
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& lfsr_bshrub_isbmoss(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& lfsr_moss_cmp(
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bmoss,
|
||||
moss) == 0) {
|
||||
last = &((lfsr_obshrub_t*)o)->bshrub.u.bmoss;
|
||||
}
|
||||
}
|
||||
if (last && moss != last) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return LFSR_TAG_DSIZE + lfsr_data_size(*moss);
|
||||
}
|
||||
|
||||
static int lfsr_moss_compact(lfs_t *lfs, const lfsr_rbyd_t *rbyd_,
|
||||
lfsr_data_t *moss_, const lfsr_data_t *moss) {
|
||||
// this gets a bit weird, since upper layers need to do the actual
|
||||
// compaction, we just update internal state here
|
||||
|
||||
// this is a bit tricky since we don't know the tag size,
|
||||
// but we have just enough info
|
||||
lfsr_data_t moss__ = LFSR_DATA_DISK(
|
||||
rbyd_->blocks[0],
|
||||
rbyd_->eoff - lfsr_data_size(*moss),
|
||||
lfsr_data_size(*moss));
|
||||
|
||||
// stage any opened inlined files with their new location so we
|
||||
// can update these later if our commit is a success
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& lfsr_bshrub_isbmoss(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& lfsr_moss_cmp(
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bmoss,
|
||||
moss) == 0) {
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bmoss = moss__;
|
||||
}
|
||||
}
|
||||
|
||||
*moss_ = moss__;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// shrub things
|
||||
|
||||
// create an empty shrub
|
||||
@@ -6167,6 +6094,9 @@ static int lfsr_data_readshrub(lfs_t *lfs, lfsr_data_t *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// needed in lfsr_shrub_estimate
|
||||
static inline bool lfsr_o_isbshrub(uint32_t flags);
|
||||
|
||||
// these are used in mdir commit/compaction
|
||||
static lfs_ssize_t lfsr_shrub_estimate(lfs_t *lfs,
|
||||
const lfsr_shrub_t *shrub) {
|
||||
@@ -6280,8 +6210,8 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
|
||||
(void)bshrub;
|
||||
lfs_size_t estimate = 0;
|
||||
|
||||
// include all unique mosses/shrubs related to our file,
|
||||
// including the on-disk moss/shrub
|
||||
// include all unique shrubs related to our file, including the
|
||||
// on-disk shrub
|
||||
lfsr_tag_t tag;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_mdir_lookupnext(lfs, mdir, LFSR_TAG_DATA,
|
||||
@@ -6290,14 +6220,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_DATA) {
|
||||
lfs_ssize_t dsize = lfsr_moss_estimate(lfs, &data);
|
||||
if (dsize < 0) {
|
||||
return dsize;
|
||||
}
|
||||
estimate += dsize;
|
||||
|
||||
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
|
||||
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
|
||||
lfsr_shrub_t shrub;
|
||||
err = lfsr_data_readshrub(lfs, &data, mdir,
|
||||
&shrub);
|
||||
@@ -6316,16 +6239,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& o->mdir.mid == mdir->mid) {
|
||||
if (lfsr_bshrub_isbmoss(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)) {
|
||||
lfs_ssize_t dsize = lfsr_moss_estimate(lfs,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bmoss);
|
||||
if (dsize < 0) {
|
||||
return dsize;
|
||||
}
|
||||
estimate += dsize;
|
||||
|
||||
} else if (lfsr_bshrub_isbshrub(&o->mdir,
|
||||
if (lfsr_bshrub_isbshrub(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)) {
|
||||
lfs_ssize_t dsize = lfsr_shrub_estimate(lfs,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
@@ -6345,147 +6259,92 @@ static int lfsr_bshrub_lookupnext(lfs_t *lfs,
|
||||
lfsr_bid_t bid,
|
||||
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bid_t *weight_,
|
||||
lfsr_bptr_t *bptr_) {
|
||||
(void)mdir;
|
||||
// out of bounds?
|
||||
if (bid >= lfsr_bshrub_size(bshrub)) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
// the above size check should make this impossible
|
||||
LFS_ASSERT(!lfsr_bshrub_isbnull(bshrub));
|
||||
|
||||
// inlined data?
|
||||
if (lfsr_bshrub_isbmoss(mdir, bshrub)) {
|
||||
if (bid_) {
|
||||
*bid_ = lfsr_data_size(bshrub->u.bmoss)-1;
|
||||
}
|
||||
if (tag_) {
|
||||
*tag_ = LFSR_TAG_DATA;
|
||||
}
|
||||
if (weight_) {
|
||||
*weight_ = lfsr_data_size(bshrub->u.bmoss);
|
||||
}
|
||||
if (bptr_) {
|
||||
bptr_->data = bshrub->u.bmoss;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// direct block?
|
||||
} else if (lfsr_bshrub_isbptr(mdir, bshrub)) {
|
||||
if (bid_) {
|
||||
*bid_ = lfsr_data_size(bshrub->u.bsprout.data)-1;
|
||||
}
|
||||
if (tag_) {
|
||||
*tag_ = LFSR_TAG_BLOCK;
|
||||
}
|
||||
if (weight_) {
|
||||
*weight_ = lfsr_data_size(bshrub->u.bsprout.data);
|
||||
}
|
||||
if (bptr_) {
|
||||
*bptr_ = bshrub->u.bsprout;
|
||||
}
|
||||
return 0;
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
|
||||
|
||||
// bshrub/btree?
|
||||
} else if (lfsr_bshrub_isbshruborbtree(bshrub)) {
|
||||
lfsr_bid_t bid__;
|
||||
lfsr_rbyd_t rbyd;
|
||||
lfsr_srid_t rid;
|
||||
lfsr_tag_t tag;
|
||||
lfsr_bid_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_btree_lookupnext_(lfs, &bshrub->u.btree, bid,
|
||||
&bid__, &rbyd, &rid, &tag, &weight, &data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
return err;
|
||||
}
|
||||
LFS_ASSERT(tag == LFSR_TAG_DATA
|
||||
|| tag == LFSR_TAG_BLOCK);
|
||||
|
||||
if (bid_) {
|
||||
*bid_ = bid__;
|
||||
}
|
||||
if (tag_) {
|
||||
*tag_ = tag;
|
||||
}
|
||||
if (weight_) {
|
||||
*weight_ = weight;
|
||||
}
|
||||
if (bptr_) {
|
||||
// decode bptrs
|
||||
if (tag == LFSR_TAG_DATA) {
|
||||
bptr_->data = data;
|
||||
} else {
|
||||
err = lfsr_data_readbptr(lfs, &data, bptr_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
LFS_ASSERT(lfsr_data_size(bptr_->data) <= weight);
|
||||
}
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
LFS_UNREACHABLE();
|
||||
lfsr_bid_t bid__;
|
||||
lfsr_rbyd_t rbyd;
|
||||
lfsr_srid_t rid;
|
||||
lfsr_tag_t tag;
|
||||
lfsr_bid_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_btree_lookupnext_(lfs, &bshrub->u.btree, bid,
|
||||
&bid__, &rbyd, &rid, &tag, &weight, &data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
return err;
|
||||
}
|
||||
LFS_ASSERT(tag == LFSR_TAG_DATA
|
||||
|| tag == LFSR_TAG_BLOCK);
|
||||
|
||||
if (bid_) {
|
||||
*bid_ = bid__;
|
||||
}
|
||||
if (tag_) {
|
||||
*tag_ = tag;
|
||||
}
|
||||
if (weight_) {
|
||||
*weight_ = weight;
|
||||
}
|
||||
if (bptr_) {
|
||||
// decode bptrs
|
||||
if (tag == LFSR_TAG_DATA) {
|
||||
bptr_->data = data;
|
||||
} else {
|
||||
err = lfsr_data_readbptr(lfs, &data, bptr_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
LFS_ASSERT(lfsr_data_size(bptr_->data) <= weight);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfsr_bshrub_traverse(lfs_t *lfs,
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub,
|
||||
lfsr_btraversal_t *bt,
|
||||
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bptr_t *bptr_) {
|
||||
// bnull/bmoss does nothing
|
||||
if (lfsr_bshrub_isbnull(bshrub)
|
||||
|| lfsr_bshrub_isbmoss(mdir, bshrub)) {
|
||||
(void)mdir;
|
||||
// bnull does nothing
|
||||
if (lfsr_bshrub_isbnull(bshrub)) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
|
||||
|
||||
// bsprout?
|
||||
if (lfsr_bshrub_isbptr(mdir, bshrub)) {
|
||||
if (bt->bid > 0) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
|
||||
if (bid_) {
|
||||
*bid_ = lfsr_data_size(bshrub->u.bsprout.data)-1;
|
||||
}
|
||||
if (tag_) {
|
||||
*tag_ = LFSR_TAG_BLOCK;
|
||||
}
|
||||
if (bptr_) {
|
||||
*bptr_ = bshrub->u.bsprout;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// bshrub/btree?
|
||||
} else if (lfsr_bshrub_isbshruborbtree(bshrub)) {
|
||||
lfsr_tag_t tag;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_btree_traverse(lfs, &bshrub->u.btree, bt,
|
||||
bid_, &tag, &data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// decode bptrs
|
||||
if (tag_) {
|
||||
*tag_ = tag;
|
||||
}
|
||||
if (bptr_) {
|
||||
if (tag == LFSR_TAG_BLOCK) {
|
||||
err = lfsr_data_readbptr(lfs, &data,
|
||||
bptr_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
bptr_->data = data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
LFS_UNREACHABLE();
|
||||
lfsr_tag_t tag;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_btree_traverse(lfs, &bshrub->u.btree, bt,
|
||||
bid_, &tag, &data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// decode bptrs
|
||||
if (tag_) {
|
||||
*tag_ = tag;
|
||||
}
|
||||
if (bptr_) {
|
||||
if (tag == LFSR_TAG_BLOCK) {
|
||||
err = lfsr_data_readbptr(lfs, &data,
|
||||
bptr_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
bptr_->data = data;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// needed in lfsr_bshrub_commit_
|
||||
@@ -7657,7 +7516,6 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
// us due to mdir compactions
|
||||
//
|
||||
// TODO should we preserve mode for all of these?
|
||||
// TODO should we do the same for mosses?
|
||||
} else if (lfsr_tag_key(rats[i].tag) == LFSR_TAG_SHRUBTRUNK) {
|
||||
// find the staging shrub
|
||||
lfsr_shrub_t *shrub = (lfsr_shrub_t*)rats[i].cat;
|
||||
@@ -7696,25 +7554,9 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
return err;
|
||||
}
|
||||
|
||||
// found an inlined moss? we can just copy this like
|
||||
// normal but we need to update any opened inlined files
|
||||
if (tag == LFSR_TAG_DATA) {
|
||||
err = lfsr_rbyd_appendrat(lfs, &mdir->rbyd,
|
||||
rid - lfs_smax(start_rid, 0),
|
||||
LFSR_RAT_CAT_(tag, 0, &data, 1));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_moss_compact(lfs, &mdir->rbyd, &data,
|
||||
&data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// found an inlined shrub? we need to compact the shrub
|
||||
// as well to bring it along with us
|
||||
} else if (tag == LFSR_TAG_BSHRUB) {
|
||||
if (tag == LFSR_TAG_BSHRUB) {
|
||||
lfsr_shrub_t shrub;
|
||||
err = lfsr_data_readshrub(lfs, &data, mdir__,
|
||||
&shrub);
|
||||
@@ -7761,29 +7603,8 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined moss?
|
||||
if (lfsr_bshrub_isbmoss(&bshrub->o.mdir, &bshrub->bshrub)
|
||||
// only compact once, first compact should stage
|
||||
// the new block
|
||||
&& bshrub->bshrub_.u.bmoss.u.disk.block
|
||||
!= mdir->rbyd.blocks[0]) {
|
||||
int err = lfsr_rbyd_appendcompactrat(lfs, &mdir->rbyd,
|
||||
LFSR_RAT_CAT_(
|
||||
LFSR_TAG_SHRUB | LFSR_TAG_DATA, 0,
|
||||
&bshrub->bshrub.u.bmoss, 1));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_moss_compact(lfs, &mdir->rbyd,
|
||||
&bshrub->bshrub_.u.bmoss,
|
||||
&bshrub->bshrub.u.bmoss);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// inlined shrub?
|
||||
} else if (lfsr_bshrub_isbshrub(
|
||||
if (lfsr_bshrub_isbshrub(
|
||||
&bshrub->o.mdir, &bshrub->bshrub)
|
||||
// only compact once, first compact should stage
|
||||
// the new block
|
||||
@@ -7971,21 +7792,13 @@ static lfs_ssize_t lfsr_mdir_estimate__(lfs_t *lfs, const lfsr_mdir_t *mdir,
|
||||
break;
|
||||
}
|
||||
|
||||
// special handling for mosses, just to avoid duplicate cost
|
||||
if (tag == LFSR_TAG_DATA) {
|
||||
lfs_ssize_t dsize__ = lfsr_moss_estimate(lfs, &data);
|
||||
if (dsize__ < 0) {
|
||||
return dsize__;
|
||||
}
|
||||
dsize_ += lfs->rat_estimate + dsize__;
|
||||
|
||||
// special handling for shrub trunks, we need to include the
|
||||
// compacted cost of the shrub in our estimate
|
||||
//
|
||||
// this is what would make lfsr_rbyd_estimate recursive, and
|
||||
// why we need a second function...
|
||||
//
|
||||
} else if (tag == LFSR_TAG_BSHRUB) {
|
||||
if (tag == LFSR_TAG_BSHRUB) {
|
||||
// include the cost of this trunk
|
||||
dsize_ += LFSR_SHRUB_DSIZE;
|
||||
|
||||
@@ -8021,18 +7834,8 @@ static lfs_ssize_t lfsr_mdir_estimate__(lfs_t *lfs, const lfsr_mdir_t *mdir,
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined moss?
|
||||
if (lfsr_bshrub_isbmoss(&bshrub->o.mdir,
|
||||
&bshrub->bshrub)) {
|
||||
lfs_ssize_t dsize__ = lfsr_moss_estimate(lfs,
|
||||
&bshrub->bshrub.u.bmoss);
|
||||
if (dsize__ < 0) {
|
||||
return dsize__;
|
||||
}
|
||||
dsize_ += dsize__;
|
||||
|
||||
// inlined shrub?
|
||||
} else if (lfsr_bshrub_isbshrub(&bshrub->o.mdir,
|
||||
if (lfsr_bshrub_isbshrub(&bshrub->o.mdir,
|
||||
&bshrub->bshrub)) {
|
||||
lfs_ssize_t dsize__ = lfsr_shrub_estimate(lfs,
|
||||
&bshrub->bshrub.u.bshrub);
|
||||
@@ -8102,26 +7905,9 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
||||
break;
|
||||
}
|
||||
|
||||
// found an inlined moss? we can just copy this like normal but
|
||||
// we need to update any opened inlined files
|
||||
if (tag == LFSR_TAG_DATA) {
|
||||
err = lfsr_rbyd_appendcompactrat(lfs, &mdir_->rbyd,
|
||||
LFSR_RAT_CAT_(tag, weight, &data, 1));
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_moss_compact(lfs, &mdir_->rbyd, &data,
|
||||
&data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// found an inlined shrub? we need to compact the shrub as well to
|
||||
// bring it along with us
|
||||
} else if (tag == LFSR_TAG_BSHRUB) {
|
||||
if (tag == LFSR_TAG_BSHRUB) {
|
||||
lfsr_shrub_t shrub;
|
||||
err = lfsr_data_readshrub(lfs, &data, mdir,
|
||||
&shrub);
|
||||
@@ -8177,29 +7963,8 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined moss?
|
||||
if (lfsr_bshrub_isbmoss(&bshrub->o.mdir, &bshrub->bshrub)
|
||||
// only compact once, first compact should stage the new block
|
||||
&& bshrub->bshrub_.u.bmoss.u.disk.block
|
||||
!= mdir_->rbyd.blocks[0]) {
|
||||
err = lfsr_rbyd_appendcompactrat(lfs, &mdir_->rbyd,
|
||||
LFSR_RAT_CAT_(
|
||||
LFSR_TAG_SHRUB | LFSR_TAG_DATA, 0,
|
||||
&bshrub->bshrub.u.bmoss, 1));
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_moss_compact(lfs, &mdir_->rbyd,
|
||||
&bshrub->bshrub_.u.bmoss, &bshrub->bshrub.u.bmoss);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// inlined shrub?
|
||||
} else if (lfsr_bshrub_isbshrub(&bshrub->o.mdir, &bshrub->bshrub)
|
||||
if (lfsr_bshrub_isbshrub(&bshrub->o.mdir, &bshrub->bshrub)
|
||||
// only compact once, first compact should stage the new block
|
||||
&& bshrub->bshrub_.u.bshrub.blocks[0]
|
||||
!= mdir_->rbyd.blocks[0]) {
|
||||
@@ -8445,7 +8210,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
o->mdir.rbyd.eoff = -1;
|
||||
}
|
||||
|
||||
// stage any bmosses/bshrubs
|
||||
// stage any bshrubs
|
||||
if (lfsr_o_isbshrub(o->flags)) {
|
||||
((lfsr_obshrub_t*)o)->bshrub_ = ((lfsr_obshrub_t*)o)->bshrub;
|
||||
}
|
||||
@@ -9481,15 +9246,8 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_traversal_t *t,
|
||||
return err;
|
||||
}
|
||||
|
||||
// found a bsprout (direct block)?
|
||||
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BLOCK) {
|
||||
err = lfsr_data_readbptr(lfs, &data, &t->o.bshrub.u.bsprout);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// found a bshrub (inlined btree)?
|
||||
} else 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,
|
||||
&t->o.bshrub.u.bshrub);
|
||||
if (err) {
|
||||
@@ -11098,10 +10856,6 @@ static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) {
|
||||
|
||||
// file operations
|
||||
|
||||
// needed in lfsr_file_fetch
|
||||
static lfs_ssize_t lfsr_file_read_(lfs_t *lfs, const lfsr_file_t *file,
|
||||
lfs_off_t pos, uint8_t *buffer, lfs_size_t size);
|
||||
|
||||
static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
|
||||
// default data state
|
||||
lfsr_bshrub_init(&file->o.bshrub);
|
||||
@@ -11127,20 +10881,8 @@ static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
|
||||
// bshrub
|
||||
file->o.bshrub_ = file->o.bshrub;
|
||||
|
||||
// may be a bmoss (inlined data)
|
||||
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_DATA) {
|
||||
file->o.bshrub_.u.bmoss = data;
|
||||
|
||||
// or a bsprout (direct block)
|
||||
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BLOCK) {
|
||||
err = lfsr_data_readbptr(lfs, &data,
|
||||
&file->o.bshrub_.u.bsprout);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// or a bshrub (inlined btree)
|
||||
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
|
||||
// may be a bshrub (inlined btree)
|
||||
if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
|
||||
err = lfsr_data_readshrub(lfs, &data, &file->o.o.mdir,
|
||||
&file->o.bshrub_.u.bshrub);
|
||||
if (err) {
|
||||
@@ -11514,25 +11256,6 @@ static lfs_ssize_t lfsr_file_readnext(lfs_t *lfs, const lfsr_file_t *file,
|
||||
return pos_ - pos;
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfsr_file_read_(lfs_t *lfs, const lfsr_file_t *file,
|
||||
lfs_off_t pos, uint8_t *buffer, lfs_size_t size) {
|
||||
lfs_off_t pos_ = pos;
|
||||
while (size > 0 && pos_ < lfsr_bshrub_size(&file->o.bshrub)) {
|
||||
lfs_ssize_t d = lfsr_file_readnext(lfs, file,
|
||||
pos_, buffer, size);
|
||||
if (d < 0) {
|
||||
LFS_ASSERT(d != LFS_ERR_NOENT);
|
||||
return d;
|
||||
}
|
||||
|
||||
pos_ += d;
|
||||
buffer += d;
|
||||
size -= d;
|
||||
}
|
||||
|
||||
return pos_ - pos;
|
||||
}
|
||||
|
||||
// high-level file reading
|
||||
|
||||
lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
|
||||
@@ -11670,33 +11393,11 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
||||
|
||||
// always convert to bshrub/btree when this function is called
|
||||
if (!lfsr_bshrub_isbshruborbtree(&file->o.bshrub)) {
|
||||
// this does risk losing our moss/sprout if there is an error,
|
||||
// but note that's already a risk with how file carve deletes
|
||||
// data before insertion
|
||||
if (lfsr_bshrub_isbmoss(&file->o.o.mdir, &file->o.bshrub)) {
|
||||
rats[rat_count++] = LFSR_RAT_CAT_(
|
||||
LFSR_TAG_DATA, +lfsr_bshrub_size(&file->o.bshrub),
|
||||
&file->o.bshrub.u.bmoss, 1);
|
||||
} else if (lfsr_bshrub_isbptr(&file->o.o.mdir, &file->o.bshrub)) {
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_BLOCK, +lfsr_bshrub_size(&file->o.bshrub),
|
||||
LFSR_DATA_BPTR(&file->o.bshrub.u.bsprout, left.buf));
|
||||
}
|
||||
|
||||
// file must be a bnull here
|
||||
LFS_ASSERT(lfsr_bshrub_isbnull(&file->o.bshrub));
|
||||
// initialize bshrub's shrub
|
||||
lfsr_shrub_init(&file->o.bshrub.u.bshrub,
|
||||
file->o.o.mdir.rbyd.blocks[0]);
|
||||
|
||||
if (rat_count > 0) {
|
||||
LFS_ASSERT(rat_count <= sizeof(rats)/sizeof(lfsr_rat_t));
|
||||
|
||||
int err = lfsr_file_commit(lfs, file, 0,
|
||||
rats, rat_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rat_count = 0;
|
||||
}
|
||||
|
||||
// need a hole?
|
||||
@@ -13493,8 +13194,6 @@ static int lfs_deinit(lfs_t *lfs) {
|
||||
(LFSR_RCOMPAT_GRM \
|
||||
| LFSR_RCOMPAT_MMOSS \
|
||||
| LFSR_RCOMPAT_MTREE \
|
||||
| LFSR_RCOMPAT_BMOSS \
|
||||
| LFSR_RCOMPAT_BSPROUT \
|
||||
| LFSR_RCOMPAT_BSHRUB \
|
||||
| LFSR_RCOMPAT_BTREE)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user