Flipped btree encoding to allow variable redund blocks

This should have been done as a part of the earlier tag reencoding work,
since having the block at the end was what allowed us to move the
redund-count out of the tag encoding.

New encoding:

  [-- 32-bit csum   --]
  [-- leb128 weight --]
  [-- leb128 trunk  --]
  [-- leb128 block  --]

Note that since our tags have an explicit size, we can store a variable
number of blocks. The plan is to use this to eventually store redundant
copies for error correction:

  [-- 32-bit csum   --]
  [-- leb128 weight --]
  [-- leb128 trunk  --]
  [-- leb128 block  --] -.
  [-- leb128 block  --]  +- n redundant blocks
  [-- leb128 block  --]  |
           ...          -'

This does have a significant tradeoff, we need to know the checksum size
to access the btree structure. This doesn't seem like a big deal, but
with the possibility of different checksum types may be an annoying
issue.

Note that FCRC was also flipped for consistency.
This commit is contained in:
Christopher Haster
2023-06-19 13:17:52 -05:00
parent a5e7ff7be0
commit 799e7cfc81
3 changed files with 30 additions and 28 deletions

42
lfs.c
View File

@@ -1338,8 +1338,8 @@ typedef struct lfsr_attr {
// fcrc on-disk encoding
typedef struct lfsr_fcrc {
lfs_size_t size;
uint32_t crc;
lfs_size_t size;
} lfsr_fcrc_t;
// 1 leb128 + 1 crc32c => 9 bytes (worst case)
@@ -1349,28 +1349,29 @@ static lfs_ssize_t lfsr_fcrc_todisk(lfs_t *lfs, const lfsr_fcrc_t *fcrc,
uint8_t buffer[static LFSR_FCRC_DSIZE]) {
(void)lfs;
lfs_ssize_t d = 0;
lfs_ssize_t d_ = lfs_toleb128(fcrc->size, &buffer[0], 5);
lfs_tole32_(fcrc->crc, &buffer[d]);
d += 4;
lfs_ssize_t d_ = lfs_toleb128(fcrc->size, &buffer[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
lfs_tole32_(fcrc->crc, &buffer[d]);
d += 4;
return d;
}
static lfs_ssize_t lfsr_fcrc_fromdisk(lfs_t *lfs, lfsr_fcrc_t *fcrc,
lfsr_data_t data) {
lfs_ssize_t d = 0;
lfs_ssize_t d_ = lfsr_data_readleb128(lfs, data, d, &fcrc->size);
lfs_ssize_t d_ = lfsr_data_readle32(lfs, data, d, &fcrc->crc);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfsr_data_readle32(lfs, data, d, &fcrc->crc);
d_ = lfsr_data_readleb128(lfs, data, d, &fcrc->size);
if (d_ < 0) {
return d_;
}
@@ -2650,7 +2651,7 @@ static int lfsr_rbyd_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// find the expected fcrc, don't bother avoiding a reread of the
// perturb byte, as it should still be in our cache
lfsr_fcrc_t fcrc = {.size=lfs->cfg->prog_size, .crc=0};
lfsr_fcrc_t fcrc = {.crc=0, .size=lfs->cfg->prog_size};
err = lfsr_bd_csum(lfs, rbyd_.block, aligned, lfs->cfg->prog_size,
lfs->cfg->prog_size,
&fcrc.crc);
@@ -3042,13 +3043,17 @@ static inline lfs_size_t lfsr_btree_setinlined(lfs_size_t weight) {
// branch on-disk encoding
// 3 leb128 + 1 crc32c => 19 bytes (worst case)
#define LFSR_BRANCH_DSIZE (5+5+5+4)
// 1 crc32c + 3 leb128 => 19 bytes (worst case)
#define LFSR_BRANCH_DSIZE (4+5+5+5)
static lfs_ssize_t lfsr_branch_todisk(lfs_t *lfs, const lfsr_rbyd_t *branch,
uint8_t buffer[static LFSR_BRANCH_DSIZE]) {
(void)lfs;
lfs_ssize_t d = 0;
lfs_tole32_(branch->crc, &buffer[d]);
d += 4;
lfs_ssize_t d_ = lfs_toleb128(branch->weight, &buffer[d], 5);
if (d_ < 0) {
return d_;
@@ -3067,9 +3072,6 @@ static lfs_ssize_t lfsr_branch_todisk(lfs_t *lfs, const lfsr_rbyd_t *branch,
}
d += d_;
lfs_tole32_(branch->crc, &buffer[d]);
d += 4;
return d;
}
@@ -3080,7 +3082,13 @@ static lfs_ssize_t lfsr_branch_fromdisk(lfs_t *lfs, lfsr_rbyd_t *branch,
branch->off = 0;
lfs_ssize_t d = 0;
lfs_ssize_t d_ = lfsr_data_readleb128(lfs, data, d, &branch->weight);
lfs_ssize_t d_ = lfsr_data_readle32(lfs, data, d, &branch->crc);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfsr_data_readleb128(lfs, data, d, &branch->weight);
if (d_ < 0) {
return d_;
}
@@ -3098,12 +3106,6 @@ static lfs_ssize_t lfsr_branch_fromdisk(lfs_t *lfs, lfsr_rbyd_t *branch,
}
d += d_;
d_ = lfsr_data_readle32(lfs, data, d, &branch->crc);
if (d_ < 0) {
return d_;
}
d += d_;
return d;
}

View File

@@ -93,10 +93,10 @@ def fromtag(data):
return tag>>15, tag&0x7fff, weight, size, 2+d+d_
def frombtree(data):
w, d1 = fromleb128(data)
trunk, d2 = fromleb128(data[d1:])
block, d3 = fromleb128(data[d1+d2:])
crc = fromle32(data[d1+d2+d3:])
crc = fromle32(data)
w, d1 = fromleb128(data[4:])
trunk, d2 = fromleb128(data[4+d1:])
block, d3 = fromleb128(data[4+d1+d2:])
return w, trunk, block, crc
def popc(x):

View File

@@ -102,10 +102,10 @@ def frommdir(data):
return blocks
def frombtree(data):
w, d1 = fromleb128(data)
trunk, d2 = fromleb128(data[d1:])
block, d3 = fromleb128(data[d1+d2:])
crc = fromle32(data[d1+d2+d3:])
crc = fromle32(data)
w, d1 = fromleb128(data[4:])
trunk, d2 = fromleb128(data[4+d1:])
block, d3 = fromleb128(data[4+d1+d2:])
return w, trunk, block, crc
def popc(x):