Added weight-adjusting insert operations, though it is currently very hacky
This commit is contained in:
@@ -412,24 +412,26 @@ typedef uint32_t lfs_rtag_t;
|
|||||||
typedef int32_t lfs_srtag_t;
|
typedef int32_t lfs_srtag_t;
|
||||||
|
|
||||||
enum lfs_rtag_type1 {
|
enum lfs_rtag_type1 {
|
||||||
LFS_TYPE1_CREATE = 0x40,
|
LFS_TYPE1_CREATE = 0x0040,
|
||||||
LFS_TYPE1_DELETE = 0x48,
|
LFS_TYPE1_CREATEREG = 0x00c0,
|
||||||
LFS_TYPE1_STRUCT = 0x50,
|
LFS_TYPE1_CREATEDIR = 0x0140,
|
||||||
LFS_TYPE1_UATTR = 0x60,
|
LFS_TYPE1_DELETE = 0x0048,
|
||||||
|
LFS_TYPE1_STRUCT = 0x0050,
|
||||||
|
LFS_TYPE1_UATTR = 0x0060,
|
||||||
|
|
||||||
LFS_TYPE1_TAIL = 0x08,
|
LFS_TYPE1_TAIL = 0x0008,
|
||||||
LFS_TYPE1_GSTATE = 0x10,
|
LFS_TYPE1_GSTATE = 0x0010,
|
||||||
|
|
||||||
LFS_TYPE1_CRC0 = 0x02,
|
LFS_TYPE1_CRC = 0x0002,
|
||||||
LFS_TYPE1_CRC1 = 0x03,
|
LFS_TYPE1_FCRC = 0x000a,
|
||||||
LFS_TYPE1_FCRC = 0x0a,
|
|
||||||
|
|
||||||
LFS_TYPE1_RM = 0x01,
|
LFS_TYPE1_RM = 0x0001,
|
||||||
|
LFS_TYPE1_ALT = 0x0004,
|
||||||
|
};
|
||||||
|
|
||||||
LFS_TYPE1_ALTBLT = 0x04,
|
enum lfs_rtag_pat {
|
||||||
LFS_TYPE1_ALTRLT = 0x05,
|
LFS_PAT_GET = 0x0000,
|
||||||
LFS_TYPE1_ALTBGT = 0x06,
|
LFS_PAT_FIND = 0x0001,
|
||||||
LFS_TYPE1_ALTRGT = 0x07,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LFS_ALT_B false
|
#define LFS_ALT_B false
|
||||||
@@ -452,8 +454,14 @@ enum lfs_rtag_type1 {
|
|||||||
#define LFS_MKRRMTAG(type1, type2, id) \
|
#define LFS_MKRRMTAG(type1, type2, id) \
|
||||||
LFS_MKRRMTAG_(LFS_TYPE1_##type1, type2, id)
|
LFS_MKRRMTAG_(LFS_TYPE1_##type1, type2, id)
|
||||||
|
|
||||||
|
#define LFS_MKRPATTAG_(pat, type1, type2, id) \
|
||||||
|
LFS_MKRTAG_((pat) | (type1), type2, id)
|
||||||
|
|
||||||
|
#define LFS_MKRPATTAG(pat, type1, type2, id) \
|
||||||
|
LFS_MKRPATTAG_(LFS_PAT_##pat, type1, type2, id)
|
||||||
|
|
||||||
#define LFS_MKRALT_(color, dir, weight) \
|
#define LFS_MKRALT_(color, dir, weight) \
|
||||||
(LFS_TYPE1_ALTBLT \
|
(LFS_TYPE1_ALT \
|
||||||
| ((0x1 & (lfs_rtag_t)(color)) << 0) \
|
| ((0x1 & (lfs_rtag_t)(color)) << 0) \
|
||||||
| ((0x1 & (lfs_rtag_t)(dir)) << 1) \
|
| ((0x1 & (lfs_rtag_t)(dir)) << 1) \
|
||||||
| ((0xfffffff & (lfs_rtag_t)(weight)) << 3))
|
| ((0xfffffff & (lfs_rtag_t)(weight)) << 3))
|
||||||
@@ -466,6 +474,14 @@ static inline bool lfs_rtag_isvalid(lfs_rtag_t tag) {
|
|||||||
return !(tag & 0x80000000);
|
return !(tag & 0x80000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline lfs_rtag_t lfs_rtag_valid(lfs_rtag_t tag) {
|
||||||
|
return tag & ~0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfs_rtag_t lfs_rtag_invalid(lfs_rtag_t tag) {
|
||||||
|
return tag | 0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool lfs_rtag_isalt(lfs_rtag_t tag) {
|
static inline bool lfs_rtag_isalt(lfs_rtag_t tag) {
|
||||||
return tag & 0x4;
|
return tag & 0x4;
|
||||||
}
|
}
|
||||||
@@ -498,10 +514,22 @@ static inline lfs_rtag_t lfs_rtag_setid(lfs_rtag_t tag, uint16_t id) {
|
|||||||
return (tag & 0x7fff) | ((lfs_rtag_t)id << 15);
|
return (tag & 0x7fff) | ((lfs_rtag_t)id << 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline lfs_rtag_t lfs_rtag_incid(lfs_rtag_t tag) {
|
||||||
|
return tag + (1 << 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfs_rtag_t lfs_rtag_decid(lfs_rtag_t tag) {
|
||||||
|
return tag - (1 << 15);
|
||||||
|
}
|
||||||
|
|
||||||
static inline lfs_rtag_t lfs_rtag_inc(lfs_rtag_t tag) {
|
static inline lfs_rtag_t lfs_rtag_inc(lfs_rtag_t tag) {
|
||||||
return tag + 0x8;
|
return tag + 0x8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t lfs_rtag_pat(lfs_rtag_t tag) {
|
||||||
|
return tag & 0x7;
|
||||||
|
}
|
||||||
|
|
||||||
// alt operations
|
// alt operations
|
||||||
static inline bool lfs_rtag_isblack(lfs_rtag_t tag) {
|
static inline bool lfs_rtag_isblack(lfs_rtag_t tag) {
|
||||||
return !(tag & 0x1);
|
return !(tag & 0x1);
|
||||||
@@ -545,7 +573,7 @@ static inline lfs_srtag_t lfs_rtag_weight_lt(lfs_rtag_t tag, uint16_t count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline lfs_srtag_t lfs_rtag_weight_gt(lfs_rtag_t tag, uint16_t count) {
|
static inline lfs_srtag_t lfs_rtag_weight_gt(lfs_rtag_t tag, uint16_t count) {
|
||||||
return (((lfs_srtag_t)count+1) << 12)-1 - lfs_rtag_weight(tag);
|
return (((lfs_srtag_t)count) << 12)-1 - lfs_rtag_weight(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs_rtag_follow(lfs_rtag_t alt,
|
static inline bool lfs_rtag_follow(lfs_rtag_t alt,
|
||||||
@@ -606,40 +634,55 @@ struct lfs_rattr {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define LFS_MKRATTR_(...) \
|
#define LFS_MKRATTR_(...) \
|
||||||
(&(struct lfs_rattr){__VA_ARGS__})
|
(&(const struct lfs_rattr){__VA_ARGS__})
|
||||||
|
|
||||||
#define LFS_MKRATTR(type1, type2, id, buffer, size, next) \
|
#define LFS_MKRATTR(type1, type2, id, buffer, size, next) \
|
||||||
(&(struct lfs_rattr){LFS_MKRTAG(type1, type2, id), buffer, size, next})
|
(&(const struct lfs_rattr){ \
|
||||||
|
LFS_MKRTAG(type1, type2, id), \
|
||||||
|
buffer, size, next})
|
||||||
|
|
||||||
#define LFS_MKRRMATTR(type1, type2, id, next) \
|
#define LFS_MKRRMATTR(type1, type2, id, next) \
|
||||||
(&(struct lfs_rattr){LFS_MKRRMTAG(type1, type2, id), NULL, 0, next})
|
(&(const struct lfs_rattr){ \
|
||||||
|
LFS_MKRRMTAG(type1, type2, id), \
|
||||||
|
NULL, 0, next})
|
||||||
|
|
||||||
|
|
||||||
// operations on pattern lists
|
// operations on pattern lists
|
||||||
enum lfs_fetchpattern_type {
|
struct lfs_rpat {
|
||||||
LFS_FETCHPATTERN_NAME = 0,
|
|
||||||
LFS_FETCHPATTERN_PAIR = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lfs_fetchpattern {
|
|
||||||
lfs_rtag_t tag;
|
lfs_rtag_t tag;
|
||||||
const void *buffer;
|
union {
|
||||||
lfs_size_t size;
|
struct {
|
||||||
struct lfs_fetchpattern *next;
|
void *buffer;
|
||||||
|
lfs_size_t size;
|
||||||
|
} get;
|
||||||
|
struct {
|
||||||
|
const void *buffer;
|
||||||
|
lfs_size_t size;
|
||||||
|
} find;
|
||||||
|
} u;
|
||||||
|
struct lfs_rpat *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LFS_MKRPATTERN_(...) \
|
#define LFS_MKRGETPAT_(tag, buffer, size, next) \
|
||||||
(&(struct lfs_fetchpattern){__VA_ARGS__})
|
(&(struct lfs_rpat){ \
|
||||||
|
.tag = LFS_PAT_GET | (tag), \
|
||||||
|
.u.get.buffer = buffer, \
|
||||||
|
.u.get.size = size, \
|
||||||
|
.next = next})
|
||||||
|
|
||||||
#define LFS_MKRPATTERN(type, type1, type2, buffer, size, next) \
|
#define LFS_MKRGETPAT(type1, type2, buffer, size, next) \
|
||||||
(&(struct lfs_fetchpattern){ \
|
LFS_MKRGET_(LFS_MKRTAG(type1, type2, 0), buffer, size, next)
|
||||||
LFS_MKRTAG(LFS_FETCHPATTERN_##type | type1, type2, 0), \
|
|
||||||
buffer, size, next})
|
#define LFS_MKRFINDPAT_(tag, buffer, size, next) \
|
||||||
|
(&(struct lfs_rpat){ \
|
||||||
|
.tag = LFS_PAT_FIND | (tag), \
|
||||||
|
.u.find.buffer = buffer, \
|
||||||
|
.u.find.size = size, \
|
||||||
|
.next = next})
|
||||||
|
|
||||||
|
#define LFS_MKRFINDPAT(type1, type2, buffer, size, next) \
|
||||||
|
LFS_MKRFIND_(LFS_MKRTAG(type1, type2, 0), buffer, size, next)
|
||||||
|
|
||||||
static inline uint8_t lfs_fetchpattern_type(
|
|
||||||
const struct lfs_fetchpattern *pattern) {
|
|
||||||
return pattern->tag & 0x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// operations on global state
|
// operations on global state
|
||||||
static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
|
static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) {
|
||||||
@@ -989,9 +1032,14 @@ static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs,
|
|||||||
|
|
||||||
static int lfs_rbyd_fetch(lfs_t *lfs,
|
static int lfs_rbyd_fetch(lfs_t *lfs,
|
||||||
lfs_rbyd_t *rbyd, lfs_block_t block,
|
lfs_rbyd_t *rbyd, lfs_block_t block,
|
||||||
struct lfs_fetchpattern *patterns) {
|
struct lfs_rpat *patterns) {
|
||||||
// TODO rm this
|
// TODO this
|
||||||
(void)patterns;
|
// first mark patterns as invalid until we find matches
|
||||||
|
for (struct lfs_rpat *pattern = patterns;
|
||||||
|
pattern;
|
||||||
|
pattern = pattern->next) {
|
||||||
|
pattern->tag = lfs_rtag_invalid(pattern->tag);
|
||||||
|
}
|
||||||
|
|
||||||
// read the revision count and get the crc started
|
// read the revision count and get the crc started
|
||||||
uint32_t rev;
|
uint32_t rev;
|
||||||
@@ -1007,6 +1055,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
|
|||||||
lfs_off_t off = sizeof(uint32_t);
|
lfs_off_t off = sizeof(uint32_t);
|
||||||
lfs_off_t trunk = 0;
|
lfs_off_t trunk = 0;
|
||||||
bool wastrunk = false;
|
bool wastrunk = false;
|
||||||
|
uint16_t count = 0;
|
||||||
|
|
||||||
rbyd->block = block;
|
rbyd->block = block;
|
||||||
rbyd->rev = lfs_fromle32_(&rev);
|
rbyd->rev = lfs_fromle32_(&rev);
|
||||||
@@ -1057,7 +1106,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// not an end-of-commit crc
|
// not an end-of-commit crc
|
||||||
if ((lfs_rtag_type1(tag) & ~0x1) != LFS_TYPE1_CRC0) {
|
if ((lfs_rtag_type1(tag) & ~0x1) != LFS_TYPE1_CRC) {
|
||||||
// fcrc is only valid if the last tag was a crc
|
// fcrc is only valid if the last tag was a crc
|
||||||
hasfcrc = false;
|
hasfcrc = false;
|
||||||
|
|
||||||
@@ -1072,8 +1121,11 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found an fcrc?
|
// found a create? increase count of ids
|
||||||
if (lfs_rtag_type1(tag) == LFS_TYPE1_FCRC) {
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
|
||||||
|
count += 1;
|
||||||
|
// found an fcrc? save for later
|
||||||
|
} else if (lfs_rtag_type1(tag) == LFS_TYPE1_FCRC) {
|
||||||
err = lfs_bd_read(lfs,
|
err = lfs_bd_read(lfs,
|
||||||
NULL, &lfs->rcache, lfs->cfg->block_size,
|
NULL, &lfs->rcache, lfs->cfg->block_size,
|
||||||
block, off, &fcrc,
|
block, off, &fcrc,
|
||||||
@@ -1121,6 +1173,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
|
|||||||
rbyd->trunk = trunk;
|
rbyd->trunk = trunk;
|
||||||
rbyd->off = off;
|
rbyd->off = off;
|
||||||
rbyd->crc = crc;
|
rbyd->crc = crc;
|
||||||
|
rbyd->count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
off += size;
|
off += size;
|
||||||
@@ -1163,8 +1216,8 @@ tryagain:;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// weights for pruning
|
// weights for pruning
|
||||||
lfs_srtag_t lt = lfs_rtag_weight_lt(tag, rbyd->count);
|
lfs_srtag_t lt = lfs_rtag_weight_lt(tag, rbyd->count+1);
|
||||||
lfs_srtag_t gt = lfs_rtag_weight_gt(tag, rbyd->count);
|
lfs_srtag_t gt = lfs_rtag_weight_gt(tag, rbyd->count+1);
|
||||||
printf("lt, gt = (%x, %x)\n", lt, gt);
|
printf("lt, gt = (%x, %x)\n", lt, gt);
|
||||||
|
|
||||||
// descend down tree
|
// descend down tree
|
||||||
@@ -1417,9 +1470,9 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// setup commit state
|
// setup commit state
|
||||||
const lfs_block_t block = rbyd->block;
|
const lfs_block_t block = rbyd->block;
|
||||||
lfs_off_t trunk = rbyd->trunk;
|
lfs_off_t trunk = rbyd->trunk;
|
||||||
uint16_t count = rbyd->count;
|
|
||||||
lfs_off_t off = rbyd->off;
|
lfs_off_t off = rbyd->off;
|
||||||
uint32_t crc = rbyd->crc;
|
uint32_t crc = rbyd->crc;
|
||||||
|
uint16_t count = rbyd->count;
|
||||||
bool erased = false;
|
bool erased = false;
|
||||||
|
|
||||||
// mark as unerased in case we fail
|
// mark as unerased in case we fail
|
||||||
@@ -1442,6 +1495,8 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// append each tag to the tree
|
// append each tag to the tree
|
||||||
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
|
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
|
||||||
printf("append()\n");
|
printf("append()\n");
|
||||||
|
LFS_ASSERT(lfs_rtag_id(attr->tag) <= count+1);
|
||||||
|
|
||||||
// assume we'll update our trunk
|
// assume we'll update our trunk
|
||||||
lfs_off_t branch = trunk;
|
lfs_off_t branch = trunk;
|
||||||
trunk = off;
|
trunk = off;
|
||||||
@@ -1452,8 +1507,25 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// weights for pruning
|
// weights for pruning
|
||||||
lfs_srtag_t lt = lfs_rtag_weight_lt(attr->tag, count);
|
lfs_srtag_t lt;
|
||||||
lfs_srtag_t gt = lfs_rtag_weight_gt(attr->tag, count);
|
lfs_srtag_t gt;
|
||||||
|
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
||||||
|
// inserting a new id? align down
|
||||||
|
// TODO special function for this?
|
||||||
|
// if (lfs_rtag_id(attr->tag) == count+1) {
|
||||||
|
// lt = (count+1) << 12;
|
||||||
|
// gt = 0;
|
||||||
|
// } else {
|
||||||
|
// lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
|
||||||
|
// gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1);
|
||||||
|
// }
|
||||||
|
lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
|
||||||
|
gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1) + 1;
|
||||||
|
} else {
|
||||||
|
lt = lfs_rtag_weight_lt(attr->tag, count+1);
|
||||||
|
gt = lfs_rtag_weight_gt(attr->tag, count+1);
|
||||||
|
}
|
||||||
|
|
||||||
printf("lt, gt = (%x, %x)\n", lt, gt);
|
printf("lt, gt = (%x, %x)\n", lt, gt);
|
||||||
|
|
||||||
// queue of pending alts we can emulate rotations with
|
// queue of pending alts we can emulate rotations with
|
||||||
@@ -1533,7 +1605,8 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// should've taken red alt? needs a flip
|
// should've taken red alt? needs a flip
|
||||||
if (lt < 0 || gt < 0) {
|
if (lt < 0 || gt < 0) {
|
||||||
LFS_ASSERT(lfs_rtag_isblack(alt));
|
LFS_ASSERT(lfs_rtag_isblack(alt));
|
||||||
LFS_ASSERT(p_alts[0] && lfs_rtag_isred(p_alts[0]));
|
LFS_ASSERT(p_alts[0]);
|
||||||
|
LFS_ASSERT(lfs_rtag_isred(p_alts[0]));
|
||||||
|
|
||||||
printf("rflip %s (%x,%x)\n",
|
printf("rflip %s (%x,%x)\n",
|
||||||
lfs_rtag_isparallel(alt, p_alts[0]) ? "parallel" : "perpendicular",
|
lfs_rtag_isparallel(alt, p_alts[0]) ? "parallel" : "perpendicular",
|
||||||
@@ -1588,18 +1661,83 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// update the tag id
|
// update the tag id
|
||||||
// TODO should this be a function? maybe see what create/delete need
|
// TODO should this be a function? maybe see what create/delete need
|
||||||
// TODO alternatively can we do this a bit more directly here
|
// TODO alternatively can we do this a bit more directly here
|
||||||
|
// lfs_rtag_t tag_ = lfs_rtag_setid(alt,
|
||||||
|
// lfs_min(lfs_rtag_id(attr->tag), count));
|
||||||
lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(attr->tag));
|
lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(attr->tag));
|
||||||
|
// TODO I don't really know why this works
|
||||||
|
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE && gt == 0) {
|
||||||
|
tag_ = lfs_rtag_decid(tag_);
|
||||||
|
}
|
||||||
|
//gt == 0 ? lfs_rtag_id(attr->tag)-1 : lfs_rtag_id(attr->tag));
|
||||||
|
printf("found %x (%d, %d)\n", tag_, lt >> 12, gt >> 12);
|
||||||
|
|
||||||
// split leaf?
|
// split leaf?
|
||||||
if (tag_ != attr->tag) {
|
// TODO we might be able to rearrange this a bit better
|
||||||
// bias the weights so that lookups always find the
|
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE
|
||||||
// next biggest tag
|
|| tag_ != attr->tag) {
|
||||||
if (lfs_rtag_weight(tag_) < lfs_rtag_weight(attr->tag)) {
|
// inserting a new id?
|
||||||
alt = LFS_MKRALT(B, LT, lt+1
|
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
||||||
+ lfs_rtag_weight(tag_)
|
// bias the weights so that lookups always find the
|
||||||
- lfs_rtag_weight(attr->tag));
|
// next biggest tag
|
||||||
|
if (lfs_rtag_weight(tag_)
|
||||||
|
< lfs_rtag_weight(attr->tag & ~0x7fff)) {
|
||||||
|
printf("lt insert\n");
|
||||||
|
//
|
||||||
|
// lt gt
|
||||||
|
// .----'---. .-'.
|
||||||
|
// alt
|
||||||
|
// .--'--.
|
||||||
|
// <---+------+---|--+--|---+------+--->
|
||||||
|
// a old new d e
|
||||||
|
//
|
||||||
|
alt = LFS_MKRALT(B, LT, lt
|
||||||
|
- (lfs_rtag_weight(attr->tag & ~0x7fff)-1
|
||||||
|
- lfs_rtag_weight(tag_))
|
||||||
|
+ 1);
|
||||||
|
} else {
|
||||||
|
printf("gt insert\n");
|
||||||
|
printf("hmmm? %08x %08x\n", lfs_rtag_weight(tag_), lfs_rtag_weight(attr->tag & ~0x7fff));
|
||||||
|
//
|
||||||
|
// lt gt
|
||||||
|
// .-----'--. .-'.
|
||||||
|
// alt
|
||||||
|
// .--'--.
|
||||||
|
// <---+------+---|--+--|---+------+--->
|
||||||
|
// a b new old e
|
||||||
|
//
|
||||||
|
alt = LFS_MKRALT(B, GT,
|
||||||
|
// TODO hm, can this be done differently?
|
||||||
|
lfs_rtag_weight(lfs_rtag_incid(tag_))
|
||||||
|
- lfs_rtag_weight(attr->tag));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alt = LFS_MKRALT(B, GT, gt);
|
// bias the weights so that lookups always find the
|
||||||
|
// next biggest tag
|
||||||
|
if (lfs_rtag_weight(tag_)
|
||||||
|
< lfs_rtag_weight(attr->tag)) {
|
||||||
|
//
|
||||||
|
// lt gt
|
||||||
|
// .-----'-----. .--'--.
|
||||||
|
// alt
|
||||||
|
// .--'--.
|
||||||
|
// <---+------+------+------+------+--->
|
||||||
|
// a old new d e
|
||||||
|
//
|
||||||
|
alt = LFS_MKRALT(B, LT, lt
|
||||||
|
+ 1
|
||||||
|
- (lfs_rtag_weight(attr->tag)
|
||||||
|
- lfs_rtag_weight(tag_)));
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// lt gt
|
||||||
|
// .-----'-----. .--'--.
|
||||||
|
// alt
|
||||||
|
// .--'--.
|
||||||
|
// <---+------+------+------+------+--->
|
||||||
|
// a b new old e
|
||||||
|
//
|
||||||
|
alt = LFS_MKRALT(B, GT, gt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lfs_ssize_t delta = lfs_rbyd_p_push(lfs,
|
lfs_ssize_t delta = lfs_rbyd_p_push(lfs,
|
||||||
@@ -1651,6 +1789,15 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
}
|
}
|
||||||
off += attr->size;
|
off += attr->size;
|
||||||
|
|
||||||
|
// if we're inserting, increase the id count, indirectly shifting
|
||||||
|
// all ids >= over one
|
||||||
|
//
|
||||||
|
// note we do this here since it is possible to insert into an
|
||||||
|
// empty tree
|
||||||
|
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1726,7 +1873,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// get around this catch-22 we just always write a fully-expanded leb128
|
// get around this catch-22 we just always write a fully-expanded leb128
|
||||||
// encoding
|
// encoding
|
||||||
uint8_t buffer[1+4+4];
|
uint8_t buffer[1+4+4];
|
||||||
buffer[0] = (LFS_MKRTAG(CRC0, 0, 0) << 1) | (lfs_popc(crc) & 1);
|
buffer[0] = (LFS_MKRTAG(CRC, 0, 0) << 1) | (lfs_popc(crc) & 1);
|
||||||
|
|
||||||
lfs_off_t padding = aligned - (off + 1+4);
|
lfs_off_t padding = aligned - (off + 1+4);
|
||||||
buffer[1] = 0x80 | (0x7f & (padding >> 0));
|
buffer[1] = 0x80 | (0x7f & (padding >> 0));
|
||||||
@@ -1778,6 +1925,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
rbyd->trunk = trunk;
|
rbyd->trunk = trunk;
|
||||||
rbyd->off = aligned;
|
rbyd->off = aligned;
|
||||||
rbyd->crc = crc;
|
rbyd->crc = crc;
|
||||||
|
rbyd->count = count;
|
||||||
rbyd->erased = erased;
|
rbyd->erased = erased;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+575
-1
@@ -87,6 +87,8 @@ code = '''
|
|||||||
# [cases.test_rbyd_fetchmatch]
|
# [cases.test_rbyd_fetchmatch]
|
||||||
# [cases.test_rbyd_multi_fetchmatch]
|
# [cases.test_rbyd_multi_fetchmatch]
|
||||||
|
|
||||||
|
# TODO we really need to test dense keys...
|
||||||
|
|
||||||
[cases.test_rbyd_lookup]
|
[cases.test_rbyd_lookup]
|
||||||
in = 'lfs.c'
|
in = 'lfs.c'
|
||||||
code = '''
|
code = '''
|
||||||
@@ -1737,6 +1739,7 @@ code = '''
|
|||||||
|
|
||||||
// check that we can still lookup all the tags
|
// check that we can still lookup all the tags
|
||||||
prng = 42;
|
prng = 42;
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
for (lfs_size_t i = 0; i < count; i++) {
|
for (lfs_size_t i = 0; i < count; i++) {
|
||||||
uint8_t x
|
uint8_t x
|
||||||
= (ORDER == 0) ? (uint8_t)i
|
= (ORDER == 0) ? (uint8_t)i
|
||||||
@@ -1749,7 +1752,7 @@ code = '''
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
### removal testing ###
|
### Removal testing ###
|
||||||
|
|
||||||
[cases.test_rbyd_remove]
|
[cases.test_rbyd_remove]
|
||||||
in = 'lfs.c'
|
in = 'lfs.c'
|
||||||
@@ -2146,3 +2149,574 @@ code = '''
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
### Insertion testing ###
|
||||||
|
|
||||||
|
[cases.test_rbyd_insert]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.off = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.crc = 0,
|
||||||
|
.count = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfs_rbyd_t rbyd;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// try to insert one id
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 1);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4)
|
||||||
|
=> 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 1);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4)
|
||||||
|
=> 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
|
||||||
|
// try to insert two ids
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
// try to insert two in the other direction
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third to the right
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third to the left
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third in the middle
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)))) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_multi_insert]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.off = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.crc = 0,
|
||||||
|
.count = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfs_rbyd_t rbyd;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// try to insert one id
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 1);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4)
|
||||||
|
=> 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 1);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4)
|
||||||
|
=> 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
|
||||||
|
// try to insert two ids
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
// try to insert two in the other direction
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 2);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third to the right
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third to the left
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
// insert a third in the middle
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0;
|
||||||
|
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == 3);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_insert_permutations]
|
||||||
|
defines.N = 'range(1, 8)'
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.off = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.crc = 0,
|
||||||
|
.count = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfs_rbyd_t rbyd;
|
||||||
|
const uint8_t names[6][4] = {
|
||||||
|
"\xaa\xaa\xaa\xaa",
|
||||||
|
"\xbb\xbb\xbb\xbb",
|
||||||
|
"\xcc\xcc\xcc\xcc",
|
||||||
|
"\xdd\xdd\xdd\xdd",
|
||||||
|
"\xee\xee\xee\xee",
|
||||||
|
"\xff\xff\xff\xff",
|
||||||
|
};
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// test all permutations of a given size
|
||||||
|
uint8_t perm[N];
|
||||||
|
uint8_t stack[N];
|
||||||
|
for (uint8_t i = 0; i < N; i++) {
|
||||||
|
perm[i] = i;
|
||||||
|
stack[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t i = 1;
|
||||||
|
while (i < N) {
|
||||||
|
// print permutation to help debugging
|
||||||
|
printf("--- permutation: [");
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
if (j > 0) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("%d", perm[j]+1);
|
||||||
|
}
|
||||||
|
printf("] ---\n");
|
||||||
|
|
||||||
|
// build the attribute list for the current permutation
|
||||||
|
struct lfs_rattr attrs[N];
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
// adjust id based on future insertions
|
||||||
|
uint16_t id = perm[j];
|
||||||
|
for (int k = j+1; k < N; k++) {
|
||||||
|
if (perm[j] > perm[k]) {
|
||||||
|
id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs[j] = *LFS_MKRATTR(
|
||||||
|
CREATEREG, 0, id+1,
|
||||||
|
names[perm[j] % 6], 4,
|
||||||
|
(j+1 < N) ? &attrs[j+1] : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test the given permutation
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd, attrs) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == N);
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd,
|
||||||
|
LFS_MKRTAG(CREATEREG, 0, j+1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// next permutation using Heap's algorithm
|
||||||
|
if (stack[i] < i) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
uint8_t t = perm[0];
|
||||||
|
perm[0] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
} else {
|
||||||
|
uint8_t t = perm[stack[i]];
|
||||||
|
perm[stack[i]] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
}
|
||||||
|
stack[i] += 1;
|
||||||
|
i = 1;
|
||||||
|
} else {
|
||||||
|
stack[i] = 0;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_multi_insert_permutations]
|
||||||
|
defines.N = 'range(1, 8)'
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.off = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.crc = 0,
|
||||||
|
.count = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfs_rbyd_t rbyd;
|
||||||
|
const uint8_t names[6][4] = {
|
||||||
|
"\xaa\xaa\xaa\xaa",
|
||||||
|
"\xbb\xbb\xbb\xbb",
|
||||||
|
"\xcc\xcc\xcc\xcc",
|
||||||
|
"\xdd\xdd\xdd\xdd",
|
||||||
|
"\xee\xee\xee\xee",
|
||||||
|
"\xff\xff\xff\xff",
|
||||||
|
};
|
||||||
|
uint8_t buffer[4];
|
||||||
|
|
||||||
|
// test all permutations of a given size
|
||||||
|
uint8_t perm[N];
|
||||||
|
uint8_t stack[N];
|
||||||
|
for (uint8_t i = 0; i < N; i++) {
|
||||||
|
perm[i] = i;
|
||||||
|
stack[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t i = 1;
|
||||||
|
while (i < N) {
|
||||||
|
// print permutation to help debugging
|
||||||
|
printf("--- permutation: [");
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
if (j > 0) {
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("%d", perm[j]+1);
|
||||||
|
}
|
||||||
|
printf("] ---\n");
|
||||||
|
|
||||||
|
// test the given permutation with multiple commits
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
// adjust id based on future insertions
|
||||||
|
uint16_t id = perm[j];
|
||||||
|
for (int k = j+1; k < N; k++) {
|
||||||
|
if (perm[j] > perm[k]) {
|
||||||
|
id -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4,
|
||||||
|
NULL)) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
assert(rbyd.count == N);
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
lfs_rbyd_get(&lfs, &rbyd,
|
||||||
|
LFS_MKRTAG(CREATEREG, 0, j+1), buffer, 4) => 4;
|
||||||
|
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// next permutation using Heap's algorithm
|
||||||
|
if (stack[i] < i) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
uint8_t t = perm[0];
|
||||||
|
perm[0] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
} else {
|
||||||
|
uint8_t t = perm[stack[i]];
|
||||||
|
perm[stack[i]] = perm[i];
|
||||||
|
perm[i] = t;
|
||||||
|
}
|
||||||
|
stack[i] += 1;
|
||||||
|
i = 1;
|
||||||
|
} else {
|
||||||
|
stack[i] = 0;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_rbyd_insert_large]
|
||||||
|
in = 'lfs.c'
|
||||||
|
# ORDER:
|
||||||
|
# 0 = in-order
|
||||||
|
# 1 = reverse-order
|
||||||
|
# 2 = random-order
|
||||||
|
defines.ORDER = [0, 1, 2]
|
||||||
|
code = '''
|
||||||
|
lfs_t lfs;
|
||||||
|
lfs_init(&lfs, cfg) => 0;
|
||||||
|
|
||||||
|
lfs_rbyd_t init_rbyd = {
|
||||||
|
.block = 0,
|
||||||
|
.trunk = 0,
|
||||||
|
.off = 0,
|
||||||
|
.rev = 1,
|
||||||
|
.crc = 0,
|
||||||
|
.count = 0,
|
||||||
|
.erased = true,
|
||||||
|
};
|
||||||
|
lfs_rbyd_t rbyd;
|
||||||
|
const uint8_t names[6][4] = {
|
||||||
|
"\xaa\xaa\xaa\xaa",
|
||||||
|
"\xbb\xbb\xbb\xbb",
|
||||||
|
"\xcc\xcc\xcc\xcc",
|
||||||
|
"\xdd\xdd\xdd\xdd",
|
||||||
|
"\xee\xee\xee\xee",
|
||||||
|
"\xff\xff\xff\xff",
|
||||||
|
};
|
||||||
|
|
||||||
|
// create the rbyd tree
|
||||||
|
rbyd = init_rbyd;
|
||||||
|
lfs_bd_erase(&lfs, rbyd.block) => 0;
|
||||||
|
|
||||||
|
// keep inserting tags until we run out of space
|
||||||
|
//
|
||||||
|
// note, the ids we create this way are both sparse and sometimes
|
||||||
|
// repeated, so we need to mod our current rbyd size to avoid invalid
|
||||||
|
// insertions
|
||||||
|
//
|
||||||
|
uint32_t prng = 42;
|
||||||
|
for (lfs_size_t i = 0;; i++) {
|
||||||
|
uint16_t x
|
||||||
|
= (ORDER == 0) ? (uint16_t)i
|
||||||
|
: (ORDER == 1) ? (uint16_t)(((lfs_size_t)-1) - i)
|
||||||
|
: (uint16_t)TEST_PRNG(&prng);
|
||||||
|
x = x % (rbyd.count+1);
|
||||||
|
|
||||||
|
int err = lfs_rbyd_commit(&lfs, &rbyd,
|
||||||
|
LFS_MKRATTR(CREATEREG, 0, x+1, names[x % 6], 4, NULL));
|
||||||
|
// if we can't fit an fcrc, erased is set to false, but if we can,
|
||||||
|
// lfs_rbyd_commit may error later with LFS_ERR_RANGE
|
||||||
|
if (!rbyd.erased || err == LFS_ERR_RANGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that we can at least lookup all the tags
|
||||||
|
lfs_off_t off;
|
||||||
|
lfs_size_t size;
|
||||||
|
lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0;
|
||||||
|
for (uint16_t x = 0; x < rbyd.count; x++) {
|
||||||
|
lfs_rbyd_lookup(&lfs, &rbyd,
|
||||||
|
LFS_MKRTAG(CREATEREG, 0, x+1), &off, &size)
|
||||||
|
=> LFS_MKRTAG(CREATEREG, 0, x+1);
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user