Fixed null tags getting stuck in the tree during range removals

Please excuse the mess.

There is a delicate game going on here with where null tags can appear
in rbyd trees.

Null tags _can_ appear at the end of the tree, and as a terminator of
unreachable trunks.

Null tags can _not_ appear inside the tree in reachable trunks, as this
would violate our right-leaning property and prevent lookupnext from
working correctly.

Long story short we need to very careful to ensure the lower diverged
trunk's null tag is truely unreachable. Otherwise the null tag necessary
to terminate the trunk (so that fetch works) breaks things.

The solution seems to be keep track of the last _alt_ on the
lower-diverged trunk, and use this alt to stich together the two
diverged trunks when writing the non-diverged + upper-diverged trunks.

This feels very similar to how you swap to remove from tree heaps, which
is interesting.

The rbyd tests are passing now, but higher-level tests are failing,
which isn't the greatest sign...
This commit is contained in:
Christopher Haster
2024-03-11 03:43:02 -05:00
parent 0b6cf7e9a7
commit dd31f610b3
+44 -37
View File
@@ -2780,17 +2780,18 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// note both normal and rm wide-tags have the same bounds, really it's // note both normal and rm wide-tags have the same bounds, really it's
// the normal non-wide-tags that are an outlier here // the normal non-wide-tags that are an outlier here
if (lfsr_tag_issup(tag)) { if (lfsr_tag_issup(tag)) {
a_tag = 0; a_tag = 0x000;
b_tag = a_tag + 0x800; b_tag = 0x800;
} else if (lfsr_tag_issub(tag)) { } else if (lfsr_tag_issub(tag)) {
a_tag = lfsr_tag_supkey(tag); a_tag = lfsr_tag_supkey(tag);
b_tag = a_tag + 0x100; b_tag = lfsr_tag_supkey(tag) + 0x100;
} else if (lfsr_tag_isrm(tag) || !lfsr_tag_key(tag)) { } else if (lfsr_tag_isrm(tag) || !lfsr_tag_key(tag)) {
//LFS_ASSERT(lfsr_tag_key(tag)); // when does this happen?
a_tag = lfsr_tag_key(tag); a_tag = lfsr_tag_key(tag);
b_tag = a_tag + 0x1; b_tag = lfsr_tag_key(tag) + 0x1;
} else { } else {
a_tag = lfsr_tag_key(tag); a_tag = lfsr_tag_key(tag);
b_tag = a_tag; b_tag = lfsr_tag_key(tag);
} }
} }
// a_tag = lfs_max16(a_tag, 0x1); // a_tag = lfs_max16(a_tag, 0x1);
@@ -2798,10 +2799,11 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// keep track of the diverged branch if we're removing a range // keep track of the diverged branch if we're removing a range
bool diverging = (a_rid != b_rid || a_tag != b_tag); bool diverging = (a_rid != b_rid || a_tag != b_tag);
bool d_lower = false; bool d_upper = false;
lfs_size_t d_branch = 0; lfs_size_t d_branch = 0;
lfsr_tag_t d_tag; lfsr_tag_t d_tag;
lfs_size_t d_branch_; lfs_size_t d_branch_;
lfsr_srid_t d_lower_rid;
lfsr_srid_t d_upper_rid; lfsr_srid_t d_upper_rid;
again:; again:;
@@ -2887,21 +2889,21 @@ again:;
lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps);
// begin diverging // begin diverging
} else if (!d_lower) { } else if (!d_upper) {
printf("diverged upper: %#x\n", a_branch); printf("diverged lower: %#x\n", a_branch);
// TODO need this? // TODO need this?
alt &= ~LFSR_TAG_R; alt &= ~LFSR_TAG_R;
d_branch = rbyd->eoff; // TODO need this? d_branch = rbyd->eoff; // TODO need this?
diverged = true; diverged = true;
// TODO too many swaps? // // TODO too many swaps?
lfs_swap16(&a_tag, &b_tag); // lfs_swap16(&a_tag, &b_tag);
lfs_sswap32(&a_rid, &b_rid); // lfs_sswap32(&a_rid, &b_rid);
// connect diverged branch // connect diverged branch
} else { } else {
printf("diverged lower: %#x\n", a_branch); printf("diverged upper: %#x\n", a_branch);
// TODO need this? // TODO need this?
alt &= ~LFSR_TAG_R; alt &= ~LFSR_TAG_R;
// if (lfsr_tag_follow2(alt, weight, // if (lfsr_tag_follow2(alt, weight,
@@ -2926,26 +2928,26 @@ again:;
lfs_swap32(&jump, &branch_); lfs_swap32(&jump, &branch_);
} }
printf("stitching: %#x %d-%d %#x\n",
LFSR_TAG_ALT(
LFSR_TAG_GT,
LFSR_TAG_B,
d_tag),
//alt,
//LFSR_TAG_ALT(LFSR_TAG_GT, LFSR_TAG_B, b_tag),
a_upper_rid, d_upper_rid,
d_branch);
// TODO ??? special handling for null? // TODO ??? special handling for null?
// if (lfsr_tag_key(d_tag)) { if (lfsr_tag_key(d_tag)) {
printf("stitching: %#x %d-%d %#x\n",
LFSR_TAG_ALT(
LFSR_TAG_LE,
LFSR_TAG_B,
d_tag),
//alt,
//LFSR_TAG_ALT(LFSR_TAG_GT, LFSR_TAG_B, b_tag),
a_lower_rid, d_lower_rid,
d_branch);
err = lfsr_rbyd_p_push(lfs, rbyd, err = lfsr_rbyd_p_push(lfs, rbyd,
p_alts, p_weights, p_jumps, p_alts, p_weights, p_jumps,
LFSR_TAG_ALT( LFSR_TAG_ALT(
LFSR_TAG_GT, LFSR_TAG_LE,
LFSR_TAG_B, LFSR_TAG_B,
d_tag), d_tag),
//lfs_smax32(weight + delta, 0), //lfs_smax32(weight + delta, 0),
a_upper_rid - d_upper_rid, d_lower_rid - a_lower_rid,
// LFSR_TAG_ALT( // LFSR_TAG_ALT(
// LFSR_TAG_LE, // LFSR_TAG_LE,
// LFSR_TAG_B, // LFSR_TAG_B,
@@ -2958,7 +2960,7 @@ again:;
if (err) { if (err) {
return err; return err;
} }
// } }
diverged = true; diverged = true;
@@ -2993,9 +2995,9 @@ again:;
// prune diverged? // prune diverged?
// TODO can we merge with yellow prune? // TODO can we merge with yellow prune?
if ((diverging && !d_lower && !diverged) if ((diverging && !d_upper && !diverged)
|| (diverged || (diverged
&& !d_lower && d_upper
^ lfsr_tag_isgt(alt) ^ lfsr_tag_isgt(alt)
^ lfsr_tag_follow2( ^ lfsr_tag_follow2(
alt, weight, alt, weight,
@@ -3263,16 +3265,19 @@ again:;
// } // }
// need a second diverging trunk? // need a second diverging trunk?
if (diverging && !d_lower) { if (diverging && !d_upper) {
// no diverging branch? guess we only need one trunk then // no diverging branch? guess we only need one trunk then
if (!diverged) { if (!diverged) {
diverging = false; diverging = false;
// TODO too many swaps // // TODO too many swaps
lfs_swap16(&a_tag, &b_tag); // lfs_swap16(&a_tag, &b_tag);
lfs_sswap32(&a_rid, &b_rid); // lfs_sswap32(&a_rid, &b_rid);
goto again; goto again;
} }
// TODO is this not a_lower_tag?
d_tag = lfsr_tag_key(p_alts[0]);
// flush any pending alts // flush any pending alts
err = lfsr_rbyd_p_flush(lfs, rbyd, err = lfsr_rbyd_p_flush(lfs, rbyd,
p_alts, p_weights, p_jumps, 3); p_alts, p_weights, p_jumps, 3);
@@ -3291,13 +3296,14 @@ again:;
} }
// save the found lower rid/tag // save the found lower rid/tag
d_tag = tag__; // d_tag = a_lower_tag; //tag__;
d_branch_ = a_branch; d_branch_ = a_branch;
d_lower_rid = a_lower_rid;
d_upper_rid = a_upper_rid; d_upper_rid = a_upper_rid;
lfs_swap16(&a_tag, &b_tag); lfs_swap16(&a_tag, &b_tag);
lfs_sswap32(&a_rid, &b_rid); lfs_sswap32(&a_rid, &b_rid);
d_lower = true; d_upper = true;
printf("found dtag: %#x: %#x\n", d_branch_, d_tag); printf("found dtag: %#x: %#x\n", d_branch_, d_tag);
goto again; goto again;
} }
@@ -3305,9 +3311,10 @@ again:;
// use the diverged lower rid for leaf weight calculation // use the diverged lower rid for leaf weight calculation
a_tag = tag__; a_tag = tag__;
if (diverged) { if (diverged) {
a_tag = d_tag; // a_tag = d_tag;
a_branch = d_branch_; // a_branch = d_branch_;
a_upper_rid = d_upper_rid; // a_upper_rid = d_upper_rid;
a_lower_rid = d_lower_rid;
} }
printf("done: %#x %d %d\n", a_tag, a_lower_rid, a_upper_rid); printf("done: %#x %d %d\n", a_tag, a_lower_rid, a_upper_rid);