Derived grows/shrinks from rbyd trunk, no longer needing explicit tags

I only recently noticed there is enough information in each rbyd trunk
to infer the effective grow/shrinks. This has a number of benefits:

- Cleans up the tag encoding a bit, no longer expecting tag size to
  sometimes contain a weight (though this could've been fixed other
  ways).

  0x6 in the lower nibble now reserved exclusively for in-device tags.

- grow/shrinks can be implicit to any tag. Will attempt to leverage this
  in the future.

- The weight of an rbyd can no longer go out-of-sync with itself. While
  this _shouldn't_ happen normally, if it does I imagine it'd be very
  hard to debug.

  Now, there is only one source of knowledge about the weight of the
  rbyd: The most recent set of alt-pointers.

Note that remove/unreachable tags now behave _very_ differently when it
comes to weight calculation, remove tags require the tree to make the
tag unreachable. This is a tradeoff for the above.
This commit is contained in:
Christopher Haster
2023-03-27 01:45:34 -05:00
parent 546fff77fb
commit 8f26b68af2
3 changed files with 203 additions and 161 deletions
+62 -46
View File
@@ -449,32 +449,35 @@ static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) {
// 16-bit metadata tags
enum lfsr_tag_type {
LFSR_TAG_NAME = 0x1000,
LFSR_TAG_BNAME = 0x1000,
LFSR_TAG_REG = 0x1010,
LFSR_TAG_DIR = 0x1020,
LFSR_TAG_UNREACHABLE = 0x0002,
LFSR_TAG_STRUCT = 0x3000,
LFSR_TAG_INLINED = 0x3000,
LFSR_TAG_BLOCK = 0x3100,
LFSR_TAG_BRANCH = 0x3200,
LFSR_TAG_BTREE = 0x3300,
LFSR_TAG_NAME = 0x1000,
LFSR_TAG_BNAME = 0x1000,
LFSR_TAG_REG = 0x1010,
LFSR_TAG_DIR = 0x1020,
LFSR_TAG_UATTR = 0x4000,
LFSR_TAG_RMUATTR = 0x4002,
LFSR_TAG_STRUCT = 0x3000,
LFSR_TAG_INLINED = 0x3000,
LFSR_TAG_BLOCK = 0x3100,
LFSR_TAG_BRANCH = 0x3200,
LFSR_TAG_BTREE = 0x3300,
LFSR_TAG_GROW = 0x0006,
LFSR_TAG_SHRINK = 0x0016,
LFSR_TAG_FROM = 0x0026, // in-device only
LFSR_TAG_UATTR = 0x4000,
LFSR_TAG_RMUATTR = 0x4002,
LFSR_TAG_ALT = 0x0008,
LFSR_TAG_ALTBLE = 0x0008,
LFSR_TAG_ALTRLE = 0x000a,
LFSR_TAG_ALTBGT = 0x000c,
LFSR_TAG_ALTRGT = 0x000e,
LFSR_TAG_ALT = 0x0008,
LFSR_TAG_ALTBLE = 0x0008,
LFSR_TAG_ALTRLE = 0x000a,
LFSR_TAG_ALTBGT = 0x000c,
LFSR_TAG_ALTRGT = 0x000e,
LFSR_TAG_CRC = 0x0004,
LFSR_TAG_FCRC = 0x1004,
LFSR_TAG_CRC = 0x0004,
LFSR_TAG_FCRC = 0x1004,
// in-device only
LFSR_TAG_GROW = 0x0006,
LFSR_TAG_SHRINK = 0x0016,
LFSR_TAG_FROM = 0x0026,
};
#define LFSR_TAG_ALT_(color, dir, key) \
@@ -512,12 +515,8 @@ static inline lfsr_tag_t lfsr_tag_mkrm(lfsr_tag_t tag) {
return tag | 0x2;
}
static inline bool lfsr_tag_hasdata(lfsr_tag_t tag) {
return (tag & 0xe) <= 0x4;
}
static inline bool lfsr_tag_istrunk(lfsr_tag_t tag) {
return (tag & 0xe) != 0x4;
return (tag & 0xc) != 0x4;
}
static inline bool lfsr_tag_isalt(lfsr_tag_t tag) {
@@ -1282,6 +1281,8 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_off_t off = sizeof(uint32_t);
lfs_off_t trunk = 0;
bool wastrunk = false;
lfs_size_t lower = 0;
lfs_size_t upper = 0;
lfs_size_t weight = 0;
// assume unerased until proven otherwise
@@ -1310,39 +1311,51 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found trunk of tree?
if (!wastrunk && lfsr_tag_istrunk(tag)) {
trunk = off;
lower = 0;
upper = 0;
}
wastrunk = lfsr_tag_isalt(tag);
off += delta;
// keep track of weight
// derive the new weight of the tree from alt pointers
//
// NOTE we can't check for overflow/underflow here because we
// may be overeagerly parsing an invalid commit, it's ok for
// this to overflow/underflow as long as we throw it out later
// on a bad crc
if (tag == LFSR_TAG_GROW) {
weight += size;
// adjust find
if (find && find->predicted_id >= id) {
find->predicted_id += size;
if (lfsr_tag_isalt(tag)) {
if (lfsr_tag_isgt(tag)) {
upper += id;
} else {
lower += id;
}
} else if (tag == LFSR_TAG_SHRINK) {
weight -= size;
// adjust find
} else if (lfsr_tag_istrunk(tag)) {
// note we need to include our id's weight in our weight
// calculation, but only when our id is included in the tree
lfs_ssize_t delta = (lower+upper) - weight;
if (!lfsr_tag_isrm(tag)
&& tag != LFSR_TAG_GROW
&& tag != LFSR_TAG_SHRINK) {
delta += id+1-lower;
}
// adjust any pending finds
if (find && find->predicted_id >= id) {
if (find->predicted_id < id+(lfs_ssize_t)size) {
// pending find removed?
if (delta < 0 && find->predicted_id < id-delta) {
find->predicted_tag = 0;
find->predicted_id = id-1;
} else {
find->predicted_id -= size;
find->predicted_id += delta;
}
}
weight += delta;
}
// we mostly just skip non-data tags here
if (!lfsr_tag_hasdata(tag)) {
if (lfsr_tag_isalt(tag)) {
continue;
}
@@ -2322,6 +2335,11 @@ leaf:;
//
// note we always need something after the alts! without something between
// alts we may not be able to find the trunk of our tree
if (tag == LFSR_TAG_GROW || tag == LFSR_TAG_SHRINK) {
tag = LFSR_TAG_UNREACHABLE;
data = LFSR_DATA_NULL;
}
err = lfsr_rbyd_progtag(lfs, rbyd,
tag, id, lfsr_data_len(data), &rbyd->crc);
if (err) {
@@ -2329,13 +2347,11 @@ leaf:;
return err;
}
if (lfsr_tag_hasdata(tag)) {
// don't forget the data!
err = lfsr_rbyd_progdata(lfs, rbyd, data, &rbyd->crc);
if (err) {
rbyd->erased = false;
return err;
}
// don't forget the data!
err = lfsr_rbyd_progdata(lfs, rbyd, data, &rbyd->crc);
if (err) {
rbyd->erased = false;
return err;
}
return 0;