Merged lfsr_btree_commit/lfsr_btree_commit__, related cleanup
This was a temporary hack to make refactoring easier. These are really the same function.
This commit is contained in:
@@ -3848,12 +3848,107 @@ static int lfsr_btree_parent(lfs_t *lfs,
|
||||
|
||||
|
||||
// core btree algorithm
|
||||
static int lfsr_btree_commit(lfs_t *lfs,
|
||||
lfsr_btree_t *btree, lfs_size_t bid,
|
||||
lfsr_rbyd_t *rbyd,
|
||||
static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||
// other layers should check for inlined btrees before this
|
||||
LFS_ASSERT(!lfsr_btree_isinlined(btree));
|
||||
// first find the effective bid and any changes to the number of tags
|
||||
lfs_size_t bid = -1;
|
||||
lfs_ssize_t tag_delta = 0;
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
// note unsigned min here chooses non-negative bids
|
||||
bid = lfs_min32(bid, attrs[i].rid);
|
||||
|
||||
// non-grow tags with deltas change the number of tags
|
||||
if (!lfsr_tag_isgrow(attrs[i].tag)) {
|
||||
tag_delta += lfs_sclamp32(attrs[i].delta, -1, +1);
|
||||
}
|
||||
}
|
||||
LFS_ASSERT(bid <= lfsr_btree_weight(btree));
|
||||
|
||||
// inlined btree? staying inlined?
|
||||
if (lfsr_btree_isinlined(btree)) {
|
||||
// staying inlined?
|
||||
if (lfs_clamp32(lfsr_btree_weight(btree), 0, 1) + tag_delta <= 1) {
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
// update our inlined tag, make sure to strip wide/grow bits
|
||||
if (lfsr_tag_suptype(lfsr_tag_key(attrs[i].tag))
|
||||
== LFSR_TAG_STRUCT) {
|
||||
btree->u.i.tag = lfsr_tag_key(attrs[i].tag);
|
||||
|
||||
lfsr_data_t data_ = attrs[i].data;
|
||||
lfs_ssize_t d = lfsr_data_read(lfs, &data_,
|
||||
btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
btree->u.i.size = d;
|
||||
}
|
||||
|
||||
// update our btree weight
|
||||
LFS_ASSERT((lfs_ssize_t)lfsr_btree_weight(btree)
|
||||
+ attrs[i].delta >= 0);
|
||||
btree->u.i.weight += attrs[i].delta;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// uninlining?
|
||||
} else {
|
||||
// allocate a root rbyd
|
||||
lfsr_rbyd_t rbyd;
|
||||
int err = lfsr_rbyd_alloc(lfs, &rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// prepend inlined tag if we have one
|
||||
if (lfsr_btree_weight(btree) > 0) {
|
||||
err = lfsr_rbyd_append(lfs, &rbyd,
|
||||
0, btree->u.i.tag, +lfsr_btree_weight(btree),
|
||||
LFSR_DATA_BUF(btree->u.i.buf, btree->u.i.size));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// commit our attrs
|
||||
err = lfsr_rbyd_appendall(lfs, &rbyd, 0, -1, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_appendcksum(lfs, &rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// save our new root
|
||||
btree->u.r.rbyd = rbyd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// lookup in which leaf our bids resides
|
||||
//
|
||||
// for lfsr_btree_commit operations to work out, we need to
|
||||
// limit our bid to an rid in the tree, which is what this min
|
||||
// is doing
|
||||
//
|
||||
// note it's entirely possible for our btree to have a weight of
|
||||
// zero here
|
||||
lfsr_rbyd_t rbyd = btree->u.r.rbyd;
|
||||
if (lfsr_btree_weight(btree) > 0) {
|
||||
lfs_ssize_t rid;
|
||||
int err = lfsr_btree_lookupnext_(lfs, btree,
|
||||
lfs_min32(bid, lfsr_btree_weight(btree)-1),
|
||||
&bid, &rbyd, &rid, NULL, NULL, NULL);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
return err;
|
||||
}
|
||||
|
||||
// adjust bid to indicate the zero-most rid
|
||||
bid -= rid;
|
||||
}
|
||||
|
||||
// we need some scratch space for tail-recursive attrs here
|
||||
lfsr_attr_t scratch_attrs[4];
|
||||
@@ -3864,7 +3959,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// we will always need our parent, so go ahead and find it
|
||||
lfsr_rbyd_t parent;
|
||||
lfs_ssize_t pid;
|
||||
int err = lfsr_btree_parent(lfs, btree, bid, rbyd, &parent, &pid);
|
||||
int err = lfsr_btree_parent(lfs, btree, bid, &rbyd, &parent, &pid);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
@@ -3872,7 +3967,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// mark pid as -1 if we have no parent
|
||||
pid = -1;
|
||||
}
|
||||
lfs_size_t pweight = rbyd->weight;
|
||||
lfs_size_t pweight = rbyd.weight;
|
||||
|
||||
// fetch our rbyd so we can mutate it
|
||||
//
|
||||
@@ -3880,15 +3975,15 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// will fail to fetch so we need to check that this rbyd is unfetched
|
||||
//
|
||||
// a strange benefit is we cache the root of our btree this way
|
||||
if (!lfsr_rbyd_isfetched(rbyd)) {
|
||||
err = lfsr_rbyd_fetch(lfs, rbyd, rbyd->block, rbyd->trunk);
|
||||
if (!lfsr_rbyd_isfetched(&rbyd)) {
|
||||
err = lfsr_rbyd_fetch(lfs, &rbyd, rbyd.block, rbyd.trunk);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// make a copy so we have a reference to the old trunk in case of split
|
||||
lfsr_rbyd_t rbyd_ = *rbyd;
|
||||
lfsr_rbyd_t rbyd_ = rbyd;
|
||||
|
||||
// is rbyd erased? can we sneak our commit into any remaining
|
||||
// erased bytes? note that the btree trunk field prevents this from
|
||||
@@ -3912,7 +4007,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
}
|
||||
|
||||
// TODO do we really need to save rbyd_?
|
||||
*rbyd = rbyd_;
|
||||
rbyd = rbyd_;
|
||||
|
||||
// done?
|
||||
if (pid == -1) {
|
||||
@@ -3920,7 +4015,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
break;
|
||||
}
|
||||
|
||||
lfs_ssize_t scratch_dsize = lfsr_branch_todisk(lfs, rbyd, scratch_buf);
|
||||
lfs_ssize_t scratch_dsize = lfsr_branch_todisk(lfs, &rbyd, scratch_buf);
|
||||
if (scratch_dsize < 0) {
|
||||
return scratch_dsize;
|
||||
}
|
||||
@@ -3930,24 +4025,24 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// note that since we defer merges to compaction time, we can
|
||||
// end up removing an rbyd here
|
||||
bid -= pid - (pweight-1);
|
||||
if (rbyd->weight == 0) {
|
||||
if (rbyd.weight == 0) {
|
||||
scratch_attrs[0] = LFSR_ATTR(
|
||||
bid+pid, RM, +rbyd->weight-pweight,
|
||||
bid+pid, RM, +rbyd.weight-pweight,
|
||||
BUF(scratch_buf, scratch_dsize));
|
||||
attrs = scratch_attrs;
|
||||
attr_count = 1;
|
||||
} else {
|
||||
scratch_attrs[0] = LFSR_ATTR(
|
||||
bid+pid, GROW(RM), +rbyd->weight-pweight,
|
||||
bid+pid, GROW(RM), +rbyd.weight-pweight,
|
||||
NULL);
|
||||
scratch_attrs[1] = LFSR_ATTR(
|
||||
bid+pid+rbyd->weight-pweight, BRANCH, 0,
|
||||
bid+pid+rbyd.weight-pweight, BRANCH, 0,
|
||||
BUF(scratch_buf, scratch_dsize));
|
||||
attrs = scratch_attrs;
|
||||
attr_count = 2;
|
||||
}
|
||||
|
||||
*rbyd = parent;
|
||||
rbyd = parent;
|
||||
continue;
|
||||
|
||||
compact:;
|
||||
@@ -3956,7 +4051,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// check if we're within our compaction threshold, otherwise we
|
||||
// need to split
|
||||
lfs_size_t split_rid;
|
||||
lfs_ssize_t estimate = lfsr_rbyd_estimateall(lfs, rbyd, -1, -1,
|
||||
lfs_ssize_t estimate = lfsr_rbyd_estimateall(lfs, &rbyd, -1, -1,
|
||||
&split_rid);
|
||||
if (estimate < 0) {
|
||||
return estimate;
|
||||
@@ -3974,7 +4069,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
}
|
||||
|
||||
// try to compact
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_, -1, -1, rbyd);
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_, -1, -1, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
@@ -4008,7 +4103,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
return err;
|
||||
}
|
||||
|
||||
*rbyd = rbyd_;
|
||||
rbyd = rbyd_;
|
||||
|
||||
// done?
|
||||
if (pid == -1) {
|
||||
@@ -4016,7 +4111,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
break;
|
||||
}
|
||||
|
||||
scratch_dsize = lfsr_branch_todisk(lfs, rbyd, scratch_buf);
|
||||
scratch_dsize = lfsr_branch_todisk(lfs, &rbyd, scratch_buf);
|
||||
if (scratch_dsize < 0) {
|
||||
return scratch_dsize;
|
||||
}
|
||||
@@ -4026,29 +4121,29 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
// note that since we defer merges to compaction time, we can
|
||||
// end up removing an rbyd here
|
||||
bid -= pid - (pweight-1);
|
||||
if (rbyd->weight == 0) {
|
||||
if (rbyd.weight == 0) {
|
||||
scratch_attrs[0] = LFSR_ATTR(
|
||||
bid+pid, RM, +rbyd->weight-pweight,
|
||||
bid+pid, RM, +rbyd.weight-pweight,
|
||||
BUF(scratch_buf, scratch_dsize));
|
||||
attrs = scratch_attrs;
|
||||
attr_count = 1;
|
||||
} else {
|
||||
scratch_attrs[0] = LFSR_ATTR(
|
||||
bid+pid, GROW(RM), +rbyd->weight-pweight,
|
||||
bid+pid, GROW(RM), +rbyd.weight-pweight,
|
||||
NULL);
|
||||
scratch_attrs[1] = LFSR_ATTR(
|
||||
bid+pid+rbyd->weight-pweight, BRANCH, 0,
|
||||
bid+pid+rbyd.weight-pweight, BRANCH, 0,
|
||||
BUF(scratch_buf, scratch_dsize));
|
||||
attrs = scratch_attrs;
|
||||
attr_count = 2;
|
||||
}
|
||||
|
||||
*rbyd = parent;
|
||||
rbyd = parent;
|
||||
continue;
|
||||
|
||||
split:;
|
||||
// we should have something to split here
|
||||
LFS_ASSERT(split_rid > 0 && split_rid < rbyd->weight);
|
||||
LFS_ASSERT(split_rid > 0 && split_rid < rbyd.weight);
|
||||
|
||||
// allocate a new rbyd
|
||||
err = lfsr_rbyd_alloc(lfs, &rbyd_);
|
||||
@@ -4064,7 +4159,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
}
|
||||
|
||||
// copy over tags < split_rid
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_, 0, split_rid, rbyd);
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_, 0, split_rid, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
@@ -4089,7 +4184,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
}
|
||||
|
||||
// copy over tags >= split_rid
|
||||
err = lfsr_rbyd_compact(lfs, &sibling, split_rid, -1, rbyd);
|
||||
err = lfsr_rbyd_compact(lfs, &sibling, split_rid, -1, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
@@ -4195,7 +4290,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
attr_count = 4;
|
||||
}
|
||||
|
||||
*rbyd = parent;
|
||||
rbyd = parent;
|
||||
continue;
|
||||
|
||||
merge:;
|
||||
@@ -4373,7 +4468,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
LFS_ASSERT(pid != -1);
|
||||
if (pweight+sweight == lfsr_btree_weight(btree)) {
|
||||
// collapse our parent, decreasing the height of the tree
|
||||
*rbyd = rbyd_;
|
||||
rbyd = rbyd_;
|
||||
break;
|
||||
|
||||
} else {
|
||||
@@ -4403,235 +4498,24 @@ static int lfsr_btree_commit(lfs_t *lfs,
|
||||
attr_count = 3;
|
||||
}
|
||||
|
||||
*rbyd = parent;
|
||||
rbyd = parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// at this point rbyd should be the trunk of our tree
|
||||
btree->u.r.rbyd = *rbyd;
|
||||
btree->u.r.rbyd = rbyd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfsr_btree_commit__(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||
// first find the effective bid and any changes to the number of tags
|
||||
lfs_size_t bid = -1;
|
||||
lfs_ssize_t tag_delta = 0;
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
// note unsigned min here chooses non-negative bids
|
||||
bid = lfs_min32(bid, attrs[i].rid);
|
||||
|
||||
// non-grow tags with deltas change the number of tags
|
||||
if (!lfsr_tag_isgrow(attrs[i].tag)) {
|
||||
tag_delta += lfs_sclamp32(attrs[i].delta, -1, +1);
|
||||
}
|
||||
}
|
||||
LFS_ASSERT(bid <= lfsr_btree_weight(btree));
|
||||
|
||||
// inlined btree? staying inlined?
|
||||
if (lfsr_btree_isinlined(btree)) {
|
||||
// staying inlined?
|
||||
if (lfs_clamp32(lfsr_btree_weight(btree), 0, 1) + tag_delta <= 1) {
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
// update our inlined tag, make sure to strip wide/grow bits
|
||||
if (lfsr_tag_suptype(lfsr_tag_key(attrs[i].tag))
|
||||
== LFSR_TAG_STRUCT) {
|
||||
btree->u.i.tag = lfsr_tag_key(attrs[i].tag);
|
||||
|
||||
lfsr_data_t data_ = attrs[i].data;
|
||||
lfs_ssize_t d = lfsr_data_read(lfs, &data_,
|
||||
btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
btree->u.i.size = d;
|
||||
}
|
||||
|
||||
// update our btree weight
|
||||
LFS_ASSERT((lfs_ssize_t)lfsr_btree_weight(btree)
|
||||
+ attrs[i].delta >= 0);
|
||||
btree->u.i.weight += attrs[i].delta;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// uninlining?
|
||||
} else {
|
||||
// allocate a root rbyd
|
||||
lfsr_rbyd_t rbyd;
|
||||
int err = lfsr_rbyd_alloc(lfs, &rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// prepend inlined tag if we have one
|
||||
if (lfsr_btree_weight(btree) > 0) {
|
||||
err = lfsr_rbyd_append(lfs, &rbyd,
|
||||
0, btree->u.i.tag, +lfsr_btree_weight(btree),
|
||||
LFSR_DATA_BUF(btree->u.i.buf, btree->u.i.size));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// commit our attrs
|
||||
err = lfsr_rbyd_appendall(lfs, &rbyd, 0, -1, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_appendcksum(lfs, &rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// save our new root
|
||||
btree->u.r.rbyd = rbyd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// lookup in which leaf our bids reside
|
||||
//
|
||||
// for lfsr_btree_commit operations to work out, we need to
|
||||
// limit our bid to an rid in the tree, which is what this min
|
||||
// is doing
|
||||
//
|
||||
// note it's entirely possible for our btree to have a weight of
|
||||
// zero here
|
||||
lfsr_rbyd_t rbyd = btree->u.r.rbyd;
|
||||
if (lfsr_btree_weight(btree) > 0) {
|
||||
lfs_ssize_t rid;
|
||||
int err = lfsr_btree_lookupnext_(lfs, btree,
|
||||
lfs_min32(bid, lfsr_btree_weight(btree)-1),
|
||||
&bid, &rbyd, &rid, NULL, NULL, NULL);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
return err;
|
||||
}
|
||||
|
||||
// adjust bid to indicate the zero-most rid
|
||||
bid -= rid;
|
||||
}
|
||||
|
||||
// commit our rid into the tree, letting lfsr_btree_commit take care
|
||||
// of the rest
|
||||
int err = lfsr_btree_commit(lfs, btree, bid, &rbyd,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// TODO move to tests
|
||||
static int lfsr_btree_push(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
lfs_size_t bid, lfsr_tag_t tag, lfs_size_t weight, lfsr_data_t data) {
|
||||
LFS_ASSERT(bid <= lfsr_btree_weight(btree));
|
||||
return lfsr_btree_commit__(lfs, btree, LFSR_ATTRS(
|
||||
return lfsr_btree_commit(lfs, btree, LFSR_ATTRS(
|
||||
LFSR_ATTR(bid, TAG(tag), +weight, DATA(data))));
|
||||
}
|
||||
|
||||
// TODO
|
||||
//static int lfsr_btree_push_(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
// lfs_size_t bid, lfsr_tag_t tag, lfs_size_t weight, lfsr_data_t data) {
|
||||
// LFS_ASSERT(bid <= lfsr_btree_weight(btree));
|
||||
//
|
||||
// // null btree?
|
||||
// if (lfsr_btree_isinlined(btree) && lfsr_btree_weight(btree) == 0) {
|
||||
// LFS_ASSERT(bid == 0);
|
||||
//
|
||||
// // mark as inlined
|
||||
// btree->u.i.weight = lfsr_btree_setinlined(weight);
|
||||
// btree->u.i.tag = tag;
|
||||
//
|
||||
// lfs_ssize_t d = lfsr_data_read(lfs, &data,
|
||||
// btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
// if (d < 0) {
|
||||
// return d;
|
||||
// }
|
||||
// LFS_ASSERT(d <= LFSR_BTREE_INLINESIZE);
|
||||
// btree->u.i.size = d;
|
||||
// return 0;
|
||||
//
|
||||
// // inlined btree, need to expand into an rbyd
|
||||
// } else if (lfsr_btree_isinlined(btree)) {
|
||||
// lfsr_rbyd_t rbyd;
|
||||
// int err = lfsr_rbyd_alloc(lfs, &rbyd);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // commit our entries
|
||||
// err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
||||
// LFSR_ATTR(0, TAG(btree->u.i.tag), +lfsr_btree_weight(btree),
|
||||
// BUF(btree->u.i.buf, btree->u.i.size)),
|
||||
// LFSR_ATTR(bid, TAG(tag), +weight, DATA(data))));
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// btree->u.r.rbyd = rbyd;
|
||||
// return 0;
|
||||
//
|
||||
// // a normal btree
|
||||
// } else {
|
||||
// // lookup in which leaf our rid resides
|
||||
// //
|
||||
// // for lfsr_btree_commit operations to work out, we need to
|
||||
// // limit our bid to an rid in the tree, which is what this min
|
||||
// // is doing
|
||||
// //
|
||||
// // note it is possible for our btree to have a weight of zero here,
|
||||
// // since we defer inlining until compaction time
|
||||
// lfs_size_t bid_ = lfs_min32(bid,
|
||||
// lfs_smax32(lfsr_btree_weight(btree)-1, 0));
|
||||
// lfsr_rbyd_t rbyd = btree->u.r.rbyd;
|
||||
// lfs_ssize_t rid = -1;
|
||||
// lfs_size_t rweight = 0;
|
||||
// int err = lfsr_btree_lookupnext_(lfs, btree, bid_,
|
||||
// NULL, &rbyd, &rid, NULL, &rweight, NULL);
|
||||
// if (err && err != LFS_ERR_NOENT) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // adjust rid for push
|
||||
// if (bid >= lfsr_btree_weight(btree)) {
|
||||
// rid += 1;
|
||||
// } else {
|
||||
// rid -= rweight-1;
|
||||
// }
|
||||
//
|
||||
// // commit our rid into the tree, letting lfsr_btree_commit take care
|
||||
// // of the rest
|
||||
// int degenerate = lfsr_btree_commit(lfs, btree, bid_, 0, &rbyd,
|
||||
// LFSR_ATTRS(
|
||||
// LFSR_ATTR(rid, TAG(tag), +weight, DATA(data))));
|
||||
// if (degenerate < 0) {
|
||||
// return degenerate;
|
||||
// }
|
||||
//
|
||||
// // revert to an inlined btree
|
||||
// if (degenerate) {
|
||||
// // mark as inlined
|
||||
// btree->u.i.weight = lfsr_btree_setinlined(weight);
|
||||
// btree->u.i.tag = tag;
|
||||
//
|
||||
// lfs_ssize_t d = lfsr_data_read(lfs, &data,
|
||||
// btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
// if (d < 0) {
|
||||
// return d;
|
||||
// }
|
||||
// LFS_ASSERT(d <= LFSR_BTREE_INLINESIZE);
|
||||
// btree->u.i.size = d;
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO
|
||||
// TODO move to tests
|
||||
static int lfsr_btree_set(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
lfs_size_t bid, lfsr_tag_t tag, lfs_size_t weight, lfsr_data_t data) {
|
||||
LFS_ASSERT(bid < lfsr_btree_weight(btree));
|
||||
@@ -4653,77 +4537,12 @@ static int lfsr_btree_set(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
// note we need a second tag here in case our entry has a
|
||||
// name attributes, the name attribute holds the weight not
|
||||
// the struct tag
|
||||
return lfsr_btree_commit__(lfs, btree, LFSR_ATTRS(
|
||||
return lfsr_btree_commit(lfs, btree, LFSR_ATTRS(
|
||||
LFSR_ATTR(bid, WIDE(TAG(tag)), 0, DATA(data)),
|
||||
LFSR_ATTR(bid, GROW(RM), weight - weight_, NULL)));
|
||||
}
|
||||
|
||||
// TODO
|
||||
//static int lfsr_btree_set(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
// lfs_size_t bid, lfsr_tag_t tag, lfs_size_t weight, lfsr_data_t data) {
|
||||
// LFS_ASSERT(bid < lfsr_btree_weight(btree));
|
||||
// LFS_ASSERT(lfsr_btree_weight(btree) > 0);
|
||||
//
|
||||
// // inlined btree?
|
||||
// if (lfsr_btree_isinlined(btree)) {
|
||||
// LFS_ASSERT(bid == lfsr_btree_weight(btree)-1);
|
||||
//
|
||||
// // mark as inlined
|
||||
// btree->u.i.weight = lfsr_btree_setinlined(weight);
|
||||
// btree->u.i.tag = tag;
|
||||
//
|
||||
// lfs_ssize_t d = lfsr_data_read(lfs, &data,
|
||||
// btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
// if (d < 0) {
|
||||
// return d;
|
||||
// }
|
||||
// LFS_ASSERT(d <= LFSR_BTREE_INLINESIZE);
|
||||
// btree->u.i.size = d;
|
||||
// return 0;
|
||||
//
|
||||
// // a normal btree
|
||||
// } else {
|
||||
// // lookup in which leaf our rid resides
|
||||
// lfsr_rbyd_t rbyd;
|
||||
// lfsr_tag_t rtag;
|
||||
// lfs_ssize_t rid;
|
||||
// lfs_size_t rweight;
|
||||
// int err = lfsr_btree_lookupnext_(lfs, btree, bid,
|
||||
// NULL, &rbyd, &rid, &rtag, &rweight, NULL);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // commit our rid into the tree, letting lfsr_btree_commit take care
|
||||
// // of the rest
|
||||
// int degenerate = lfsr_btree_commit(lfs, btree, bid, 1, &rbyd,
|
||||
// LFSR_ATTRS(
|
||||
// LFSR_ATTR(rid, WIDE(TAG(tag)), 0, DATA(data)),
|
||||
// LFSR_ATTR(rid, GROW(RM), +weight-rweight, NULL)));
|
||||
// if (degenerate < 0) {
|
||||
// return degenerate;
|
||||
// }
|
||||
//
|
||||
// // revert to an inlined btree
|
||||
// if (degenerate) {
|
||||
// // mark as inlined
|
||||
// btree->u.i.weight = lfsr_btree_setinlined(weight);
|
||||
// btree->u.i.tag = tag;
|
||||
//
|
||||
// lfs_ssize_t d = lfsr_data_read(lfs, &data,
|
||||
// btree->u.i.buf, LFSR_BTREE_INLINESIZE);
|
||||
// if (d < 0) {
|
||||
// return d;
|
||||
// }
|
||||
// LFS_ASSERT(d <= LFSR_BTREE_INLINESIZE);
|
||||
// btree->u.i.size = d;
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO
|
||||
// TODO move to tests
|
||||
static int lfsr_btree_pop(lfs_t *lfs, lfsr_btree_t *btree, lfs_size_t bid) {
|
||||
LFS_ASSERT(bid < lfsr_btree_weight(btree));
|
||||
LFS_ASSERT(lfsr_btree_weight(btree) > 0);
|
||||
@@ -4741,98 +4560,11 @@ static int lfsr_btree_pop(lfs_t *lfs, lfsr_btree_t *btree, lfs_size_t bid) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return lfsr_btree_commit__(lfs, btree, LFSR_ATTRS(
|
||||
return lfsr_btree_commit(lfs, btree, LFSR_ATTRS(
|
||||
LFSR_ATTR(bid, RM, -weight_, NULL)));
|
||||
}
|
||||
|
||||
//static int lfsr_btree_pop(lfs_t *lfs, lfsr_btree_t *btree, lfs_size_t bid) {
|
||||
// LFS_ASSERT(bid < lfsr_btree_weight(btree));
|
||||
// LFS_ASSERT(lfsr_btree_weight(btree) > 0);
|
||||
//
|
||||
// // inlined btree?
|
||||
// if (lfsr_btree_isinlined(btree)) {
|
||||
// LFS_ASSERT(bid == lfsr_btree_weight(btree)-1);
|
||||
// *btree = LFSR_BTREE_NULL;
|
||||
// return 0;
|
||||
//
|
||||
// // a normal btree
|
||||
// } else {
|
||||
// // lookup in which leaf our rid resides
|
||||
// lfsr_rbyd_t rbyd;
|
||||
// lfsr_tag_t rtag;
|
||||
// lfs_ssize_t rid;
|
||||
// lfs_size_t rweight;
|
||||
// int err = lfsr_btree_lookupnext_(lfs, btree, bid,
|
||||
// NULL, &rbyd, &rid, &rtag, &rweight, NULL);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // remove our rid, letting lfsr_btree_commit take care
|
||||
// // of the rest
|
||||
// //
|
||||
// // note we use a cutoff of 2 here, if we have 2 entries before
|
||||
// // the commit, we should have 1 entry after the commit and can
|
||||
// // revert to an inlined btree
|
||||
// int degenerate = lfsr_btree_commit(lfs, btree, bid, 2, &rbyd,
|
||||
// LFSR_ATTRS(
|
||||
// LFSR_ATTR(rid, RM, -rweight, NULL)));
|
||||
// if (degenerate < 0) {
|
||||
// return degenerate;
|
||||
// }
|
||||
//
|
||||
// // revert to a null btree
|
||||
// if (degenerate && rweight >= rbyd.weight) {
|
||||
// *btree = LFSR_BTREE_NULL;
|
||||
//
|
||||
// // revert to an inlined btree
|
||||
// } else if (degenerate) {
|
||||
// lfs_ssize_t sid;
|
||||
// // left sibling
|
||||
// if ((lfs_size_t)rid == rbyd.weight-1) {
|
||||
// sid = rid-rweight;
|
||||
// // right sibling
|
||||
// } else {
|
||||
// sid = rid+1;
|
||||
// }
|
||||
//
|
||||
// lfsr_tag_t stag;
|
||||
// lfs_size_t sweight;
|
||||
// lfsr_data_t sdata;
|
||||
// int err = lfsr_rbyd_lookupnext(lfs, &rbyd, sid, LFSR_TAG_NAME,
|
||||
// &sid, &stag, &sweight, &sdata);
|
||||
// if (err) {
|
||||
// LFS_ASSERT(err == LFS_ERR_NOENT);
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// if (lfsr_tag_suptype(stag) == LFSR_TAG_NAME) {
|
||||
// err = lfsr_rbyd_lookup(lfs, &rbyd, sid, LFSR_TAG_WIDE(STRUCT),
|
||||
// &stag, &sdata);
|
||||
// if (err) {
|
||||
// LFS_ASSERT(err == LFS_ERR_NOENT);
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// LFS_ASSERT(sweight+rweight == rbyd.weight);
|
||||
// // mark as inlined
|
||||
// btree->u.i.weight = lfsr_btree_setinlined(sweight);
|
||||
// btree->u.i.tag = stag;
|
||||
//
|
||||
// LFS_ASSERT(lfsr_data_size(&sdata) <= LFSR_BTREE_INLINESIZE);
|
||||
// err = lfsr_bd_read(lfs, sdata.u.d.block, sdata.u.d.off, 0,
|
||||
// btree->u.i.buf, lfsr_data_size(&sdata));
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
// btree->u.i.size = lfsr_data_size(&sdata);
|
||||
// }
|
||||
//
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO move to tests
|
||||
// lfsr_btree_split can be done with a update+push, but this function
|
||||
// does all this in one commit, which is much more efficient
|
||||
//
|
||||
@@ -4859,7 +4591,7 @@ static int lfsr_btree_split(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
return err;
|
||||
}
|
||||
|
||||
return lfsr_btree_commit__(lfs, btree, LFSR_ATTRS(
|
||||
return lfsr_btree_commit(lfs, btree, LFSR_ATTRS(
|
||||
LFSR_ATTR(bid, GROW(RM), +weight1-weight_, NULL),
|
||||
LFSR_ATTR(bid-(weight_-1)+weight1-1, TAG(tag1), 0, DATA(data1)),
|
||||
(lfsr_data_size(&name) > 0
|
||||
@@ -4873,75 +4605,6 @@ static int lfsr_btree_split(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
TAG(tag2), +weight2, DATA(data2)))));
|
||||
}
|
||||
|
||||
//static int lfsr_btree_split(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
// lfs_size_t bid, lfsr_data_t name,
|
||||
// lfsr_tag_t tag1, lfs_size_t weight1, lfsr_data_t data1,
|
||||
// lfsr_tag_t tag2, lfs_size_t weight2, lfsr_data_t data2) {
|
||||
// LFS_ASSERT(bid < lfsr_btree_weight(btree));
|
||||
// LFS_ASSERT(lfsr_btree_weight(btree) > 0);
|
||||
//
|
||||
// // inlined btree, need to expand into an rbyd
|
||||
// if (lfsr_btree_isinlined(btree)) {
|
||||
// lfsr_rbyd_t rbyd;
|
||||
// int err = lfsr_rbyd_alloc(lfs, &rbyd);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // commit our entries
|
||||
// err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
||||
// LFSR_ATTR(0, TAG(tag1), +weight1, DATA(data1)),
|
||||
// (lfsr_data_size(&name) > 0
|
||||
// ? LFSR_ATTR(weight1, BNAME, +weight2, DATA(name))
|
||||
// : LFSR_ATTR_NOOP),
|
||||
// (lfsr_data_size(&name) > 0
|
||||
// ? LFSR_ATTR(weight1+weight2-1, TAG(tag2), 0, DATA(data2))
|
||||
// : LFSR_ATTR(weight1, TAG(tag2), +weight2, DATA(data2)))));
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// btree->u.r.rbyd = rbyd;
|
||||
// return 0;
|
||||
//
|
||||
// // a normal btree
|
||||
// } else {
|
||||
// // lookup in which leaf our bid resides
|
||||
// lfsr_rbyd_t rbyd;
|
||||
// lfs_ssize_t rid;
|
||||
// lfs_size_t rweight;
|
||||
// int err = lfsr_btree_lookupnext_(lfs, btree, bid,
|
||||
// NULL, &rbyd, &rid, NULL, &rweight, NULL);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // commit our bid into the tree, letting lfsr_btree_commit take care
|
||||
// // of the rest
|
||||
// int degenerate = lfsr_btree_commit(lfs, btree, bid, &rbyd,
|
||||
// LFSR_ATTRS(
|
||||
// LFSR_ATTR(rid, GROW(RM), +weight1-rweight, NULL),
|
||||
// LFSR_ATTR(rid-(rweight-1)+weight1-1, TAG(tag1), 0,
|
||||
// DATA(data1)),
|
||||
// (lfsr_data_size(&name) > 0
|
||||
// ? LFSR_ATTR(rid-(rweight-1)+weight1,
|
||||
// BNAME, +weight2, DATA(name))
|
||||
// : LFSR_ATTR_NOOP),
|
||||
// (lfsr_data_size(&name) > 0
|
||||
// ? LFSR_ATTR(rid-(rweight-1)+weight1+weight2-1,
|
||||
// TAG(tag2), 0, DATA(data2))
|
||||
// : LFSR_ATTR(rid-(rweight-1)+weight1,
|
||||
// TAG(tag2), +weight2, DATA(data2)))));
|
||||
// if (degenerate < 0) {
|
||||
// return degenerate;
|
||||
// }
|
||||
//
|
||||
// // this should never happen
|
||||
// LFS_ASSERT(!degenerate);
|
||||
// return 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// lookup in a btree by name
|
||||
static int lfsr_btree_namelookup(lfs_t *lfs, const lfsr_btree_t *btree,
|
||||
lfs_size_t did, const char *name, lfs_size_t name_size,
|
||||
|
||||
@@ -2448,264 +2448,6 @@ code = '''
|
||||
free(sim);
|
||||
'''
|
||||
|
||||
# TODO
|
||||
## test we reinline (go from uninlined to inlined) correctly, this is a bit
|
||||
## tricky since our btrees lazily reinline
|
||||
#[cases.test_btree_reinline_pop_set]
|
||||
#in = 'lfs.c'
|
||||
#code = '''
|
||||
# lfs_t lfs;
|
||||
# lfs_init(&lfs, CFG) => 0;
|
||||
# // create free lookahead
|
||||
# memset(lfs.lookahead.buffer, 0, CFG->lookahead_size);
|
||||
# lfs.lookahead.start = 0;
|
||||
# lfs.lookahead.size = lfs_min(8*CFG->lookahead_size,
|
||||
# CFG->block_count);
|
||||
# lfs.lookahead.next = 0;
|
||||
# lfs_alloc_ack(&lfs);
|
||||
#
|
||||
# // create an uninlined tree
|
||||
# lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
# lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("a", 1)) => 0;
|
||||
# lfsr_btree_push(&lfs, &btree, 1, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("b", 1)) => 0;
|
||||
# assert(lfsr_btree_weight(&btree) == 2);
|
||||
# assert(!lfsr_btree_isinlined(&btree));
|
||||
#
|
||||
# // pop! our btree should now be reinlinable
|
||||
# lfsr_btree_pop(&lfs, &btree, 0) => 0;
|
||||
#
|
||||
# // but thanks to lazy reinlining, our btree won't reinline until
|
||||
# // it is compacted, so we need to add commits until it is compacted
|
||||
# lfs_block_t before_block = btree.u.r.rbyd.block;
|
||||
# for (lfs_block_t i = 0;; i++) {
|
||||
# // a bit hacky, but this catches infinite loops
|
||||
# assert(i < BLOCK_SIZE);
|
||||
#
|
||||
# // commit to btree
|
||||
# lfsr_btree_set(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("b", 1)) => 0;
|
||||
#
|
||||
# assert(lfsr_btree_weight(&btree) == 1);
|
||||
#
|
||||
# // try looking up tag to hopefully catch if something breaks
|
||||
# uint8_t buffer[4];
|
||||
# lfsr_tag_t tag_;
|
||||
# lfs_size_t weight_;
|
||||
#
|
||||
# lfsr_btree_get(&lfs, &btree, 0,
|
||||
# &tag_, &weight_, buffer, 4) => 1;
|
||||
# assert(tag_ == LFSR_TAG_INLINED);
|
||||
# assert(weight_ == 1);
|
||||
# assert(memcmp(buffer, "b", 1) == 0);
|
||||
#
|
||||
# // inlined? consider this a success
|
||||
# if (lfsr_btree_isinlined(&btree)) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // assert if a compaction occurred that wasn't inlined
|
||||
# assert(btree.u.r.rbyd.block == before_block);
|
||||
# }
|
||||
#
|
||||
# printf("btree: w%d 0x%x.%x\n",
|
||||
# btree.u.r.rbyd.weight,
|
||||
# btree.u.r.rbyd.block,
|
||||
# btree.u.r.rbyd.trunk);
|
||||
#'''
|
||||
#
|
||||
#[cases.test_btree_reinline_pop_pop_push]
|
||||
#in = 'lfs.c'
|
||||
#defines.SHIFT = 'range(5)'
|
||||
#code = '''
|
||||
# lfs_t lfs;
|
||||
# lfs_init(&lfs, CFG) => 0;
|
||||
# // create free lookahead
|
||||
# memset(lfs.lookahead.buffer, 0, CFG->lookahead_size);
|
||||
# lfs.lookahead.start = 0;
|
||||
# lfs.lookahead.size = lfs_min(8*CFG->lookahead_size,
|
||||
# CFG->block_count);
|
||||
# lfs.lookahead.next = 0;
|
||||
# lfs_alloc_ack(&lfs);
|
||||
#
|
||||
# // create an uninlined tree
|
||||
# lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
# lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("a", 1)) => 0;
|
||||
# lfsr_btree_push(&lfs, &btree, 1, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("b", 1)) => 0;
|
||||
# assert(lfsr_btree_weight(&btree) == 2);
|
||||
# assert(!lfsr_btree_isinlined(&btree));
|
||||
#
|
||||
# // pop! our btree should now be reinlinable
|
||||
# lfsr_btree_pop(&lfs, &btree, 0) => 0;
|
||||
#
|
||||
# // It's difficult to test reinlining during push or pop, since we can't just
|
||||
# // repeat the action until compaction occurs.
|
||||
# //
|
||||
# // What we do here is alternate between 0 and 1 entries, eventually we
|
||||
# // will compact during one of either a push or pop. To try to cover both,
|
||||
# // test with some number of extra commits to hopefully adjust where the
|
||||
# // compaction ends up.
|
||||
# for (lfs_size_t i = 0; i < SHIFT; i++) {
|
||||
# lfsr_btree_set(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("b", 1)) => 0;
|
||||
# }
|
||||
#
|
||||
# // alternate between push/pop until compaction occurs
|
||||
# lfs_block_t before_block = btree.u.r.rbyd.block;
|
||||
# for (lfs_block_t i = 0;; i++) {
|
||||
# // a bit hacky, but this catches infinite loops
|
||||
# assert(i < BLOCK_SIZE);
|
||||
#
|
||||
# // pop!
|
||||
# lfsr_btree_pop(&lfs, &btree, 0) => 0;
|
||||
#
|
||||
# assert(lfsr_btree_weight(&btree) == 0);
|
||||
#
|
||||
# // inlined? consider this a success
|
||||
# if (lfsr_btree_isinlined(&btree)) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // assert if a compaction occurred that wasn't inlined
|
||||
# assert(btree.u.r.rbyd.block == before_block);
|
||||
#
|
||||
# // push!
|
||||
# lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("c", 1)) => 0;
|
||||
#
|
||||
# // try looking up tag to hopefully catch if something breaks
|
||||
# uint8_t buffer[4];
|
||||
# lfsr_tag_t tag_;
|
||||
# lfs_size_t weight_;
|
||||
#
|
||||
# lfsr_btree_get(&lfs, &btree, 0,
|
||||
# &tag_, &weight_, buffer, 4) => 1;
|
||||
# assert(tag_ == LFSR_TAG_INLINED);
|
||||
# assert(weight_ == 1);
|
||||
# assert(memcmp(buffer, "c", 1) == 0);
|
||||
#
|
||||
# // inlined? consider this a success
|
||||
# if (lfsr_btree_isinlined(&btree)) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // assert if a compaction occurred that wasn't inlined
|
||||
# assert(btree.u.r.rbyd.block == before_block);
|
||||
# }
|
||||
#
|
||||
# printf("btree: w%d 0x%x.%x\n",
|
||||
# btree.u.r.rbyd.weight,
|
||||
# btree.u.r.rbyd.block,
|
||||
# btree.u.r.rbyd.trunk);
|
||||
#'''
|
||||
#
|
||||
#[cases.test_btree_reinline_pop_push]
|
||||
#in = 'lfs.c'
|
||||
#defines.SIBLING = [0, 1]
|
||||
#defines.SHIFT = 'range(5)'
|
||||
#code = '''
|
||||
# lfs_t lfs;
|
||||
# lfs_init(&lfs, CFG) => 0;
|
||||
# // create free lookahead
|
||||
# memset(lfs.lookahead.buffer, 0, CFG->lookahead_size);
|
||||
# lfs.lookahead.start = 0;
|
||||
# lfs.lookahead.size = lfs_min(8*CFG->lookahead_size,
|
||||
# CFG->block_count);
|
||||
# lfs.lookahead.next = 0;
|
||||
# lfs_alloc_ack(&lfs);
|
||||
#
|
||||
# // create an uninlined tree
|
||||
# lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
# lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("a", 1)) => 0;
|
||||
# lfsr_btree_push(&lfs, &btree, 1, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("b", 1)) => 0;
|
||||
# assert(lfsr_btree_weight(&btree) == 2);
|
||||
# assert(!lfsr_btree_isinlined(&btree));
|
||||
#
|
||||
# // It's difficult to test reinlining during push or pop, since we can't just
|
||||
# // repeat the action until compaction occurs.
|
||||
# //
|
||||
# // Here we alternate between 1 and 2 entries, with the hope that compaction
|
||||
# // occurs on the pop. We try this with some number of extra commits to make
|
||||
# // it more likely pop is tested.
|
||||
# //
|
||||
# // It's possible our commits line up so compaction always occurs on a push!
|
||||
# // For this reason, we end the test if an non-reinlining compaction occurs.
|
||||
# for (lfs_size_t i = 0; i < SHIFT; i++) {
|
||||
# lfsr_btree_set(&lfs, &btree, 0, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("a", 1)) => 0;
|
||||
# }
|
||||
#
|
||||
# // alternate between push/pop until compaction occurs
|
||||
# lfs_block_t before_block = btree.u.r.rbyd.block;
|
||||
# for (lfs_block_t i = 0;; i++) {
|
||||
# // a bit hacky, but this catches infinite loops
|
||||
# assert(i < BLOCK_SIZE);
|
||||
#
|
||||
# // pop!
|
||||
# lfsr_btree_pop(&lfs, &btree, SIBLING) => 0;
|
||||
#
|
||||
# assert(lfsr_btree_weight(&btree) == 1);
|
||||
#
|
||||
# // try looking up tag to hopefully catch if something breaks
|
||||
# uint8_t buffer[4];
|
||||
# lfsr_tag_t tag_;
|
||||
# lfs_size_t weight_;
|
||||
#
|
||||
# lfsr_btree_get(&lfs, &btree, 0,
|
||||
# &tag_, &weight_, buffer, 4) => 1;
|
||||
# assert(tag_ == LFSR_TAG_INLINED);
|
||||
# assert(weight_ == 1);
|
||||
# assert(memcmp(buffer, (SIBLING == 1 ? "a" : "b"), 1) == 0);
|
||||
#
|
||||
# // inlined? consider this a success
|
||||
# if (lfsr_btree_isinlined(&btree)) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // abort if a compaction occurs
|
||||
# if (btree.u.r.rbyd.block != before_block) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // push!
|
||||
# lfsr_btree_push(&lfs, &btree, SIBLING, LFSR_TAG_INLINED, 1,
|
||||
# LFSR_DATA("c", 1)) => 0;
|
||||
#
|
||||
# // try looking up tag to hopefully catch if something breaks
|
||||
# lfsr_btree_get(&lfs, &btree, 0,
|
||||
# &tag_, &weight_, buffer, 4) => 1;
|
||||
# assert(tag_ == LFSR_TAG_INLINED);
|
||||
# assert(weight_ == 1);
|
||||
# assert(memcmp(buffer, (SIBLING == 1 ? "a" : "c"), 1) == 0);
|
||||
#
|
||||
# lfsr_btree_get(&lfs, &btree, 1,
|
||||
# &tag_, &weight_, buffer, 4) => 1;
|
||||
# assert(tag_ == LFSR_TAG_INLINED);
|
||||
# assert(weight_ == 1);
|
||||
# assert(memcmp(buffer, (SIBLING == 1 ? "c" : "b"), 1) == 0);
|
||||
#
|
||||
# // inlined? consider this a success
|
||||
# if (lfsr_btree_isinlined(&btree)) {
|
||||
# break;
|
||||
# }
|
||||
#
|
||||
# // abort if a compaction occurs
|
||||
# if (btree.u.r.rbyd.block != before_block) {
|
||||
# break;
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# printf("btree: w%d 0x%x.%x\n",
|
||||
# btree.u.r.rbyd.weight,
|
||||
# btree.u.r.rbyd.block,
|
||||
# btree.u.r.rbyd.trunk);
|
||||
#'''
|
||||
|
||||
|
||||
# Some more general fuzz testing
|
||||
[cases.test_btree_general_fuzz]
|
||||
|
||||
Reference in New Issue
Block a user