Simplified lfsr_bshrub_t representation
Now that we don't use bmoss or bsprouts anymore, we can drop the
LFSR_BSHRUB_ISNULLORBMOSSORBPTR flag and simplify our lfsr_bshrub_t
struct quite a bit.
However, we do still need a bnull representation, which is surprisingly
tricky... And annoying...
Current solution: Bnulls are bshrubs with weight=0. This works, but
unfortunately does mean we need to update bnull blocks on mdir
relocation/compaction, and risks bnull blocks falling out-of-sync, which
is a really weird thing to worry about:
bnull: bshrub: btree:
.---+---+---+---. .. .---+---+---+---. .. .---+---+---+---.
| weight=0 | | weight>0 | | weight |
+---+---+---+---+ +---+---+---+---+ +---+---+---+---+
| block=mdir | | block=mdir | | block!=mdir |
+---+---+---+---+ .. +---+---+---+---+ +---+---+---+---+
| (unused) | | (unused) | | (unused) |
+ + +---+---+---+---+ +---+---+---+---+
| | | trunk | | trunk |
+ + +---+---+---+---+ .. +---+---+---+---+
| | | estimate | | eoff |
+ + +---+---+---+---+ +---+---+---+---+
| | | (unused) | | cksum |
'---+---+---+---' '---+---+---+---' '---+---+---+---'
Note we can't just assume all weight=0 files are bnulls, or else we
won't use erased-state in empty btree roots. This risks thrashing in
files oscillating around weight=0.
Technically, weight=0 bshrubs _are_ slightly different than bnulls (
bshrubs point to a null tag, while bnulls simply have no tree), but
unlike btrees, there's no reason to keep weight=0 bshrubs around. Any
bshrub erased-state can still be used by the mdir.
This change also makes LFS_O_TRUNC and lfsr_file_truncate/fruncate
behave slightly differently, with LFS_O_TRUNC unconditionally reverting
to a bnull, while lfsr_file_truncate/fruncate tries to keep the btree
root around. This may be worth revisiting...
---
Despite the awkward encoding, this simplification still ends up saving a
nice bit of code and stack:
code stack ctx
before: 36668 2616 640
after: 36460 (-0.6%) 2608 (-0.3%) 640 (+0.0%)
This commit is contained in:
@@ -5946,60 +5946,6 @@ static int lfsr_btree_traverse(lfs_t *lfs, const lfsr_btree_t *btree,
|
||||
|
||||
/// B-shrub operations ///
|
||||
|
||||
#define LFSR_BSHRUB_ISBNULLORBMOSSORBPTR 0x80000000
|
||||
|
||||
// create an empty bshrub
|
||||
static void lfsr_bshrub_init(lfsr_bshrub_t *bshrub) {
|
||||
bshrub->u.size = LFSR_BSHRUB_ISBNULLORBMOSSORBPTR | 0;
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbnull(const lfsr_bshrub_t *bshrub) {
|
||||
return (lfs_size_t)bshrub->u.size
|
||||
== (LFSR_BSHRUB_ISBNULLORBMOSSORBPTR | 0);
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbmoss(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return (lfs_size_t)bshrub->u.size
|
||||
> (LFSR_BSHRUB_ISBNULLORBMOSSORBPTR | 0)
|
||||
&& bshrub->u.bmoss.u.disk.block == mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbptr(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return (lfs_size_t)bshrub->u.size
|
||||
> (LFSR_BSHRUB_ISBNULLORBMOSSORBPTR | 0)
|
||||
&& bshrub->u.bmoss.u.disk.block != mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbshrub(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return !(bshrub->u.size & LFSR_BSHRUB_ISBNULLORBMOSSORBPTR)
|
||||
&& bshrub->u.bshrub.blocks[0] == mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbtree(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return !(bshrub->u.size & LFSR_BSHRUB_ISBNULLORBMOSSORBPTR)
|
||||
&& bshrub->u.bshrub.blocks[0] != mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbnullorbmossorbptr(
|
||||
const lfsr_bshrub_t *bshrub) {
|
||||
return bshrub->u.size & LFSR_BSHRUB_ISBNULLORBMOSSORBPTR;
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbshruborbtree(
|
||||
const lfsr_bshrub_t *bshrub) {
|
||||
return !(bshrub->u.size & LFSR_BSHRUB_ISBNULLORBMOSSORBPTR);
|
||||
}
|
||||
|
||||
// the on-disk size/weight lines up to the same word across all unions
|
||||
static inline lfs_off_t lfsr_bshrub_size(const lfsr_bshrub_t *bshrub) {
|
||||
return bshrub->u.size & ~LFSR_BSHRUB_ISBNULLORBMOSSORBPTR;
|
||||
}
|
||||
|
||||
|
||||
// shrub things
|
||||
|
||||
// create an empty shrub
|
||||
@@ -6104,8 +6050,6 @@ static lfs_ssize_t lfsr_shrub_estimate(lfs_t *lfs,
|
||||
const lfsr_shrub_t *last = NULL;
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& lfsr_bshrub_isbshrub(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& lfsr_shrub_cmp(
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub,
|
||||
shrub) == 0) {
|
||||
@@ -6138,15 +6082,12 @@ static int lfsr_shrub_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
|
||||
// this should include our current bshrub
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& lfsr_bshrub_isbshrub(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& lfsr_shrub_cmp(
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub,
|
||||
shrub) == 0) {
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
bshrub->bshrub_.u.bshrub.blocks[0] = rbyd_->blocks[0];
|
||||
bshrub->bshrub_.u.bshrub.trunk = rbyd_->trunk;
|
||||
bshrub->bshrub_.u.bshrub.weight = rbyd_->weight;
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0] = rbyd_->blocks[0];
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.trunk = rbyd_->trunk;
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.weight = rbyd_->weight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6198,6 +6139,28 @@ static int lfsr_shrub_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
|
||||
|
||||
// ok, actual bshrub things
|
||||
|
||||
// create an empty bshrub
|
||||
static void lfsr_bshrub_init(
|
||||
const lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub) {
|
||||
lfsr_shrub_init(&bshrub->u.bshrub, mdir->rbyd.blocks[0]);
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbshrub(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return bshrub->u.bshrub.blocks[0] == mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline bool lfsr_bshrub_isbtree(
|
||||
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
|
||||
return bshrub->u.bshrub.blocks[0] != mdir->rbyd.blocks[0];
|
||||
}
|
||||
|
||||
static inline int lfsr_bshrub_cmp(
|
||||
const lfsr_bshrub_t *a,
|
||||
const lfsr_bshrub_t *b) {
|
||||
return lfsr_btree_cmp(&a->u.btree, &b->u.btree);
|
||||
}
|
||||
|
||||
// needed in lfsr_bshrub_estimate
|
||||
static int lfsr_mdir_lookupnext(lfs_t *lfs, const lfsr_mdir_t *mdir,
|
||||
lfsr_tag_t tag,
|
||||
@@ -6238,16 +6201,16 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
|
||||
// this includes our current shrub
|
||||
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_isbshrub(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)) {
|
||||
lfs_ssize_t dsize = lfsr_shrub_estimate(lfs,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
if (dsize < 0) {
|
||||
return dsize;
|
||||
}
|
||||
estimate += dsize;
|
||||
&& o->mdir.mid == mdir->mid
|
||||
&& lfsr_bshrub_isbshrub(
|
||||
&o->mdir, &((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& ((lfsr_obshrub_t*)o)->bshrub.u.weight > 0) {
|
||||
lfs_ssize_t dsize = lfsr_shrub_estimate(lfs,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
if (dsize < 0) {
|
||||
return dsize;
|
||||
}
|
||||
estimate += dsize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6261,13 +6224,9 @@ static int lfsr_bshrub_lookupnext(lfs_t *lfs,
|
||||
lfsr_bptr_t *bptr_) {
|
||||
(void)mdir;
|
||||
// out of bounds?
|
||||
if (bid >= lfsr_bshrub_size(bshrub)) {
|
||||
if (bid >= bshrub->u.weight) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
// the above size check should make this impossible
|
||||
LFS_ASSERT(!lfsr_bshrub_isbnull(bshrub));
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
|
||||
|
||||
// bshrub/btree?
|
||||
lfsr_bid_t bid__;
|
||||
@@ -6314,13 +6273,6 @@ static int lfsr_bshrub_traverse(lfs_t *lfs,
|
||||
lfsr_btraversal_t *bt,
|
||||
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bptr_t *bptr_) {
|
||||
(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));
|
||||
|
||||
lfsr_tag_t tag;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_btree_traverse(lfs, &bshrub->u.btree, bt,
|
||||
@@ -6356,17 +6308,12 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
|
||||
lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub,
|
||||
lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid,
|
||||
const lfsr_rat_t *rats, lfs_size_t rat_count) {
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
|
||||
|
||||
// before we touch anything, we need to mark all other btree references
|
||||
// as unerased
|
||||
if (lfsr_bshrub_isbtree(mdir, bshrub)) {
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
&& &((lfsr_obshrub_t*)o)->bshrub != bshrub
|
||||
&& lfsr_bshrub_isbshruborbtree(
|
||||
&((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& lfsr_btree_cmp(
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.btree,
|
||||
&bshrub->u.btree) == 0) {
|
||||
@@ -6454,8 +6401,8 @@ static int lfsr_bshrub_commit_(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
|
||||
&& lfsr_bshrub_isbshrub(&o->mdir,
|
||||
&((lfsr_obshrub_t*)o)->bshrub)) {
|
||||
&& lfsr_bshrub_isbshrub(
|
||||
&o->mdir, &((lfsr_obshrub_t*)o)->bshrub)) {
|
||||
((lfsr_obshrub_t*)o)->bshrub.u.bshrub.estimate = estimate;
|
||||
}
|
||||
}
|
||||
@@ -6528,8 +6475,6 @@ relocate:;
|
||||
static int lfsr_bshrub_commit(lfs_t *lfs,
|
||||
lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub,
|
||||
lfsr_bid_t bid, const lfsr_rat_t *rats, lfs_size_t rat_count) {
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
|
||||
return lfsr_bshrub_commit_(lfs, mdir, bshrub, bid, NULL, -1,
|
||||
rats, rat_count);
|
||||
}
|
||||
@@ -7596,25 +7541,32 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
// we're not quite done! we also need to bring over any
|
||||
// unsynced files
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
// belongs to our mid?
|
||||
if (!(lfsr_o_isbshrub(o->flags)
|
||||
&& o->mdir.mid == mdir__->mid)) {
|
||||
continue;
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined shrub?
|
||||
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]
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
// belongs to our mid?
|
||||
&& o->mdir.mid == mdir__->mid
|
||||
// is a bshrub?
|
||||
&& lfsr_bshrub_isbshrub(
|
||||
&o->mdir, &((lfsr_obshrub_t*)o)->bshrub)
|
||||
// only compact once, first compact should
|
||||
// stage the new block
|
||||
&& ((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0]
|
||||
!= mdir->rbyd.blocks[0]) {
|
||||
int err = lfsr_shrub_compact(lfs, &mdir->rbyd,
|
||||
&bshrub->bshrub_.u.bshrub,
|
||||
&bshrub->bshrub.u.bshrub);
|
||||
if (err) {
|
||||
return err;
|
||||
// empty bshrubs are a little bit weird in that
|
||||
// we don't want to write anything, but we still
|
||||
// need to update the block
|
||||
if (((lfsr_obshrub_t*)o)->bshrub.u.weight == 0) {
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.weight = 0;
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0]
|
||||
= mdir->rbyd.blocks[0];
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.trunk
|
||||
= LFSR_RBYD_ISSHRUB | 0;
|
||||
} else {
|
||||
int err = lfsr_shrub_compact(lfs, &mdir->rbyd,
|
||||
&((lfsr_obshrub_t*)o)->bshrub_.u.bshrub,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7826,19 +7778,16 @@ static lfs_ssize_t lfsr_mdir_estimate__(lfs_t *lfs, const lfsr_mdir_t *mdir,
|
||||
// files, I suppose if this becomes a problem we could sort
|
||||
// opened files by mid
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
// belongs to our mdir + rid?
|
||||
if (!(lfsr_o_isbshrub(o->flags)
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
// belongs to our mdir + rid?
|
||||
&& lfsr_mdir_cmp(&o->mdir, mdir) == 0
|
||||
&& lfsr_mid_rid(lfs, o->mdir.mid) == a_rid)) {
|
||||
continue;
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined shrub?
|
||||
if (lfsr_bshrub_isbshrub(&bshrub->o.mdir,
|
||||
&bshrub->bshrub)) {
|
||||
&& lfsr_mid_rid(lfs, o->mdir.mid) == a_rid
|
||||
// is a bshrub?
|
||||
&& lfsr_bshrub_isbshrub(
|
||||
&o->mdir, &((lfsr_obshrub_t*)o)->bshrub)
|
||||
&& ((lfsr_obshrub_t*)o)->bshrub.u.weight > 0) {
|
||||
lfs_ssize_t dsize__ = lfsr_shrub_estimate(lfs,
|
||||
&bshrub->bshrub.u.bshrub);
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
if (dsize__ < 0) {
|
||||
return dsize__;
|
||||
}
|
||||
@@ -7953,26 +7902,36 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
||||
|
||||
// we're not quite done! we also need to bring over any unsynced files
|
||||
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
|
||||
// belongs to our mdir?
|
||||
if (!(lfsr_o_isbshrub(o->flags)
|
||||
if (lfsr_o_isbshrub(o->flags)
|
||||
// belongs to our mdir?
|
||||
&& lfsr_mdir_cmp(&o->mdir, mdir) == 0
|
||||
&& lfsr_mid_rid(lfs, o->mdir.mid) >= start_rid
|
||||
&& (lfsr_rid_t)lfsr_mid_rid(lfs, o->mdir.mid)
|
||||
< (lfsr_rid_t)end_rid)) {
|
||||
continue;
|
||||
}
|
||||
lfsr_obshrub_t *bshrub = (lfsr_obshrub_t*)o;
|
||||
|
||||
// inlined shrub?
|
||||
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]
|
||||
< (lfsr_rid_t)end_rid
|
||||
// is a bshrub?
|
||||
&& lfsr_bshrub_isbshrub(
|
||||
&o->mdir, &((lfsr_obshrub_t*)o)->bshrub)
|
||||
// only compact once, first compact should
|
||||
// stage the new block
|
||||
&& ((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0]
|
||||
!= mdir_->rbyd.blocks[0]) {
|
||||
err = lfsr_shrub_compact(lfs, &mdir_->rbyd,
|
||||
&bshrub->bshrub_.u.bshrub, &bshrub->bshrub.u.bshrub);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
// empty bshrubs are a little bit weird in that
|
||||
// we don't want to write anything, but we still
|
||||
// need to update the block
|
||||
if (((lfsr_obshrub_t*)o)->bshrub.u.weight == 0) {
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.weight = 0;
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.blocks[0]
|
||||
= mdir_->rbyd.blocks[0];
|
||||
((lfsr_obshrub_t*)o)->bshrub_.u.bshrub.trunk
|
||||
= LFSR_RBYD_ISSHRUB | 0;
|
||||
} else {
|
||||
int err = lfsr_shrub_compact(lfs, &mdir_->rbyd,
|
||||
&((lfsr_obshrub_t*)o)->bshrub_.u.bshrub,
|
||||
&((lfsr_obshrub_t*)o)->bshrub.u.bshrub);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10851,14 +10810,14 @@ static inline lfs_size_t lfsr_file_inlinesize(lfs_t *lfs,
|
||||
static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) {
|
||||
return lfs_max(
|
||||
file->buffer.pos + file->buffer.size,
|
||||
lfsr_bshrub_size(&file->o.bshrub));
|
||||
file->o.bshrub.u.weight);
|
||||
}
|
||||
|
||||
// file operations
|
||||
|
||||
static int lfsr_file_fetch(lfs_t *lfs, lfsr_file_t *file, bool trunc) {
|
||||
// default data state
|
||||
lfsr_bshrub_init(&file->o.bshrub);
|
||||
lfsr_bshrub_init(&file->o.o.mdir, &file->o.bshrub);
|
||||
// discard the current buffer
|
||||
file->buffer.pos = 0;
|
||||
file->buffer.size = 0;
|
||||
@@ -11294,7 +11253,7 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
|
||||
}
|
||||
|
||||
// any data in our btree?
|
||||
if (pos_ < lfsr_bshrub_size(&file->o.bshrub)) {
|
||||
if (pos_ < file->o.bshrub.u.weight) {
|
||||
// bypass buffer?
|
||||
if ((lfs_size_t)d >= lfsr_file_buffersize(lfs, file)) {
|
||||
lfs_ssize_t d_ = lfsr_file_readnext(lfs, file,
|
||||
@@ -11354,8 +11313,6 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
|
||||
|
||||
static int lfsr_file_commit(lfs_t *lfs, lfsr_file_t *file,
|
||||
lfs_off_t pos, const lfsr_rat_t *rats, lfs_size_t rat_count) {
|
||||
// file must be a bshrub/btree here
|
||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(&file->o.bshrub));
|
||||
return lfsr_bshrub_commit(lfs,
|
||||
&file->o.o.mdir, &file->o.bshrub,
|
||||
pos, rats, rat_count);
|
||||
@@ -11379,7 +11336,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
||||
// possible in case we ever don't track temporary copies.
|
||||
|
||||
// try to merge commits where possible
|
||||
lfsr_bid_t bid = lfsr_bshrub_size(&file->o.bshrub);
|
||||
lfsr_bid_t bid = file->o.bshrub.u.weight;
|
||||
lfsr_rat_t rats[5];
|
||||
lfs_size_t rat_count = 0;
|
||||
union {
|
||||
@@ -11391,36 +11348,27 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
||||
uint8_t buf[LFSR_BPTR_DSIZE];
|
||||
} right;
|
||||
|
||||
// always convert to bshrub/btree when this function is called
|
||||
if (!lfsr_bshrub_isbshruborbtree(&file->o.bshrub)) {
|
||||
// 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]);
|
||||
}
|
||||
|
||||
// need a hole?
|
||||
if (pos > lfsr_bshrub_size(&file->o.bshrub)) {
|
||||
if (pos > file->o.bshrub.u.weight) {
|
||||
// can we coalesce?
|
||||
if (lfsr_bshrub_size(&file->o.bshrub) > 0) {
|
||||
bid = lfs_min(bid, lfsr_bshrub_size(&file->o.bshrub)-1);
|
||||
if (file->o.bshrub.u.weight > 0) {
|
||||
bid = lfs_min(bid, file->o.bshrub.u.weight-1);
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_GROW, +(pos - lfsr_bshrub_size(&file->o.bshrub)),
|
||||
LFSR_TAG_GROW, +(pos - file->o.bshrub.u.weight),
|
||||
LFSR_DATA_NULL());
|
||||
|
||||
// new hole
|
||||
} else {
|
||||
bid = lfs_min(bid, lfsr_bshrub_size(&file->o.bshrub));
|
||||
bid = lfs_min(bid, file->o.bshrub.u.weight);
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_DATA, +(pos - lfsr_bshrub_size(&file->o.bshrub)),
|
||||
LFSR_TAG_DATA, +(pos - file->o.bshrub.u.weight),
|
||||
LFSR_DATA_NULL());
|
||||
}
|
||||
}
|
||||
|
||||
// try to carve any existing data
|
||||
lfsr_rat_t right_rat_ = {.tag=0};
|
||||
while (pos < lfsr_bshrub_size(&file->o.bshrub)) {
|
||||
while (pos < file->o.bshrub.u.weight) {
|
||||
lfsr_tag_t tag_;
|
||||
lfsr_bid_t weight_;
|
||||
lfsr_bptr_t bptr_;
|
||||
@@ -11610,21 +11558,21 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
||||
if (weight + rat.weight > 0) {
|
||||
// can we coalesce a hole?
|
||||
if (lfsr_rat_size(rat) == 0 && pos > 0) {
|
||||
bid = lfs_min(bid, lfsr_bshrub_size(&file->o.bshrub)-1);
|
||||
bid = lfs_min(bid, file->o.bshrub.u.weight-1);
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_GROW, +(weight + rat.weight),
|
||||
LFSR_DATA_NULL());
|
||||
|
||||
// need a new hole?
|
||||
} else if (lfsr_rat_size(rat) == 0) {
|
||||
bid = lfs_min(bid, lfsr_bshrub_size(&file->o.bshrub));
|
||||
bid = lfs_min(bid, file->o.bshrub.u.weight);
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_DATA, +(weight + rat.weight),
|
||||
LFSR_DATA_NULL());
|
||||
|
||||
// append new fragment/bptr?
|
||||
} else {
|
||||
bid = lfs_min(bid, lfsr_bshrub_size(&file->o.bshrub));
|
||||
bid = lfs_min(bid, file->o.bshrub.u.weight);
|
||||
rats[rat_count++] = LFSR_RAT_(
|
||||
rat.tag, +(weight + rat.weight),
|
||||
rat.cat, rat.count);
|
||||
@@ -11674,8 +11622,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
if (pos > 0
|
||||
&& lfs->cfg->crystal_thresh > 0
|
||||
&& (lfs_soff_t)(pos - (lfs->cfg->crystal_thresh-1))
|
||||
< (lfs_soff_t)lfsr_bshrub_size(&file->o.bshrub)
|
||||
&& lfsr_bshrub_size(&file->o.bshrub) > 0
|
||||
< (lfs_soff_t)file->o.bshrub.u.weight
|
||||
&& file->o.bshrub.u.weight > 0
|
||||
// don't bother to lookup left after the first block
|
||||
&& !aligned) {
|
||||
lfsr_bid_t bid;
|
||||
@@ -11728,14 +11676,14 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
// if we haven't already exceeded our crystallization threshold,
|
||||
// find right crystal neighbor
|
||||
if (crystal_end - crystal_start < lfs->cfg->crystal_thresh
|
||||
&& lfsr_bshrub_size(&file->o.bshrub) > 0) {
|
||||
&& file->o.bshrub.u.weight > 0) {
|
||||
lfsr_bid_t bid;
|
||||
lfsr_tag_t tag;
|
||||
lfsr_bid_t weight;
|
||||
int err = lfsr_file_lookupnext(lfs, file,
|
||||
lfs_min(
|
||||
crystal_start + (lfs->cfg->crystal_thresh-1),
|
||||
lfsr_bshrub_size(&file->o.bshrub)-1),
|
||||
file->o.bshrub.u.weight-1),
|
||||
&bid, &tag, &weight, &bptr);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
@@ -11771,7 +11719,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
// crystal for this
|
||||
block_start = crystal_start;
|
||||
if (crystal_start > 0
|
||||
&& lfsr_bshrub_size(&file->o.bshrub) > 0
|
||||
&& file->o.bshrub.u.weight > 0
|
||||
// don't bother to lookup left after the first block
|
||||
&& !aligned) {
|
||||
lfsr_bid_t bid;
|
||||
@@ -11780,7 +11728,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
int err = lfsr_file_lookupnext(lfs, file,
|
||||
lfs_min(
|
||||
crystal_start-1,
|
||||
lfsr_bshrub_size(&file->o.bshrub)-1),
|
||||
file->o.bshrub.u.weight-1),
|
||||
&bid, &tag, &weight, &bptr);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
@@ -11847,14 +11795,14 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
+ (lfs->cfg->block_size - bptr.data.u.disk.off),
|
||||
lfs_max(
|
||||
pos + size,
|
||||
lfsr_bshrub_size(&file->o.bshrub)))) {
|
||||
file->o.bshrub.u.weight))) {
|
||||
// keep track of the next highest priority data offset
|
||||
lfs_ssize_t d = lfs_min(
|
||||
block_start
|
||||
+ (lfs->cfg->block_size - bptr.data.u.disk.off),
|
||||
lfs_max(
|
||||
pos + size,
|
||||
lfsr_bshrub_size(&file->o.bshrub))) - pos_;
|
||||
file->o.bshrub.u.weight)) - pos_;
|
||||
|
||||
// any data in our buffer?
|
||||
if (pos_ < pos + size && size > 0) {
|
||||
@@ -11889,7 +11837,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
||||
}
|
||||
|
||||
// any data on disk?
|
||||
if (pos_ < lfsr_bshrub_size(&file->o.bshrub)) {
|
||||
if (pos_ < file->o.bshrub.u.weight) {
|
||||
lfsr_bid_t bid_;
|
||||
lfsr_tag_t tag_;
|
||||
lfsr_bid_t weight_;
|
||||
@@ -12059,7 +12007,7 @@ fragment:;
|
||||
|
||||
// do we have a left sibling?
|
||||
if (fragment_start > 0
|
||||
&& lfsr_bshrub_size(&file->o.bshrub) >= fragment_start
|
||||
&& file->o.bshrub.u.weight >= fragment_start
|
||||
// don't bother to lookup left after first fragment
|
||||
&& !aligned) {
|
||||
lfsr_bid_t bid;
|
||||
@@ -12107,7 +12055,7 @@ fragment:;
|
||||
// do we have a right sibling?
|
||||
//
|
||||
// note this may the same as our left sibling
|
||||
if (fragment_end < lfsr_bshrub_size(&file->o.bshrub)
|
||||
if (fragment_end < file->o.bshrub.u.weight
|
||||
// don't bother to lookup right if fragment is already full
|
||||
&& fragment_end - fragment_start < lfs->cfg->fragment_size) {
|
||||
lfsr_bid_t bid;
|
||||
@@ -12382,13 +12330,6 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// note because of small-file caching and our current write
|
||||
// strategy, we never actually end up with only a direct data
|
||||
// or bptr
|
||||
//
|
||||
// this is convenient because bptrs are a bit annoying to commit
|
||||
LFS_ASSERT(!lfsr_bshrub_isbmoss(&file->o.o.mdir, &file->o.bshrub));
|
||||
LFS_ASSERT(!lfsr_bshrub_isbptr(&file->o.o.mdir, &file->o.bshrub));
|
||||
// uncreated files must be unsynced
|
||||
LFS_ASSERT(!lfsr_o_isuncreat(file->o.o.flags)
|
||||
|| lfsr_o_isunsync(file->o.o.flags));
|
||||
@@ -12422,8 +12363,9 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// null? no rat?
|
||||
if (lfsr_file_size_(file) == 0) {
|
||||
// bnull? no rat?
|
||||
if (lfsr_bshrub_isbshrub(&file->o.o.mdir, &file->o.bshrub)
|
||||
&& file->o.bshrub.u.weight == 0) {
|
||||
rats[rat_count++] = LFSR_RAT(
|
||||
LFSR_TAG_RM | LFSR_TAG_SUB | LFSR_TAG_STRUCT, 0,
|
||||
LFSR_DATA_NULL());
|
||||
|
||||
Reference in New Issue
Block a user