Cleaned up reworked commit logic, deduplicated rbyd/attr things again
This attempts to clean up and deduplicate rbyd operations where
possible, without losing the cleaner logic introduced by the commit
rework.
Some tradeoffs were made:
- In btree merges, we append the split name after the compaction.
This means the split name doesn't get compacted when we merge, but
avoids making the merge compactions special cases.
- We never clean up vestigial names.
This one bothers me, since it means we can end up with names that
never get cleaned up. But then again, that's already true of any names
that get pushed up in the btree inner nodes that aren't the leading
btree entry.
By never cleaning these up, all rbyd compactions in the system behave
the same.
- We don't push gstate into the mroot during relocations.
This would be a nice-to-have, but would require lfsr_mdir_commit__ to
know if we are relocating or extending. And mdirs need to reserve space
for gstate anyways, so it's not the end of the world to leave a bit
of extra gstate around.
Also some attr-list operations are not deduplicated due to how special
they are:
- The writing of attrs in lfsr_mdir_commit__, this is where we adjust
mids->rids and handle special internal attr.
This is a pain, since we end up duplicating the attr-list range
operations, but on the plus side keeps the special mdir attrs out of
the rbyd layers, and saves a bit of RAM from the hot-path.
- The copying of config attrs during mroot extensions.
This one is just tricky because we want to keep the config attrs, but
not the gstate attrs or any custom attributes. An explicit compaction
of only the subrange of config attrs gets the job done.
These changes get our code/RAM costs pretty much back where they
started:
code stack
before mdir rework: 20826 1744
after mdir rework: 21434 (+2.8%) 1768 (+1.4%)
after mdir cleanup: 20850 (+0.1%) 1736 (-0.5%)
It's interesting to note the slight tradeoff of code/RAM here (though
this is very close to the compiler noise floor) comes from the moving of
special mdir attr logic up into lfsr_mdir_commit__.
I wasn't expecting this, but it makes sense since this moves the special
attr handling out of the hot-path going through the mtree commit.
This commit is contained in:
@@ -2856,41 +2856,32 @@ failed:;
|
||||
return err;
|
||||
}
|
||||
|
||||
// append and consume any pending gstate
|
||||
static int lfsr_rbyd_appendgdelta(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
// need GRM delta?
|
||||
if (!lfsr_grm_iszero(lfs->dgrm)) {
|
||||
// calculate our delta
|
||||
uint8_t grm_buf[LFSR_GRM_DSIZE];
|
||||
memset(grm_buf, 0, LFSR_GRM_DSIZE);
|
||||
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookup(lfs, rbyd, -1, LFSR_TAG_GRM, NULL, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err != LFS_ERR_NOENT) {
|
||||
lfs_ssize_t grm_dsize = lfsr_data_read(lfs, &data,
|
||||
grm_buf, LFSR_GRM_DSIZE);
|
||||
if (grm_dsize < 0) {
|
||||
return grm_dsize;
|
||||
static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid,
|
||||
const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||
// append each tag to the tree
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
// don't write tags outside of the requested range
|
||||
if (attrs[i].rid >= start_rid
|
||||
// note the use of rid+1 and unsigned comparison here to
|
||||
// treat end_rid=-1 as "unbounded" in such a way that rid=-1
|
||||
// is still included
|
||||
&& (lfs_size_t)(attrs[i].rid + 1) <= (lfs_size_t)end_rid) {
|
||||
int err = lfsr_rbyd_appendattr(lfs, rbyd,
|
||||
attrs[i].rid - lfs_smax32(start_rid, 0),
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_grm_xor(lfs, grm_buf, LFSR_DATA(
|
||||
&lfs->dgrm, LFSR_GRM_DSIZE));
|
||||
if (err) {
|
||||
return err;
|
||||
// we need to make sure we keep start_rid/end_rid updated with
|
||||
// weight changes
|
||||
if (attrs[i].rid < start_rid) {
|
||||
start_rid += attrs[i].delta;
|
||||
}
|
||||
|
||||
// append to our rbyd, note this replaces the original delta
|
||||
lfs_size_t size = lfsr_grm_size(grm_buf);
|
||||
err = lfsr_rbyd_appendattr(lfs, rbyd, -1,
|
||||
// opportunistically remove this tag if delta is all zero
|
||||
(size == 0 ? LFSR_TAG_RM(GRM) : LFSR_TAG_GRM), 0,
|
||||
LFSR_DATA(grm_buf, size));
|
||||
if (err) {
|
||||
return err;
|
||||
if (attrs[i].rid < end_rid) {
|
||||
end_rid += attrs[i].delta;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2972,6 +2963,40 @@ failed:;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lfsr_rbyd_appendcompactrbyd(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid,
|
||||
const lfsr_rbyd_t *rbyd) {
|
||||
// copy over tags in the rbyd in order
|
||||
lfs_ssize_t rid = start_rid;
|
||||
lfsr_tag_t tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookupnext(lfs, rbyd,
|
||||
rid, lfsr_tag_next(tag),
|
||||
&rid, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
// end of range? note the use of rid+1 and unsigned comparison here to
|
||||
// treat end_rid=-1 as "unbounded" in such a way that rid=-1 is still
|
||||
// included
|
||||
if (err == LFS_ERR_NOENT
|
||||
|| (lfs_size_t)(rid + 1) > (lfs_size_t)end_rid) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, rbyd_, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
// must fetch before mutating!
|
||||
LFS_ASSERT(lfsr_rbyd_isfetched(rbyd));
|
||||
@@ -3076,6 +3101,47 @@ failed:;
|
||||
return err;
|
||||
}
|
||||
|
||||
// append and consume any pending gstate
|
||||
static int lfsr_rbyd_appendgdelta(lfs_t *lfs, lfsr_rbyd_t *rbyd) {
|
||||
// need GRM delta?
|
||||
if (!lfsr_grm_iszero(lfs->dgrm)) {
|
||||
// calculate our delta
|
||||
uint8_t grm_buf[LFSR_GRM_DSIZE];
|
||||
memset(grm_buf, 0, LFSR_GRM_DSIZE);
|
||||
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookup(lfs, rbyd, -1, LFSR_TAG_GRM, NULL, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err != LFS_ERR_NOENT) {
|
||||
lfs_ssize_t grm_dsize = lfsr_data_read(lfs, &data,
|
||||
grm_buf, LFSR_GRM_DSIZE);
|
||||
if (grm_dsize < 0) {
|
||||
return grm_dsize;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_grm_xor(lfs, grm_buf, LFSR_DATA(
|
||||
&lfs->dgrm, LFSR_GRM_DSIZE));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// append to our rbyd, note this replaces the original delta
|
||||
lfs_size_t size = lfsr_grm_size(grm_buf);
|
||||
err = lfsr_rbyd_appendattr(lfs, rbyd, -1,
|
||||
// opportunistically remove this tag if delta is all zero
|
||||
(size == 0 ? LFSR_TAG_RM(GRM) : LFSR_TAG_GRM), 0,
|
||||
LFSR_DATA(grm_buf, size));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// the following are mostly btree helpers, but since they operate on rbyds,
|
||||
// exist in the rbyd namespace
|
||||
@@ -3144,10 +3210,8 @@ static lfs_ssize_t lfsr_rbyd_estimate(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
// note that we don't include -1 tags yet, -1 tags are always cleaned up
|
||||
// during a split so they shouldn't affect the split_rid
|
||||
//
|
||||
lfs_ssize_t lower_rid = (start_rid < 0 ? 0 : start_rid);
|
||||
lfs_ssize_t upper_rid = (end_rid < 0
|
||||
? (lfs_ssize_t)rbyd->weight-1
|
||||
: end_rid-1);
|
||||
lfs_ssize_t lower_rid = lfs_smax32(start_rid, 0);
|
||||
lfs_ssize_t upper_rid = lfs_min32(rbyd->weight, end_rid)-1;
|
||||
lfs_size_t lower_dsize = 0;
|
||||
lfs_size_t upper_dsize = 0;
|
||||
|
||||
@@ -3188,40 +3252,6 @@ static lfs_ssize_t lfsr_rbyd_estimate(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
return dsize + lower_dsize + upper_dsize;
|
||||
}
|
||||
|
||||
// TODO
|
||||
//// determine if there are fewer than "cutoff" unique ids in the rbyd,
|
||||
//// this is used to determine if the underlying rbyd is degenerate and can
|
||||
//// be reverted to an inlined btree
|
||||
////
|
||||
//// note cutoff is expected to be quite small, <= 2, so we should make sure
|
||||
//// to exit our traverse early
|
||||
//static int lfsr_rbyd_isdegenerate(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
// lfs_ssize_t cutoff) {
|
||||
// // cutoff=-1 => no cutoff
|
||||
// if (cutoff < 0) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // count ids until we exceed our cutoff
|
||||
// lfs_ssize_t rid = -1;
|
||||
// lfs_size_t count = 0;
|
||||
// while (true) {
|
||||
// int err = lfsr_rbyd_lookupnext(lfs, rbyd, rid+1, 0,
|
||||
// &rid, NULL, NULL, NULL);
|
||||
// if (err && err != LFS_ERR_NOENT) {
|
||||
// return err;
|
||||
// }
|
||||
// if (err == LFS_ERR_NOENT) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// count += 1;
|
||||
// if (count > (lfs_size_t)cutoff) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
// some low-level name things
|
||||
//
|
||||
@@ -3688,12 +3718,10 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
}
|
||||
|
||||
// commit our attrs
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd, attrs[i].rid,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &rbyd, -1, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_appendcksum(lfs, &rbyd);
|
||||
@@ -3766,16 +3794,14 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
// erased bytes? note that the btree trunk field prevents this from
|
||||
// interacting with other references to the rbyd
|
||||
lfsr_rbyd_t rbyd_ = rbyd;
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd_, attrs[i].rid - bid,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err && err != LFS_ERR_RANGE) {
|
||||
// TODO wait should we also move if there is corruption here?
|
||||
return err;
|
||||
}
|
||||
if (err) {
|
||||
goto compact;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &rbyd_, bid, -1,
|
||||
attrs, attr_count);
|
||||
if (err && err != LFS_ERR_RANGE) {
|
||||
// TODO wait should we also move if there is corruption here?
|
||||
return err;
|
||||
}
|
||||
if (err) {
|
||||
goto compact;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_appendcksum(lfs, &rbyd_);
|
||||
@@ -3916,27 +3942,10 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
}
|
||||
|
||||
// try to compact
|
||||
lfs_ssize_t rid_ = 0;
|
||||
lfsr_tag_t tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &rbyd,
|
||||
rid_, lfsr_tag_next(tag),
|
||||
&rid_, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, -1, -1, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_);
|
||||
@@ -3947,13 +3956,11 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
|
||||
// append any pending attrs, it's up to upper
|
||||
// layers to make sure these always fit
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd_, attrs[i].rid - bid,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &rbyd_, bid, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// finalize commit
|
||||
@@ -3982,27 +3989,10 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
}
|
||||
|
||||
// copy over tags < split_rid
|
||||
rid_ = 0;
|
||||
tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &rbyd,
|
||||
rid_, lfsr_tag_next(tag),
|
||||
&rid_, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT || rid_ >= (lfs_ssize_t)split_rid) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, -1, split_rid, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_);
|
||||
@@ -4015,23 +4005,11 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
//
|
||||
// upper layers should make sure this can't fail by limiting the
|
||||
// maximum commit size
|
||||
lfs_ssize_t split_rid_ = split_rid;
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
if (attrs[i].rid - (lfs_ssize_t)bid < split_rid_) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd_,
|
||||
attrs[i].rid - bid,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to make sure we keep split_rid updated with
|
||||
// weight changes
|
||||
if (attrs[i].rid - (lfs_ssize_t)bid < split_rid_) {
|
||||
split_rid_ += attrs[i].delta;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &rbyd_, bid, bid+split_rid,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// finalize commit
|
||||
@@ -4042,27 +4020,10 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
}
|
||||
|
||||
// copy over tags >= split_rid
|
||||
rid_ = split_rid;
|
||||
tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &rbyd,
|
||||
rid_, lfsr_tag_next(tag),
|
||||
&rid_, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &sibling, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendcompactrbyd(lfs, &sibling, split_rid, -1, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &sibling);
|
||||
@@ -4075,23 +4036,11 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
//
|
||||
// upper layers should make sure this can't fail by limiting the
|
||||
// maximum commit size
|
||||
split_rid_ = split_rid;
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
if (attrs[i].rid - (lfs_ssize_t)bid >= split_rid_) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &sibling,
|
||||
attrs[i].rid - bid - split_rid_,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to make sure we keep split_rid updated with
|
||||
// weight changes
|
||||
if (attrs[i].rid - (lfs_ssize_t)bid < split_rid_) {
|
||||
split_rid_ += attrs[i].delta;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &sibling, bid+split_rid, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// finalize commit
|
||||
@@ -4187,27 +4136,22 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
}
|
||||
|
||||
// merge the siblings together
|
||||
rid_ = 0;
|
||||
tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &rbyd,
|
||||
rid_, lfsr_tag_next(tag),
|
||||
&rid_, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, -1, -1, &rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendcompactrbyd(lfs, &rbyd_, -1, -1, &sibling);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// bring in name that previously split the siblings
|
||||
@@ -4218,63 +4162,31 @@ static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
|
||||
return err;
|
||||
}
|
||||
|
||||
lfs_size_t split_weight = 0;
|
||||
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
|
||||
// lookup the weight of the previously-split entry
|
||||
err = lfsr_rbyd_lookupnext(lfs, &sibling,
|
||||
0, LFSR_TAG_NAME,
|
||||
NULL, NULL, &split_weight, NULL);
|
||||
// lookup the rid (weight really) of the previously-split entry
|
||||
lfs_ssize_t split_rid;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &rbyd_,
|
||||
rbyd.weight, LFSR_TAG_NAME,
|
||||
&split_rid, NULL, NULL, NULL);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_,
|
||||
split_tag, split_weight, split_data);
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd_,
|
||||
split_rid, split_tag, 0, split_data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rid_ = split_weight-1;
|
||||
// TODO inclusive?
|
||||
tag = LFSR_TAG_STRUCT-1;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
err = lfsr_rbyd_lookupnext(lfs, &sibling,
|
||||
rid_, lfsr_tag_next(tag),
|
||||
&rid_, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_, tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &rbyd_);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// append any pending attrs, it's up to upper
|
||||
// layers to make sure these always fit
|
||||
for (lfs_size_t i = 0; i < attr_count; i++) {
|
||||
err = lfsr_rbyd_appendattr(lfs, &rbyd_, attrs[i].rid - bid,
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
err = lfsr_rbyd_appendattrs(lfs, &rbyd_, bid, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// finalize the commit
|
||||
@@ -4935,52 +4847,6 @@ static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) {
|
||||
}
|
||||
|
||||
|
||||
// low-level mdir attr handling, special attrs are handled here
|
||||
static int lfsr_mdir_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||
lfs_ssize_t rid, lfsr_tag_t tag, lfs_ssize_t delta,
|
||||
lfsr_data_t data) {
|
||||
// this is a bit of a hack, but ignore any gstate tags here,
|
||||
// these need to be handled specially by upper-layers
|
||||
if (lfsr_tag_suptype(tag) == LFSR_TAG_GSTATE) {
|
||||
// do nothing
|
||||
return 0;
|
||||
|
||||
// move tags copy over any tags associated with the source's rid
|
||||
} else if (lfsr_tag_suptype(tag) == LFSR_TAG_MOVE) {
|
||||
// weighted moves are not supported
|
||||
LFS_ASSERT(delta == 0);
|
||||
const lfsr_mdir_t *mdir = (const lfsr_mdir_t*)data.u.b.buffer;
|
||||
|
||||
// skip the name tag, this is always replaced by upper layers
|
||||
lfsr_tag_t tag = LFSR_TAG_STRUCT-1;
|
||||
while (true) {
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_mdir_lookupnext(lfs, mdir,
|
||||
mdir->mid, lfsr_tag_next(tag),
|
||||
&tag, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// append the attr
|
||||
err = lfsr_rbyd_appendattr(lfs, rbyd, rid, tag, 0, data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
// write out normal tags normally
|
||||
} else {
|
||||
LFS_ASSERT(!lfsr_tag_isinternal(tag));
|
||||
return lfsr_rbyd_appendattr(lfs, rbyd, rid, tag, delta, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int lfsr_mdir_alloc(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_ssize_t mid) {
|
||||
// assign the mid
|
||||
mdir->mid = mid;
|
||||
@@ -5083,8 +4949,9 @@ static int lfsr_mdir_swap(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
||||
|
||||
// low-level mdir commit, does not handle mtree/mlist/compaction/etc
|
||||
static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid, bool gstate,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid,
|
||||
const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||
// TODO do we need to copy here?
|
||||
// try to append a commit
|
||||
lfsr_mdir_t mdir_ = *mdir;
|
||||
// TODO handle this differently?
|
||||
@@ -5104,11 +4971,51 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
// treat end_rid=-1 as "unbounded" in such a way that rid=-1
|
||||
// is still included
|
||||
&& (lfs_size_t)(rid + 1) <= (lfs_size_t)end_rid) {
|
||||
int err = lfsr_mdir_appendattr(lfs, &mdir_.u.r.rbyd,
|
||||
rid - lfs_smax32(start_rid, 0),
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
return err;
|
||||
// this is a bit of a hack, but ignore any gstate tags here,
|
||||
// these need to be handled specially by upper-layers
|
||||
if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_GSTATE) {
|
||||
// do nothing
|
||||
|
||||
// move tags copy over any tags associated with the source's rid
|
||||
} else if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_MOVE) {
|
||||
// weighted moves are not supported
|
||||
LFS_ASSERT(attrs[i].delta == 0);
|
||||
const lfsr_mdir_t *mdir
|
||||
= (const lfsr_mdir_t*)attrs[i].data.u.b.buffer;
|
||||
|
||||
// skip the name tag, this is always replaced by upper layers
|
||||
lfsr_tag_t tag = LFSR_TAG_STRUCT-1;
|
||||
while (true) {
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_mdir_lookupnext(lfs, mdir,
|
||||
mdir->mid, lfsr_tag_next(tag),
|
||||
&tag, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// append the attr
|
||||
err = lfsr_rbyd_appendattr(lfs, &mdir_.u.r.rbyd,
|
||||
rid - lfs_smax32(start_rid, 0),
|
||||
tag, 0, data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// write out normal tags normally
|
||||
} else {
|
||||
LFS_ASSERT(!lfsr_tag_isinternal(attrs[i].tag));
|
||||
|
||||
int err = lfsr_rbyd_appendattr(lfs, &mdir_.u.r.rbyd,
|
||||
rid - lfs_smax32(start_rid, 0),
|
||||
attrs[i].tag, attrs[i].delta, attrs[i].data);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5138,7 +5045,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
lfs_cache_zero(lfs, &lfs->pcache);
|
||||
|
||||
} else {
|
||||
if (gstate) {
|
||||
if (start_rid == -1) {
|
||||
// only append gstate if we are not dropping
|
||||
int err = lfsr_rbyd_appendgdelta(lfs, &mdir_.u.r.rbyd);
|
||||
if (err) {
|
||||
@@ -5152,7 +5059,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (gstate) {
|
||||
if (start_rid == -1) {
|
||||
// success? gstate is committed
|
||||
lfsr_fs_flushgdelta(lfs);
|
||||
}
|
||||
@@ -5163,13 +5070,30 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid,
|
||||
const lfsr_mdir_t *mdir) {
|
||||
int err = lfsr_rbyd_appendcompactrbyd(lfs, &mdir_->u.r.rbyd,
|
||||
start_rid, end_rid, &mdir->u.r.rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &mdir_->u.r.rbyd);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// mid-level mdir commit, this one will at least compact on overflow
|
||||
static int lfsr_mdir_commit_(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
lfs_ssize_t start_rid, lfs_ssize_t end_rid,
|
||||
lfs_size_t *split_rid_,
|
||||
const lfsr_attr_t *attrs, lfs_size_t attr_count) {
|
||||
// try to commit
|
||||
int err = lfsr_mdir_commit__(lfs, mdir, start_rid, end_rid, true,
|
||||
int err = lfsr_mdir_commit__(lfs, mdir, start_rid, end_rid,
|
||||
attrs, attr_count);
|
||||
if (err && err != LFS_ERR_RANGE) {
|
||||
return err;
|
||||
@@ -5203,52 +5127,8 @@ compact:;
|
||||
return err;
|
||||
}
|
||||
|
||||
// consume any gstate on original rbyd, we need this even if we drop
|
||||
// our mdir to avoid losing info
|
||||
//
|
||||
// if succesful, this should get immediately appended to our new commit
|
||||
err = lfsr_fs_consumegdelta(lfs, mdir);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// copy over attrs
|
||||
lfs_ssize_t rid = start_rid;
|
||||
lfsr_tag_t tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookupnext(lfs, &mdir->u.r.rbyd,
|
||||
rid, lfsr_tag_next(tag),
|
||||
&rid, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
// note the use of rid+1 and unsigned comparison here to
|
||||
// treat end_rid=-1 as "unbounded" in such a way that rid=-1
|
||||
// is still included
|
||||
if (err == LFS_ERR_NOENT
|
||||
|| (lfs_size_t)(rid + 1) > (lfs_size_t)end_rid) {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO is this really the best way to do this?
|
||||
// this is a bit of a hack, but ignore any gstate tags here,
|
||||
// these need to be handled specially by upper-layers
|
||||
if (lfsr_tag_suptype(tag) == LFSR_TAG_GSTATE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &mdir_.u.r.rbyd,
|
||||
tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &mdir_.u.r.rbyd);
|
||||
// compact our rbyd
|
||||
err = lfsr_mdir_compact__(lfs, &mdir_, start_rid, end_rid, mdir);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
@@ -5259,14 +5139,6 @@ compact:;
|
||||
// upper layers should make sure this can't fail by limiting the
|
||||
// maximum commit size
|
||||
err = lfsr_mdir_commit__(lfs, &mdir_, start_rid, end_rid,
|
||||
// only append gstate if 1. we are not dropped, 2. we have not
|
||||
// been relocated/split/etc, unless we are an mroot
|
||||
//
|
||||
// this pushes gstate up into the mroot when relocating, and
|
||||
// helps avoid corner case issues when splitting/dropping
|
||||
(lfsr_mdir_cmp(&mdir_, mdir) == 0
|
||||
|| mdir_.mid == -1
|
||||
|| lfsr_mtree_isinlined(lfs)),
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
@@ -5374,38 +5246,13 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
return err;
|
||||
}
|
||||
|
||||
// copy over attrs
|
||||
lfs_ssize_t rid = 0;
|
||||
lfsr_tag_t tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookupnext(lfs, &mdir->u.r.rbyd,
|
||||
rid, lfsr_tag_next(tag),
|
||||
&rid, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT || rid >= (lfs_ssize_t)split_rid) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &mdir_.u.r.rbyd,
|
||||
tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &mdir_.u.r.rbyd);
|
||||
err = lfsr_mdir_compact__(lfs, &mdir_, 0, split_rid, mdir);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_mdir_commit__(lfs, &mdir_, 0, split_rid, false,
|
||||
err = lfsr_mdir_commit__(lfs, &mdir_, 0, split_rid,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
@@ -5419,38 +5266,13 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
return err;
|
||||
}
|
||||
|
||||
// copy over attrs
|
||||
rid = split_rid;
|
||||
tag = 0;
|
||||
while (true) {
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookupnext(lfs, &mdir->u.r.rbyd,
|
||||
rid, lfsr_tag_next(tag),
|
||||
&rid, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
// write the tag
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &msibling_.u.r.rbyd,
|
||||
tag, weight, data);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &msibling_.u.r.rbyd);
|
||||
err = lfsr_mdir_compact__(lfs, &msibling_, split_rid, -1, mdir);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_mdir_commit__(lfs, &msibling_, split_rid, -1, false,
|
||||
err = lfsr_mdir_commit__(lfs, &msibling_, split_rid, -1,
|
||||
attrs, attr_count);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
@@ -5773,18 +5595,19 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
}
|
||||
|
||||
// copy only the config over
|
||||
lfs_ssize_t rid = -1;
|
||||
lfsr_tag_t tag = 0;
|
||||
while (true) {
|
||||
lfs_ssize_t rid;
|
||||
lfs_size_t weight;
|
||||
lfsr_data_t data;
|
||||
int err = lfsr_rbyd_lookupnext(lfs, &mchildroot.u.r.rbyd,
|
||||
rid, lfsr_tag_next(tag),
|
||||
-1, lfsr_tag_next(tag),
|
||||
&rid, &tag, &weight, &data);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
if (err == LFS_ERR_NOENT || rid >= 0 || tag >= LFSR_TAG_GSTATE) {
|
||||
// TODO use suptype == CONFIG here?
|
||||
if (err == LFS_ERR_NOENT || rid != -1 || tag >= LFSR_TAG_GSTATE) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5797,23 +5620,16 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
|
||||
}
|
||||
}
|
||||
|
||||
// and our new mroot
|
||||
err = lfsr_rbyd_appendcompactattr(lfs, &mparentroot.u.r.rbyd,
|
||||
LFSR_TAG_MROOT, 0,
|
||||
LFSR_DATA_BUF(mchildroot_buf, mchildroot_dsize));
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfsr_rbyd_compact(lfs, &mparentroot.u.r.rbyd);
|
||||
if (err) {
|
||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||
return err;
|
||||
}
|
||||
|
||||
// finalize commit
|
||||
err = lfsr_rbyd_appendcksum(lfs, &mparentroot.u.r.rbyd);
|
||||
// and commit our new mroot
|
||||
err = lfsr_mdir_commit__(lfs, &mparentroot, -1, -1, LFSR_ATTRS(
|
||||
LFSR_ATTR(-1,
|
||||
WIDE(MROOT), 0, BUF(mchildroot_buf, mchildroot_dsize))));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user