Rough implementation of btree append
This involves many, many hacks, but is enough to test the concept and start looking at how it interacts with different block sizes. Note only append (lfsr_btree_push on the end) is implemented, and it makes some assumption about how the ids can interact when splitting rbyds.
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
|
||||
# maximize lookahead buffer, we don't actually gc so we only get one pass
|
||||
# of the disk for these tests
|
||||
defines.LOOKAHEAD_SIZE = 'BLOCK_COUNT / 8'
|
||||
|
||||
|
||||
# test an empty tree
|
||||
[cases.test_btree_zero]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_init(&lfs, cfg) => 0;
|
||||
// create free lookahead
|
||||
memset(lfs.free.buffer, 0, lfs.cfg->lookahead_size);
|
||||
lfs.free.off = 0;
|
||||
lfs.free.size = lfs_min(8*lfs.cfg->lookahead_size,
|
||||
lfs.cfg->block_count);
|
||||
lfs.free.i = 0;
|
||||
lfs_alloc_ack(&lfs);
|
||||
|
||||
// create an empty tree
|
||||
lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
|
||||
// try looking up tags
|
||||
uint8_t buffer[4];
|
||||
lfsr_tag_t tag_;
|
||||
lfs_size_t id_;
|
||||
lfs_size_t weight_;
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 0,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => LFS_ERR_NOENT;
|
||||
'''
|
||||
|
||||
# test an inlined tree
|
||||
[cases.test_btree_one]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_init(&lfs, cfg) => 0;
|
||||
// create free lookahead
|
||||
memset(lfs.free.buffer, 0, lfs.cfg->lookahead_size);
|
||||
lfs.free.off = 0;
|
||||
lfs.free.size = lfs_min(8*lfs.cfg->lookahead_size,
|
||||
lfs.cfg->block_count);
|
||||
lfs.free.i = 0;
|
||||
lfs_alloc_ack(&lfs);
|
||||
|
||||
// create a single-entry tree
|
||||
lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1, "a", 1) => 0;
|
||||
|
||||
// try looking up tags
|
||||
uint8_t buffer[4];
|
||||
lfsr_tag_t tag_;
|
||||
lfs_size_t id_;
|
||||
lfs_size_t weight_;
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 0,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 0);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "a", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 1,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => LFS_ERR_NOENT;
|
||||
'''
|
||||
|
||||
# test a single-rbyd tree
|
||||
[cases.test_btree_two]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_init(&lfs, cfg) => 0;
|
||||
// create free lookahead
|
||||
memset(lfs.free.buffer, 0, lfs.cfg->lookahead_size);
|
||||
lfs.free.off = 0;
|
||||
lfs.free.size = lfs_min(8*lfs.cfg->lookahead_size,
|
||||
lfs.cfg->block_count);
|
||||
lfs.free.i = 0;
|
||||
lfs_alloc_ack(&lfs);
|
||||
|
||||
// create a two-entry tree
|
||||
lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1, "a", 1) => 0;
|
||||
lfsr_btree_push(&lfs, &btree, 1, LFSR_TAG_INLINED, 1, "b", 1) => 0;
|
||||
|
||||
// try looking up tags
|
||||
uint8_t buffer[4];
|
||||
lfsr_tag_t tag_;
|
||||
lfs_size_t id_;
|
||||
lfs_size_t weight_;
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 0,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 0);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "a", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 1,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 1);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "b", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 2,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => LFS_ERR_NOENT;
|
||||
'''
|
||||
|
||||
# still a single-rbyd tree, just making sure it works
|
||||
[cases.test_btree_three]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_init(&lfs, cfg) => 0;
|
||||
// create free lookahead
|
||||
memset(lfs.free.buffer, 0, lfs.cfg->lookahead_size);
|
||||
lfs.free.off = 0;
|
||||
lfs.free.size = lfs_min(8*lfs.cfg->lookahead_size,
|
||||
lfs.cfg->block_count);
|
||||
lfs.free.i = 0;
|
||||
lfs_alloc_ack(&lfs);
|
||||
|
||||
// create a two-entry tree
|
||||
lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
lfsr_btree_push(&lfs, &btree, 0, LFSR_TAG_INLINED, 1, "a", 1) => 0;
|
||||
lfsr_btree_push(&lfs, &btree, 1, LFSR_TAG_INLINED, 1, "b", 1) => 0;
|
||||
lfsr_btree_push(&lfs, &btree, 2, LFSR_TAG_INLINED, 1, "c", 1) => 0;
|
||||
|
||||
// try looking up tags
|
||||
uint8_t buffer[4];
|
||||
lfsr_tag_t tag_;
|
||||
lfs_size_t id_;
|
||||
lfs_size_t weight_;
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 0,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 0);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "a", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 1,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 1);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "b", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 2,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == 2);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, "c", 1) == 0);
|
||||
|
||||
lfsr_btree_get(&lfs, &btree, 3,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => LFS_ERR_NOENT;
|
||||
'''
|
||||
|
||||
# try larger trees, when exactly a tree splits depends on the disk geometry, so
|
||||
# we don't really have a better way of testing multi-rbyd trees
|
||||
[cases.test_btree_more]
|
||||
defines.N = 'range(10, 1001, 50)'
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfs_init(&lfs, cfg) => 0;
|
||||
// create free lookahead
|
||||
memset(lfs.free.buffer, 0, lfs.cfg->lookahead_size);
|
||||
lfs.free.off = 0;
|
||||
lfs.free.size = lfs_min(8*lfs.cfg->lookahead_size,
|
||||
lfs.cfg->block_count);
|
||||
lfs.free.i = 0;
|
||||
lfs_alloc_ack(&lfs);
|
||||
|
||||
// create a tree with N elements
|
||||
lfsr_btree_t btree = LFSR_BTREE_NULL;
|
||||
const char *alphas = "abcdefghijklmnopqrstuvwxyz";
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
lfsr_btree_push(&lfs, &btree, i, LFSR_TAG_INLINED, 1,
|
||||
&alphas[i % 26], 1) => 0;
|
||||
}
|
||||
|
||||
// check that the elements are in the tree
|
||||
uint8_t buffer[4];
|
||||
lfsr_tag_t tag_;
|
||||
lfs_size_t id_;
|
||||
lfs_size_t weight_;
|
||||
|
||||
for (lfs_size_t i = 0; i < N; i++) {
|
||||
lfsr_btree_get(&lfs, &btree, i,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => 1;
|
||||
assert(tag_ == LFSR_TAG_INLINED);
|
||||
assert(id_ == i);
|
||||
assert(weight_ == 1);
|
||||
assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
|
||||
}
|
||||
|
||||
// and check that we can't lookup elements that aren't in the tree
|
||||
lfsr_btree_get(&lfs, &btree, N,
|
||||
&tag_, &id_, &weight_,
|
||||
buffer, 4) => LFS_ERR_NOENT;
|
||||
'''
|
||||
+30
-27
@@ -12039,7 +12039,7 @@ code = '''
|
||||
|
||||
// test lookup both written/unwritten
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(j+1), -1,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
||||
@@ -12051,14 +12051,14 @@ code = '''
|
||||
tag_ = 0;
|
||||
id_ = -1;
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(j+1));
|
||||
assert(id_ == -1);
|
||||
assert(lfsr_data_len(data_) == 4);
|
||||
}
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => LFS_ERR_NOENT;
|
||||
}
|
||||
@@ -12202,7 +12202,8 @@ code = '''
|
||||
printf("rbyd: [");
|
||||
first = true;
|
||||
for (unsigned attr = 0; attr < N; attr++) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(attr), -1, buffer, 4);
|
||||
if (size >= 0) {
|
||||
if (!first) {
|
||||
@@ -12215,7 +12216,8 @@ code = '''
|
||||
printf("]\n");
|
||||
|
||||
for (unsigned attr = 0; attr < N; attr++) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(attr), -1, buffer, 4);
|
||||
if (sim[attr]) {
|
||||
assert(size == 1);
|
||||
@@ -12319,7 +12321,7 @@ code = '''
|
||||
|
||||
// test lookup both written/unwritten
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
||||
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
||||
}
|
||||
@@ -12328,14 +12330,14 @@ code = '''
|
||||
tag_ = 0;
|
||||
id_ = -1;
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_MKREG);
|
||||
assert(id_ == j);
|
||||
assert(lfsr_data_len(data_) == 4);
|
||||
}
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => LFS_ERR_NOENT;
|
||||
}
|
||||
@@ -12484,7 +12486,8 @@ code = '''
|
||||
printf("]\n");
|
||||
printf("rbyd: [");
|
||||
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id, buffer, 4);
|
||||
if (size >= 0) {
|
||||
printf("%.*s", size, buffer);
|
||||
@@ -12498,7 +12501,7 @@ code = '''
|
||||
printf("]\n");
|
||||
|
||||
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id, buffer, 4) => 1;
|
||||
assert(memcmp(&sim[id], buffer, 1) == 0);
|
||||
}
|
||||
@@ -12613,7 +12616,7 @@ code = '''
|
||||
assert(rbyd.weight == (w >= 0 ? w : 0));
|
||||
|
||||
// test lookup both written/unwritten
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(3), -1,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(3));
|
||||
@@ -12621,12 +12624,12 @@ code = '''
|
||||
assert(lfsr_data_len(data_) == 9);
|
||||
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, j, buffer, 4) => 4;
|
||||
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
||||
|
||||
for (unsigned u = 0; u < M; u++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(u+1), j, buffer, 4) => 2;
|
||||
assert(memcmp(buffer, names[j % 6], 2) == 0);
|
||||
}
|
||||
@@ -12635,7 +12638,7 @@ code = '''
|
||||
// test traverse both written/unwritten
|
||||
tag_ = 0;
|
||||
id_ = -1;
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(3));
|
||||
@@ -12643,7 +12646,7 @@ code = '''
|
||||
assert(lfsr_data_len(data_) == 9);
|
||||
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_MKREG);
|
||||
@@ -12651,7 +12654,7 @@ code = '''
|
||||
assert(lfsr_data_len(data_) == 4);
|
||||
|
||||
for (unsigned u = 0; u < M; u++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_UATTR(u+1));
|
||||
@@ -12659,7 +12662,7 @@ code = '''
|
||||
assert(lfsr_data_len(data_) == 2);
|
||||
}
|
||||
}
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => LFS_ERR_NOENT;
|
||||
}
|
||||
@@ -12863,7 +12866,7 @@ code = '''
|
||||
printf("]\n");
|
||||
printf("rbyd: [");
|
||||
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id, buffer, 4);
|
||||
if (size >= 0) {
|
||||
@@ -12872,7 +12875,7 @@ code = '''
|
||||
printf("?");
|
||||
}
|
||||
for (uint8_t u = 0; u < M; u++) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_UATTR(u), id, buffer, 4);
|
||||
if (size >= 0) {
|
||||
@@ -12888,7 +12891,7 @@ code = '''
|
||||
printf("]\n");
|
||||
|
||||
for (lfs_ssize_t id = 0; id < (lfs_ssize_t)count; id++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id, buffer, 4) => 1;
|
||||
assert(memcmp(&sim[id*(M+1)], buffer, 1) == 0);
|
||||
}
|
||||
@@ -12988,7 +12991,7 @@ code = '''
|
||||
|
||||
// test lookup both written/unwritten
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, j*W+W-1, buffer, 4) => 4;
|
||||
assert(memcmp(buffer, names[j % 6], 4) == 0);
|
||||
}
|
||||
@@ -12997,14 +13000,14 @@ code = '''
|
||||
tag_ = 0;
|
||||
id_ = -1;
|
||||
for (unsigned j = 0; j < N; j++) {
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
assert(tag_ == LFSR_TAG_MKREG);
|
||||
assert(id_ == j*W+W-1);
|
||||
assert(lfsr_data_len(data_) == 4);
|
||||
}
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_tag_next(tag_), id_,
|
||||
&tag_, &id_, &data_) => LFS_ERR_NOENT;
|
||||
}
|
||||
@@ -13229,12 +13232,12 @@ code = '''
|
||||
id__ += sim_weights[j];
|
||||
}
|
||||
|
||||
int err = lfsr_rbyd_pendinglookup(
|
||||
int err = lfsr_rbyd_predictedlookup(
|
||||
&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id__,
|
||||
&tag_, &id_, &data_);
|
||||
if (!err) {
|
||||
lfs_ssize_t size = lfsr_rbyd_pendingget(
|
||||
lfs_ssize_t size = lfsr_rbyd_predictedget(
|
||||
&lfs, &rbyd, unwritten,
|
||||
tag_, id_, buffer, 4);
|
||||
if (size >= 0) {
|
||||
@@ -13258,10 +13261,10 @@ code = '''
|
||||
id__ += sim_weights[j];
|
||||
}
|
||||
|
||||
lfsr_rbyd_pendinglookup(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedlookup(&lfs, &rbyd, unwritten,
|
||||
LFSR_TAG_MKREG, id__,
|
||||
&tag_, &id_, &data_) => 0;
|
||||
lfsr_rbyd_pendingget(&lfs, &rbyd, unwritten,
|
||||
lfsr_rbyd_predictedget(&lfs, &rbyd, unwritten,
|
||||
tag_, id_, buffer, 4) => 1;
|
||||
assert(memcmp(&sim[id], buffer, 1) == 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user