Changed bshrub functions to operate on mdir+bshrub directly

This gets a bit messy, since lfsr_bshrub_commit really requires the
bshrub to be enrolled in the opened mdir list to stage correctly.

To make this work, our internal SHRUBCOMMIT and SHRUBTRUNK attrs now
take a pointer to the active shrub, and assume it is followed by a
staging shrub in memory. This is a big hack/assumption that leaks
through lfsr_bshrub_commit, but it at gets the job done in our current
system.

Note some functions were renamed instead, these didn't really make sense
as pure-bshrub functions:

- lfsr_bshrub_readnext -> lfsr_file_readnext
- lfsr_bshrub_read -> lfsr_file_read_

---

The main reason for this is to comply with C99's strict aliasing rules,
which can be a real PIA sometimes.

We need to track a bshrub in lfsr_mtraversal_t, but we really don't want
to pay the RAM cost for an entire lfsr_file_t. The best option I've
found is to pass around multiple pointers to the relevant internal
structs (mdir+bshrub), but this adds a stack+code cost.

So far, strict aliasing is a net downside:

                         code          stack
  before:               34478           2624
  -fno-strict-aliasing: 34502 (+0.1%)   2616 (-0.3%)
  after:                34566 (+0.3%)   2632 (+0.3%)

But it's baked into the standard and we can't always rely on
-fno-strict-aliasing being available.
This commit is contained in:
Christopher Haster
2024-06-23 13:05:06 -05:00
parent d155750f14
commit 55d9f5c76a
2 changed files with 120 additions and 99 deletions
+117 -92
View File
@@ -6199,18 +6199,21 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
// in our rbyd // in our rbyd
} else if (attrs[i].tag == LFSR_TAG_SHRUBCOMMIT) { } else if (attrs[i].tag == LFSR_TAG_SHRUBCOMMIT) {
const lfsr_shrubcommit_t *shrubcommit = attrs[i].cat; const lfsr_shrubcommit_t *shrubcommit = attrs[i].cat;
// find the staging shrub
lfsr_shrub_t *shrub = shrubcommit->shrub;
lfsr_shrub_t *shrub_ = &((lfsr_bshrub_t*)shrub + 1)->u.bshrub;
// 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
if (shrubcommit->shrub->blocks[0] != rbyd_.blocks[0]) { if (shrub_->blocks[0] != rbyd_.blocks[0]) {
shrubcommit->shrub->blocks[0] = rbyd_.blocks[0]; shrub_->blocks[0] = rbyd_.blocks[0];
shrubcommit->shrub->trunk = LFSR_RBYD_ISSHRUB | 0; shrub_->trunk = LFSR_RBYD_ISSHRUB | 0;
shrubcommit->shrub->weight = 0; shrub_->weight = 0;
} }
// commit to shrub // commit to shrub
int err = lfsr_shrub_commit(lfs, &rbyd_, int err = lfsr_shrub_commit(lfs, &rbyd_,
shrubcommit->shrub, shrubcommit->rid, shrub_, shrubcommit->rid,
shrubcommit->attrs, shrubcommit->attr_count); shrubcommit->attrs, shrubcommit->attr_count);
if (err) { if (err) {
return err; return err;
@@ -6222,7 +6225,9 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
// TODO should we preserve mode for all of these? // TODO should we preserve mode for all of these?
// TODO should we do the same for sprouts? // TODO should we do the same for sprouts?
} else if (lfsr_tag_key(attrs[i].tag) == LFSR_TAG_SHRUBTRUNK) { } else if (lfsr_tag_key(attrs[i].tag) == LFSR_TAG_SHRUBTRUNK) {
const lfsr_shrub_t *shrub = attrs[i].cat; // find the staging shrub
lfsr_shrub_t *shrub = (lfsr_shrub_t*)attrs[i].cat;
lfsr_shrub_t *shrub_ = &((lfsr_bshrub_t*)shrub + 1)->u.bshrub;
uint8_t shrub_buf[LFSR_SHRUB_DSIZE]; uint8_t shrub_buf[LFSR_SHRUB_DSIZE];
int err = lfsr_rbyd_appendattr(lfs, &rbyd_, int err = lfsr_rbyd_appendattr(lfs, &rbyd_,
@@ -6231,7 +6236,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
lfsr_tag_mode(attrs[i].tag) | LFSR_TAG_BSHRUB, lfsr_tag_mode(attrs[i].tag) | LFSR_TAG_BSHRUB,
attrs[i].weight, attrs[i].weight,
// note we use the staged trunk here // note we use the staged trunk here
LFSR_DATA_SHRUB_(shrub, shrub_buf))); LFSR_DATA_SHRUB_(shrub_, shrub_buf)));
if (err) { if (err) {
return err; return err;
} }
@@ -7884,7 +7889,8 @@ typedef lfsr_btinfo_t lfsr_mtinfo_t;
// needed in lfsr_mtree_traverse_ // needed in lfsr_mtree_traverse_
static inline bool lfsr_f_isunsync(uint32_t flags); static inline bool lfsr_f_isunsync(uint32_t flags);
static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_file_t *file, static int lfsr_bshrub_traverse(lfs_t *lfs,
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub,
lfsr_btraversal_t *bt, lfsr_btraversal_t *bt,
lfsr_bid_t *bid_, lfsr_btinfo_t *btinfo); lfsr_bid_t *bid_, lfsr_btinfo_t *btinfo);
@@ -8120,7 +8126,8 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_mtraversal_t *mt,
case LFSR_MTRAVERSAL_BTREE:; case LFSR_MTRAVERSAL_BTREE:;
case LFSR_MTRAVERSAL_OBTREE:; case LFSR_MTRAVERSAL_OBTREE:;
// traverse through our file // traverse through our file
err = lfsr_bshrub_traverse(lfs, (const lfsr_file_t*)mt, &mt->u.bt, err = lfsr_bshrub_traverse(lfs, &mt->o.mdir, &mt->bshrub,
&mt->u.bt,
NULL, mtinfo); NULL, mtinfo);
if (err) { if (err) {
if (err == LFS_ERR_NOENT) { if (err == LFS_ERR_NOENT) {
@@ -10432,7 +10439,7 @@ static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) {
// file operations // file operations
// needed in lfsr_file_opencfg // needed in lfsr_file_opencfg
static lfs_ssize_t lfsr_bshrub_read(lfs_t *lfs, const lfsr_file_t *file, 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, uint8_t *buffer, lfs_size_t size);
int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
@@ -10591,7 +10598,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
// if our file is small, try to keep the whole thing in our buffer // if our file is small, try to keep the whole thing in our buffer
if (lfsr_bshrub_size(&file->bshrub) <= lfsr_file_inlinesize(lfs, file)) { if (lfsr_bshrub_size(&file->bshrub) <= lfsr_file_inlinesize(lfs, file)) {
lfs_ssize_t d = lfsr_bshrub_read(lfs, file, lfs_ssize_t d = lfsr_file_read_(lfs, file,
0, file->buffer.buffer, lfsr_bshrub_size(&file->bshrub)); 0, file->buffer.buffer, lfsr_bshrub_size(&file->bshrub));
if (d < 0) { if (d < 0) {
err = d; err = d;
@@ -10673,14 +10680,16 @@ int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) {
// find a tight upper bound on the _full_ bshrub size, this includes // find a tight upper bound on the _full_ bshrub size, this includes
// any on-disk bshrubs, and all pending bshrubs // any on-disk bshrubs, and all pending bshrubs
static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs, const lfsr_file_t *file) { static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs,
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub) {
(void)bshrub;
lfs_size_t estimate = 0; lfs_size_t estimate = 0;
// include all unique sprouts/shrubs related to our file, // include all unique sprouts/shrubs related to our file,
// including the on-disk sprout/shrub // including the on-disk sprout/shrub
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookupnext(lfs, &file->o.mdir, LFSR_TAG_DATA, int err = lfsr_mdir_lookupnext(lfs, mdir, LFSR_TAG_DATA,
&tag, &data); &tag, &data);
if (err < 0 && err != LFS_ERR_NOENT) { if (err < 0 && err != LFS_ERR_NOENT) {
return err; return err;
@@ -10695,7 +10704,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs, const lfsr_file_t *file) {
} else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) { } else if (err != LFS_ERR_NOENT && tag == LFSR_TAG_BSHRUB) {
lfsr_shrub_t shrub; lfsr_shrub_t shrub;
err = lfsr_data_readshrub(lfs, &data, &file->o.mdir, err = lfsr_data_readshrub(lfs, &data, mdir,
&shrub); &shrub);
if (err < 0) { if (err < 0) {
return err; return err;
@@ -10712,7 +10721,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs, const lfsr_file_t *file) {
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) { for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
lfsr_file_t *file_ = (lfsr_file_t*)o; lfsr_file_t *file_ = (lfsr_file_t*)o;
if (file_->o.type == LFS_TYPE_REG if (file_->o.type == LFS_TYPE_REG
&& file_->o.mdir.mid == file->o.mdir.mid) { && file_->o.mdir.mid == mdir->mid) {
if (lfsr_bshrub_isbsprout(&file_->o.mdir, &file_->bshrub)) { if (lfsr_bshrub_isbsprout(&file_->o.mdir, &file_->bshrub)) {
lfs_ssize_t dsize = lfsr_sprout_estimate(lfs, lfs_ssize_t dsize = lfsr_sprout_estimate(lfs,
&file_->bshrub.u.bsprout); &file_->bshrub.u.bsprout);
@@ -10735,57 +10744,59 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs, const lfsr_file_t *file) {
return estimate; return estimate;
} }
static int lfsr_bshrub_lookupnext(lfs_t *lfs, const lfsr_file_t *file, static int lfsr_bshrub_lookupnext(lfs_t *lfs,
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub,
lfs_off_t pos, lfs_off_t pos,
lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bid_t *weight_, lfsr_bid_t *bid_, lfsr_tag_t *tag_, lfsr_bid_t *weight_,
lfsr_bptr_t *bptr_) { lfsr_bptr_t *bptr_) {
if (pos >= lfsr_bshrub_size(&file->bshrub)) { // out of bounds?
if (pos >= lfsr_bshrub_size(bshrub)) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
// the above size check should make this impossible // the above size check should make this impossible
LFS_ASSERT(!lfsr_bshrub_isbnull(&file->bshrub)); LFS_ASSERT(!lfsr_bshrub_isbnull(bshrub));
// inlined sprout? // inlined sprout?
if (lfsr_bshrub_isbsprout(&file->o.mdir, &file->bshrub)) { if (lfsr_bshrub_isbsprout(mdir, bshrub)) {
if (bid_) { if (bid_) {
*bid_ = lfsr_data_size(file->bshrub.u.bsprout)-1; *bid_ = lfsr_data_size(bshrub->u.bsprout)-1;
} }
if (tag_) { if (tag_) {
*tag_ = LFSR_TAG_DATA; *tag_ = LFSR_TAG_DATA;
} }
if (weight_) { if (weight_) {
*weight_ = lfsr_data_size(file->bshrub.u.bsprout); *weight_ = lfsr_data_size(bshrub->u.bsprout);
} }
if (bptr_) { if (bptr_) {
bptr_->data = file->bshrub.u.bsprout; bptr_->data = bshrub->u.bsprout;
} }
return 0; return 0;
// block pointer? // block pointer?
} else if (lfsr_bshrub_isbptr(&file->o.mdir, &file->bshrub)) { } else if (lfsr_bshrub_isbptr(mdir, bshrub)) {
if (bid_) { if (bid_) {
*bid_ = lfsr_data_size(file->bshrub.u.bptr.data)-1; *bid_ = lfsr_data_size(bshrub->u.bptr.data)-1;
} }
if (tag_) { if (tag_) {
*tag_ = LFSR_TAG_BLOCK; *tag_ = LFSR_TAG_BLOCK;
} }
if (weight_) { if (weight_) {
*weight_ = lfsr_data_size(file->bshrub.u.bptr.data); *weight_ = lfsr_data_size(bshrub->u.bptr.data);
} }
if (bptr_) { if (bptr_) {
*bptr_ = file->bshrub.u.bptr; *bptr_ = bshrub->u.bptr;
} }
return 0; return 0;
// bshrub/btree? // bshrub/btree?
} else if (lfsr_bshrub_isbshruborbtree(&file->bshrub)) { } else if (lfsr_bshrub_isbshruborbtree(bshrub)) {
lfsr_bid_t bid; lfsr_bid_t bid;
lfsr_rbyd_t rbyd; lfsr_rbyd_t rbyd;
lfsr_srid_t rid; lfsr_srid_t rid;
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, &file->bshrub.u.btree, pos, int err = lfsr_btree_lookupnext_(lfs, &bshrub->u.btree, pos,
&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);
@@ -10822,31 +10833,32 @@ static int lfsr_bshrub_lookupnext(lfs_t *lfs, const lfsr_file_t *file,
} }
} }
static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_file_t *file, static int lfsr_bshrub_traverse(lfs_t *lfs,
const lfsr_mdir_t *mdir, const lfsr_bshrub_t *bshrub,
lfsr_btraversal_t *bt, lfsr_btraversal_t *bt,
lfsr_bid_t *bid_, lfsr_btinfo_t *btinfo) { lfsr_bid_t *bid_, lfsr_btinfo_t *btinfo) {
// bnull/bsprout do nothing // bnull/bsprout do nothing
if (lfsr_bshrub_isbnull(&file->bshrub) if (lfsr_bshrub_isbnull(bshrub)
|| lfsr_bshrub_isbsprout(&file->o.mdir, &file->bshrub)) { || lfsr_bshrub_isbsprout(mdir, bshrub)) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
// block pointer? // block pointer?
if (lfsr_bshrub_isbptr(&file->o.mdir, &file->bshrub)) { if (lfsr_bshrub_isbptr(mdir, bshrub)) {
if (bt->bid > 0) { if (bt->bid > 0) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
if (bid_) { if (bid_) {
*bid_ = lfsr_data_size(file->bshrub.u.bptr.data)-1; *bid_ = lfsr_data_size(bshrub->u.bptr.data)-1;
} }
btinfo->tag = LFSR_TAG_BLOCK; btinfo->tag = LFSR_TAG_BLOCK;
btinfo->u.bptr = file->bshrub.u.bptr; btinfo->u.bptr = bshrub->u.bptr;
return 0; return 0;
// bshrub/btree? // bshrub/btree?
} else if (lfsr_bshrub_isbshruborbtree(&file->bshrub)) { } else if (lfsr_bshrub_isbshruborbtree(bshrub)) {
int err = lfsr_btree_traverse_(lfs, &file->bshrub.u.btree, bt, int err = lfsr_btree_traverse_(lfs, &bshrub->u.btree, bt,
bid_, btinfo); bid_, btinfo);
if (err) { if (err) {
return err; return err;
@@ -10869,7 +10881,7 @@ static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_file_t *file,
} }
} }
static lfs_ssize_t lfsr_bshrub_readnext(lfs_t *lfs, const lfsr_file_t *file, static lfs_ssize_t lfsr_file_readnext(lfs_t *lfs, const lfsr_file_t *file,
lfs_off_t pos, uint8_t *buffer, lfs_size_t size) { lfs_off_t pos, uint8_t *buffer, lfs_size_t size) {
lfs_off_t pos_ = pos; lfs_off_t pos_ = pos;
// read one btree entry // read one btree entry
@@ -10877,7 +10889,7 @@ static lfs_ssize_t lfsr_bshrub_readnext(lfs_t *lfs, const lfsr_file_t *file,
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_bid_t weight; lfsr_bid_t weight;
lfsr_bptr_t bptr; lfsr_bptr_t bptr;
int err = lfsr_bshrub_lookupnext(lfs, file, pos_, int err = lfsr_bshrub_lookupnext(lfs, &file->o.mdir, &file->bshrub, pos_,
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
return err; return err;
@@ -10916,11 +10928,11 @@ static lfs_ssize_t lfsr_bshrub_readnext(lfs_t *lfs, const lfsr_file_t *file,
return pos_ - pos; return pos_ - pos;
} }
static lfs_ssize_t lfsr_bshrub_read(lfs_t *lfs, const lfsr_file_t *file, 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, uint8_t *buffer, lfs_size_t size) {
lfs_off_t pos_ = pos; lfs_off_t pos_ = pos;
while (size > 0 && pos_ < lfsr_bshrub_size(&file->bshrub)) { while (size > 0 && pos_ < lfsr_bshrub_size(&file->bshrub)) {
lfs_ssize_t d = lfsr_bshrub_readnext(lfs, file, lfs_ssize_t d = lfsr_file_readnext(lfs, file,
pos_, buffer, size); pos_, buffer, size);
if (d < 0) { if (d < 0) {
LFS_ASSERT(d != LFS_ERR_NOENT); LFS_ASSERT(d != LFS_ERR_NOENT);
@@ -10936,22 +10948,23 @@ static lfs_ssize_t lfsr_bshrub_read(lfs_t *lfs, const lfsr_file_t *file,
} }
// this is atomic // this is atomic
static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file, static int lfsr_bshrub_commit(lfs_t *lfs,
lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub,
lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) { lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) {
// file must be a bshrub/btree here // file must be a bshrub/btree here
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(&file->bshrub)); LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
// before we touch anything, we need to mark all other btree references // before we touch anything, we need to mark all other btree references
// as unerased // as unerased
if (lfsr_bshrub_isbtree(&file->o.mdir, &file->bshrub)) { if (lfsr_bshrub_isbtree(mdir, bshrub)) {
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) { for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
lfsr_file_t *file_ = (lfsr_file_t*)o; lfsr_file_t *file_ = (lfsr_file_t*)o;
if (file_->o.type == LFS_TYPE_REG if (file_->o.type == LFS_TYPE_REG
&& file_ != file && &file_->bshrub != bshrub
&& lfsr_bshrub_isbshruborbtree(&file_->bshrub) && lfsr_bshrub_isbshruborbtree(&file_->bshrub)
&& lfsr_btree_cmp( && lfsr_btree_cmp(
&file_->bshrub.u.btree, &file_->bshrub.u.btree,
&file->bshrub.u.btree) == 0) { &bshrub->u.btree) == 0) {
// mark as unerased // mark as unerased
file_->bshrub.u.btree.eoff = -1; file_->bshrub.u.btree.eoff = -1;
} }
@@ -10960,7 +10973,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
// try to commit to the btree // try to commit to the btree
lfsr_btree_scratch_t scratch; lfsr_btree_scratch_t scratch;
int err = lfsr_btree_commit_(lfs, &file->bshrub.u.btree, &scratch, int err = lfsr_btree_commit_(lfs, &bshrub->u.btree, &scratch,
&bid, &attrs, &attr_count); &bid, &attrs, &attr_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
@@ -10996,11 +11009,11 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
// accurate estimate // accurate estimate
lfs_ssize_t estimate = (alloc) lfs_ssize_t estimate = (alloc)
? (lfs_size_t)-1 ? (lfs_size_t)-1
: file->bshrub.u.bshrub.estimate; : 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) {
estimate = lfsr_bshrub_estimate(lfs, file); estimate = lfsr_bshrub_estimate(lfs, mdir, bshrub);
if (estimate < 0) { if (estimate < 0) {
return estimate; return estimate;
} }
@@ -11023,32 +11036,30 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
estimate += commit_estimate; estimate += commit_estimate;
// commit to shrub // commit to shrub
int err = lfsr_mdir_commit(lfs, &file->o.mdir, LFSR_ATTRS( int err = lfsr_mdir_commit(lfs, mdir, LFSR_ATTRS(
LFSR_ATTR_SHRUBCOMMIT( LFSR_ATTR_SHRUBCOMMIT(
LFSR_TAG_SHRUBCOMMIT, 0, LFSR_TAG_SHRUBCOMMIT, 0,
&file->bshrub_.u.bshrub, bid, &bshrub->u.bshrub, bid, attrs, attr_count)));
attrs, attr_count)));
if (err) { if (err) {
return err; return err;
} }
LFS_ASSERT(file->bshrub.u.bshrub.blocks[0] LFS_ASSERT(bshrub->u.bshrub.blocks[0] == mdir->rbyd.blocks[0]);
== file->o.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) {
lfsr_file_t *file_ = (lfsr_file_t*)o; lfsr_file_t *file_ = (lfsr_file_t*)o;
if (file_->o.type == LFS_TYPE_REG if (file_->o.type == LFS_TYPE_REG
&& file_->o.mdir.mid == file->o.mdir.mid && file_->o.mdir.mid == mdir->mid
&& lfsr_bshrub_isbshrub(&file_->o.mdir, &file_->bshrub)) { && lfsr_bshrub_isbshrub(&file_->o.mdir, &file_->bshrub)) {
file_->bshrub.u.bshrub.estimate = estimate; file_->bshrub.u.bshrub.estimate = estimate;
} }
} }
LFS_ASSERT(file->bshrub.u.bshrub.estimate == (lfs_size_t)estimate); LFS_ASSERT(bshrub->u.bshrub.estimate == (lfs_size_t)estimate);
return 0; return 0;
} }
LFS_ASSERT(lfsr_shrub_trunk(&file->bshrub.u.bshrub)); LFS_ASSERT(lfsr_shrub_trunk(&bshrub->u.bshrub));
return 0; return 0;
relocate:; relocate:;
@@ -11062,7 +11073,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, err = lfsr_rbyd_compact(lfs, &rbyd,
&file->bshrub.u.btree, -1, -1); &bshrub->u.btree, -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
@@ -11084,7 +11095,7 @@ relocate:;
return err; return err;
} }
file->bshrub.u.btree = rbyd; bshrub->u.btree = rbyd;
return 0; return 0;
} }
@@ -11138,7 +11149,9 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
if (attr_count > 0) { if (attr_count > 0) {
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
int err = lfsr_bshrub_commit(lfs, file, 0, attrs, attr_count); int err = lfsr_bshrub_commit(lfs,
&file->o.mdir, &file->bshrub, 0,
attrs, attr_count);
if (err) { if (err) {
return err; return err;
} }
@@ -11171,7 +11184,8 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
lfsr_tag_t tag_; lfsr_tag_t tag_;
lfsr_bid_t weight_; lfsr_bid_t weight_;
lfsr_bptr_t bptr_; lfsr_bptr_t bptr_;
int err = lfsr_bshrub_lookupnext(lfs, file, pos, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub, pos,
&bid, &tag_, &weight_, &bptr_); &bid, &tag_, &weight_, &bptr_);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -11195,15 +11209,17 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
lfs->cfg->fragment_size, lfs->cfg->fragment_size,
-1); -1);
err = lfsr_bshrub_commit(lfs, file, bid, LFSR_ATTRS( err = lfsr_bshrub_commit(lfs,
LFSR_ATTR_CAT( &file->o.mdir, &file->bshrub, bid, LFSR_ATTRS(
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA, LFSR_ATTR_CAT(
-(weight_ - lfs->cfg->fragment_size), LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA,
lfsr_data_truncate(left_slice_, -(weight_ - lfs->cfg->fragment_size),
lfs->cfg->fragment_size)), lfsr_data_truncate(left_slice_,
LFSR_ATTR( lfs->cfg->fragment_size)),
LFSR_TAG_BLOCK, +(weight_ - lfs->cfg->fragment_size), LFSR_ATTR(
LFSR_DATA_BPTR_(&bptr_, left.buf)))); LFSR_TAG_BLOCK,
+(weight_ - lfs->cfg->fragment_size),
LFSR_DATA_BPTR_(&bptr_, left.buf))));
if (err) { if (err) {
return err; return err;
} }
@@ -11223,16 +11239,17 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
-1, -1,
lfsr_data_size(bptr_.data) - lfs->cfg->fragment_size); lfsr_data_size(bptr_.data) - lfs->cfg->fragment_size);
err = lfsr_bshrub_commit(lfs, file, bid, LFSR_ATTRS( err = lfsr_bshrub_commit(lfs,
LFSR_ATTR( &file->o.mdir, &file->bshrub, bid, LFSR_ATTRS(
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK, LFSR_ATTR(
-(weight_ - lfsr_data_size(bptr_.data)), LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK,
LFSR_DATA_BPTR_(&bptr_, right.buf)), -(weight_ - lfsr_data_size(bptr_.data)),
LFSR_ATTR_CAT( LFSR_DATA_BPTR_(&bptr_, right.buf)),
LFSR_TAG_DATA, LFSR_ATTR_CAT(
+(weight_ - lfsr_data_size(bptr_.data)), LFSR_TAG_DATA,
lfsr_data_fruncate(right_slice_, +(weight_ - lfsr_data_size(bptr_.data)),
lfs->cfg->fragment_size)))); lfsr_data_fruncate(right_slice_,
lfs->cfg->fragment_size))));
if (err) { if (err) {
return err; return err;
} }
@@ -11287,7 +11304,8 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
LFS_ASSERT(lfsr_data_size(right_slice_) == 0); LFS_ASSERT(lfsr_data_size(right_slice_) == 0);
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
err = lfsr_bshrub_commit(lfs, file, bid, err = lfsr_bshrub_commit(lfs,
&file->o.mdir, &file->bshrub, bid,
attrs, attr_count); attrs, attr_count);
if (err) { if (err) {
return err; return err;
@@ -11369,7 +11387,8 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
if (attr_count > 0) { if (attr_count > 0) {
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
int err = lfsr_bshrub_commit(lfs, file, bid, int err = lfsr_bshrub_commit(lfs,
&file->o.mdir, &file->bshrub, bid,
attrs, attr_count); attrs, attr_count);
if (err) { if (err) {
return err; return err;
@@ -11410,7 +11429,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
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_bshrub_lookupnext(lfs, file, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub,
lfs_smax(pos - (lfs->cfg->crystal_thresh-1), 0), lfs_smax(pos - (lfs->cfg->crystal_thresh-1), 0),
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
@@ -11459,7 +11479,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
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_bshrub_lookupnext(lfs, file, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub,
lfs_min( lfs_min(
crystal_start + (lfs->cfg->crystal_thresh-1), crystal_start + (lfs->cfg->crystal_thresh-1),
lfsr_bshrub_size(&file->bshrub)-1), lfsr_bshrub_size(&file->bshrub)-1),
@@ -11504,7 +11525,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
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_bshrub_lookupnext(lfs, file, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub,
lfs_min( lfs_min(
crystal_start-1, crystal_start-1,
lfsr_bshrub_size(&file->bshrub)-1), lfsr_bshrub_size(&file->bshrub)-1),
@@ -11613,7 +11635,8 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
lfsr_tag_t tag_; lfsr_tag_t tag_;
lfsr_bid_t weight_; lfsr_bid_t weight_;
lfsr_bptr_t bptr_; lfsr_bptr_t bptr_;
int err = lfsr_bshrub_lookupnext(lfs, file, pos_, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub, pos_,
&bid_, &tag_, &weight_, &bptr_); &bid_, &tag_, &weight_, &bptr_);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -11758,7 +11781,8 @@ fragment:;
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_bid_t weight; lfsr_bid_t weight;
lfsr_bptr_t bptr; lfsr_bptr_t bptr;
int err = lfsr_bshrub_lookupnext(lfs, file, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub,
fragment_start-1, fragment_start-1,
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
@@ -11795,7 +11819,8 @@ fragment:;
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_bid_t weight; lfsr_bid_t weight;
lfsr_bptr_t bptr; lfsr_bptr_t bptr;
int err = lfsr_bshrub_lookupnext(lfs, file, int err = lfsr_bshrub_lookupnext(lfs,
&file->o.mdir, &file->bshrub,
fragment_end, fragment_end,
&bid, &tag, &weight, &bptr); &bid, &tag, &weight, &bptr);
if (err) { if (err) {
@@ -11885,7 +11910,7 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
if (pos_ < lfsr_bshrub_size(&file->bshrub)) { if (pos_ < lfsr_bshrub_size(&file->bshrub)) {
// 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_bshrub_readnext(lfs, file, lfs_ssize_t d_ = lfsr_file_readnext(lfs, file,
pos_, buffer_, d); pos_, buffer_, d);
if (d_ < 0) { if (d_ < 0) {
LFS_ASSERT(d_ != LFS_ERR_NOENT); LFS_ASSERT(d_ != LFS_ERR_NOENT);
@@ -11913,7 +11938,7 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file,
} }
// try to fill our buffer with some data // try to fill our buffer with some data
lfs_ssize_t d_ = lfsr_bshrub_readnext(lfs, file, lfs_ssize_t d_ = lfsr_file_readnext(lfs, file,
pos_, file->buffer.buffer, d); pos_, file->buffer.buffer, d);
if (d_ < 0) { if (d_ < 0) {
LFS_ASSERT(d != LFS_ERR_NOENT); LFS_ASSERT(d != LFS_ERR_NOENT);
@@ -12237,7 +12262,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
} else if (lfsr_bshrub_isbshrub(&file->o.mdir, &file->bshrub)) { } else if (lfsr_bshrub_isbshrub(&file->o.mdir, &file->bshrub)) {
attrs[attr_count++] = LFSR_ATTR_SHRUBTRUNK( attrs[attr_count++] = LFSR_ATTR_SHRUBTRUNK(
LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0, LFSR_TAG_SUB | LFSR_TAG_SHRUBTRUNK, 0,
&file->bshrub_.u.bshrub); &file->bshrub.u.bshrub);
// btree? // btree?
} else if (lfsr_bshrub_isbtree(&file->o.mdir, &file->bshrub)) { } else if (lfsr_bshrub_isbtree(&file->o.mdir, &file->bshrub)) {
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
@@ -12401,7 +12426,7 @@ int lfsr_file_truncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
file->buffer.pos = 0; file->buffer.pos = 0;
file->buffer.size = 0; file->buffer.size = 0;
lfs_ssize_t d = lfsr_bshrub_read(lfs, file, lfs_ssize_t d = lfsr_file_read_(lfs, file,
0, file->buffer.buffer, size_); 0, file->buffer.buffer, size_);
if (d < 0) { if (d < 0) {
err = d; err = d;
@@ -12508,7 +12533,7 @@ int lfsr_file_fruncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size_) {
file->buffer.pos = 0; file->buffer.pos = 0;
file->buffer.size = 0; file->buffer.size = 0;
lfs_ssize_t d = lfsr_bshrub_read(lfs, file, lfs_ssize_t d = lfsr_file_read_(lfs, file,
lfsr_bshrub_size(&file->bshrub) - lfs_min( lfsr_bshrub_size(&file->bshrub) - lfs_min(
size_, size_,
lfsr_bshrub_size(&file->bshrub)), lfsr_bshrub_size(&file->bshrub)),
+3 -7
View File
@@ -605,14 +605,10 @@ typedef struct lfsr_btraversal {
typedef struct lfsr_mtraversal { typedef struct lfsr_mtraversal {
// core state machine in o.state // core state machine in o.state
lfsr_omdir_t o; lfsr_omdir_t o;
// we really don't want to pay the RAM cost for a full file, // opened file state
// so only store the relevant bits, is this a hack? yes
const struct lfs_file_config *cfg;
lfsr_bshrub_t bshrub;
// opened file state, we use an indirect pointer here so we
// always point to data associated with the current mid
lfsr_omdir_t *ot; lfsr_omdir_t *ot;
// bshrub/btree state
lfsr_bshrub_t bshrub;
union { union {
// cycle detection state, only valid when traversing the mroot chain // cycle detection state, only valid when traversing the mroot chain
struct { struct {