rbyd: Simplified diverged stitching, fixed unexpected balance issue
Found with LFS_ASSERTRBYDBALANCE, the way we were introducing a new alt
to stitch together diverged trunks was preventing unreachable diverged
trunks from being pruned.
This isn't a hard error, since we end up appending a null tag to
terminate the tree, but like our compaction balance issue, the
terminating null tag leads to balance issues down the road:
.---> a .---> a
.---r-b-> b .---r-b-> b
| .---> c | .---> c
.---r-b-r-b-> d .---r-b-r-b-> d
| .---b---b-> e .---y-r---b---b-> e
r-b---------> null => | .-------------> f
| | .-----------> g
| | | .---------> h
b-y-r-b---------> i
'--------.--------'
unbalanced :(
Fortunately, after fiddling around with the algorithm a bit, it turns
out we don't really need a special case for the stitching alt as long as
we adjust the weight a bit.
This allows pruning of the stitching alt and avoids this unexpected
balance issue, while also simplifying how we stitch diverged trunks. Win
win.
Goes to show LFS_ASSERTRBYDBALANCE will probably be quite a valuable
assertion, assuming the remaining balance issues are solvable.
---
Test changes, this gets at least all non-weighted/non-range test_rbyd
tests passing with balance asserts:
test_rbyd+balance before: 351/385878 failed
test_rbyd+balance after: 306/385878 failed (-12.8%)
Ran with:
$ DEBUG=1 \
TESTS=tests/test_rbyd.toml \
CFLAGS=-DLFS_ASSERTRBYDBALANCE \
make test-runner -j \
&& ./scripts/test.py -j -B -k
While even saving code:
code stack ctx
before: 38440 2624 640
after: 38408 (-0.1%) 2624 (+0.0%) 640 (+0.0%)
---
Also please excuse the mess, this is going to be a rough series of
commits...
This commit is contained in:
@@ -2956,6 +2956,7 @@ static int lfsr_rbyd_fetch_(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// all branches should have the same height
|
// all branches should have the same height
|
||||||
|
LFS_DEBUG("%d 0x%04x: height %d", rid, tag, height_);
|
||||||
if (height != -1) {
|
if (height != -1) {
|
||||||
LFS_ASSERT(height_ == height);
|
LFS_ASSERT(height_ == height);
|
||||||
}
|
}
|
||||||
@@ -3512,6 +3513,8 @@ static int lfsr_rbyd_appendrat(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
|||||||
//
|
//
|
||||||
bool diverged = false;
|
bool diverged = false;
|
||||||
lfsr_srid_t d_rid = 0;
|
lfsr_srid_t d_rid = 0;
|
||||||
|
lfsr_srid_t d_upper_rid = rbyd->weight;
|
||||||
|
lfsr_srid_t d_weight = 0;
|
||||||
lfsr_tag_t d_tag = 0;
|
lfsr_tag_t d_tag = 0;
|
||||||
|
|
||||||
// follow the current trunk
|
// follow the current trunk
|
||||||
@@ -3638,8 +3641,11 @@ trunk:;
|
|||||||
// give up if we find a yellow alt
|
// give up if we find a yellow alt
|
||||||
|| lfsr_tag_isred(p[0].alt))
|
|| lfsr_tag_isred(p[0].alt))
|
||||||
&& (diverging || diverging_red)) {
|
&& (diverging || diverging_red)) {
|
||||||
|
LFS_DEBUG("%04x->%04x: diverging",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
diverged = true;
|
diverged = true;
|
||||||
|
|
||||||
|
// TODO need this? does this ever get triggered?
|
||||||
// both diverging? collapse
|
// both diverging? collapse
|
||||||
// <r >b
|
// <r >b
|
||||||
// .----'| .-'|
|
// .----'| .-'|
|
||||||
@@ -3647,6 +3653,8 @@ trunk:;
|
|||||||
// | .-'| .-----|--'
|
// | .-'| .-----|--'
|
||||||
// 1 2 3 1 2 3 x
|
// 1 2 3 1 2 3 x
|
||||||
if (diverging && diverging_red) {
|
if (diverging && diverging_red) {
|
||||||
|
LFS_DEBUG("%04x->%04x: both diverging",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
LFS_ASSERT(a_rid < b_rid || a_tag < b_tag);
|
LFS_ASSERT(a_rid < b_rid || a_tag < b_tag);
|
||||||
LFS_ASSERT(lfsr_tag_isparallel(alt, p[0].alt));
|
LFS_ASSERT(lfsr_tag_isparallel(alt, p[0].alt));
|
||||||
|
|
||||||
@@ -3664,24 +3672,61 @@ trunk:;
|
|||||||
// | .-'| | .-----'
|
// | .-'| | .-----'
|
||||||
// 1 2 3 4 x 1 2 3 4 x x
|
// 1 2 3 4 x 1 2 3 4 x x
|
||||||
if (a_rid > b_rid || a_tag > b_tag) {
|
if (a_rid > b_rid || a_tag > b_tag) {
|
||||||
lfsr_tag_trim2(
|
LFS_DEBUG("%04x->%04x: stitching %d ((%d, %d), (%d, %d)) "
|
||||||
alt, weight,
|
"%04x %04x",
|
||||||
p[0].alt, p[0].weight,
|
branch, lfsr_rbyd_eoff(rbyd),
|
||||||
&lower_rid, &upper_rid,
|
d_rid - lower_rid,
|
||||||
&lower_tag, &upper_tag);
|
d_rid, d_upper_rid,
|
||||||
|
lower_rid, upper_rid,
|
||||||
|
alt, d_tag);
|
||||||
|
|
||||||
|
// TODO is this uh, how much of this is already in
|
||||||
|
// the diverging alt?
|
||||||
|
|
||||||
// stitch together both trunks
|
// stitch together both trunks
|
||||||
err = lfsr_rbyd_p_push(lfs, rbyd, p,
|
lfsr_srid_t weight_ = weight;
|
||||||
LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_LE, d_tag),
|
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_LE, d_tag);
|
||||||
d_rid - (lower_rid - weight),
|
//weight = (d_rid - lower_rid) - lfs_smax(-rat.weight, 0);
|
||||||
jump);
|
//weight = d_rid - lower_rid;
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue to next alt
|
lfsr_srid_t delta =
|
||||||
branch = branch_;
|
lfs_smax(-rat.weight, d_upper_rid - d_rid);
|
||||||
continue;
|
// lfs_smax(-rat.weight, 0)
|
||||||
|
// + (d_upper_rid - d_rid);
|
||||||
|
// (lfs_smax(-rat.weight, 0) > 0)
|
||||||
|
// ? lfs_smax(-rat.weight, 0)
|
||||||
|
// : (d_upper_rid - d_rid);
|
||||||
|
|
||||||
|
// + lfs_smax(-rat.weight, 0);
|
||||||
|
// + (weight - (d_rid - lower_rid));
|
||||||
|
|
||||||
|
// weight = weight
|
||||||
|
// - lfs_smax(-rat.weight, 0)
|
||||||
|
// - (weight - (d_rid - lower_rid));
|
||||||
|
weight -= delta;
|
||||||
|
branch = jump;
|
||||||
|
|
||||||
|
// lower_rid += lfs_smax(-rat.weight, 0);
|
||||||
|
lower_rid += delta;
|
||||||
|
|
||||||
|
// lfsr_tag_trim2(
|
||||||
|
// alt, weight,
|
||||||
|
// p[0].alt, p[0].weight,
|
||||||
|
// &lower_rid, &upper_rid,
|
||||||
|
// &lower_tag, &upper_tag);
|
||||||
|
//
|
||||||
|
// // stitch together both trunks
|
||||||
|
// err = lfsr_rbyd_p_push(lfs, rbyd, p,
|
||||||
|
// LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_LE, d_tag),
|
||||||
|
// d_rid - (lower_rid - weight),
|
||||||
|
// jump);
|
||||||
|
// if (err) {
|
||||||
|
// return err;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // continue to next alt
|
||||||
|
// branch = branch_;
|
||||||
|
// continue;
|
||||||
}
|
}
|
||||||
// diverged?
|
// diverged?
|
||||||
// : :
|
// : :
|
||||||
@@ -3689,6 +3734,8 @@ trunk:;
|
|||||||
// .-'| .--'
|
// .-'| .--'
|
||||||
// 3 4 3 4 x
|
// 3 4 3 4 x
|
||||||
} else if (diverged && diverging) {
|
} else if (diverged && diverging) {
|
||||||
|
LFS_DEBUG("%04x->%04x: div pruning",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
// trim so alt is pruned
|
// trim so alt is pruned
|
||||||
lfsr_tag_trim(
|
lfsr_tag_trim(
|
||||||
alt, weight,
|
alt, weight,
|
||||||
@@ -3774,7 +3821,9 @@ trunk:;
|
|||||||
(diverged && !(a_rid < b_rid || a_tag < b_tag))
|
(diverged && !(a_rid < b_rid || a_tag < b_tag))
|
||||||
? d_tag
|
? d_tag
|
||||||
: lower_tag);
|
: lower_tag);
|
||||||
|
// TODO hmmmmm?
|
||||||
LFS_ASSERT(weight == 0);
|
LFS_ASSERT(weight == 0);
|
||||||
|
//weight = 0;
|
||||||
// we don't need to, but setting jump=0 asserts this
|
// we don't need to, but setting jump=0 asserts this
|
||||||
// alt is unreachable while also minimizing the the
|
// alt is unreachable while also minimizing the the
|
||||||
// encoding
|
// encoding
|
||||||
@@ -3885,6 +3934,9 @@ trunk:;
|
|||||||
// keep track of the lower diverged bound
|
// keep track of the lower diverged bound
|
||||||
d_rid = lower_rid;
|
d_rid = lower_rid;
|
||||||
d_tag = lower_tag;
|
d_tag = lower_tag;
|
||||||
|
// TODO need this?
|
||||||
|
d_upper_rid = upper_rid;
|
||||||
|
d_weight = upper_rid - lower_rid;
|
||||||
|
|
||||||
// flush any pending alts
|
// flush any pending alts
|
||||||
err = lfsr_rbyd_p_flush(lfs, rbyd, p, 3);
|
err = lfsr_rbyd_p_flush(lfs, rbyd, p, 3);
|
||||||
@@ -3951,11 +4003,15 @@ stem:;
|
|||||||
&& lfsr_tag_key(tag_)
|
&& lfsr_tag_key(tag_)
|
||||||
< lfsr_tag_key(rat.tag)))))) {
|
< lfsr_tag_key(rat.tag)))))) {
|
||||||
if (lfsr_tag_isrm(rat.tag) || !lfsr_tag_key(rat.tag)) {
|
if (lfsr_tag_isrm(rat.tag) || !lfsr_tag_key(rat.tag)) {
|
||||||
|
LFS_DEBUG("%04x->%04x: leaf unr lt",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
// if removed, make our tag unreachable
|
// if removed, make our tag unreachable
|
||||||
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, lower_tag);
|
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, lower_tag);
|
||||||
weight = upper_rid - lower_rid + rat.weight;
|
weight = upper_rid - lower_rid + rat.weight;
|
||||||
upper_rid -= weight;
|
upper_rid -= weight;
|
||||||
} else {
|
} else {
|
||||||
|
LFS_DEBUG("%04x->%04x: leaf split lt",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
// split less than
|
// split less than
|
||||||
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_LE, tag_);
|
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_LE, tag_);
|
||||||
weight = upper_rid - lower_rid;
|
weight = upper_rid - lower_rid;
|
||||||
@@ -3974,11 +4030,15 @@ stem:;
|
|||||||
&& lfsr_tag_key(tag_)
|
&& lfsr_tag_key(tag_)
|
||||||
> lfsr_tag_key(rat.tag)))))) {
|
> lfsr_tag_key(rat.tag)))))) {
|
||||||
if (lfsr_tag_isrm(rat.tag) || !lfsr_tag_key(rat.tag)) {
|
if (lfsr_tag_isrm(rat.tag) || !lfsr_tag_key(rat.tag)) {
|
||||||
|
LFS_DEBUG("%04x->%04x: leaf unr gt",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
// if removed, make our tag unreachable
|
// if removed, make our tag unreachable
|
||||||
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, lower_tag);
|
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, lower_tag);
|
||||||
weight = upper_rid - lower_rid + rat.weight;
|
weight = upper_rid - lower_rid + rat.weight;
|
||||||
upper_rid -= weight;
|
upper_rid -= weight;
|
||||||
} else {
|
} else {
|
||||||
|
LFS_DEBUG("%04x->%04x: leaf split gt",
|
||||||
|
branch, lfsr_rbyd_eoff(rbyd));
|
||||||
// split greater than
|
// split greater than
|
||||||
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, rat.tag);
|
alt = LFSR_TAG_ALT(LFSR_TAG_B, LFSR_TAG_GT, rat.tag);
|
||||||
weight = upper_rid - (rid+1);
|
weight = upper_rid - (rid+1);
|
||||||
|
|||||||
Reference in New Issue
Block a user