Changed lfsr_rbyd_append back to using tag bits for diverged/found state

With the lower 4 tag bits getting all sorts of in-device-only uses,
reusing these bits to maintain diverged state during lfsr_rbyd_append is
less of a special case.

And anything that replaces the awkward 5-state, idiosyncratic diverged
state machine is a win in my opinion.
This commit is contained in:
Christopher Haster
2023-04-03 02:25:12 -05:00
parent d917e8c9cc
commit c59124a70a
+56 -35
View File
@@ -545,20 +545,39 @@ static inline bool lfsr_tag_isalt(lfsr_tag_t tag) {
return tag & 0x8;
}
//static inline bool lfsr_tag_isfound(lfsr_tag_t tag) {
// // note that this is only for driver bookkeeping and never
// // exists on disk
// return tag & 0x1;
//}
//
//static inline lfsr_tag_t lfsr_tag_setfound(lfsr_tag_t tag) {
// return tag | 0x1;
//}
static inline lfsr_tag_t lfsr_tag_next(lfsr_tag_t tag) {
return tag + 0x10;
}
// lfsr_rbyd_append specific flags
static inline bool lfsr_tag_isfound(lfsr_tag_t tag) {
return tag & 0x1;
}
static inline lfsr_tag_t lfsr_tag_setfound(lfsr_tag_t tag) {
return tag | 0x1;
}
static inline bool lfsr_tag_isupper(lfsr_tag_t tag) {
return tag & 0x4;
}
static inline bool lfsr_tag_islower(lfsr_tag_t tag) {
return !lfsr_tag_isupper(tag);
}
static inline lfsr_tag_t lfsr_tag_setupper(lfsr_tag_t tag) {
return tag | 0x4;
}
static inline bool lfsr_tag_hasdiverged(lfsr_tag_t tag) {
return tag & 0x8;
}
static inline lfsr_tag_t lfsr_tag_setdiverged(lfsr_tag_t tag) {
return tag | 0x8;
}
// alt operations
static inline bool lfsr_tag_isblack(lfsr_tag_t tag) {
return !(tag & 0x2);
@@ -1990,6 +2009,9 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
}
// figure out the range of tags we're operating on
//
// several lower bits are reserved, so we repurpose these
// to keep track of some append state
lfs_ssize_t id_;
lfs_ssize_t other_id_;
lfsr_tag_t tag_;
@@ -2004,7 +2026,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
other_id_ = id + 1;
// also note these tags MUST NOT be zero, due to unreachable tag holes
tag_ = 0x10;
other_tag_ = 0x10;
other_tag_ = lfsr_tag_setupper(0x10);
} else if (lfsr_tag_ismk(tag) && delta < 0) {
LFS_ASSERT(id < rbyd->weight);
@@ -2015,21 +2037,21 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
other_id_ = id;
// also note these tags MUST NOT be zero, due to unreachable tag holes
tag_ = 0x10;
other_tag_ = 0x10;
other_tag_ = lfsr_tag_setupper(0x10);
} else if (lfsr_tag_isrm(tag)) {
LFS_ASSERT(id < rbyd->weight);
id_ = id - lfs_smax32(-delta, 0);
other_id_ = id;
tag_ = lfsr_tag_key(tag);
other_tag_ = lfsr_tag_key(tag) + 0x10;
other_tag_ = lfsr_tag_setupper(lfsr_tag_key(tag) + 0x10);
} else {
LFS_ASSERT(id < rbyd->weight);
id_ = id - lfs_smax32(-delta, 0);
other_id_ = id;
tag_ = lfsr_tag_key(tag);
other_tag_ = lfsr_tag_key(tag);
other_tag_ = lfsr_tag_setupper(lfsr_tag_key(tag));
}
// keep track of bounds as we descend down the tree
@@ -2050,14 +2072,6 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
//
// note we can't just perform two searches sequentially, or else our tree
// will end up very unbalanced.
//
// we end up going through several states when diverging:
// diverged=0 => not diverged
// diverged=4 => diverged, on lower path
// diverged=5 => diverged, on upper path
// diverged=2 => diverged, found one tag, on lower path
// diverged=3 => diverged, found one tag, on upper path
uint8_t diverged = 0;
lfs_off_t other_branch = 0;
lfs_ssize_t other_lower_id = 0;
lfs_ssize_t other_upper_id = 0;
@@ -2104,7 +2118,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_off_t branch_ = branch + d;
// do bounds want to take different paths? begin cutting
if (!diverged
if (!lfsr_tag_hasdiverged(tag_)
&& lfsr_tag_follow2(alt, weight,
p_alts[0], p_weights[0],
lower_id, upper_id,
@@ -2121,7 +2135,8 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
branch_ = branch;
lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps);
} else {
diverged = 4;
tag_ = lfsr_tag_setdiverged(tag_);
other_tag_ = lfsr_tag_setdiverged(other_tag_);
other_branch = branch;
other_lower_id = lower_id;
other_upper_id = upper_id;
@@ -2133,7 +2148,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// if we're diverging, go ahead and make alt black, this isn't
// perfect but it's simpler and compact will take care of any
// balance issues that may occur
if (diverged) {
if (lfsr_tag_hasdiverged(tag_)) {
alt = lfsr_tag_setblack(alt);
}
@@ -2277,7 +2292,8 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
branch = branch_;
// prune inner alts if our tags diverged
if (diverged && (diverged & 0x1) != lfsr_tag_isgt(alt)) {
if (lfsr_tag_hasdiverged(tag_)
&& lfsr_tag_isupper(tag_) != lfsr_tag_isgt(alt)) {
continue;
}
@@ -2294,20 +2310,23 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found end of tree?
} else {
// update the found tag/id
tag_ = alt;
//
// note we:
// - preserve diverged bit (0x8)
// - preserve is upper tag (0x4)
// - set found tag (0x1)
tag_ = lfsr_tag_setfound(alt | (tag_ & 0xc));
id_ = upper_id-1;
// done?
if (diverged >= 4) {
diverged -= 2;
} else {
if (!lfsr_tag_hasdiverged(tag_)
|| lfsr_tag_isfound(other_tag_)) {
break;
}
}
// switch to the other path if we have diverged
if (diverged >= 4 || !lfsr_tag_isalt(alt)) {
diverged ^= 0x1;
if (lfsr_tag_hasdiverged(tag_) || !lfsr_tag_isalt(alt)) {
lfs_swap16(&tag_, &other_tag_);
lfs_sswap32(&id_, &other_id_);
lfs_swap32(&branch, &other_branch);
@@ -2322,14 +2341,16 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
LFS_ASSERT(lfsr_tag_isblack(p_alts[0]));
// if we diverged, merge the bounds
LFS_ASSERT(diverged < 4);
if (diverged == 2) {
LFS_ASSERT(lfsr_tag_isfound(tag_));
LFS_ASSERT(!lfsr_tag_hasdiverged(tag_)
|| lfsr_tag_isfound(other_tag_));
if (lfsr_tag_hasdiverged(tag_) && lfsr_tag_islower(tag_)) {
// finished on lower path
tag_ = other_tag_;
id_ = other_id_;
branch = other_branch;
upper_id = other_upper_id;
} else if (diverged == 3) {
} else if (lfsr_tag_hasdiverged(tag_) && lfsr_tag_isupper(tag_)) {
// finished on upper path
lower_id = other_lower_id;
}