Flipped btree/bshrub logic so commit__ implicitly finds rbyd

This does a few things:

- Deduplicates bshrub/btree rbyd lookups when rbyd is not explicitly
  provided -- note this is by far the most common case.

- Moves the mid-level rbyd allocation out of the stack-hot-path.

  Assuming lfsr_mtree_gc is never in the stack-hot-path, which seems
  unlikely.

- Reduces pointer chasing in lfsr_btree_commit__, giving the compiler
  more flexibility + assumptions and hopefully allowing it to optimize
  better.

  This may also be disentangling several cross-layer struct references,
  which is probably a good thing.

The result is rather significant stack savings for what is a minor
refactor:

           code          stack
  before: 35440           2800
  after:  35268 (-0.5%)   2680 (-4.3%)

This doesn't quite get us back to pre-commit_-rbyd levels, but it's
pretty close:

                                   code          stack
  before commit_-rbyd:            34652           2640
  commit_-rbyd-explicit (before): 35440 (+2.3%)   2800 (+6.1%)
  commit_-rbyd-implicit (after):  35268 (+1.8%)   2680 (+1.5%)
This commit is contained in:
Christopher Haster
2024-07-01 16:33:30 -05:00
parent e2ec25e511
commit 7f4384fa27
+147 -161
View File
@@ -4306,12 +4306,40 @@ typedef struct lfsr_bscratch {
// //
static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree, static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
lfsr_bscratch_t *bscratch, lfsr_bscratch_t *bscratch,
lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t *rid_, lfsr_bid_t *bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid,
const lfsr_attr_t **attrs_, lfs_size_t *attr_count_) { const lfsr_attr_t **attrs, lfs_size_t *attr_count) {
LFS_ASSERT(bid <= (lfsr_bid_t)btree->weight); lfsr_bid_t bid_ = *bid;
lfsr_srid_t rid = *rid_; LFS_ASSERT(bid_ <= (lfsr_bid_t)btree->weight);
const lfsr_attr_t *attrs = *attrs_; const lfsr_attr_t *attrs_ = *attrs;
lfs_size_t attr_count = *attr_count_; lfs_size_t attr_count_ = *attr_count;
// if rbyd is NULL, lookup which leaf our bid resides
//
// for lfsr_btree_commit operations to work out, we need to
// limit our bid to an rid in the tree, which is what this min
// is doing
lfsr_rbyd_t rbyd_;
lfsr_srid_t rid_;
if (!rbyd) {
rbyd_ = *btree;
rid_ = bid_;
if (btree->weight > 0) {
lfsr_srid_t rid__;
int err = lfsr_btree_lookupnext_(lfs, btree,
lfs_min(bid_, btree->weight-1),
&bid_, &rbyd_, &rid__, NULL, NULL, NULL);
if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT);
return err;
}
// adjust rid
rid_ -= (bid_-rid__);
}
} else {
rbyd_ = *rbyd;
rid_ = rid;
}
// tail-recursively commit to btree // tail-recursively commit to btree
while (true) { while (true) {
@@ -4319,16 +4347,16 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
lfsr_rbyd_t parent = {.trunk=0, .weight=0}; lfsr_rbyd_t parent = {.trunk=0, .weight=0};
lfsr_srid_t pid = 0; lfsr_srid_t pid = 0;
// are we root? // are we root?
if (rbyd->blocks[0] == btree->blocks[0] if (rbyd_.blocks[0] == btree->blocks[0]
|| !lfsr_rbyd_trunk(rbyd)) { || !lfsr_rbyd_trunk(&rbyd_)) {
// new root? shrub root? yield the final root commit to // new root? shrub root? yield the final root commit to
// higher-level btree/bshrub logic // higher-level btree/bshrub logic
if (!lfsr_rbyd_trunk(rbyd) if (!lfsr_rbyd_trunk(&rbyd_)
|| lfsr_rbyd_isshrub(btree)) { || lfsr_rbyd_isshrub(btree)) {
*rid_ = rid; *bid = rid_;
*attrs_ = attrs; *attrs = attrs_;
*attr_count_ = attr_count; *attr_count = attr_count_;
return (!lfsr_rbyd_trunk(rbyd)) ? LFS_ERR_RANGE : 0; return (!lfsr_rbyd_trunk(&rbyd_)) ? LFS_ERR_RANGE : 0;
} }
// mark btree as unerased in case of failure, our btree rbyd and // mark btree as unerased in case of failure, our btree rbyd and
@@ -4337,7 +4365,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
btree->eoff = -1; btree->eoff = -1;
} else { } else {
int err = lfsr_btree_parent(lfs, btree, bid, rbyd, int err = lfsr_btree_parent(lfs, btree, bid_, &rbyd_,
&parent, &pid); &parent, &pid);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -4352,10 +4380,10 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// unfetched // unfetched
// //
// a funny benefit is we cache the root of our btree this way // a funny benefit is we cache the root of our btree this way
if (!lfsr_rbyd_isfetched(rbyd)) { if (!lfsr_rbyd_isfetched(&rbyd_)) {
int err = lfsr_rbyd_fetchck(lfs, rbyd, int err = lfsr_rbyd_fetchck(lfs, &rbyd_,
rbyd->blocks[0], lfsr_rbyd_trunk(rbyd), rbyd_.blocks[0], lfsr_rbyd_trunk(&rbyd_),
rbyd->cksum); rbyd_.cksum);
if (err) { if (err) {
return err; return err;
} }
@@ -4364,9 +4392,9 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// is rbyd erased? can we sneak our commit into any remaining // is rbyd erased? can we sneak our commit into any remaining
// erased bytes? note that the btree trunk field prevents this from // erased bytes? note that the btree trunk field prevents this from
// interacting with other references to the rbyd // interacting with other references to the rbyd
lfsr_rbyd_t rbyd_ = *rbyd; lfsr_rbyd_t rbyd__ = rbyd_;
int err = lfsr_rbyd_commit(lfs, &rbyd_, rid, int err = lfsr_rbyd_commit(lfs, &rbyd__, rid_,
attrs, attr_count); attrs_, attr_count_);
if (err) { if (err) {
if (err == LFS_ERR_RANGE || err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_RANGE || err == LFS_ERR_CORRUPT) {
goto compact; goto compact;
@@ -4379,7 +4407,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
compact:; compact:;
// estimate our compacted size // estimate our compacted size
lfsr_srid_t split_rid; lfsr_srid_t split_rid;
lfs_ssize_t estimate = lfsr_rbyd_estimate(lfs, rbyd, -1, -1, lfs_ssize_t estimate = lfsr_rbyd_estimate(lfs, &rbyd_, -1, -1,
&split_rid); &split_rid);
if (estimate < 0) { if (estimate < 0) {
return estimate; return estimate;
@@ -4445,14 +4473,14 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
} }
// try the left sibling // try the left sibling
if (pid-(lfsr_srid_t)rbyd->weight >= 0) { if (pid-(lfsr_srid_t)rbyd_.weight >= 0) {
// try looking up the sibling // try looking up the sibling
lfsr_srid_t sibling_rid; lfsr_srid_t sibling_rid;
lfsr_tag_t sibling_tag; lfsr_tag_t sibling_tag;
lfsr_rid_t sibling_weight; lfsr_rid_t sibling_weight;
lfsr_data_t sibling_data; lfsr_data_t sibling_data;
err = lfsr_rbyd_lookupnext(lfs, &parent, err = lfsr_rbyd_lookupnext(lfs, &parent,
pid-rbyd->weight, LFSR_TAG_NAME, pid-rbyd_.weight, LFSR_TAG_NAME,
&sibling_rid, &sibling_tag, &sibling_weight, &sibling_rid, &sibling_tag, &sibling_weight,
&sibling_data); &sibling_data);
if (err) { if (err) {
@@ -4490,13 +4518,13 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
< lfs->cfg->block_size/2) { < lfs->cfg->block_size/2) {
// if we're merging our left sibling, swap our rbyds // if we're merging our left sibling, swap our rbyds
// so our sibling is on the right // so our sibling is on the right
bid -= sibling.weight; bid_ -= sibling.weight;
rid += sibling.weight; rid_ += sibling.weight;
pid -= rbyd->weight; pid -= rbyd_.weight;
rbyd_ = sibling; rbyd__ = sibling;
sibling = *rbyd; sibling = rbyd_;
*rbyd = rbyd_; rbyd_ = rbyd__;
goto merge; goto merge;
} }
@@ -4505,13 +4533,13 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
compact_relocate:; compact_relocate:;
// allocate a new rbyd // allocate a new rbyd
err = lfsr_rbyd_alloc(lfs, &rbyd_); err = lfsr_rbyd_alloc(lfs, &rbyd__);
if (err) { if (err) {
return err; return err;
} }
// try to compact // try to compact
err = lfsr_rbyd_compact(lfs, &rbyd_, rbyd, -1, -1); err = lfsr_rbyd_compact(lfs, &rbyd__, &rbyd_, -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
@@ -4523,8 +4551,8 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// append any pending attrs, it's up to upper // append any pending attrs, it's up to upper
// layers to make sure these always fit // layers to make sure these always fit
err = lfsr_rbyd_commit(lfs, &rbyd_, rid, err = lfsr_rbyd_commit(lfs, &rbyd__, rid_,
attrs, attr_count); attrs_, attr_count_);
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
@@ -4539,17 +4567,17 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
split:; split:;
// we should have something to split here // we should have something to split here
LFS_ASSERT(split_rid > 0 LFS_ASSERT(split_rid > 0
&& split_rid < (lfsr_srid_t)rbyd->weight); && split_rid < (lfsr_srid_t)rbyd_.weight);
split_relocate_l:; split_relocate_l:;
// allocate a new rbyd // allocate a new rbyd
err = lfsr_rbyd_alloc(lfs, &rbyd_); err = lfsr_rbyd_alloc(lfs, &rbyd__);
if (err) { if (err) {
return err; return err;
} }
// copy over tags < split_rid // copy over tags < split_rid
err = lfsr_rbyd_compact(lfs, &rbyd_, rbyd, -1, split_rid); err = lfsr_rbyd_compact(lfs, &rbyd__, &rbyd_, -1, split_rid);
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
@@ -4563,8 +4591,8 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// //
// upper layers should make sure this can't fail by limiting the // upper layers should make sure this can't fail by limiting the
// maximum commit size // maximum commit size
err = lfsr_rbyd_appendattrs(lfs, &rbyd_, rid, -1, split_rid, err = lfsr_rbyd_appendattrs(lfs, &rbyd__, rid_, -1, split_rid,
attrs, attr_count); attrs_, attr_count_);
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
@@ -4575,7 +4603,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
} }
// finalize commit // finalize commit
err = lfsr_rbyd_appendcksum(lfs, &rbyd_); err = lfsr_rbyd_appendcksum(lfs, &rbyd__);
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
@@ -4593,7 +4621,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
} }
// copy over tags >= split_rid // copy over tags >= split_rid
err = lfsr_rbyd_compact(lfs, &sibling, rbyd, split_rid, -1); err = lfsr_rbyd_compact(lfs, &sibling, &rbyd_, split_rid, -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
@@ -4607,8 +4635,8 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// //
// upper layers should make sure this can't fail by limiting the // upper layers should make sure this can't fail by limiting the
// maximum commit size // maximum commit size
err = lfsr_rbyd_appendattrs(lfs, &sibling, rid, split_rid, -1, err = lfsr_rbyd_appendattrs(lfs, &sibling, rid_, split_rid, -1,
attrs, attr_count); attrs_, attr_count_);
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
@@ -4631,9 +4659,9 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// did one of our siblings drop to zero? yes this can happen! revert // did one of our siblings drop to zero? yes this can happen! revert
// to a normal commit in that case // to a normal commit in that case
if (rbyd_.weight == 0 || sibling.weight == 0) { if (rbyd__.weight == 0 || sibling.weight == 0) {
if (rbyd_.weight == 0) { if (rbyd__.weight == 0) {
rbyd_ = sibling; rbyd__ = sibling;
} }
goto recurse; goto recurse;
} }
@@ -4651,66 +4679,66 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
} }
// prepare commit to parent, tail recursing upwards // prepare commit to parent, tail recursing upwards
LFS_ASSERT(rbyd_.weight > 0); LFS_ASSERT(rbyd__.weight > 0);
LFS_ASSERT(sibling.weight > 0); LFS_ASSERT(sibling.weight > 0);
attr_count = 0; attr_count_ = 0;
// new root? // new root?
if (!lfsr_rbyd_trunk(&parent)) { if (!lfsr_rbyd_trunk(&parent)) {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +rbyd_.weight, LFSR_TAG_BRANCH, +rbyd__.weight,
LFSR_DATA_BRANCH_( LFSR_DATA_BRANCH_(
&rbyd_, &rbyd__,
&bscratch->buf[0*LFSR_BRANCH_DSIZE])); &bscratch->buf[0*LFSR_BRANCH_DSIZE]));
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +sibling.weight, LFSR_TAG_BRANCH, +sibling.weight,
LFSR_DATA_BRANCH_( LFSR_DATA_BRANCH_(
&sibling, &sibling,
&bscratch->buf[1*LFSR_BRANCH_DSIZE])); &bscratch->buf[1*LFSR_BRANCH_DSIZE]));
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) { if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
bscratch->attrs[attr_count++] = LFSR_ATTR_CAT_( bscratch->attrs[attr_count_++] = LFSR_ATTR_CAT_(
LFSR_TAG_NAME, 0, LFSR_TAG_NAME, 0,
&bscratch->split_data, 1); &bscratch->split_data, 1);
} }
// split root? // split root?
} else { } else {
bid -= pid - (rbyd->weight-1); bid_ -= pid - (rbyd_.weight-1);
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
LFSR_DATA_BRANCH_( LFSR_DATA_BRANCH_(
&rbyd_, &rbyd__,
&bscratch->buf[0*LFSR_BRANCH_DSIZE])); &bscratch->buf[0*LFSR_BRANCH_DSIZE]));
if (rbyd_.weight != rbyd->weight) { if (rbyd__.weight != rbyd_.weight) {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd->weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd_.weight + rbyd__.weight,
LFSR_DATA_NULL()); LFSR_DATA_NULL());
} }
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +sibling.weight, LFSR_TAG_BRANCH, +sibling.weight,
LFSR_DATA_BRANCH_( LFSR_DATA_BRANCH_(
&sibling, &sibling,
&bscratch->buf[1*LFSR_BRANCH_DSIZE])); &bscratch->buf[1*LFSR_BRANCH_DSIZE]));
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) { if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
bscratch->attrs[attr_count++] = LFSR_ATTR_CAT_( bscratch->attrs[attr_count_++] = LFSR_ATTR_CAT_(
LFSR_TAG_NAME, 0, LFSR_TAG_NAME, 0,
&bscratch->split_data, 1); &bscratch->split_data, 1);
} }
} }
attrs = bscratch->attrs; attrs_ = bscratch->attrs;
*rbyd = parent; rbyd_ = parent;
rid = pid; rid_ = pid;
continue; continue;
merge:; merge:;
merge_relocate:; merge_relocate:;
// allocate a new rbyd // allocate a new rbyd
err = lfsr_rbyd_alloc(lfs, &rbyd_); err = lfsr_rbyd_alloc(lfs, &rbyd__);
if (err) { if (err) {
return err; return err;
} }
// merge the siblings together // merge the siblings together
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, rbyd, -1, -1); err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd__, &rbyd_, -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
@@ -4720,7 +4748,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
return err; return err;
} }
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, &sibling, -1, -1); err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd__, &sibling, -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
@@ -4730,7 +4758,7 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
return err; return err;
} }
err = lfsr_rbyd_appendcompaction(lfs, &rbyd_, 0); err = lfsr_rbyd_appendcompaction(lfs, &rbyd__, 0);
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
@@ -4742,8 +4770,8 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// append any pending attrs, it's up to upper // append any pending attrs, it's up to upper
// layers to make sure these always fit // layers to make sure these always fit
err = lfsr_rbyd_commit(lfs, &rbyd_, rid, err = lfsr_rbyd_commit(lfs, &rbyd__, rid_,
attrs, attr_count); attrs_, attr_count_);
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
@@ -4756,46 +4784,46 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// we must have a parent at this point, but is our parent the root // we must have a parent at this point, but is our parent the root
// and is the root degenerate? // and is the root degenerate?
LFS_ASSERT(lfsr_rbyd_trunk(&parent)); LFS_ASSERT(lfsr_rbyd_trunk(&parent));
if (rbyd->weight+sibling.weight == btree->weight) { if (rbyd_.weight+sibling.weight == btree->weight) {
// collapse the root, decreasing the height of the tree // collapse the root, decreasing the height of the tree
*btree = rbyd_; *btree = rbyd__;
*attr_count_ = 0; *attr_count = 0;
return 0; return 0;
} }
// prepare commit to parent, tail recursing upwards // prepare commit to parent, tail recursing upwards
LFS_ASSERT(rbyd_.weight > 0); LFS_ASSERT(rbyd__.weight > 0);
attr_count = 0; attr_count_ = 0;
bid -= pid - (rbyd->weight-1); bid_ -= pid - (rbyd_.weight-1);
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_RM, -sibling.weight, LFSR_DATA_NULL()); LFSR_TAG_RM, -sibling.weight, LFSR_DATA_NULL());
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
LFSR_DATA_BRANCH_(&rbyd_, bscratch->buf)); LFSR_DATA_BRANCH_(&rbyd__, bscratch->buf));
if (rbyd_.weight != rbyd->weight) { if (rbyd__.weight != rbyd_.weight) {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd->weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd_.weight + rbyd__.weight,
LFSR_DATA_NULL()); LFSR_DATA_NULL());
} }
attrs = bscratch->attrs; attrs_ = bscratch->attrs;
*rbyd = parent; rbyd_ = parent;
rid = pid + sibling.weight; rid_ = pid + sibling.weight;
continue; continue;
recurse:; recurse:;
// done? // done?
if (!lfsr_rbyd_trunk(&parent)) { if (!lfsr_rbyd_trunk(&parent)) {
*btree = rbyd_; *btree = rbyd__;
*attr_count_ = 0; *attr_count = 0;
return 0; return 0;
} }
// is our parent the root and is the root degenerate? // is our parent the root and is the root degenerate?
if (rbyd->weight == btree->weight) { if (rbyd_.weight == btree->weight) {
// collapse the root, decreasing the height of the tree // collapse the root, decreasing the height of the tree
*btree = rbyd_; *btree = rbyd__;
*attr_count_ = 0; *attr_count = 0;
return 0; return 0;
} }
@@ -4803,36 +4831,37 @@ static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
// //
// note that since we defer merges to compaction time, we can // note that since we defer merges to compaction time, we can
// end up removing an rbyd here // end up removing an rbyd here
attr_count = 0; attr_count_ = 0;
bid -= pid - (rbyd->weight-1); bid_ -= pid - (rbyd_.weight-1);
if (rbyd_.weight == 0) { if (rbyd__.weight == 0) {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_RM, -rbyd->weight, LFSR_DATA_NULL()); LFSR_TAG_RM, -rbyd_.weight, LFSR_DATA_NULL());
} else { } else {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
LFSR_DATA_BRANCH_(&rbyd_, bscratch->buf)); LFSR_DATA_BRANCH_(&rbyd__, bscratch->buf));
if (rbyd_.weight != rbyd->weight) { if (rbyd__.weight != rbyd_.weight) {
bscratch->attrs[attr_count++] = LFSR_ATTR( bscratch->attrs[attr_count_++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd->weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd_.weight + rbyd__.weight,
LFSR_DATA_NULL()); LFSR_DATA_NULL());
} }
} }
attrs = bscratch->attrs; attrs_ = bscratch->attrs;
*rbyd = parent; rbyd_ = parent;
rid = pid; rid_ = pid;
continue; continue;
} }
} }
// commit to btree with optional rbyd
static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree, static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid, lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid,
const lfsr_attr_t *attrs, lfs_size_t attr_count) { const lfsr_attr_t *attrs, lfs_size_t attr_count) {
// 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, btree, &bscratch, int err = lfsr_btree_commit__(lfs, btree, &bscratch,
bid, rbyd, &rid, &attrs, &attr_count); &bid, rbyd, rid, &attrs, &attr_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
} }
@@ -4842,12 +4871,13 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
LFS_ASSERT(attr_count > 0); LFS_ASSERT(attr_count > 0);
relocate:; relocate:;
err = lfsr_rbyd_alloc(lfs, rbyd); lfsr_rbyd_t rbyd_;
err = lfsr_rbyd_alloc(lfs, &rbyd_);
if (err) { if (err) {
return err; return err;
} }
err = lfsr_rbyd_commit(lfs, rbyd, rid, attrs, attr_count); err = lfsr_rbyd_commit(lfs, &rbyd_, bid, attrs, attr_count);
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
@@ -4857,7 +4887,7 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
return err; return err;
} }
*btree = *rbyd; *btree = rbyd_;
} }
LFS_ASSERT(lfsr_rbyd_trunk(btree)); LFS_ASSERT(lfsr_rbyd_trunk(btree));
@@ -4876,28 +4906,7 @@ static int lfsr_btree_compact_(lfs_t *lfs, lfsr_btree_t *btree,
// commit to a btree, this is atomic // commit to a btree, this is atomic
static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
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) {
// lookup in which leaf our bids resides return lfsr_btree_commit_(lfs, btree, bid, NULL, -1,
//
// for lfsr_btree_commit operations to work out, we need to
// limit our bid to an rid in the tree, which is what this min
// is doing
lfsr_rbyd_t rbyd = *btree;
lfsr_srid_t rid = bid;
if (btree->weight > 0) {
lfsr_srid_t rid_;
int err = lfsr_btree_lookupnext_(lfs, btree,
lfs_min(bid, btree->weight-1),
&bid, &rbyd, &rid_, NULL, NULL, NULL);
if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT);
return err;
}
// adjust rid
rid -= (bid-rid_);
}
return lfsr_btree_commit_(lfs, btree, bid, &rbyd, rid,
attrs, attr_count); attrs, attr_count);
} }
@@ -5624,6 +5633,7 @@ static int lfsr_bshrub_traverse(lfs_t *lfs,
static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
const lfsr_attr_t *attrs, lfs_size_t attr_count); const lfsr_attr_t *attrs, lfs_size_t attr_count);
// commit to bshrub with optional rbyd
static int lfsr_bshrub_commit_(lfs_t *lfs, static int lfsr_bshrub_commit_(lfs_t *lfs,
lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub, lfsr_mdir_t *mdir, lfsr_bshrub_t *bshrub,
lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid, lfsr_bid_t bid, lfsr_rbyd_t *rbyd, lfsr_srid_t rid,
@@ -5652,7 +5662,7 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
// 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->u.btree, &bscratch,
bid, rbyd, &rid, &attrs, &attr_count); &bid, rbyd, rid, &attrs, &attr_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
} }
@@ -5717,7 +5727,7 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
int err = lfsr_mdir_commit(lfs, 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,
&bshrub->u.bshrub, rid, attrs, attr_count))); &bshrub->u.bshrub, bid, attrs, attr_count)));
if (err) { if (err) {
return err; return err;
} }
@@ -5743,15 +5753,15 @@ static int lfsr_bshrub_commit_(lfs_t *lfs,
relocate:; relocate:;
// convert to btree // convert to btree
err = lfsr_rbyd_alloc(lfs, rbyd); lfsr_rbyd_t rbyd_;
err = lfsr_rbyd_alloc(lfs, &rbyd_);
if (err) { if (err) {
return err; return err;
} }
// 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_, &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
@@ -5762,8 +5772,7 @@ relocate:;
} }
} }
err = lfsr_rbyd_commit(lfs, rbyd, rid, err = lfsr_rbyd_commit(lfs, &rbyd_, bid, attrs, attr_count);
attrs, attr_count);
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
@@ -5773,7 +5782,7 @@ relocate:;
return err; return err;
} }
bshrub->u.btree = *rbyd; bshrub->u.btree = rbyd_;
return 0; return 0;
} }
@@ -5793,30 +5802,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs,
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(bshrub)); LFS_ASSERT(lfsr_bshrub_isbshruborbtree(bshrub));
return lfsr_bshrub_commit_(lfs, mdir, bshrub, bid, NULL, -1,
// TODO can we dedup the lookup logic?
// lookup in which leaf our bids resides
//
// for lfsr_btree_commit operations to work out, we need to
// limit our bid to an rid in the tree, which is what this min
// is doing
lfsr_rbyd_t rbyd = bshrub->u.btree;
lfsr_srid_t rid = bid;
if (bshrub->u.btree.weight > 0) {
lfsr_srid_t rid_;
int err = lfsr_btree_lookupnext_(lfs, &bshrub->u.btree,
lfs_min(bid, bshrub->u.btree.weight-1),
&bid, &rbyd, &rid_, NULL, NULL, NULL);
if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT);
return err;
}
// adjust rid
rid -= (bid-rid_);
}
return lfsr_bshrub_commit_(lfs, mdir, bshrub, bid, &rbyd, rid,
attrs, attr_count); attrs, attr_count);
} }