Unrolled the sibling estimate loop in btree merge
This simplifies control flow at a code cost. Unrolling for now as it
avoids all of the iteration derived special handling (which obscures the
underlying logic) and it may be possible to recoup the code cost through
more shared branch utility functions.
code stack
before: 20650 1712
after: 20742 (+0.4%) 1712 (+0.0%)
May revert in the future.
This commit is contained in:
@@ -3952,40 +3952,21 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
if ((lfs_size_t)estimate <= lfs->cfg->block_size/4
|
if ((lfs_size_t)estimate <= lfs->cfg->block_size/4
|
||||||
// no parent? can't merge
|
// no parent? can't merge
|
||||||
&& rid != -1) {
|
&& rid != -1) {
|
||||||
for (uint8_t i = 0; i < 2; i++) {
|
// try the right sibling
|
||||||
lfs_ssize_t sibling_rid;
|
if (rid+1 < (lfs_ssize_t)parent.weight) {
|
||||||
// try the right sibling
|
|
||||||
if (i == 0) {
|
|
||||||
sibling_rid = rid+1;
|
|
||||||
// no right sibling? can't merge
|
|
||||||
if (sibling_rid >= (lfs_ssize_t)parent.weight) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try the left sibling
|
|
||||||
} else {
|
|
||||||
sibling_rid = rid-rbyd.weight;
|
|
||||||
// no left sibling? can't merge
|
|
||||||
if (sibling_rid < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try looking up the sibling
|
// try looking up the sibling
|
||||||
// TODO do we really need to fetch sibling_weight if we get
|
// TODO do we really need to fetch sibling_weight if we get
|
||||||
// it in our btree struct?
|
// it in our btree struct?
|
||||||
|
lfs_ssize_t sibling_rid;
|
||||||
lfsr_tag_t sibling_tag;
|
lfsr_tag_t sibling_tag;
|
||||||
lfs_size_t sibling_weight;
|
lfs_size_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,
|
||||||
sibling_rid, LFSR_TAG_NAME,
|
rid+1, LFSR_TAG_NAME,
|
||||||
&sibling_rid, &sibling_tag, &sibling_weight,
|
&sibling_rid, &sibling_tag, &sibling_weight,
|
||||||
&sibling_data);
|
&sibling_data);
|
||||||
if (err) {
|
if (err) {
|
||||||
// no sibling? can't merge
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
if (err == LFS_ERR_NOENT) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4011,22 +3992,71 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
&sibling, -1, -1,
|
&sibling, -1, -1,
|
||||||
NULL);
|
NULL);
|
||||||
if (sibling_estimate < 0) {
|
if (sibling_estimate < 0) {
|
||||||
return estimate;
|
return sibling_estimate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fits? try to merge
|
// fits? try to merge
|
||||||
if ((lfs_size_t)(estimate + sibling_estimate)
|
if ((lfs_size_t)(estimate + sibling_estimate)
|
||||||
< lfs->cfg->block_size/2) {
|
< lfs->cfg->block_size/2) {
|
||||||
if (i == 1) {
|
goto merge;
|
||||||
// if we're merging our left sibling, swap our rbyds
|
}
|
||||||
// so our sibling is on the right
|
}
|
||||||
bid -= sibling.weight;
|
|
||||||
rid -= rbyd.weight;
|
|
||||||
|
|
||||||
rbyd_ = sibling;
|
// try the left sibling
|
||||||
sibling = rbyd;
|
if (rid-(lfs_ssize_t)rbyd.weight >= 0) {
|
||||||
rbyd = rbyd_;
|
// try looking up the sibling
|
||||||
|
// TODO do we really need to fetch sibling_weight if we get
|
||||||
|
// it in our btree struct?
|
||||||
|
lfs_ssize_t sibling_rid;
|
||||||
|
lfsr_tag_t sibling_tag;
|
||||||
|
lfs_size_t sibling_weight;
|
||||||
|
lfsr_data_t sibling_data;
|
||||||
|
err = lfsr_rbyd_lookupnext(lfs, &parent,
|
||||||
|
rid-rbyd.weight, LFSR_TAG_NAME,
|
||||||
|
&sibling_rid, &sibling_tag, &sibling_weight,
|
||||||
|
&sibling_data);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sibling_tag == LFSR_TAG_NAME) {
|
||||||
|
err = lfsr_rbyd_lookup(lfs, &parent,
|
||||||
|
sibling_rid, LFSR_TAG_WIDE(STRUCT),
|
||||||
|
&sibling_tag, &sibling_data);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LFS_ASSERT(sibling_tag == LFSR_TAG_BRANCH);
|
||||||
|
err = lfsr_data_readbranch(lfs, &sibling_data, sibling_weight,
|
||||||
|
&sibling);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// estimate if our sibling will fit
|
||||||
|
lfs_ssize_t sibling_estimate = lfsr_rbyd_estimate(lfs,
|
||||||
|
&sibling, -1, -1,
|
||||||
|
NULL);
|
||||||
|
if (sibling_estimate < 0) {
|
||||||
|
return sibling_estimate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fits? try to merge
|
||||||
|
if ((lfs_size_t)(estimate + sibling_estimate)
|
||||||
|
< lfs->cfg->block_size/2) {
|
||||||
|
// if we're merging our left sibling, swap our rbyds
|
||||||
|
// so our sibling is on the right
|
||||||
|
bid -= sibling.weight;
|
||||||
|
rid -= rbyd.weight;
|
||||||
|
|
||||||
|
rbyd_ = sibling;
|
||||||
|
sibling = rbyd;
|
||||||
|
rbyd = rbyd_;
|
||||||
|
|
||||||
goto merge;
|
goto merge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user