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:
Christopher Haster
2023-03-02 21:46:23 -06:00
parent 361dfb0625
commit 88e3db98a9
4 changed files with 626 additions and 117 deletions
+217
View File
@@ -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
View File
@@ -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);
}