Dropped shrub struct, shoved shrub.estimate into shrub.eoff
We still have an lfsr_shrub_t, it's just a simple alias of lfsr_rbyd_t.
The only difference between these two structs was that lfsr_rbyd_t had
the eoff/cksum fields, to enable incremental commits, and lfsr_shrub_t
had the estimate field, to keep track of the current shrub estimate so
we evict before overflow.
Unfortunately C makes this overlap a bit annoying. We can either add a
union, making a mess of field accesses, or use probably problematic
casting of structs with common initial sequences.
Instead of dealing with this headache, I'm just going to shove the
shrub estimate into the rbyd's eoff field and ignore the name abuse.
In normal rbyd use, eoff does effectively contain the on-disk size of
the rbyd, so it's not too far from its intended use...
This does move our estimate to overlap the eoff field instead of the
cksum field, which means we need to be a bit more careful about setting
erased state for btrees. This adds a small code cost:
code stack
before: 33928 2912
after: 33956 (+0.1%) 2912 (+0.0%)
This commit is contained in:
@@ -3550,9 +3550,6 @@ static int lfsr_rbyd_appendgdelta(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// needed in lfsr_rbyd_appendshrub
|
|
||||||
static inline const lfsr_rbyd_t *lfsr_shrub_rbyd(const lfsr_shrub_t *shrub);
|
|
||||||
|
|
||||||
// append a secondary "shrub" tree
|
// append a secondary "shrub" tree
|
||||||
static int lfsr_rbyd_appendshrub(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
static int lfsr_rbyd_appendshrub(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||||
const lfsr_shrub_t *shrub) {
|
const lfsr_shrub_t *shrub) {
|
||||||
@@ -3562,8 +3559,7 @@ static int lfsr_rbyd_appendshrub(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
|||||||
rbyd->trunk |= LFSR_RBYD_SHRUB;
|
rbyd->trunk |= LFSR_RBYD_SHRUB;
|
||||||
|
|
||||||
// compact our shrub
|
// compact our shrub
|
||||||
int err = lfsr_rbyd_appendcompactrbyd(lfs, rbyd, -1, -1,
|
int err = lfsr_rbyd_appendcompactrbyd(lfs, rbyd, -1, -1, shrub);
|
||||||
lfsr_shrub_rbyd(shrub));
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -4806,14 +4802,10 @@ static inline bool lfsr_shrub_hastrunk(const lfsr_shrub_t *shrub) {
|
|||||||
return lfsr_shrub_trunk(shrub) != 0;
|
return lfsr_shrub_trunk(shrub) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const lfsr_rbyd_t *lfsr_shrub_rbyd(const lfsr_shrub_t *shrub) {
|
|
||||||
return (const lfsr_rbyd_t*)shrub;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int lfsr_shrub_cmp(
|
static inline int lfsr_shrub_cmp(
|
||||||
const lfsr_shrub_t *a,
|
const lfsr_shrub_t *a,
|
||||||
const lfsr_shrub_t *b) {
|
const lfsr_shrub_t *b) {
|
||||||
return lfsr_rbyd_cmp(lfsr_shrub_rbyd(a), lfsr_shrub_rbyd(b));
|
return lfsr_rbyd_cmp(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shrub on-disk encoding
|
// shrub on-disk encoding
|
||||||
@@ -4848,7 +4840,7 @@ static int lfsr_data_readshrub(lfs_t *lfs, lfsr_data_t *data,
|
|||||||
// copy the mdir block
|
// copy the mdir block
|
||||||
shrub->blocks[0] = mdir->rbyd.blocks[0];
|
shrub->blocks[0] = mdir->rbyd.blocks[0];
|
||||||
// force estimate recalculation if we write to this shrub
|
// force estimate recalculation if we write to this shrub
|
||||||
shrub->estimate = -1;
|
shrub->eoff = -1;
|
||||||
|
|
||||||
int err = lfsr_data_readleb128(lfs, data, &shrub->weight);
|
int err = lfsr_data_readleb128(lfs, data, &shrub->weight);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -4886,7 +4878,7 @@ static lfs_ssize_t lfsr_shrub_estimate(lfs_t *lfs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return lfsr_rbyd_estimate(lfs, lfsr_shrub_rbyd(shrub), -1, -1,
|
return lfsr_rbyd_estimate(lfs, shrub, -1, -1,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9611,9 +9603,7 @@ static int lfsr_bshrub_traverse(lfs_t *lfs, const lfsr_file_t *file,
|
|||||||
|
|
||||||
// bshrub/btree?
|
// bshrub/btree?
|
||||||
} else if (lfsr_bshrub_isbshruborbtree(&file->bshrub)) {
|
} else if (lfsr_bshrub_isbshruborbtree(&file->bshrub)) {
|
||||||
int err = lfsr_btree_traverse_(lfs,
|
int err = lfsr_btree_traverse_(lfs, &file->bshrub.u.bshrub, btraversal,
|
||||||
lfsr_shrub_rbyd(&file->bshrub.u.bshrub),
|
|
||||||
btraversal,
|
|
||||||
bid_, tinfo_);
|
bid_, tinfo_);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -9708,20 +9698,22 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
// file must be a bshrub/btree here
|
// file must be a bshrub/btree here
|
||||||
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(&file->bshrub));
|
LFS_ASSERT(lfsr_bshrub_isbshruborbtree(&file->bshrub));
|
||||||
|
|
||||||
// before we touch anything, we need to mark all other references
|
// before we touch anything, we need to mark all other btree references
|
||||||
// as unerased
|
// as unerased
|
||||||
for (lfsr_opened_t *opened_ = lfs->opened;
|
if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) {
|
||||||
opened_;
|
for (lfsr_opened_t *opened_ = lfs->opened;
|
||||||
opened_ = opened_->next) {
|
opened_;
|
||||||
lfsr_file_t *file_ = (lfsr_file_t*)opened_;
|
opened_ = opened_->next) {
|
||||||
if (file_->m.type == LFS_TYPE_REG
|
lfsr_file_t *file_ = (lfsr_file_t*)opened_;
|
||||||
&& file_ != file
|
if (file_->m.type == LFS_TYPE_REG
|
||||||
&& lfsr_bshrub_isbshruborbtree(&file_->bshrub)
|
&& file_ != file
|
||||||
&& lfsr_btree_cmp(
|
&& lfsr_bshrub_isbshruborbtree(&file_->bshrub)
|
||||||
&file_->bshrub.u.btree,
|
&& lfsr_btree_cmp(
|
||||||
&file->bshrub.u.btree) == 0) {
|
&file_->bshrub.u.btree,
|
||||||
// mark as unerased
|
&file->bshrub.u.btree) == 0) {
|
||||||
file_->bshrub.u.btree.eoff = -1;
|
// mark as unerased
|
||||||
|
file_->bshrub.u.btree.eoff = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9767,7 +9759,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
// accurate estimate
|
// accurate estimate
|
||||||
lfs_ssize_t estimate = (alloc)
|
lfs_ssize_t estimate = (alloc)
|
||||||
? (lfs_size_t)-1
|
? (lfs_size_t)-1
|
||||||
: file->bshrub.u.bshrub.estimate;
|
: file->bshrub.u.bshrub.eoff;
|
||||||
// this double condition avoids overflow issues
|
// this double condition avoids overflow issues
|
||||||
if ((lfs_size_t)estimate > lfs->cfg->shrub_size
|
if ((lfs_size_t)estimate > lfs->cfg->shrub_size
|
||||||
|| estimate + commit_estimate > lfs->cfg->shrub_size) {
|
|| estimate + commit_estimate > lfs->cfg->shrub_size) {
|
||||||
@@ -9812,10 +9804,10 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
if (file_->m.type == LFS_TYPE_REG
|
if (file_->m.type == LFS_TYPE_REG
|
||||||
&& file_->m.mdir.mid == file->m.mdir.mid
|
&& file_->m.mdir.mid == file->m.mdir.mid
|
||||||
&& lfsr_bshrub_isbshrub(&file_->m.mdir, &file_->bshrub)) {
|
&& lfsr_bshrub_isbshrub(&file_->m.mdir, &file_->bshrub)) {
|
||||||
file_->bshrub.u.bshrub.estimate = estimate;
|
file_->bshrub.u.bshrub.eoff = estimate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LFS_ASSERT(file->bshrub.u.bshrub.estimate = (lfs_size_t)estimate);
|
LFS_ASSERT(file->bshrub.u.bshrub.eoff = (lfs_size_t)estimate);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -9833,8 +9825,7 @@ evict:;
|
|||||||
|
|
||||||
// note this may be a new root
|
// note this may be a new root
|
||||||
if (!alloc) {
|
if (!alloc) {
|
||||||
err = lfsr_rbyd_compact(lfs, &rbyd, -1, -1,
|
err = lfsr_rbyd_compact(lfs, &rbyd, -1, -1, &file->bshrub.u.bshrub);
|
||||||
lfsr_shrub_rbyd(&file->bshrub.u.bshrub));
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
return err;
|
return err;
|
||||||
@@ -9900,7 +9891,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
file->bshrub.u.bshrub.trunk = LFSR_RBYD_SHRUB | 0;
|
file->bshrub.u.bshrub.trunk = LFSR_RBYD_SHRUB | 0;
|
||||||
file->bshrub.u.bshrub.weight = 0;
|
file->bshrub.u.bshrub.weight = 0;
|
||||||
// force estimate recalculation
|
// force estimate recalculation
|
||||||
file->bshrub.u.bshrub.estimate = -1;
|
file->bshrub.u.bshrub.eoff = -1;
|
||||||
|
|
||||||
if (attr_count > 0) {
|
if (attr_count > 0) {
|
||||||
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
||||||
|
|||||||
@@ -489,18 +489,13 @@ typedef struct lfsr_bptr {
|
|||||||
uint32_t cksum;
|
uint32_t cksum;
|
||||||
} lfsr_bptr_t;
|
} lfsr_bptr_t;
|
||||||
|
|
||||||
// a shrub is a secondary trunk in an mdir, we really only need
|
// a shrub is a secondary trunk in an mdir
|
||||||
// trunk/weight/block, so we sneak our estimate into some
|
//
|
||||||
// overlapping fields
|
// note:
|
||||||
typedef struct lfsr_shrub {
|
// - sign(trunk)=1 => shrub
|
||||||
// this all lines up with lfsr_rbyd_t
|
// - we shove our shrub estimate into rbyd.eoff, C makes it too annoying
|
||||||
lfsr_srid_t weight;
|
// to union another field
|
||||||
lfs_block_t blocks[2];
|
typedef lfsr_rbyd_t lfsr_shrub_t;
|
||||||
lfs_ssize_t trunk;
|
|
||||||
lfs_size_t eoff;
|
|
||||||
// an upper-bound estimate on the on-disk shrub size
|
|
||||||
lfs_size_t estimate;
|
|
||||||
} lfsr_shrub_t;
|
|
||||||
|
|
||||||
// the lfsr_bshrub_t struct represents the on-disk component of a file
|
// the lfsr_bshrub_t struct represents the on-disk component of a file
|
||||||
typedef struct lfsr_bshrub {
|
typedef struct lfsr_bshrub {
|
||||||
|
|||||||
Reference in New Issue
Block a user