Unified attr-list context into little attr arenas
The idea is for cases where we need to incrementally allocate attrs +
context, to allocate from both sides of a statically allocated attr
array. This keeps all of the attr-list state in one place, simplifying
state allocation:
.---+---+---+---.
| attr |
+---+---+---+---+
| attr ----------.
+---+---+---+---+ |
| attr --------. |
+---+---+---+---+ | |
| | | | |
| v | | |
| | | |
| ^ | | |
| | | | |
+---+---+---+---+ | |
| data | <-' |
+---+---+---+---+ |
| encoded bptr | <---'
'---+---+---+---'
This is especially useful for the non-terminating tail-recursive
lfsr_btree_commit_, which needs to pass this state through a function
call.
Unfortunately, to make this work we needed to implement more-or-less a
full arena allocator, complete with annoying alignment handling. alignof
isn't even available in C99, so we needed a few more intrinsics:
- LFS_ALIGNOF(t) - Alignment of type t
- LFS_ALIGNEDSIZEOF(t) - Necessary size to force alignment for t
- LFS_MIN(a, b) - Compile-time min
- LFS_MAX(a, b) - Compile-time max
Technically only LFS_ALIGNOF was required, but the others are nice to
have. LFS_MIN/LFS_MAX is also useful anywhere you need to calculate
complicated compile-time sizes.
At least in C11 we get alignof, so we won't need compiler extensions/
hacks for this in the future...
---
Unfortunately this ended up a net-negative. Pushing up the code/stack
cost to near pre-cat levels:
code stack
before cat: 33856 2824
before scratch: 33812 (-0.1%) 2800 (-0.8%)
after: 33844 (-0.0%) 2824 (+0.0%)
I think the two main culprits are 1. the extra logic needed to calculate
alignment, and 2. wasted stack due to aligning scratch space up to the
nearest lfsr_attr_t.
This commit is contained in:
@@ -1631,6 +1631,29 @@ static inline lfsr_shrub_t *lfsr_attr_shrubtrunk(const lfsr_attr_t *attr) {
|
|||||||
return (lfsr_shrub_t*)attr->cat.u.buf.buffer;
|
return (lfsr_shrub_t*)attr->cat.u.buf.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sometimes we want some extra scratch space associated with an
|
||||||
|
// attribute list
|
||||||
|
#define LFSR_ATTR_SCRATCH(_size) \
|
||||||
|
(((_size)+sizeof(lfsr_attr_t)-1) / sizeof(lfsr_attr_t))
|
||||||
|
|
||||||
|
static inline void *lfsr_attr_scratch(
|
||||||
|
lfsr_attr_t *attr, lfs_size_t *attr_scratch,
|
||||||
|
lfs_size_t size) {
|
||||||
|
lfs_size_t attr_scratch_ = *attr_scratch - size;
|
||||||
|
*attr_scratch = attr_scratch_;
|
||||||
|
return &((uint8_t*)attr)[attr_scratch_];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline lfsr_data_t *lfsr_attr_scratchdata(
|
||||||
|
lfsr_attr_t *attr, lfs_size_t *attr_scratch) {
|
||||||
|
lfs_size_t attr_scratch_ = *attr_scratch - sizeof(lfsr_data_t);
|
||||||
|
// align down
|
||||||
|
attr_scratch_ -= (uintptr_t)&((uint8_t*)attr)[attr_scratch_]
|
||||||
|
% LFS_ALIGNOF(lfsr_data_t);
|
||||||
|
*attr_scratch = attr_scratch_;
|
||||||
|
return (lfsr_data_t*)&((uint8_t*)attr)[attr_scratch_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// generalized info returned by traveral functions
|
// generalized info returned by traveral functions
|
||||||
@@ -4374,6 +4397,11 @@ static int lfsr_btree_parent(lfs_t *lfs, const lfsr_btree_t *btree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// attrs needed for lfsr_btree_commit_
|
||||||
|
#define LFSR_BTREE_COMMIT_ATTRS \
|
||||||
|
(4 + LFSR_ATTR_SCRATCH( \
|
||||||
|
LFS_ALIGNEDSIZEOF(lfsr_data_t) + 2*LFSR_BRANCH_DSIZE))
|
||||||
|
|
||||||
// core btree algorithm
|
// core btree algorithm
|
||||||
//
|
//
|
||||||
// this commits up to the root, but stops if:
|
// this commits up to the root, but stops if:
|
||||||
@@ -4382,10 +4410,7 @@ static int lfsr_btree_parent(lfs_t *lfs, const lfsr_btree_t *btree,
|
|||||||
//
|
//
|
||||||
static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
||||||
lfsr_bid_t *bid_, const lfsr_attr_t **attrs_, lfs_size_t *attr_count_,
|
lfsr_bid_t *bid_, const lfsr_attr_t **attrs_, lfs_size_t *attr_count_,
|
||||||
lfsr_attr_t attrs__[static 4],
|
lfsr_attr_t attrs__[static LFSR_BTREE_COMMIT_ATTRS]) {
|
||||||
uint8_t buf__[static 2*LFSR_BRANCH_DSIZE],
|
|
||||||
// TODO can we carve this out of buf__?
|
|
||||||
lfsr_data_t split_data__[static 1]) {
|
|
||||||
lfsr_bid_t bid = *bid_;
|
lfsr_bid_t bid = *bid_;
|
||||||
LFS_ASSERT(bid <= (lfsr_bid_t)btree->weight);
|
LFS_ASSERT(bid <= (lfsr_bid_t)btree->weight);
|
||||||
const lfsr_attr_t *attrs = *attrs_;
|
const lfsr_attr_t *attrs = *attrs_;
|
||||||
@@ -4506,16 +4531,17 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
// note that since we defer merges to compaction time, we can
|
// note that since we defer merges to compaction time, we can
|
||||||
// end up removing an rbyd here
|
// end up removing an rbyd here
|
||||||
attr_count = 0;
|
attr_count = 0;
|
||||||
lfs_size_t buf_size = 0;
|
lfs_size_t attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
|
||||||
bid -= pid - (rbyd.weight-1);
|
bid -= pid - (rbyd.weight-1);
|
||||||
if (rbyd_.weight == 0) {
|
if (rbyd_.weight == 0) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_RM, -rbyd.weight, LFSR_CAT_NULL());
|
LFSR_TAG_RM, -rbyd.weight, LFSR_CAT_NULL());
|
||||||
} else {
|
} else {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, 0,
|
LFSR_TAG_BRANCH, 0,
|
||||||
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size]));
|
lfsr_cat_frombranch(&rbyd_, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
|
||||||
if (rbyd_.weight != rbyd.weight) {
|
if (rbyd_.weight != rbyd.weight) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
||||||
@@ -4762,58 +4788,65 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
goto finalize;
|
goto finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare commit to parent, tail recursing upwards
|
||||||
|
LFS_ASSERT(rbyd_.weight > 0);
|
||||||
|
LFS_ASSERT(sibling.weight > 0);
|
||||||
|
attr_count = 0;
|
||||||
|
attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
|
||||||
|
|
||||||
// lookup first name in sibling to use as the split name
|
// lookup first name in sibling to use as the split name
|
||||||
//
|
//
|
||||||
// note we need to do this after playing out pending attrs in case
|
// note we need to do this after playing out pending attrs in case
|
||||||
// they introduce a new name!
|
// they introduce a new name!
|
||||||
lfsr_tag_t split_tag;
|
lfsr_tag_t split_tag;
|
||||||
|
lfsr_data_t *split_data = lfsr_attr_scratchdata(
|
||||||
|
attrs__, &attr_scratch);
|
||||||
err = lfsr_rbyd_lookupnext(lfs, &sibling, 0, LFSR_TAG_NAME,
|
err = lfsr_rbyd_lookupnext(lfs, &sibling, 0, LFSR_TAG_NAME,
|
||||||
NULL, &split_tag, NULL, &split_data__[0]);
|
NULL, &split_tag, NULL, split_data);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare commit to parent, tail recursing upwards
|
|
||||||
LFS_ASSERT(rbyd_.weight > 0);
|
|
||||||
LFS_ASSERT(sibling.weight > 0);
|
|
||||||
attr_count = 0;
|
|
||||||
buf_size = 0;
|
|
||||||
// new root?
|
// new root?
|
||||||
if (!lfsr_rbyd_trunk(&parent)) {
|
if (!lfsr_rbyd_trunk(&parent)) {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, +rbyd_.weight,
|
LFSR_TAG_BRANCH, +rbyd_.weight,
|
||||||
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size]));
|
lfsr_cat_frombranch(&rbyd_, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, +sibling.weight,
|
LFSR_TAG_BRANCH, +sibling.weight,
|
||||||
lfsr_cat_frombranch(&sibling, &buf__[buf_size]));
|
lfsr_cat_frombranch(&sibling, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
|
||||||
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
|
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_NAME, 0,
|
LFSR_TAG_NAME, 0,
|
||||||
lfsr_cat_fromdatas(&split_data__[0], 1));
|
LFSR_CAT_DATA(split_data));
|
||||||
}
|
}
|
||||||
// split root?
|
// split root?
|
||||||
} else {
|
} else {
|
||||||
bid -= pid - (rbyd.weight-1);
|
bid -= pid - (rbyd.weight-1);
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, 0,
|
LFSR_TAG_BRANCH, 0,
|
||||||
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size]));
|
lfsr_cat_frombranch(&rbyd_, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
|
||||||
if (rbyd_.weight != rbyd.weight) {
|
if (rbyd_.weight != rbyd.weight) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
||||||
LFSR_CAT_NULL());
|
LFSR_CAT_NULL());
|
||||||
}
|
}
|
||||||
|
buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, +sibling.weight,
|
LFSR_TAG_BRANCH, +sibling.weight,
|
||||||
lfsr_cat_frombranch(&sibling, &buf__[buf_size]));
|
lfsr_cat_frombranch(&sibling, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
|
||||||
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
|
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_NAME, 0,
|
LFSR_TAG_NAME, 0,
|
||||||
lfsr_cat_fromdatas(&split_data__[0], 1));
|
LFSR_CAT_DATA(split_data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attrs = attrs__;
|
attrs = attrs__;
|
||||||
@@ -4876,14 +4909,15 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
// prepare commit to parent, tail recursing upwards
|
// prepare commit to parent, tail recursing upwards
|
||||||
LFS_ASSERT(rbyd_.weight > 0);
|
LFS_ASSERT(rbyd_.weight > 0);
|
||||||
attr_count = 0;
|
attr_count = 0;
|
||||||
buf_size = 0;
|
attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
|
||||||
bid -= pid - (rbyd.weight-1);
|
bid -= pid - (rbyd.weight-1);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_RM, -sibling.weight, LFSR_CAT_NULL());
|
LFSR_TAG_RM, -sibling.weight, LFSR_CAT_NULL());
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
|
||||||
|
LFSR_BRANCH_DSIZE);
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BRANCH, 0,
|
LFSR_TAG_BRANCH, 0,
|
||||||
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size]));
|
lfsr_cat_frombranch(&rbyd_, buf));
|
||||||
buf_size += LFSR_BRANCH_DSIZE;
|
|
||||||
if (rbyd_.weight != rbyd.weight) {
|
if (rbyd_.weight != rbyd.weight) {
|
||||||
attrs__[attr_count++] = LFSR_ATTR(
|
attrs__[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
|
||||||
@@ -4900,15 +4934,11 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
|
|||||||
// this is atomic
|
// this is atomic
|
||||||
static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||||
lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||||
// we need some scratch space for tail-recursive attrs
|
|
||||||
lfsr_attr_t attrs__[4];
|
|
||||||
uint8_t buffer[2*LFSR_BRANCH_DSIZE];
|
|
||||||
lfsr_data_t split_data__[1];
|
|
||||||
|
|
||||||
// try to commit to the btree
|
// try to commit to the btree
|
||||||
|
lfsr_attr_t attrs__[LFSR_BTREE_COMMIT_ATTRS];
|
||||||
int err = lfsr_btree_commit_(lfs, btree,
|
int err = lfsr_btree_commit_(lfs, btree,
|
||||||
&bid, &attrs, &attr_count,
|
&bid, &attrs, &attr_count,
|
||||||
attrs__, buffer, split_data__);
|
attrs__);
|
||||||
if (err && err != LFS_ERR_RANGE) {
|
if (err && err != LFS_ERR_RANGE) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -5687,10 +5717,7 @@ static bool lfsr_mid_isopen(lfs_t *lfs, lfsr_smid_t mid) {
|
|||||||
.u.mptr.weight=(LFSR_MTREE_ISMPTR | (_weight)), \
|
.u.mptr.weight=(LFSR_MTREE_ISMPTR | (_weight)), \
|
||||||
.u.mptr.mptr=_mptr})
|
.u.mptr.mptr=_mptr})
|
||||||
|
|
||||||
#define LFSR_MTREE_DSIZE ( \
|
#define LFSR_MTREE_DSIZE LFS_MAX(LFSR_MPTR_DSIZE, LFSR_BTREE_DSIZE)
|
||||||
(LFSR_MPTR_DSIZE > LFSR_BTREE_DSIZE) \
|
|
||||||
? LFSR_MPTR_DSIZE \
|
|
||||||
: LFSR_BTREE_DSIZE)
|
|
||||||
|
|
||||||
static inline bool lfsr_mtree_isnull(const lfsr_mtree_t *mtree) {
|
static inline bool lfsr_mtree_isnull(const lfsr_mtree_t *mtree) {
|
||||||
return mtree->u.weight == (LFSR_MTREE_ISMPTR | 0);
|
return mtree->u.weight == (LFSR_MTREE_ISMPTR | 0);
|
||||||
@@ -10153,15 +10180,11 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need some scratch space for tail-recursive attrs
|
|
||||||
lfsr_attr_t attrs__[4];
|
|
||||||
uint8_t buffer[2*LFSR_BRANCH_DSIZE];
|
|
||||||
lfsr_data_t split_data__[1];
|
|
||||||
|
|
||||||
// try to commit to the btree
|
// try to commit to the btree
|
||||||
|
lfsr_attr_t attrs__[LFSR_BTREE_COMMIT_ATTRS];
|
||||||
int err = lfsr_btree_commit_(lfs, &file->bshrub.u.btree,
|
int err = lfsr_btree_commit_(lfs, &file->bshrub.u.btree,
|
||||||
&bid, &attrs, &attr_count,
|
&bid, &attrs, &attr_count,
|
||||||
attrs__, buffer, split_data__);
|
attrs__);
|
||||||
if (err && err != LFS_ERR_RANGE) {
|
if (err && err != LFS_ERR_RANGE) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -10304,10 +10327,10 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
|
|
||||||
// try to merge commits where possible
|
// try to merge commits where possible
|
||||||
lfsr_bid_t bid = lfsr_bshrub_size(&file->bshrub);
|
lfsr_bid_t bid = lfsr_bshrub_size(&file->bshrub);
|
||||||
lfsr_attr_t attrs[5];
|
lfsr_attr_t attrs[5 + LFSR_ATTR_SCRATCH(
|
||||||
|
2*LFS_MAX(LFS_ALIGNEDSIZEOF(lfsr_data_t), LFSR_BPTR_DSIZE))];
|
||||||
lfs_size_t attr_count = 0;
|
lfs_size_t attr_count = 0;
|
||||||
uint8_t buf[2*LFSR_BPTR_DSIZE];
|
lfs_size_t attr_scratch = sizeof(attrs);
|
||||||
lfs_size_t buf_size = 0;
|
|
||||||
|
|
||||||
// always convert to bshrub/btree when this function is called
|
// always convert to bshrub/btree when this function is called
|
||||||
if (!lfsr_bshrub_isbshruborbtree(&file->bshrub)) {
|
if (!lfsr_bshrub_isbshruborbtree(&file->bshrub)) {
|
||||||
@@ -10319,10 +10342,11 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
LFSR_TAG_DATA, +lfsr_bshrub_size(&file->bshrub),
|
LFSR_TAG_DATA, +lfsr_bshrub_size(&file->bshrub),
|
||||||
LFSR_CAT_DATA(&file->bshrub.u.bsprout));
|
LFSR_CAT_DATA(&file->bshrub.u.bsprout));
|
||||||
} else if (lfsr_bshrub_isbptr(&file->m.mdir, &file->bshrub)) {
|
} else if (lfsr_bshrub_isbptr(&file->m.mdir, &file->bshrub)) {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
|
||||||
|
LFSR_BPTR_DSIZE);
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BLOCK, +lfsr_bshrub_size(&file->bshrub),
|
LFSR_TAG_BLOCK, +lfsr_bshrub_size(&file->bshrub),
|
||||||
lfsr_cat_frombptr(&file->bshrub.u.bptr, &buf[buf_size]));
|
lfsr_cat_frombptr(&file->bshrub.u.bptr, buf));
|
||||||
buf_size += LFSR_BPTR_DSIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file->bshrub.u.bshrub.blocks[0] = file->m.mdir.rbyd.blocks[0];
|
file->bshrub.u.bshrub.blocks[0] = file->m.mdir.rbyd.blocks[0];
|
||||||
@@ -10332,8 +10356,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
file->bshrub.u.bshrub.estimate = -1;
|
file->bshrub.u.bshrub.estimate = -1;
|
||||||
|
|
||||||
if (attr_count > 0) {
|
if (attr_count > 0) {
|
||||||
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
|
||||||
LFS_ASSERT(buf_size <= sizeof(buf));
|
|
||||||
|
|
||||||
int err = lfsr_bshrub_commit(lfs, file, 0, attrs, attr_count);
|
int err = lfsr_bshrub_commit(lfs, file, 0, attrs, attr_count);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -10342,7 +10365,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
attr_count = 0;
|
attr_count = 0;
|
||||||
buf_size = 0;
|
attr_scratch = sizeof(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// need a hole?
|
// need a hole?
|
||||||
@@ -10367,9 +10390,6 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
lfsr_tag_t right_tag_ = 0;
|
lfsr_tag_t right_tag_ = 0;
|
||||||
lfsr_bid_t right_weight_;
|
lfsr_bid_t right_weight_;
|
||||||
lfsr_bptr_t right_bptr_;
|
lfsr_bptr_t right_bptr_;
|
||||||
// TODO should we handle left/right slice/bptr differently? allocate
|
|
||||||
// from buf maybe?
|
|
||||||
lfsr_data_t left_slice_;
|
|
||||||
while (pos < lfsr_bshrub_size(&file->bshrub)) {
|
while (pos < lfsr_bshrub_size(&file->bshrub)) {
|
||||||
lfsr_tag_t tag_;
|
lfsr_tag_t tag_;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight_;
|
||||||
@@ -10382,7 +10402,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// note, an entry can be both a left and right sibling
|
// note, an entry can be both a left and right sibling
|
||||||
left_slice_ = lfsr_data_slice(bptr_.data,
|
lfsr_data_t left_slice_ = lfsr_data_slice(bptr_.data,
|
||||||
-1,
|
-1,
|
||||||
pos - (bid-(weight_-1)));
|
pos - (bid-(weight_-1)));
|
||||||
lfsr_data_t right_slice_ = lfsr_data_slice(bptr_.data,
|
lfsr_data_t right_slice_ = lfsr_data_slice(bptr_.data,
|
||||||
@@ -10458,13 +10478,18 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
|
|
||||||
// carve fragment?
|
// carve fragment?
|
||||||
} else if (tag_ == LFSR_TAG_DATA) {
|
} else if (tag_ == LFSR_TAG_DATA) {
|
||||||
|
lfsr_data_t *data = lfsr_attr_scratchdata(
|
||||||
|
attrs, &attr_scratch);
|
||||||
|
*data = left_slice_;
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA,
|
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA,
|
||||||
-(bid+1 - pos),
|
-(bid+1 - pos),
|
||||||
LFSR_CAT_DATA(&left_slice_));
|
LFSR_CAT_DATA(data));
|
||||||
|
|
||||||
// carve bptr?
|
// carve bptr?
|
||||||
} else if (tag_ == LFSR_TAG_BLOCK) {
|
} else if (tag_ == LFSR_TAG_BLOCK) {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
|
||||||
|
LFSR_BPTR_DSIZE);
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK,
|
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK,
|
||||||
-(bid+1 - pos),
|
-(bid+1 - pos),
|
||||||
@@ -10473,8 +10498,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
.data = left_slice_,
|
.data = left_slice_,
|
||||||
.cksize = bptr_.cksize,
|
.cksize = bptr_.cksize,
|
||||||
.cksum = bptr_.cksum},
|
.cksum = bptr_.cksum},
|
||||||
&buf[buf_size]));
|
buf));
|
||||||
buf_size += LFSR_BPTR_DSIZE;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LFS_UNREACHABLE();
|
LFS_UNREACHABLE();
|
||||||
@@ -10490,8 +10514,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
// so commit what we have and move on to next entry
|
// so commit what we have and move on to next entry
|
||||||
if (pos+weight > bid+1) {
|
if (pos+weight > bid+1) {
|
||||||
LFS_ASSERT(lfsr_data_size(right_slice_) == 0);
|
LFS_ASSERT(lfsr_data_size(right_slice_) == 0);
|
||||||
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
|
||||||
LFS_ASSERT(buf_size <= sizeof(buf));
|
|
||||||
|
|
||||||
err = lfsr_bshrub_commit(lfs, file, bid,
|
err = lfsr_bshrub_commit(lfs, file, bid,
|
||||||
attrs, attr_count);
|
attrs, attr_count);
|
||||||
@@ -10502,7 +10525,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
delta += lfs_min32(weight, bid+1 - pos);
|
delta += lfs_min32(weight, bid+1 - pos);
|
||||||
weight -= lfs_min32(weight, bid+1 - pos);
|
weight -= lfs_min32(weight, bid+1 - pos);
|
||||||
attr_count = 0;
|
attr_count = 0;
|
||||||
buf_size = 0;
|
attr_scratch = sizeof(attrs);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10564,16 +10587,19 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
if (right_tag_) {
|
if (right_tag_) {
|
||||||
// right fragment?
|
// right fragment?
|
||||||
if (right_tag_ == LFSR_TAG_DATA) {
|
if (right_tag_ == LFSR_TAG_DATA) {
|
||||||
|
lfsr_data_t *data = lfsr_attr_scratchdata(attrs, &attr_scratch);
|
||||||
|
*data = right_bptr_.data;
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_DATA, +right_weight_,
|
LFSR_TAG_DATA, +right_weight_,
|
||||||
LFSR_CAT_DATA(&right_bptr_.data));
|
LFSR_CAT_DATA(data));
|
||||||
|
|
||||||
// right bptr?
|
// right bptr?
|
||||||
} else if (right_tag_ == LFSR_TAG_BLOCK) {
|
} else if (right_tag_ == LFSR_TAG_BLOCK) {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
|
||||||
|
LFSR_BPTR_DSIZE);
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_BLOCK, +right_weight_,
|
LFSR_TAG_BLOCK, +right_weight_,
|
||||||
lfsr_cat_frombptr(&right_bptr_, &buf[buf_size]));
|
lfsr_cat_frombptr(&right_bptr_, buf));
|
||||||
buf_size += LFSR_BPTR_DSIZE;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LFS_UNREACHABLE();
|
LFS_UNREACHABLE();
|
||||||
@@ -10582,8 +10608,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
|
|
||||||
// commit pending attrs
|
// commit pending attrs
|
||||||
if (attr_count > 0) {
|
if (attr_count > 0) {
|
||||||
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
|
||||||
LFS_ASSERT(buf_size <= sizeof(buf));
|
|
||||||
|
|
||||||
int err = lfsr_bshrub_commit(lfs, file, bid,
|
int err = lfsr_bshrub_commit(lfs, file, bid,
|
||||||
attrs, attr_count);
|
attrs, attr_count);
|
||||||
@@ -11399,17 +11424,16 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
lfs_alloc_ckpoint(lfs);
|
lfs_alloc_ckpoint(lfs);
|
||||||
|
|
||||||
// commit our file's metadata
|
// commit our file's metadata
|
||||||
lfsr_attr_t attrs[2];
|
lfsr_attr_t attrs[2 + LFSR_ATTR_SCRATCH(
|
||||||
|
LFS_ALIGNEDSIZEOF(lfsr_data_t) + LFSR_BTREE_DSIZE)];
|
||||||
lfs_size_t attr_count = 0;
|
lfs_size_t attr_count = 0;
|
||||||
uint8_t buf[LFSR_BTREE_DSIZE];
|
lfs_size_t attr_scratch = sizeof(attrs);
|
||||||
lfs_size_t buf_size = 0;
|
|
||||||
// TODO should we carve this out of buf?
|
|
||||||
lfsr_data_t data;
|
|
||||||
|
|
||||||
// not created yet? need to convert orphan to normal file
|
// not created yet? need to convert orphan to normal file
|
||||||
if (lfsr_f_isorphan(file->m.flags)) {
|
if (lfsr_f_isorphan(file->m.flags)) {
|
||||||
|
lfsr_data_t *data = lfsr_attr_scratchdata(attrs, &attr_scratch);
|
||||||
err = lfsr_mdir_lookup(lfs, &file->m.mdir, LFSR_TAG_ORPHAN,
|
err = lfsr_mdir_lookup(lfs, &file->m.mdir, LFSR_TAG_ORPHAN,
|
||||||
&data);
|
data);
|
||||||
if (err) {
|
if (err) {
|
||||||
// we must have an orphan at this point
|
// we must have an orphan at this point
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
@@ -11418,7 +11442,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
|
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_SUB | LFSR_TAG_REG, 0,
|
LFSR_TAG_SUB | LFSR_TAG_REG, 0,
|
||||||
LFSR_CAT_DATA(&data));
|
LFSR_CAT_DATA(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit the file state
|
// commit the file state
|
||||||
@@ -11440,18 +11464,16 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
&file->bshrub_.u.bshrub);
|
&file->bshrub_.u.bshrub);
|
||||||
// btree?
|
// btree?
|
||||||
} else if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) {
|
} else if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) {
|
||||||
|
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
|
||||||
|
LFSR_BTREE_DSIZE);
|
||||||
attrs[attr_count++] = LFSR_ATTR(
|
attrs[attr_count++] = LFSR_ATTR(
|
||||||
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
|
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
|
||||||
lfsr_cat_frombtree(
|
lfsr_cat_frombtree(&file->bshrub.u.btree, buf));
|
||||||
&file->bshrub.u.btree,
|
|
||||||
&buf[buf_size]));
|
|
||||||
buf_size += LFSR_BTREE_DSIZE;
|
|
||||||
} else {
|
} else {
|
||||||
LFS_UNREACHABLE();
|
LFS_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t));
|
LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
|
||||||
LFS_ASSERT(buf_size <= sizeof(buf));
|
|
||||||
|
|
||||||
err = lfsr_mdir_commit(lfs, &file->m.mdir,
|
err = lfsr_mdir_commit(lfs, &file->m.mdir,
|
||||||
attrs, attr_count);
|
attrs, attr_count);
|
||||||
|
|||||||
+22
-8
@@ -142,16 +142,16 @@ extern "C"
|
|||||||
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
|
||||||
// expensive basic C implementation for debugging purposes
|
// expensive basic C implementation for debugging purposes
|
||||||
|
|
||||||
// Min/max functions for unsigned 32-bit numbers
|
// Compile time min/max
|
||||||
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
|
#define LFS_MIN(a, b) ((a < b) ? a : b)
|
||||||
return (a > b) ? a : b;
|
#define LFS_MAX(a, b) ((a > b) ? a : b)
|
||||||
}
|
|
||||||
|
|
||||||
|
// Min/max functions for unsigned 32-bit numbers
|
||||||
static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
|
static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
|
||||||
return (a < b) ? a : b;
|
return (a < b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t lfs_max32(uint32_t a, uint32_t b) {
|
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
|
||||||
return (a > b) ? a : b;
|
return (a > b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ static inline uint32_t lfs_min32(uint32_t a, uint32_t b) {
|
|||||||
return (a < b) ? a : b;
|
return (a < b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int32_t lfs_smax32(int32_t a, int32_t b) {
|
static inline uint32_t lfs_max32(uint32_t a, uint32_t b) {
|
||||||
return (a > b) ? a : b;
|
return (a > b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,15 +167,19 @@ static inline int32_t lfs_smin32(int32_t a, int32_t b) {
|
|||||||
return (a < b) ? a : b;
|
return (a < b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO other 16-bit ops?
|
static inline int32_t lfs_smax32(int32_t a, int32_t b) {
|
||||||
static inline uint16_t lfs_max16(uint16_t a, uint16_t b) {
|
|
||||||
return (a > b) ? a : b;
|
return (a > b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO other 16-bit ops?
|
||||||
static inline uint16_t lfs_min16(uint16_t a, uint16_t b) {
|
static inline uint16_t lfs_min16(uint16_t a, uint16_t b) {
|
||||||
return (a < b) ? a : b;
|
return (a < b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint16_t lfs_max16(uint16_t a, uint16_t b) {
|
||||||
|
return (a > b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
// Clamp is useful as the logic for min/max when clamping can become confusing
|
// Clamp is useful as the logic for min/max when clamping can become confusing
|
||||||
static inline uint32_t lfs_clamp32(uint32_t a, uint32_t min, uint32_t max) {
|
static inline uint32_t lfs_clamp32(uint32_t a, uint32_t min, uint32_t max) {
|
||||||
return lfs_min32(lfs_max32(a, min), max);
|
return lfs_min32(lfs_max32(a, min), max);
|
||||||
@@ -217,6 +221,16 @@ static inline void lfs_sswap32(int32_t *a, int32_t *b) {
|
|||||||
*b = t;
|
*b = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find alignment of a type at compile time
|
||||||
|
#if !defined(LFS_NO_INTRINSICS)
|
||||||
|
#define LFS_ALIGNOF(t) __alignof__(t)
|
||||||
|
#else
|
||||||
|
#define LFS_ALIGNOF(t) ((size_t)&((struct {char a; t b;}*)0)->b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Find size necessary to align type at compile time
|
||||||
|
#define LFS_ALIGNEDSIZEOF(t) (sizeof(t) + LFS_ALIGNOF(t)-1)
|
||||||
|
|
||||||
// Align to nearest multiple of a size
|
// Align to nearest multiple of a size
|
||||||
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
|
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
|
||||||
return a - (a % alignment);
|
return a - (a % alignment);
|
||||||
|
|||||||
Reference in New Issue
Block a user