Rough draft of general btree implementation, needs work
This implements a common B-tree using rbyd's as inner nodes. Since our rbyds actually map to sorted arrays, this fits together quite well. The main caveat/concern is that we can't rely on strict knowledge on the on-disk size of these things. This first shows up with B-tree insertion, we can't split in preparation to insert as we descend down the tree. Normally, this means our B-tree would require recursion in order to keep track of each parent as we descend down our tree. However, we can avoid this by not storing our parent, but by looking it up again on each step of the splitting operation. This brute-force-ish approach makes our algorithm tail-recursive, so bounded RAM, but raises our runtime from O(logB(n)) to O(logB(n)^2) That being said, O(logB(n)^2) is still sublinear, and, thanks to B-tree's extremely high branching factor, may be insignificant.
This commit is contained in:
@@ -343,10 +343,43 @@ typedef struct lfsr_rbyd {
|
||||
bool erased;
|
||||
} lfsr_rbyd_t;
|
||||
|
||||
typedef struct lfsr_btree {
|
||||
//typedef struct lfsr_btree {
|
||||
// // TODO do we need this field? it's needed for inlined
|
||||
// // btrees but is redundent when we have an rbyd
|
||||
// // a weight of zero indicates no tree
|
||||
// lfs_size_t weight;
|
||||
// // a limit of zero indicates an inlined tree
|
||||
// lfs_size_t limit;
|
||||
// lfs_block_t trunk;
|
||||
//} lfsr_btree_t;
|
||||
|
||||
// The maximum size of inlined pointers in a btree, this depends on littlefs's
|
||||
// on-disk pointer representations (there are several), but doesn't change at
|
||||
// runtime.
|
||||
//
|
||||
// Pointers we store:
|
||||
// - block addresses => 1 leb128 => 5 bytes (worst case)
|
||||
#define LFSR_BTREE_INLINE_SIZE 5
|
||||
|
||||
typedef struct lfsr_branch {
|
||||
lfs_block_t block;
|
||||
lfs_size_t limit;
|
||||
lfs_size_t weight;
|
||||
} lfsr_branch_t;
|
||||
|
||||
typedef struct lfsr_btree {
|
||||
// TODO do we need full tag actually? this fits in a byte?
|
||||
lfsr_tag_t tag;
|
||||
// how can we take advantage of byte packing with union alignment?
|
||||
union {
|
||||
struct {
|
||||
lfs_size_t weight;
|
||||
uint8_t size;
|
||||
uint8_t buf[LFSR_BTREE_INLINE_SIZE];
|
||||
} inlined;
|
||||
|
||||
// if we're not inlined, point to the trunk rbyd block of the btree
|
||||
lfsr_branch_t trunk;
|
||||
} u;
|
||||
} lfsr_btree_t;
|
||||
|
||||
typedef struct lfs_mdir {
|
||||
|
||||
+9
-3
@@ -62,6 +62,12 @@ def tagrepr(tag, id, w, size, off=None):
|
||||
id,
|
||||
' w%d' % w if w is not None else '',
|
||||
size)
|
||||
elif tag == 0x0810:
|
||||
return 'block id%d %d' % (id, size)
|
||||
elif tag == 0x0820:
|
||||
return 'btree id%d %d' % (id, size)
|
||||
elif tag == 0x0830:
|
||||
return 'branch id%d %d' % (id, size)
|
||||
elif (tag & ~0xff2) == 0x2000:
|
||||
return '%suattr 0x%02x%s%s' % (
|
||||
'rm' if tag & 0x2 else '',
|
||||
@@ -180,7 +186,8 @@ def show_log(block_size, data, rev, off, *,
|
||||
grow = None
|
||||
colors = ['']
|
||||
colors_i = 0
|
||||
lifetimes = [(0, 0, -1, weights.copy(), colors.copy())]
|
||||
# note these slices are also copying the arrays
|
||||
lifetimes = [(0, 0, -1, weights[:-1], colors[:-1])]
|
||||
|
||||
j_ = 4
|
||||
while j_ < (block_size if args.get('all') else off):
|
||||
@@ -190,7 +197,6 @@ def show_log(block_size, data, rev, off, *,
|
||||
if (tag & 0xe) <= 0x4:
|
||||
j_ += size
|
||||
|
||||
# note these slices are also copying the arrays
|
||||
if grow is not None:
|
||||
if (tag & ~0x3f0) == 0x0400 and id == grow[1]:
|
||||
i, p = index(weights, id)
|
||||
@@ -241,7 +247,7 @@ def show_log(block_size, data, rev, off, *,
|
||||
else '\\ ' if g > 0 and id < a
|
||||
else '\'' if g < 0 and id >= a and id < b
|
||||
else '/ ' if g < 0 and id < a
|
||||
else '* ' if not tag & 0x8 and id >= a and id < b
|
||||
else '* ' if id >= a and id < b
|
||||
else '| ',
|
||||
'\x1b[m' if color else '')
|
||||
for (a, b), c in zip(ranges(weights), colors)),
|
||||
|
||||
Reference in New Issue
Block a user