diff --git a/lfs.c b/lfs.c index e597f00f..03f33107 100644 --- a/lfs.c +++ b/lfs.c @@ -468,7 +468,7 @@ static inline uint16_t lfs_rtag_type3(lfs_rtag_t tag) { } static inline uint16_t lfs_rtag_id(lfs_rtag_t tag) { - return (tag >> 15) & 0xffff; + return tag >> 15; } static inline bool lfs_rtag_islt(lfs_rtag_t tag) { @@ -487,11 +487,11 @@ static inline bool lfs_rtag_isred(lfs_rtag_t tag) { return tag & 0x1; } -static inline lfs_rtag_t lfs_rtag_weight(lfs_rtag_t tag) { - return (tag >> 3) & 0xfffffff; +static inline lfs_srtag_t lfs_rtag_weight(lfs_rtag_t tag) { + return tag >> 3; } -static inline lfs_rtag_t lfs_rtag_weight2(lfs_rtag_t tag, lfs_rtag_t tag2) { +static inline lfs_srtag_t lfs_rtag_weight2(lfs_rtag_t tag, lfs_rtag_t tag2) { return lfs_rtag_weight(tag) + lfs_rtag_weight(tag2); } @@ -952,7 +952,6 @@ static int lfs_rbyd_fetch(lfs_t *lfs, } // found trunk of tree? - printf("%x: %08x => %d %d\n", off, tag, wastrunk, lfs_rtag_intree(tag)); if (!wastrunk && (lfs_rtag_isalt(tag) || lfs_rtag_intree(tag))) { trunk = off; wastrunk = true; @@ -1071,7 +1070,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs, // TODO make these rtag functions? static inline bool lfs_rbyd_follow(lfs_rtag_t alt, - lfs_rtag_t lt, lfs_rtag_t gt) { + lfs_srtag_t lt, lfs_srtag_t gt) { if (lfs_rtag_islt(alt)) { return lfs_rtag_weight(alt) > lt; } else { @@ -1080,7 +1079,7 @@ static inline bool lfs_rbyd_follow(lfs_rtag_t alt, } static inline bool lfs_rbyd_follow2( - lfs_rtag_t alt, lfs_rtag_t alt_, lfs_rtag_t lt, lfs_rtag_t gt) { + lfs_rtag_t alt, lfs_rtag_t alt_, lfs_srtag_t lt, lfs_srtag_t gt) { if (lfs_rtag_islt(alt) && lfs_rtag_islt(alt_)) { return lfs_rtag_weight(alt) + lfs_rtag_weight(alt_) > lt; } else if (lfs_rtag_isgt(alt) && lfs_rtag_isgt(alt_)) { @@ -1110,35 +1109,53 @@ static inline lfs_rtag_t lfs_rbyd_flip2( } static inline void lfs_rbyd_trim(lfs_rtag_t alt, - lfs_rtag_t *lt, lfs_rtag_t *gt) { - lfs_rtag_t lt_ = *lt; - lfs_rtag_t gt_ = *gt; - + lfs_srtag_t *lt, lfs_srtag_t *gt) { if (lfs_rtag_islt(alt)) { - if (lfs_rbyd_follow(alt, lt_, gt_)) { - *gt = lfs_rtag_weight(alt)-1 - *lt; - } else { - *lt = *lt - lfs_rtag_weight(alt); - } + *lt = *lt - lfs_rtag_weight(alt); } else { - if (lfs_rbyd_follow(alt, lt_, gt_)) { - *lt = lfs_rtag_weight(alt)-1 - *gt; - } else { - *gt = *gt - lfs_rtag_weight(alt); - } + *gt = *gt - lfs_rtag_weight(alt); } } +static inline void lfs_rbyd_untrim(lfs_rtag_t alt, + lfs_srtag_t *lt, lfs_srtag_t *gt) { + if (lfs_rtag_islt(alt)) { + *lt = *lt + lfs_rtag_weight(alt); + } else { + *gt = *gt + lfs_rtag_weight(alt); + } +} + +//static inline void lfs_rbyd_trim(lfs_rtag_t alt, +// lfs_rtag_t *lt, lfs_rtag_t *gt) { +// lfs_rtag_t lt_ = *lt; +// lfs_rtag_t gt_ = *gt; +// +// if (lfs_rtag_islt(alt)) { +// if (lfs_rbyd_follow(alt, lt_, gt_)) { +// *gt = lfs_rtag_weight(alt)-1 - *lt; +// } else { +// *lt = *lt - lfs_rtag_weight(alt); +// } +// } else { +// if (lfs_rbyd_follow(alt, lt_, gt_)) { +// *lt = lfs_rtag_weight(alt)-1 - *gt; +// } else { +// *gt = *gt - lfs_rtag_weight(alt); +// } +// } +//} + // TODO lfs_rtag_weight_lt? -static inline lfs_rtag_t lfs_rbyd_partition_lt( +static inline lfs_srtag_t lfs_rbyd_partition_lt( lfs_rtag_t tag, uint16_t count) { (void)count; return lfs_rtag_weight(tag); } -static inline lfs_rtag_t lfs_rbyd_partition_gt( +static inline lfs_srtag_t lfs_rbyd_partition_gt( lfs_rtag_t tag, uint16_t count) { - return (((lfs_rtag_t)count << 12) + 0xff8)-1 - lfs_rtag_weight(tag); + return (((lfs_srtag_t)count << 12) + 0xff8)-1 - lfs_rtag_weight(tag); } //static inline void lfs_rbyd_trim(lfs_rtag_t alt, @@ -1160,7 +1177,7 @@ static inline lfs_rtag_t lfs_rbyd_partition_gt( //} static lfs_srtag_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, - lfs_rtag_t tag, lfs_off_t *off, lfs_size_t *size, lfs_rtag_t *ntag) { + lfs_rtag_t tag, lfs_off_t *off, lfs_size_t *size) { // no trunk yet? lfs_off_t branch = rbyd->trunk; if (!branch) { @@ -1168,11 +1185,11 @@ static lfs_srtag_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, } // weights for pruning - lfs_rtag_t lt = lfs_rbyd_partition_lt(tag, rbyd->count); - lfs_rtag_t gt = lfs_rbyd_partition_gt(tag, rbyd->count); + lfs_srtag_t lt = lfs_rbyd_partition_lt(tag, rbyd->count); + lfs_srtag_t gt = lfs_rbyd_partition_gt(tag, rbyd->count); printf("lt, gt = (%x, %x)\n", lt, gt); - // descend down tree, building alt pointers + // descend down tree while (true) { lfs_rtag_t alt; lfs_off_t jump; @@ -1189,9 +1206,9 @@ static lfs_srtag_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, jump = branch - jump; branch += delta; - printf("follow %x (%x, %x)? => %d\n", alt, lt, gt, lfs_rbyd_follow(alt, lt, gt)); + printf("follow %c%x (%x, %x)? => %d\n", lfs_rtag_isgt(alt) ? '>' : '<', lfs_rtag_weight(alt), lt, gt, lfs_rbyd_follow(alt, lt, gt)); if (lfs_rbyd_follow(alt, lt, gt)) { - lfs_rbyd_trim(alt, <, >); + lfs_rbyd_trim(lfs_rbyd_flip(alt, lt, gt), <, >); branch = jump; } else { lfs_rbyd_trim(alt, <, >); @@ -1208,7 +1225,7 @@ static lfs_srtag_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, lfs_rtag_t tag_ = LFS_MKRTAG_( lfs_rtag_type1(alt), lfs_rtag_type2(alt), - lt >> 12); // TODO there's no way this can be right + lfs_rtag_id(tag)); // not what we're looking for? if (tag_ < tag) { @@ -1218,17 +1235,9 @@ static lfs_srtag_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, // save what we found *off = branch + delta; *size = jump; - if (ntag) { - if (gt == lfs_rbyd_partition_gt(tag, rbyd->count)) { - *ntag = LFS_ERR_NOENT; - } else { - *ntag = tag + ((gt+1) << 3); - } - } printf("lt, gt = (%x, %x)\n", lt, gt); printf("lookup %08x => %08x (raw %08x)\n", tag, tag_, alt); - if (ntag) { printf("ntag %08x => %08x\n", tag, *ntag); } //return alt; // TODO adjust //return lt << 3; //return lfs_rtag_setid(alt, lt >> 12); @@ -1304,13 +1313,13 @@ static lfs_ssize_t lfs_rbyd_p_push(lfs_t *lfs, lfs_rtag_t p_alts[static 3], lfs_off_t p_jumps[static 3], lfs_rtag_t alt, lfs_off_t jump, uint32_t *crc) { - lfs_ssize_t delta = 0; - // too many alts, need to write one out? + lfs_ssize_t delta = 0; if (p_alts[2]) { // change to relative jump at the last minute lfs_rtag_t alt_ = p_alts[2]; lfs_off_t jump_ = off - p_jumps[2]; + printf("%x: writing %08x %08x\n", off, alt_, jump_); delta = lfs_rbyd_progtag(lfs, pcache, rcache, @@ -1348,12 +1357,12 @@ static lfs_ssize_t lfs_rbyd_p_flush(lfs_t *lfs, lfs_block_t block, lfs_off_t off, lfs_rtag_t p_alts[static 3], lfs_rtag_t p_jumps[static 3], uint32_t *crc) { + // just push zeros into everything is written out lfs_ssize_t delta = 0; - for (unsigned i = 0; i < 3; i++) { lfs_ssize_t delta_ = lfs_rbyd_p_push(lfs, pcache, rcache, - block, off, + block, off+delta, p_alts, p_jumps, 0, 0, crc); if (delta_ < 0) { return delta_; @@ -1442,14 +1451,14 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, } // weights for pruning - lfs_rtag_t lt = lfs_rbyd_partition_lt(attr->tag, count); - lfs_rtag_t gt = lfs_rbyd_partition_gt(attr->tag, count); + lfs_srtag_t lt = lfs_rbyd_partition_lt(attr->tag, count); + lfs_srtag_t gt = lfs_rbyd_partition_gt(attr->tag, count); printf("lt, gt = (%x, %x)\n", lt, gt); // queue of pending alts we can emulate rotations with lfs_rtag_t p_alts[3] = {0, 0, 0}; lfs_off_t p_jumps[3] = {0, 0, 0}; - lfs_rtag_t incoming = 0; + lfs_rtag_t stump = 0; // descend down tree, building alt pointers while (true) { @@ -1469,118 +1478,156 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, lfs_rtag_t branch_ = branch; // TODO can this be done a better way? branch += delta; - // prune? - // TODO ugh, just clean this up later - if (p_alts[0] - && lfs_rtag_isred(p_alts[0]) - && lfs_rtag_weight2(alt, p_alts[0]) >= lt+gt+1) { - LFS_ASSERT(p_alts[0]); - - branch = jump; - alt = lfs_rtag_black(p_alts[0]); - jump = p_jumps[0]; - lfs_rbyd_p_pop(p_alts, p_jumps); - - } else if (lfs_rtag_weight(alt) >= lt+gt+1) { - // TODO does this get hit? - // TODO can we simplify these two? - LFS_ASSERT(p_alts[0]); - - branch = jump; - alt = lfs_rtag_black(p_alts[0]); - jump = p_jumps[0]; - lfs_rbyd_p_pop(p_alts, p_jumps); - } - - - // split? - if (lfs_rtag_isred(alt) - && p_alts[0] - && lfs_rtag_isred(p_alts[0])) { - LFS_ASSERT(lfs_rtag_parallel(alt, p_alts[0])); - - if (lfs_rbyd_follow2(alt, p_alts[0], lt, gt)) { - lfs_rtag_t alt_ = p_alts[0]; - lfs_off_t jump_ = p_jumps[0]; - p_alts[0] = lfs_rtag_black( - lfs_rbyd_flip2(alt, alt_, lt, gt)); - p_jumps[0] = jump; - alt = lfs_rtag_black(alt_); - jump = jump_; - - lfs_rbyd_trim(alt_, <, >); - lfs_rbyd_trim(alt, <, >); - lfs_rbyd_p_red(p_alts, p_jumps); - - } else { - lfs_rtag_t alt_ = p_alts[0]; - p_alts[0] = lfs_rtag_black(alt); - p_jumps[0] = incoming; - - lfs_rbyd_trim(alt_, <, >); - lfs_rbyd_trim(alt, <, >); - lfs_rbyd_p_red(p_alts, p_jumps); - - continue; - } - } +// // prune? +// // TODO ugh, just clean this up later +// if (p_alts[0] +// && lfs_rtag_isred(p_alts[0]) +// && lfs_rtag_weight2(alt, p_alts[0]) >= lt+gt+1) { +// LFS_ASSERT(p_alts[0]); +// +// branch = jump; +// alt = lfs_rtag_black(p_alts[0]); +// jump = p_jumps[0]; +// lfs_rbyd_p_pop(p_alts, p_jumps); +// +// } else if (lfs_rtag_weight(alt) >= lt+gt+1) { +// // TODO does this get hit? +// // TODO can we simplify these two? +// LFS_ASSERT(p_alts[0]); +// +// branch = jump; +// alt = lfs_rtag_black(p_alts[0]); +// jump = p_jumps[0]; +// lfs_rbyd_p_pop(p_alts, p_jumps); +// } +// +// +// // split? +// if (lfs_rtag_isred(alt) +// && p_alts[0] +// && lfs_rtag_isred(p_alts[0])) { +// LFS_ASSERT(lfs_rtag_parallel(alt, p_alts[0])); +// +// if (lfs_rbyd_follow2(alt, p_alts[0], lt, gt)) { +// lfs_rtag_t alt_ = p_alts[0]; +// lfs_off_t jump_ = p_jumps[0]; +// p_alts[0] = lfs_rtag_black( +// lfs_rbyd_flip2(alt, alt_, lt, gt)); +// p_jumps[0] = jump; +// alt = lfs_rtag_black(alt_); +// jump = jump_; +// +// lfs_rbyd_trim(alt_, <, >); +// lfs_rbyd_trim(alt, <, >); +// lfs_rbyd_p_red(p_alts, p_jumps); +// +// } else { +// lfs_rtag_t alt_ = p_alts[0]; +// p_alts[0] = lfs_rtag_black(alt); +// p_jumps[0] = stump; +// +// lfs_rbyd_trim(alt_, <, >); +// lfs_rbyd_trim(alt, <, >); +// lfs_rbyd_p_red(p_alts, p_jumps); +// +// continue; +// } +// } // should've taken red alt? - if (p_alts[0] - && lfs_rtag_isred(p_alts[0]) - && lfs_rbyd_follow(p_alts[0], lt, gt) - && lfs_rbyd_follow2(alt, p_alts[0], lt, gt)) { + if (lt < 0 || gt < 0) { + LFS_ASSERT(p_alts[0] && lfs_rtag_isred(p_alts[0])); LFS_ASSERT(lfs_rtag_isblack(alt)); - lfs_rtag_t alt_ = p_alts[0]; - lfs_off_t jump_ = p_jumps[0]; - p_alts[0] = lfs_rtag_red(lfs_rbyd_flip2(alt, alt_, lt, gt)); - p_jumps[0] = branch; - lfs_rbyd_trim(alt, <, >); // TODO is this the place for this? - - lfs_ssize_t delta = lfs_rbyd_p_push(lfs, - &lfs->pcache, &lfs->rcache, - block, off, - p_alts, p_jumps, - lfs_rtag_black(lfs_rbyd_flip(alt_, lt, gt)), - jump, &crc); - if (delta < 0) { - return delta; + if (lfs_rtag_parallel(alt, p_alts[0])) { + printf("rflip parallel (%x,%x)\n", lt, gt); + lfs_rtag_t alt_ = p_alts[0]; + p_alts[0] = lfs_rtag_red(lfs_rbyd_flip(alt, lt, gt)); + alt = lfs_rtag_black(alt_); + lfs_off_t jump_ = p_jumps[0]; + p_jumps[0] = branch; + branch = jump; + jump = jump_; + } else { + printf("rflip perpendicular\n"); + lfs_rtag_t alt_ = p_alts[0]; + p_alts[0] = lfs_rtag_red(alt); + alt = lfs_rtag_black(alt_); + lfs_off_t jump_ = p_jumps[0]; + p_jumps[0] = branch; + jump = jump_; } - off += delta; - lfs_rbyd_trim(alt_, <, >); - incoming = branch_; - branch = jump_; + lfs_rbyd_untrim(alt, <, >); + lfs_rbyd_trim(p_alts[0], <, >); + } - } else if (p_alts[0] - && lfs_rtag_isred(p_alts[0]) - && lfs_rbyd_follow(p_alts[0], lt, gt)) { - LFS_ASSERT(lfs_rtag_isblack(alt)); + + - lfs_rtag_t alt_ = p_alts[0]; - lfs_off_t jump_ = p_jumps[0]; - p_alts[0] = lfs_rtag_red(alt); - p_jumps[0] = jump; - lfs_rbyd_trim(alt, <, >); + + - lfs_ssize_t delta = lfs_rbyd_p_push(lfs, - &lfs->pcache, &lfs->rcache, - block, off, - p_alts, p_jumps, - lfs_rtag_black(lfs_rbyd_flip(alt_, lt, gt)), - branch, &crc); - if (delta < 0) { - return delta; - } - off += delta; - incoming = branch_; - branch = jump_; + + + +// if (p_alts[0] +// && lfs_rtag_isred(p_alts[0]) +// && lfs_rbyd_follow(p_alts[0], lt, gt) +// && lfs_rbyd_follow2(alt, p_alts[0], lt, gt)) { +// LFS_ASSERT(lfs_rtag_isblack(alt)); +// +// lfs_rtag_t alt_ = p_alts[0]; +// lfs_off_t jump_ = p_jumps[0]; +// p_alts[0] = lfs_rtag_red(lfs_rbyd_flip2(alt, alt_, lt, gt)); +// p_jumps[0] = branch; +// lfs_rbyd_trim(alt, <, >); // TODO is this the place for this? +// +// lfs_ssize_t delta = lfs_rbyd_p_push(lfs, +// &lfs->pcache, &lfs->rcache, +// block, off, +// p_alts, p_jumps, +// lfs_rtag_black(lfs_rbyd_flip(alt_, lt, gt)), +// jump, &crc); +// if (delta < 0) { +// return delta; +// } +// off += delta; +// +// lfs_rbyd_trim(alt_, <, >); +// stump = branch_; +// branch = jump_; +// +// } else if (p_alts[0] +// && lfs_rtag_isred(p_alts[0]) +// && lfs_rbyd_follow(p_alts[0], lt, gt)) { +// LFS_ASSERT(lfs_rtag_isblack(alt)); +// +// lfs_rtag_t alt_ = p_alts[0]; +// lfs_off_t jump_ = p_jumps[0]; +// p_alts[0] = lfs_rtag_red(alt); +// p_jumps[0] = jump; +// lfs_rbyd_trim(alt, <, >); +// +// lfs_ssize_t delta = lfs_rbyd_p_push(lfs, +// &lfs->pcache, &lfs->rcache, +// block, off, +// p_alts, p_jumps, +// lfs_rtag_black(lfs_rbyd_flip(alt_, lt, gt)), +// branch, &crc); +// if (delta < 0) { +// return delta; +// } +// off += delta; +// +// stump = branch_; +// branch = jump_; // take black alt? - } else if (lfs_rtag_isblack(alt) + if (lfs_rtag_isblack(alt) && lfs_rbyd_follow(alt, lt, gt)) { + printf("bflip\n"); lfs_ssize_t delta = lfs_rbyd_p_push(lfs, &lfs->pcache, &lfs->rcache, block, off, @@ -1591,12 +1638,13 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, } off += delta; - lfs_rbyd_trim(alt, <, >); - incoming = branch_; + lfs_rbyd_trim(lfs_rbyd_flip(alt, lt, gt), <, >); + stump = branch_; branch = jump; // continue down current path } else { + printf("continue\n"); lfs_ssize_t delta = lfs_rbyd_p_push(lfs, &lfs->pcache, &lfs->rcache, block, off, @@ -1608,7 +1656,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, off += delta; lfs_rbyd_trim(alt, <, >); - incoming = branch_; + stump = branch_; } // found end of tree? @@ -1796,6 +1844,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, if (crc_ != crc) { // oh no, something went wrong + printf("oh no %08x != %08x\n", crc_, crc); return LFS_ERR_CORRUPT; } diff --git a/scripts/dbgrbyd.py b/scripts/dbgrbyd.py index f06da7bd..048f7845 100755 --- a/scripts/dbgrbyd.py +++ b/scripts/dbgrbyd.py @@ -72,7 +72,7 @@ def tagrepr(tag, size, off=None): return 'fcrc x%02x %d' % (type2, size) elif type1 & 0x4: return 'alt%s%s x%x %s' % ( - 'r' if type1 & 4 else 'b', + 'r' if type1 & 1 else 'b', 'gt' if type1 & 2 else 'lt', tag >> 3, 'x%x' % (0xffffffff & (off-size)) diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index 10e70704..ef174a3e 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -1,7 +1,7 @@ # Test this inner rbyd data-structure -[cases.rbyd_commit_fetch] +[cases.test_rbyd_commit_fetch] in = 'lfs.c' defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] code = ''' @@ -41,7 +41,7 @@ code = ''' lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; ''' -[cases.rbyd_multi_commit_fetch] +[cases.test_rbyd_multi_commit_fetch] in = 'lfs.c' defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] code = ''' @@ -82,7 +82,7 @@ code = ''' lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; ''' -[cases.rbyd_commit_lookup] +[cases.test_rbyd_commit_lookup] in = 'lfs.c' defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] code = ''' @@ -107,16 +107,15 @@ code = ''' // TODO test in-between lookups for consistently finding the next >= tag? lfs_off_t off; lfs_size_t size; - lfs_rtag_t ntag; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_ERR_NOENT; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_ERR_NOENT; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_ERR_NOENT; // commit with one attribute @@ -125,27 +124,19 @@ code = ''' lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes @@ -156,42 +147,30 @@ code = ''' LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL))) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) => LFS_ERR_NOENT; ''' # TODO we should make sure lookup always returns <= the requested tag, # this may require fixing in lfs_rbyd_commit to make sure the weights lean # one way -[cases.rbyd_multi_commit_lookup] +[cases.test_rbyd_multi_commit_lookup] in = 'lfs.c' defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] code = ''' @@ -215,16 +194,16 @@ code = ''' lfs_off_t off; lfs_size_t size; - lfs_rtag_t ntag; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_ERR_NOENT; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + // TODO move these extra checks (for 0, in-between, enoent) to other tests + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_ERR_NOENT; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_ERR_NOENT; // commit with one attribute @@ -233,27 +212,19 @@ code = ''' lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes @@ -264,42 +235,30 @@ code = ''' lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) => LFS_ERR_NOENT; ''' -# [cases.rbyd_commit_fetchmatch] -# [cases.rbyd_multi_commit_fetchmatch] +# [cases.test_rbyd_commit_fetchmatch] +# [cases.test_rbyd_multi_commit_fetchmatch] -[cases.rbyd_leaves] +[cases.test_rbyd_bifoliate] in = 'lfs.c' defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] code = ''' @@ -317,9 +276,9 @@ code = ''' }; // create a split in the leaves - // /| - // 1 1 2 + // .-'| + // 1 1 2 lfs_rbyd_t rbyd = rbyd_init; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, @@ -329,42 +288,249 @@ code = ''' lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_off_t off; lfs_size_t size; - lfs_rtag_t ntag; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, 0x98, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) - => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); // split the other direction - // >r - // => /| - // 2 2 1 + // >b + // => .-'| + // 2 2 1 rbyd = rbyd_init; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, - LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, - LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL))) => 0; + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) => LFS_MKRTAG(GSTATE, 1, 0); - assert(size == 4); - //assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); - lfs_rbyd_lookup(&lfs, &rbyd, 0x98, &off, &size, &ntag) + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - //assert(ntag == LFS_ERR_NOENT); - lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size, &ntag) - => LFS_MKRTAG(GSTATE, 2, 0); - assert(size == 4); - assert(ntag == LFS_ERR_NOENT); ''' +[cases.test_rbyd_bflips] +in = 'lfs.c' +defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + + // ignore a black edge + // .----'| + // 1 2 1 2 2 + lfs_rbyd_t rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xcccccccc}, 4, NULL)))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_off_t off; + lfs_size_t size; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + + // flip a black edge + // b + // .-'| => .-'| + // 1 2 1 2 1 + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xcccccccc}, 4, NULL)))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); +''' + +[cases.test_rbyd_trifoliate] +in = 'lfs.c' +defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + + // without a flip + // | 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, NULL)))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_off_t off; + lfs_size_t size; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); + + // with a flip + // >r + // .-'| + // | >b + // .-'| .--|-'| + // 2 3 2 3 1 + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xcccccccc}, 4, NULL)))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); +''' + + +[cases.test_rbyd_rflips] +in = 'lfs.c' +defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + + // ignore a red edge and black edge + // | 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xdddddddd}, 4, NULL))))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_off_t off; + lfs_size_t size; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); + + // ignore a red edge, flip a black edge + // | >b + // | .-'| | .-'| + // 1 2 3 1 2 3 2 + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xdddddddd}, 4, NULL))))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); + + // flip a red edge and black edge + // r + // .----'| .-'| + // | | >b + // | .-'| .--|-'| + // 1 2 3 1 2 3 1 + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xdddddddd}, 4, NULL))))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); + + // flip a red edge, ignore a black edge + // r + // .-'| .-------'| + // | >b => | >b + // .--|-'| | .-'| + // 3 1 2 3 1 2 1 + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xbbbbbbbb}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xcccccccc}, 4, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xdddddddd}, 4, NULL))))) => 0; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 1, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 1, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 2, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 2, 0); + lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(GSTATE, 3, 0), &off, &size) + => LFS_MKRTAG(GSTATE, 3, 0); +'''