Reworked ftree/bshrub/shrub relationship, staging in ftree now
This is an attempt to simplify things a bit by moving more logic into
the ftree layer, instead of spreading things around between the
bshrub/bsprout functions.
Now, functionality is organized into high-level ftree operations and
low-level shrub/sprout operations, which only care about the inlined
portion of the shrub/sprout. No more lfsr_bshrub_commit/
lfsr_bshrub_commit__ which were mostly unrelated.
This also adds a lfsr_shrub_t type, which, by taking advantage of the
unused write-related rbyd fields to store the shrub estimate, has the
same size as lfsr_rbyd_t, but can still be casted to an rbyd/btree for
use in readonly rbyd/btree functions.
I considered merging shrub/sprout esimate and shrub/sprout compact into
some sort of ftree_estimate/compact, but it's not obvious what the
benefit would be, so leaving that on the table for now.
---
One nice change is our staging copies are now at the ftree level
(ftree.u and ftree.u_, maybe not the best names, but this is what I've
been using for unions where the name doesn't really matter, god I want
unnamed unions). This simplifies staging, and avoids staging issues
where the underlying type changes.
---
A bit unrelated, but necessary to integrate lfsr_ftree_traverse, a
generalized lfsr_tinfo_t type for all traversal functions was added
(adopted from lfsr_traversal_t really). This is a straightforward tagged
union with relevant traversal types.
The benefit of a generalized tinfo type is better chance we can just
pass the tinfo pointer through multiple layers.
Code changes:
code stack
before: 33368 2984
after: 33260 (-0.3%) 3024 (+1.3%)
This commit is contained in:
@@ -375,6 +375,7 @@ typedef struct lfsr_rbyd {
|
|||||||
uint32_t cksum;
|
uint32_t cksum;
|
||||||
} lfsr_rbyd_t;
|
} lfsr_rbyd_t;
|
||||||
|
|
||||||
|
// a btree is just the root rbyd
|
||||||
typedef lfsr_rbyd_t lfsr_btree_t;
|
typedef lfsr_rbyd_t lfsr_btree_t;
|
||||||
|
|
||||||
typedef struct lfsr_mptr {
|
typedef struct lfsr_mptr {
|
||||||
@@ -456,13 +457,6 @@ typedef struct lfsr_data {
|
|||||||
} u;
|
} u;
|
||||||
} lfsr_data_t;
|
} lfsr_data_t;
|
||||||
|
|
||||||
typedef struct lfsr_bptr {
|
|
||||||
// note data.size lines up with weight in lfsr_btree_t
|
|
||||||
lfsr_data_t data;
|
|
||||||
lfs_size_t cksize;
|
|
||||||
uint32_t cksum;
|
|
||||||
} lfsr_bptr_t;
|
|
||||||
|
|
||||||
// erased-state checksum
|
// erased-state checksum
|
||||||
typedef struct lfsr_ecksum {
|
typedef struct lfsr_ecksum {
|
||||||
// size=-1 indicates no ecksum
|
// size=-1 indicates no ecksum
|
||||||
@@ -510,12 +504,12 @@ typedef struct lfs_file {
|
|||||||
const struct lfs_file_config *cfg;
|
const struct lfs_file_config *cfg;
|
||||||
} lfs_file_t;
|
} lfs_file_t;
|
||||||
|
|
||||||
// bsprouts must always be associated with an mdir
|
typedef struct lfsr_bptr {
|
||||||
typedef struct lfsr_bsprout {
|
// note data.size lines up with weight in lfsr_btree_t
|
||||||
lfsr_data_t data;
|
lfsr_data_t data;
|
||||||
// copy for staging
|
lfs_size_t cksize;
|
||||||
lfsr_data_t data_;
|
uint32_t cksum;
|
||||||
} lfsr_bsprout_t;
|
} lfsr_bptr_t;
|
||||||
|
|
||||||
// a bleaf is just a bptr with all optional attrs
|
// a bleaf is just a bptr with all optional attrs
|
||||||
typedef struct lfsr_bleaf {
|
typedef struct lfsr_bleaf {
|
||||||
@@ -523,29 +517,40 @@ typedef struct lfsr_bleaf {
|
|||||||
lfsr_ecksum_t becksum;
|
lfsr_ecksum_t becksum;
|
||||||
} lfsr_bleaf_t;
|
} lfsr_bleaf_t;
|
||||||
|
|
||||||
// bshrubs must always be associated with an mdir
|
// a shrub is a secondary trunk in an mdir, we really only need
|
||||||
//
|
// trunk/weight/block, so we sneak our estimate into some
|
||||||
// rbyd.block == mdir.blocks[0] => bshrub
|
// overlapping fields
|
||||||
// rbyd.block != mdir.blocks[0] => btree
|
typedef struct lfsr_shrub {
|
||||||
typedef struct lfsr_bshrub {
|
// this all lines up with lfsr_rbyd_t
|
||||||
lfsr_rbyd_t rbyd;
|
lfsr_srid_t weight;
|
||||||
// copy for staging
|
lfs_block_t blocks[2];
|
||||||
lfsr_rbyd_t rbyd_;
|
lfs_size_t trunk;
|
||||||
|
lfs_size_t eoff;
|
||||||
// an upper-bound estimate on the on-disk shrub size
|
// an upper-bound estimate on the on-disk shrub size
|
||||||
lfs_size_t estimate;
|
lfs_size_t estimate;
|
||||||
} lfsr_bshrub_t;
|
} lfsr_shrub_t;
|
||||||
|
|
||||||
// the lfsr_ftree_t struct is a sort of proto-file
|
// the lfsr_ftree_t struct is a sort of proto-file
|
||||||
typedef struct lfsr_ftree {
|
typedef struct lfsr_ftree {
|
||||||
|
// ftrees contain both an active tree and staging tree, to allow
|
||||||
|
// staging files during mdir compacts
|
||||||
|
//
|
||||||
|
// navigating this union is a bit tricky, and relies on related
|
||||||
|
// mdir's block:
|
||||||
|
//
|
||||||
|
// sign(size)=1, data.size==0 => bnull
|
||||||
|
// sign(size)=1, data.block==mdir.block => bsprout
|
||||||
|
// sign(size)=1, data.block!=mdir.block => bleaf
|
||||||
|
// sign(size)=0, data.block==mdir.block => bshrub
|
||||||
|
// sign(size)=0, data.block!=mdir.block => btree
|
||||||
|
//
|
||||||
union {
|
union {
|
||||||
lfs_soff_t size;
|
lfs_soff_t size;
|
||||||
lfsr_data_t data;
|
lfsr_data_t bsprout;
|
||||||
lfsr_bsprout_t bsprout;
|
|
||||||
lfsr_bptr_t bptr;
|
|
||||||
lfsr_bleaf_t bleaf;
|
lfsr_bleaf_t bleaf;
|
||||||
lfsr_bshrub_t bshrub;
|
lfsr_shrub_t bshrub;
|
||||||
lfsr_btree_t btree;
|
lfsr_btree_t btree;
|
||||||
} u;
|
} u, u_;
|
||||||
} lfsr_ftree_t;
|
} lfsr_ftree_t;
|
||||||
|
|
||||||
typedef struct lfsr_file {
|
typedef struct lfsr_file {
|
||||||
|
|||||||
+38
-40
@@ -4294,37 +4294,36 @@ code = '''
|
|||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i <= 2*N);
|
assert(i <= 2*N);
|
||||||
|
|
||||||
lfsr_binfo_t binfo;
|
lfsr_bid_t bid;
|
||||||
int err = lfsr_btree_traverse(&lfs, &btree, &traversal, &binfo);
|
lfsr_tinfo_t tinfo;
|
||||||
|
int err = lfsr_btree_traverse(&lfs, &btree, &traversal,
|
||||||
|
&bid, &tinfo);
|
||||||
assert(!err || err == LFS_ERR_NOENT);
|
assert(!err || err == LFS_ERR_NOENT);
|
||||||
if (err == LFS_ERR_NOENT) {
|
if (err == LFS_ERR_NOENT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binfo.tag == LFSR_TAG_BRANCH) {
|
if (tinfo.tag == LFSR_TAG_BRANCH) {
|
||||||
printf("traversal: %d 0x%x w%d btree 0x%x.%x\n",
|
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag,
|
||||||
binfo.weight,
|
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
|
||||||
binfo.u.rbyd.blocks[0], binfo.u.rbyd.trunk);
|
|
||||||
|
|
||||||
// keep track of seen blocks
|
// keep track of seen blocks
|
||||||
seen[binfo.u.rbyd.blocks[0] / 8]
|
seen[tinfo.u.rbyd.blocks[0] / 8]
|
||||||
|= 1 << (binfo.u.rbyd.blocks[0] % 8);
|
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
|
||||||
|
|
||||||
} else if (binfo.tag == LFSR_TAG_DATA) {
|
} else if (tinfo.tag == LFSR_TAG_DATA) {
|
||||||
printf("traversal: %d 0x%x w%d data %d\n",
|
printf("traversal: %d 0x%x data %d\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag,
|
||||||
binfo.weight,
|
lfsr_data_size(&tinfo.u.data));
|
||||||
lfsr_data_size(&binfo.u.data));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// well this shouldn't happen
|
// well this shouldn't happen
|
||||||
printf("traversal: %d 0x%x w%d\n",
|
printf("traversal: %d 0x%x\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag);
|
||||||
binfo.weight);
|
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4447,37 +4446,36 @@ code = '''
|
|||||||
// a bit hacky, but this catches infinite loops
|
// a bit hacky, but this catches infinite loops
|
||||||
assert(i <= 2*N);
|
assert(i <= 2*N);
|
||||||
|
|
||||||
lfsr_binfo_t binfo;
|
lfsr_bid_t bid;
|
||||||
int err = lfsr_btree_traverse(&lfs, &btree, &traversal, &binfo);
|
lfsr_tinfo_t tinfo;
|
||||||
|
int err = lfsr_btree_traverse(&lfs, &btree, &traversal,
|
||||||
|
&bid, &tinfo);
|
||||||
assert(!err || err == LFS_ERR_NOENT);
|
assert(!err || err == LFS_ERR_NOENT);
|
||||||
if (err == LFS_ERR_NOENT) {
|
if (err == LFS_ERR_NOENT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binfo.tag == LFSR_TAG_BRANCH) {
|
if (tinfo.tag == LFSR_TAG_BRANCH) {
|
||||||
printf("traversal: %d 0x%x w%d btree 0x%x.%x\n",
|
printf("traversal: %d 0x%x btree 0x%x.%x\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag,
|
||||||
binfo.weight,
|
tinfo.u.rbyd.blocks[0], tinfo.u.rbyd.trunk);
|
||||||
binfo.u.rbyd.blocks[0], binfo.u.rbyd.trunk);
|
|
||||||
|
|
||||||
// keep track of seen blocks
|
// keep track of seen blocks
|
||||||
seen[binfo.u.rbyd.blocks[0] / 8]
|
seen[tinfo.u.rbyd.blocks[0] / 8]
|
||||||
|= 1 << (binfo.u.rbyd.blocks[0] % 8);
|
|= 1 << (tinfo.u.rbyd.blocks[0] % 8);
|
||||||
|
|
||||||
} else if (binfo.tag == LFSR_TAG_DATA) {
|
} else if (tinfo.tag == LFSR_TAG_DATA) {
|
||||||
printf("traversal: %d 0x%x w%d data %d\n",
|
printf("traversal: %d 0x%x data %d\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag,
|
||||||
binfo.weight,
|
lfsr_data_size(&tinfo.u.data));
|
||||||
lfsr_data_size(&binfo.u.data));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// well this shouldn't happen
|
// well this shouldn't happen
|
||||||
printf("traversal: %d 0x%x w%d\n",
|
printf("traversal: %d 0x%x\n",
|
||||||
binfo.bid,
|
bid,
|
||||||
binfo.tag,
|
tinfo.tag);
|
||||||
binfo.weight);
|
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user