Merged sprout and shrub carving paths

Noticed a lot of duplicate conditions, so tried merging these two code
paths. This does risk a difficult to read/maintain function, since there
are some rather tricky subtleties with the sprout -> shrub transition.
On the other hand, the code reuse does mean less conditions to worry
about.

Merging these code paths also saves a bit of code:

           code          stack
  before: 30960           2256
  after:  30700 (-0.8%)   2256 (+0.0%)
This commit is contained in:
Christopher Haster
2023-10-09 20:15:09 -05:00
parent addaa8fe3e
commit 92e1fafbc4
+139 -205
View File
@@ -9209,110 +9209,28 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
lfsr_data_t *datas_ = scratch_datas;
*datas_++ = data;
// TODO what happens if another driver wrote a zero-weight shrub? need
// to test this...
// keep track of how our changes affect our estimate
lfs_off_t estimate;
lfs_off_t estimate = (!lfsr_file_hasshrub(file))
? 0
: file->inlined.u.shrub.estimate;
// have a sprout/null?
// TODO should we catch when we can stay inlined?
if (!lfsr_file_hasshrub(file)) {
estimate = 0;
lfs_soff_t left_overlap = 0;
lfs_soff_t right_overlap = 0;
// left data? this may create a hole
if (pos > 0) {
// can coalesce?
if (lfsr_data_size(&file->inlined.u.data) >= pos
&& pos+weight+delta <= lfs->cfg->coalesce_size) {
scratch_datas[0] = LFSR_DATA_DISK(
file->inlined.u.data.u.disk.block,
file->inlined.u.data.u.disk.off,
pos);
scratch_datas[1] = data;
datas_ = &scratch_datas[2];
data = lfsr_data_fromcat(&scratch_datas[0], 2);
weight += pos;
pos = 0;
// need to carve
} else {
*attrs_++ = LFSR_ATTR(0,
SHRUB(INLINED), +pos, DISK(
file->inlined.u.data.u.disk.block,
file->inlined.u.data.u.disk.off,
lfs_min32(
lfsr_data_size(&file->inlined.u.data),
pos)));
estimate += LFSR_ATTR_ESTIMATE
+ lfs_min32(
lfsr_data_size(&file->inlined.u.data),
pos);
}
}
// right data? this may also create a hole if delta > 0
if (lfsr_data_size(&file->inlined.u.data) > pos + weight) {
// can coalesce?
if (lfsr_data_size(&data) == weight + delta
&& lfsr_data_size(&data)
+ lfsr_data_size(&file->inlined.u.data)
- (pos + weight)
<= lfs->cfg->coalesce_size) {
*datas_++ = LFSR_DATA_DISK(
file->inlined.u.data.u.disk.block,
file->inlined.u.data.u.disk.off
+ (pos + weight),
lfsr_data_size(&file->inlined.u.data)
- (pos + weight));
data = lfsr_data_fromcat(
scratch_datas,
datas_ - scratch_datas);
weight += lfsr_data_size(&file->inlined.u.data)
- (pos + weight);
// need to carve
} else {
*attrs_++ = LFSR_ATTR(pos,
SHRUB(INLINED), +lfsr_data_size(&file->inlined.u.data)
- (pos + weight),
DISK(
file->inlined.u.data.u.disk.block,
file->inlined.u.data.u.disk.off
+ (pos + weight),
lfsr_data_size(&file->inlined.u.data)
- (pos + weight)));
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&file->inlined.u.data)
- (pos + weight);
}
}
// append our data
if (weight + delta > 0) {
*attrs_++ = LFSR_ATTR(pos,
SHRUB(INLINED), +weight + delta, DATA(data));
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&data);
}
// have a shrub?
} else {
// TODO what if another driver wrote a zero-weight shrub? need to
// test this
//
// this should never happen, every route to zero-weight shrub
// should revert to an inlined file
LFS_ASSERT(file->inlined.u.rbyd.weight > 0);
estimate = file->inlined.u.shrub.estimate;
lfs_soff_t left_overlap = 0;
lfs_soff_t right_overlap = 0;
// has left sibling?
if (pos > 0) {
lfsr_srid_t left_rid;
// has left sibling?
if (pos > 0) {
lfsr_srid_t left_rid;
lfsr_rid_t left_weight;
lfsr_data_t left_data;
if (!lfsr_file_hasshrub(file)) {
left_rid = lfsr_data_size(&file->inlined.u.data)-1;
left_weight = lfsr_data_size(&file->inlined.u.data);
left_data = file->inlined.u.data;
} else {
lfsr_tag_t left_tag;
lfsr_rid_t left_weight;
lfsr_data_t left_data;
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
lfs_min32(
pos,
@@ -9324,55 +9242,73 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
}
LFS_ASSERT(left_tag == LFSR_TAG_SHRUB(INLINED));
LFS_ASSERT(lfsr_data_size(&left_data) <= left_weight);
// this can be negative!
left_overlap = (left_rid+1) - pos;
LFS_ASSERT(left_overlap >= 0
|| (lfs_off_t)file->inlined.u.rbyd.weight < pos);
// can we coalesce left data?
if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
>= pos
&& pos+weight+delta - (left_rid-(left_weight-1))
<= lfs->cfg->coalesce_size) {
scratch_datas[0] = LFSR_DATA_DISK(
left_data.u.disk.block,
left_data.u.disk.off,
left_weight - left_overlap);
scratch_datas[1] = data;
datas_ = &scratch_datas[2];
data = lfsr_data_fromcat(&scratch_datas[0], 2);
weight += left_weight - left_overlap;
pos = left_rid-(left_weight-1);
left_overlap = 0;
// need to carve out left data?
} else if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
> pos) {
*attrs_++ = LFSR_ATTR(left_rid,
SHRUB(GROW(INLINED)), -left_overlap,
DISK(
left_data.u.disk.block,
left_data.u.disk.off,
left_weight - left_overlap));
estimate -= left_rid-(left_weight-1)
+ lfsr_data_size(&left_data)
- pos;
// adjust left sibling with a grow attr, this may create a hole
} else if (left_overlap != 0) {
*attrs_++ = LFSR_ATTR(left_rid,
SHRUB(GROW), -left_overlap, NULL);
}
}
// has right sibling?
if (pos + weight < (lfs_off_t)file->inlined.u.rbyd.weight) {
lfsr_srid_t right_rid;
// this can be negative!
left_overlap = (left_rid+1) - pos;
LFS_ASSERT(left_overlap >= 0
|| lfsr_file_inlinedsize(file) < pos);
// can we coalesce left data?
if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
>= pos
&& pos+weight+delta - (left_rid-(left_weight-1))
<= lfs->cfg->coalesce_size) {
scratch_datas[0] = LFSR_DATA_DISK(
left_data.u.disk.block,
left_data.u.disk.off,
left_weight - left_overlap);
scratch_datas[1] = data;
datas_ = &scratch_datas[2];
data = lfsr_data_fromcat(&scratch_datas[0], 2);
weight += left_weight - left_overlap;
pos = left_rid-(left_weight-1);
left_overlap = 0;
// need to append left data? this can happend if we're
// transitioning from a sprout to a shrub
} else if (!lfsr_file_hasshrub(file)) {
*attrs_++ = LFSR_ATTR(left_rid-(left_weight-1),
SHRUB(INLINED), +left_weight - left_overlap, DISK(
left_data.u.disk.block,
left_data.u.disk.off,
left_weight - lfs_smax32(left_overlap, 0)));
estimate += LFSR_ATTR_ESTIMATE
+ (left_weight - lfs_smax32(left_overlap, 0));
// need to carve out left data?
} else if (left_rid-(left_weight-1) + lfsr_data_size(&left_data)
> pos) {
*attrs_++ = LFSR_ATTR(left_rid,
SHRUB(GROW(INLINED)), -left_overlap,
DISK(
left_data.u.disk.block,
left_data.u.disk.off,
left_weight - left_overlap));
estimate -= left_rid-(left_weight-1)
+ lfsr_data_size(&left_data)
- pos;
// adjust left sibling with a grow attr, avoiding a data copy
} else if (left_overlap != 0) {
*attrs_++ = LFSR_ATTR(left_rid,
SHRUB(GROW), -left_overlap, NULL);
}
}
// has right sibling?
if (pos + weight < lfsr_file_inlinedsize(file)) {
lfsr_srid_t right_rid;
lfsr_rid_t right_weight;
lfsr_data_t right_data;
if (!lfsr_file_hasshrub(file)) {
right_rid = lfsr_data_size(&file->inlined.u.data)-1;
right_weight = lfsr_data_size(&file->inlined.u.data);
right_data = file->inlined.u.data;
} else {
lfsr_tag_t right_tag;
lfsr_rid_t right_weight;
lfsr_data_t right_data;
int err = lfsr_rbyd_lookupnext(lfs, &file->inlined.u.rbyd,
pos + weight, 0,
&right_rid, &right_tag, &right_weight, &right_data);
@@ -9382,72 +9318,70 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
}
LFS_ASSERT(right_tag == LFSR_TAG_SHRUB(INLINED));
LFS_ASSERT(lfsr_data_size(&right_data) <= right_weight);
}
right_overlap = pos + weight
- (right_rid-(right_weight-1));
LFS_ASSERT(right_overlap >= 0);
right_overlap = pos + weight
- (right_rid-(right_weight-1));
LFS_ASSERT(right_overlap >= 0);
// can we coalesce right data?
if ((lfsr_data_size(&data) == weight + delta
|| lfsr_data_size(&right_data) - right_overlap == 0)
&& (lfs_soff_t)(lfsr_data_size(&data)
+ lfsr_data_size(&right_data)
- right_overlap)
<= (lfs_soff_t)lfs->cfg->coalesce_size) {
*datas_++ = LFSR_DATA_DISK(
// can we coalesce right data?
if ((lfsr_data_size(&data) == weight + delta
|| lfsr_data_size(&right_data) - right_overlap == 0)
&& (lfs_soff_t)(lfsr_data_size(&data)
+ lfsr_data_size(&right_data)
- right_overlap)
<= (lfs_soff_t)lfs->cfg->coalesce_size) {
*datas_++ = LFSR_DATA_DISK(
right_data.u.disk.block,
right_data.u.disk.off + right_overlap,
lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data)));
data = lfsr_data_fromcat(
scratch_datas,
datas_ - scratch_datas);
weight += right_weight - right_overlap;
right_overlap = 0;
// need to append right data? this can happen if we're
// transitioning from sprout to shrub, or left and right sibling
// are the same
} else if (!lfsr_file_hasshrub(file)
|| right_overlap > (lfs_soff_t)weight) {
*attrs_++ = LFSR_ATTR(pos - left_overlap,
SHRUB(INLINED), +right_weight - right_overlap,
DISK(
right_data.u.disk.block,
right_data.u.disk.off + right_overlap,
lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data)));
data = lfsr_data_fromcat(
scratch_datas,
datas_ - scratch_datas);
weight += right_weight - right_overlap;
right_overlap = 0;
lfsr_data_size(&right_data))));
// is right sibling the same as left sibling? need to
// split right data and handle this a bit differently
} else if (right_overlap > (lfs_soff_t)weight) {
*attrs_++ = LFSR_ATTR(right_rid+1 - left_overlap,
SHRUB(INLINED), +right_weight - right_overlap,
DISK(
right_data.u.disk.block,
right_data.u.disk.off + right_overlap,
lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data))));
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data));
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&right_data) - lfs_min32(
// need to carve out right data?
} else if (right_overlap > 0) {
*attrs_++ = LFSR_ATTR(right_rid - left_overlap,
SHRUB(GROW(INLINED)), -right_overlap,
DISK(
right_data.u.disk.block,
right_data.u.disk.off + right_overlap,
lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data));
lfsr_data_size(&right_data))));
// need to carve out right data?
} else if (right_overlap > 0) {
*attrs_++ = LFSR_ATTR(right_rid - left_overlap,
SHRUB(GROW(INLINED)), -right_overlap,
DISK(
right_data.u.disk.block,
right_data.u.disk.off + right_overlap,
lfsr_data_size(&right_data) - lfs_min32(
right_overlap,
lfsr_data_size(&right_data))));
estimate -= right_overlap;
}
estimate -= right_overlap;
}
}
// remove any data we're overwriting, accounting for sibling changes
// lfs_soff_t rm = lfs_smin32(
// weight - left_overlap - right_overlap,
// file->inlined.u.rbyd.weight
// - lfs_min32(
// pos + left_overlap,
// file->inlined.u.rbyd.weight));
// remove any data we're overwriting, accounting for sibling changes
if (lfsr_file_hasshrub(file)) {
lfs_soff_t rm = lfs_smin32(
weight,
file->inlined.u.rbyd.weight - pos)
lfsr_file_inlinedsize(file) - pos)
- left_overlap
- right_overlap;
if (rm > 0) {
@@ -9464,15 +9398,15 @@ static int lfsr_file_carveinlined(lfs_t *lfs, lfsr_file_t *file,
}
estimate -= rm_estimate;
}
}
// append our buffer
if (weight + delta > 0) {
*attrs_++ = LFSR_ATTR(pos,
SHRUB(INLINED), +weight + delta, DATA(data));
// append our buffer
if (weight + delta > 0) {
*attrs_++ = LFSR_ATTR(pos,
SHRUB(INLINED), +weight + delta, DATA(data));
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&data);
}
estimate += LFSR_ATTR_ESTIMATE
+ lfsr_data_size(&data);
}
// TODO can this happen? should we even have special handling here?