Adopted lfsr_data_t in low-level rbyd functions

The low-level rbyd functions need to parse things (mostly tags), so why
not use our parsers? In theory this offers a bit more code reuse.

In theory we can also rely on lfsr_data_t to do bounds checking of
offsets in the block, in practice we need to setup those bounds
correctly for lfsr_data_t, so not so much...

Code/stack cost:

            code          stack
  before:  21702           1992
  after:   21626 (-0.4%)   2024 (+1.6%)
This commit is contained in:
Christopher Haster
2023-08-09 19:16:29 -05:00
parent 1d39c5dd68
commit 7614cf29c1
+162 -169
View File
@@ -908,116 +908,6 @@ static inline void lfsr_tag_trim2(
lower_tag, upper_tag);
}
// support for encoding/decoding tags on disk
// each piece of metadata in an rbyd tree is prefixed with a 4-piece tag:
//
// - 8-bit suptype => 1 byte
// - 8-bit subtype => 1 byte
// - 32-bit rid/weight => 5 byte leb128 (worst case)
// - 32-bit size/jump => 5 byte leb128 (worst case)
// => 12 bytes total
//
#define LFSR_TAG_DSIZE (2+5+5)
static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off, lfs_size_t hint,
lfsr_tag_t *tag_, lfs_size_t *weight_, lfs_size_t *size_,
uint32_t *cksum_) {
// read the largest possible tag size
uint8_t tag_buf[LFSR_TAG_DSIZE];
lfs_size_t tag_dsize = lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-off);
int err = lfsr_bd_read(lfs, block, off, hint, &tag_buf, tag_dsize);
if (err) {
return err;
}
if (tag_dsize < 2) {
return LFS_ERR_CORRUPT;
}
uint16_t tag
= ((lfsr_tag_t)tag_buf[0] << 8)
| ((lfsr_tag_t)tag_buf[1] << 0);
ssize_t d = 2;
if (cksum_) {
// on-disk, the tags valid bit must reflect the parity of the
// preceding data, fortunately for crc32c, this is the same as the
// parity of the crc
//
// note we need to do this before leb128 decoding as we may not have
// valid leb128 if we're erased, but we shouldn't treat a truncated
// leb128 here as corruption
if ((tag >> 15) != (lfs_popc(*cksum_) & 1)) {
return LFS_ERR_INVAL;
}
}
lfs_ssize_t weight;
lfs_ssize_t d_ = lfs_fromleb128(&weight, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
lfs_ssize_t size;
d_ = lfs_fromleb128(&size, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
// optional checksum
if (cksum_) {
*cksum_ = lfs_crc32c(*cksum_, tag_buf, d);
}
// save what we found, clearing the valid bit from the tag, note we
// checked this earlier
*tag_ = tag & 0x7fff;
*weight_ = weight;
*size_ = size;
return d;
}
static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off,
lfsr_tag_t tag, lfs_size_t weight, lfs_size_t size,
uint32_t *cksum_) {
// check for underflow issues
LFS_ASSERT(weight < 0x80000000);
LFS_ASSERT(size < 0x80000000);
// make sure to include the parity of the current crc
tag |= (lfs_popc(*cksum_) & 1) << 15;
// encode into a be16 and pair of leb128s
uint8_t tag_buf[LFSR_TAG_DSIZE];
tag_buf[0] = (uint8_t)(tag >> 8);
tag_buf[1] = (uint8_t)(tag >> 0);
lfs_size_t d = 2;
ssize_t d_ = lfs_toleb128(weight, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfs_toleb128(size, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
int err = lfsr_bd_prog(lfs, block, off, &tag_buf, d, cksum_);
if (err) {
return err;
}
return d;
}
/// lfsr_data_t stuff ///
@@ -1310,6 +1200,121 @@ static int lfsr_bd_progdata(lfs_t *lfs,
}
// support for encoding/decoding tags on disk
// each piece of metadata in an rbyd tree is prefixed with a 4-piece tag:
//
// - 8-bit suptype => 1 byte
// - 8-bit subtype => 1 byte
// - 32-bit rid/weight => 5 byte leb128 (worst case)
// - 32-bit size/jump => 5 byte leb128 (worst case)
// => 12 bytes total
//
#define LFSR_TAG_DSIZE (2+5+5)
static int lfsr_data_readtag(lfs_t *lfs, lfsr_data_t *data,
lfsr_tag_t *tag_, lfs_size_t *weight_, lfs_size_t *size_,
uint32_t *cksum_) {
// note we make sure not to update our data offset until after decoding
lfsr_data_t data_ = *data;
// read the largest possible tag size
uint8_t tag_buf[LFSR_TAG_DSIZE];
lfs_ssize_t tag_dsize = lfsr_data_read(lfs, &data_,
tag_buf, LFSR_TAG_DSIZE);
if (tag_dsize < 0) {
return tag_dsize;
}
if (tag_dsize < 2) {
return LFS_ERR_CORRUPT;
}
uint16_t tag
= ((lfsr_tag_t)tag_buf[0] << 8)
| ((lfsr_tag_t)tag_buf[1] << 0);
ssize_t d = 2;
if (cksum_) {
// on-disk, the tags valid bit must reflect the parity of the
// preceding data, fortunately for crc32c, this is the same as the
// parity of the crc
//
// note we need to do this before leb128 decoding as we may not have
// valid leb128 if we're erased, but we shouldn't treat a truncated
// leb128 here as corruption
if ((tag >> 15) != (lfs_popc(*cksum_) & 1)) {
return LFS_ERR_INVAL;
}
}
lfs_ssize_t weight;
lfs_ssize_t d_ = lfs_fromleb128(&weight, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
lfs_ssize_t size;
d_ = lfs_fromleb128(&size, &tag_buf[d], tag_dsize-d);
if (d_ < 0) {
return d_;
}
d += d_;
// optional checksum
if (cksum_) {
*cksum_ = lfs_crc32c(*cksum_, tag_buf, d);
}
// save what we found, clearing the valid bit from the tag, note we
// checked this earlier
lfsr_data_add(data, d);
*tag_ = tag & 0x7fff;
*weight_ = weight;
*size_ = size;
return 0;
}
static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
lfs_block_t block, lfs_off_t off,
lfsr_tag_t tag, lfs_size_t weight, lfs_size_t size,
uint32_t *cksum_) {
// check for underflow issues
LFS_ASSERT(weight < 0x80000000);
LFS_ASSERT(size < 0x80000000);
// make sure to include the parity of the current crc
tag |= (lfs_popc(*cksum_) & 1) << 15;
// encode into a be16 and pair of leb128s
uint8_t tag_buf[LFSR_TAG_DSIZE];
tag_buf[0] = (uint8_t)(tag >> 8);
tag_buf[1] = (uint8_t)(tag >> 0);
lfs_size_t d = 2;
ssize_t d_ = lfs_toleb128(weight, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfs_toleb128(size, &tag_buf[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
int err = lfsr_bd_prog(lfs, block, off, &tag_buf, d, cksum_);
if (err) {
return err;
}
return d;
}
// operations on attribute lists
//struct lfs_mattr {
@@ -1833,7 +1838,8 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->trunk = 0;
// temporary state until we validate a cksum
lfs_off_t off = sizeof(uint32_t);
lfsr_data_t data = LFSR_DATA_DISK(block, sizeof(uint32_t),
lfs->cfg->block_size - sizeof(uint32_t));
lfs_off_t trunk_ = 0;
bool wastrunk = false;
lfs_size_t weight = 0;
@@ -1845,31 +1851,32 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
bool maybeerased = false;
// scan tags, checking valid bits, cksums, etc
while (off < lfs->cfg->block_size && (!trunk || rbyd->eoff <= trunk)) {
while (lfsr_data_size(&data) > 0 && (!trunk || rbyd->eoff <= trunk)) {
lfsr_tag_t tag;
lfs_size_t weight__;
lfs_size_t size;
lfs_ssize_t d = lfsr_bd_readtag(lfs,
block, off, lfs->cfg->block_size,
lfsr_data_t data_ = data;
err = lfsr_data_readtag(lfs, &data_,
&tag, &weight__, &size, &cksum);
if (d < 0) {
if (d == LFS_ERR_INVAL || d == LFS_ERR_CORRUPT) {
maybeerased = maybeerased && d == LFS_ERR_INVAL;
if (err) {
if (err == LFS_ERR_INVAL || err == LFS_ERR_CORRUPT) {
maybeerased = maybeerased && err == LFS_ERR_INVAL;
break;
}
return d;
return err;
}
off += d;
// tag goes out of range?
if (!lfsr_tag_isalt(tag) && off + size > lfs->cfg->block_size) {
if (!lfsr_tag_isalt(tag)
&& data_.u.d.off + size > lfs->cfg->block_size) {
break;
}
// not an end-of-commit cksum
if (!lfsr_tag_isalt(tag) && lfsr_tag_suptype(tag) != LFSR_TAG_CKSUM) {
// cksum the entry, hopefully leaving it in the cache
err = lfsr_bd_cksum(lfs, block, off, lfs->cfg->block_size, size,
err = lfsr_bd_cksum(lfs,
block, data_.u.d.off, lfs->cfg->block_size, size,
&cksum);
if (err) {
if (err == LFS_ERR_CORRUPT) {
@@ -1880,21 +1887,8 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found an ecksum? save for later
if (tag == LFSR_TAG_ECKSUM) {
// TODO should we use LFSR_DATA_DISK here? hint issues?
uint8_t ecksum_buf[LFSR_ECKSUM_DSIZE];
err = lfsr_bd_read(lfs, block, off, lfs->cfg->block_size,
ecksum_buf, lfs_min32(size, LFSR_ECKSUM_DSIZE));
if (err) {
if (err == LFS_ERR_CORRUPT) {
break;
}
return err;
}
err = lfsr_data_readecksum(lfs,
&LFSR_DATA(ecksum_buf,
lfs_min32(size, LFSR_ECKSUM_DSIZE)),
&ecksum);
lfsr_data_t ecksum_data = data_;
err = lfsr_data_readecksum(lfs, &ecksum_data, &ecksum);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
@@ -1907,15 +1901,14 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// is an end-of-commit cksum
} else if (!lfsr_tag_isalt(tag)) {
uint32_t cksum_ = 0;
err = lfsr_bd_read(lfs, block, off, lfs->cfg->block_size,
&cksum_, sizeof(uint32_t));
lfsr_data_t cksum_data = data_;
err = lfsr_data_readle32(lfs, &cksum_data, &cksum_);
if (err) {
if (err == LFS_ERR_CORRUPT) {
break;
}
return err;
}
cksum_ = lfs_fromle32_(&cksum_);
if (cksum != cksum_) {
// uh oh, cksums don't match
@@ -1933,7 +1926,7 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
hasecksum = false;
// save what we've found so far
rbyd->eoff = off + size;
rbyd->eoff = data_.u.d.off + size;
rbyd->cksum = cksum;
rbyd->trunk = trunk_;
rbyd->weight = weight;
@@ -1941,12 +1934,12 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// found a trunk of a tree?
if (lfsr_tag_istrunk(tag)
&& (!trunk || trunk >= off-d || wastrunk)) {
&& (!trunk || trunk >= data.u.d.off || wastrunk)) {
// start of trunk?
if (!wastrunk) {
wastrunk = true;
// save trunk entry point
trunk_ = off-d;
trunk_ = data.u.d.off;
// reset weight
weight_ = 0;
}
@@ -1967,9 +1960,12 @@ static int lfsr_rbyd_fetch(lfs_t *lfs, lfsr_rbyd_t *rbyd,
}
}
// skip data
if (!lfsr_tag_isalt(tag)) {
off += size;
lfsr_data_add(&data_, size);
}
data = data_;
}
// no valid commits?
@@ -2029,11 +2025,12 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
lfsr_tag_t alt;
lfs_size_t weight;
lfs_off_t jump;
lfs_ssize_t d = lfsr_bd_readtag(lfs,
rbyd->block, branch, 0,
lfsr_data_t data = LFSR_DATA_DISK(rbyd->block, branch,
lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-branch));
int err = lfsr_data_readtag(lfs, &data,
&alt, &weight, &jump, NULL);
if (d < 0) {
return d;
if (err) {
return err;
}
// found an alt?
@@ -2044,7 +2041,7 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
branch = branch - jump;
} else {
lfsr_tag_trim(alt, weight, &lower, &upper, NULL, NULL);
branch = branch + d;
branch = data.u.d.off;
}
// found end of tree?
@@ -2073,7 +2070,7 @@ static int lfsr_rbyd_lookupnext(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
*weight_ = rid__ - lower;
}
if (data_) {
*data_ = LFSR_DATA_DISK(rbyd->block, branch + d, jump);
*data_ = LFSR_DATA_DISK(rbyd->block, data.u.d.off, jump);
}
return 0;
}
@@ -2393,11 +2390,11 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfsr_tag_t alt;
lfs_size_t weight;
lfs_off_t jump;
lfs_ssize_t d = lfsr_bd_readtag(lfs,
rbyd->block, branch, 0,
lfsr_data_t data = LFSR_DATA_DISK(rbyd->block, branch,
lfs_min32(LFSR_TAG_DSIZE, lfs->cfg->block_size-branch));
err = lfsr_data_readtag(lfs, &data,
&alt, &weight, &jump, NULL);
if (d < 0) {
err = d;
if (err) {
goto failed;
}
@@ -2405,7 +2402,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
if (lfsr_tag_isalt(alt)) {
// make jump absolute
jump = branch - jump;
lfs_off_t branch_ = branch + d;
lfs_off_t branch_ = data.u.d.off;
// do bounds want to take different paths? begin cutting
if (!lfsr_tag_hasdiverged(tag_)
@@ -2907,7 +2904,7 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_size_t layer_weight = 0;
// first copy over raw tags, note this doesn't create a tree
lfs_off_t layer_start = rbyd->eoff;
lfs_off_t layer_off = rbyd->eoff;
lfs_ssize_t rid = start_rid;
lfsr_tag_t tag = 0;
while (true) {
@@ -2951,7 +2948,6 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
layer_trunks += 1;
layer_weight += weight;
}
lfs_off_t layer_end = rbyd->eoff;
// connect every other trunk together, building layers of a perfectly
// balanced binary tree upwards until we have a single trunk
@@ -2960,30 +2956,28 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
layer_trunks = 0;
layer_weight = 0;
lfs_off_t off = layer_start;
layer_start = rbyd->eoff;
while (off < layer_end) {
lfsr_data_t data = LFSR_DATA_DISK(rbyd->block,
layer_off, rbyd->eoff - layer_off);
layer_off = rbyd->eoff;
while (lfsr_data_size(&data) > 0) {
// connect two trunks together with a new binary trunk
for (int i = 0; i < 2 && off < layer_end; i++) {
lfs_off_t trunk_off = off;
for (int i = 0; i < 2 && lfsr_data_size(&data) > 0; i++) {
lfs_off_t trunk_off = data.u.d.off;
lfsr_tag_t trunk_tag = 0;
lfs_size_t trunk_weight = 0;
while (true) {
lfsr_tag_t tag;
lfs_size_t weight;
lfs_size_t size;
lfs_ssize_t d = lfsr_bd_readtag(lfs, rbyd->block, off,
layer_end-off,
err = lfsr_data_readtag(lfs, &data,
&tag, &weight, &size, NULL);
if (d < 0) {
err = d;
if (err) {
goto failed;
}
off += d;
// skip any data
if (!lfsr_tag_isalt(tag)) {
off += size;
lfsr_data_add(&data, size);
}
// keep track of trunk/layer weight, and the last non-null
@@ -3028,14 +3022,13 @@ static int lfsr_rbyd_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// keep track of the number of trunks
layer_trunks += 1;
}
layer_end = rbyd->eoff;
}
// done! just need to update our trunk/weight, note we could have
// no trunks after compaction. Leave this to upper layers to take
// care of
if (layer_trunks >= 1) {
rbyd->trunk = layer_start;
rbyd->trunk = layer_off;
}
rbyd->weight = layer_weight;