Different rbyd struct usage in commit, moved append into its own function
Under any optimization level the compiler should inline lfs_rbyd_append into lfs_rbyd_commit, but this code organization was desperately needed.
This commit is contained in:
@@ -969,6 +969,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
|||||||
|
|
||||||
/// Red-black-yellow Dhara tree operations ///
|
/// Red-black-yellow Dhara tree operations ///
|
||||||
|
|
||||||
|
// TODO actually should this be an lfs_bd_ operation?
|
||||||
static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs,
|
static lfs_ssize_t lfs_rbyd_readtag(lfs_t *lfs,
|
||||||
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
|
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
|
||||||
lfs_block_t block, lfs_off_t off,
|
lfs_block_t block, lfs_off_t off,
|
||||||
@@ -1052,16 +1053,18 @@ static int lfs_rbyd_fetch(lfs_t *lfs,
|
|||||||
|
|
||||||
// calculate crc before endian conversion
|
// calculate crc before endian conversion
|
||||||
uint32_t crc = lfs_crc32c(0, &rev, sizeof(uint32_t));
|
uint32_t crc = lfs_crc32c(0, &rev, sizeof(uint32_t));
|
||||||
|
rev = lfs_fromle32_(&rev);
|
||||||
|
|
||||||
|
rbyd->block = block;
|
||||||
|
rbyd->off = 0;
|
||||||
|
rbyd->rev = rev;
|
||||||
|
|
||||||
|
// temporary state until we validate a crc
|
||||||
lfs_off_t off = sizeof(uint32_t);
|
lfs_off_t off = sizeof(uint32_t);
|
||||||
lfs_off_t trunk = 0;
|
lfs_off_t trunk = 0;
|
||||||
bool wastrunk = false;
|
bool wastrunk = false;
|
||||||
uint16_t count = 0;
|
uint16_t count = 0;
|
||||||
|
|
||||||
rbyd->block = block;
|
|
||||||
rbyd->rev = lfs_fromle32_(&rev);
|
|
||||||
rbyd->trunk = 0;
|
|
||||||
rbyd->off = 0;
|
|
||||||
|
|
||||||
// assume unerased until proven otherwise
|
// assume unerased until proven otherwise
|
||||||
bool maybeerased = false;
|
bool maybeerased = false;
|
||||||
bool hasfcrc = false;
|
bool hasfcrc = false;
|
||||||
@@ -1297,24 +1300,27 @@ static lfs_ssize_t lfs_rbyd_get(lfs_t *lfs, const lfs_rbyd_t *rbyd,
|
|||||||
return found_size;
|
return found_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_rbyd_prog(lfs_t *lfs,
|
static int lfs_rbyd_prog(lfs_t *lfs, lfs_rbyd_t *rbyd_,
|
||||||
lfs_cache_t *pcache, lfs_cache_t *rcache,
|
|
||||||
lfs_block_t block, lfs_off_t off,
|
|
||||||
const void *buffer, lfs_size_t size, uint32_t *crc) {
|
const void *buffer, lfs_size_t size, uint32_t *crc) {
|
||||||
// check for out-of-bounds here
|
// check for out-of-bounds here
|
||||||
// TODO should we just move this to lfs_bd_prog?
|
// TODO should we just move this to lfs_bd_prog?
|
||||||
// TODO actually should we just build crc into lfs_bd_prog as well?
|
// TODO actually should we just build crc into lfs_bd_prog as well?
|
||||||
if (off+size > lfs->cfg->block_size) {
|
if (rbyd_->off+size > lfs->cfg->block_size) {
|
||||||
return LFS_ERR_RANGE;
|
return LFS_ERR_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = lfs_bd_prog(lfs,
|
int err = lfs_bd_prog(lfs,
|
||||||
pcache, rcache, false,
|
&lfs->pcache, &lfs->rcache, false,
|
||||||
block, off, buffer, size);
|
rbyd_->block, rbyd_->off, buffer, size);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update off
|
||||||
|
rbyd_->off += size;
|
||||||
|
// TODO should this not be optional? should we move the range check
|
||||||
|
// into bd_prog? so we can get rid of the one use of this in
|
||||||
|
// lfs_rbyd_commit?
|
||||||
// optionally crc
|
// optionally crc
|
||||||
if (crc) {
|
if (crc) {
|
||||||
*crc = lfs_crc32c(*crc, buffer, size);
|
*crc = lfs_crc32c(*crc, buffer, size);
|
||||||
@@ -1323,86 +1329,67 @@ static int lfs_rbyd_prog(lfs_t *lfs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static lfs_ssize_t lfs_rbyd_progtag(lfs_t *lfs,
|
static int lfs_rbyd_progtag(lfs_t *lfs, lfs_rbyd_t *rbyd_,
|
||||||
lfs_cache_t *pcache, lfs_cache_t *rcache,
|
|
||||||
lfs_block_t block, lfs_off_t off,
|
|
||||||
lfs_rtag_t tag, lfs_size_t size, uint32_t *crc) {
|
lfs_rtag_t tag, lfs_size_t size, uint32_t *crc) {
|
||||||
// convert to on-disk repr
|
// convert to on-disk repr
|
||||||
tag <<= 1;
|
tag <<= 1;
|
||||||
|
|
||||||
// make sure to include the parity of the current crc
|
// make sure to include the parity of the current crc
|
||||||
tag |= lfs_popc(*crc) & 1;
|
tag |= lfs_popc(rbyd_->crc) & 1;
|
||||||
|
|
||||||
// compress into pair of leb128s
|
// compress into pair of leb128s
|
||||||
uint8_t buffer[2*4];
|
uint8_t buffer[2*4];
|
||||||
lfs_size_t i = 0;
|
lfs_size_t delta = 0;
|
||||||
|
|
||||||
ssize_t delta = lfs_toleb128(tag, &buffer[i], 4);
|
ssize_t delta_ = lfs_toleb128(tag, &buffer[delta], 4);
|
||||||
if (delta < 0) {
|
if (delta_ < 0) {
|
||||||
return delta;
|
return delta_;
|
||||||
}
|
}
|
||||||
i += delta;
|
delta += delta_;
|
||||||
|
|
||||||
delta = lfs_toleb128(size, &buffer[i], 4);
|
delta_ = lfs_toleb128(size, &buffer[delta], 4);
|
||||||
if (delta < 0) {
|
if (delta_ < 0) {
|
||||||
return delta;
|
return delta_;
|
||||||
}
|
}
|
||||||
i += delta;
|
delta += delta_;
|
||||||
|
|
||||||
int err = lfs_rbyd_prog(lfs,
|
int err = lfs_rbyd_prog(lfs, rbyd_, &buffer, delta, crc);
|
||||||
pcache, rcache,
|
|
||||||
block, off, &buffer, i, crc);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static lfs_ssize_t lfs_rbyd_p_flush(lfs_t *lfs,
|
static int lfs_rbyd_p_flush(lfs_t *lfs, lfs_rbyd_t *rbyd_,
|
||||||
lfs_cache_t *pcache, lfs_cache_t *rcache,
|
|
||||||
lfs_block_t block, lfs_off_t off,
|
|
||||||
lfs_rtag_t p_alts[static 3],
|
lfs_rtag_t p_alts[static 3],
|
||||||
lfs_rtag_t p_jumps[static 3],
|
lfs_rtag_t p_jumps[static 3],
|
||||||
unsigned count,
|
unsigned count) {
|
||||||
uint32_t *crc) {
|
|
||||||
lfs_off_t off_ = off;
|
|
||||||
|
|
||||||
// write out some number of alt pointers in our queue
|
// write out some number of alt pointers in our queue
|
||||||
for (unsigned i = 0; i < count; i++) {
|
for (unsigned i = 0; i < count; i++) {
|
||||||
if (p_alts[3-1-i]) {
|
if (p_alts[3-1-i]) {
|
||||||
// change to a relative jump at the last minute
|
// change to a relative jump at the last minute
|
||||||
lfs_rtag_t alt = p_alts[3-1-i];
|
lfs_rtag_t alt = p_alts[3-1-i];
|
||||||
lfs_off_t jump = off_ - p_jumps[3-1-i];
|
lfs_off_t jump = rbyd_->off - p_jumps[3-1-i];
|
||||||
printf("%x: writing %08x %08x\n", off_, alt, jump);
|
printf("%x: writing %08x %08x\n", rbyd_->off, alt, jump);
|
||||||
|
|
||||||
lfs_ssize_t delta = lfs_rbyd_progtag(lfs,
|
int err = lfs_rbyd_progtag(lfs, rbyd_, alt, jump, &rbyd_->crc);
|
||||||
pcache, rcache,
|
if (err) {
|
||||||
block, off_,
|
return err;
|
||||||
alt, jump, crc);
|
|
||||||
if (delta < 0) {
|
|
||||||
return delta;
|
|
||||||
}
|
}
|
||||||
off_ += delta;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return off_ - off;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline lfs_ssize_t lfs_rbyd_p_push(lfs_t *lfs,
|
static inline int lfs_rbyd_p_push(lfs_t *lfs, lfs_rbyd_t *rbyd_,
|
||||||
lfs_cache_t *pcache, lfs_cache_t *rcache,
|
|
||||||
lfs_block_t block, lfs_off_t off,
|
|
||||||
lfs_rtag_t p_alts[static 3],
|
lfs_rtag_t p_alts[static 3],
|
||||||
lfs_off_t p_jumps[static 3],
|
lfs_off_t p_jumps[static 3],
|
||||||
lfs_rtag_t alt, lfs_off_t jump,
|
lfs_rtag_t alt, lfs_off_t jump) {
|
||||||
uint32_t *crc) {
|
int err = lfs_rbyd_p_flush(lfs, rbyd_, p_alts, p_jumps, 1);
|
||||||
lfs_ssize_t delta = lfs_rbyd_p_flush(lfs,
|
if (err) {
|
||||||
pcache, rcache,
|
return err;
|
||||||
block, off,
|
|
||||||
p_alts, p_jumps, 1, crc);
|
|
||||||
if (delta < 0) {
|
|
||||||
return delta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p_alts[2] = p_alts[1];
|
p_alts[2] = p_alts[1];
|
||||||
@@ -1412,7 +1399,7 @@ static inline lfs_ssize_t lfs_rbyd_p_push(lfs_t *lfs,
|
|||||||
p_alts[0] = alt;
|
p_alts[0] = alt;
|
||||||
p_jumps[0] = jump;
|
p_jumps[0] = jump;
|
||||||
|
|
||||||
return delta;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void lfs_rbyd_p_pop(
|
static inline void lfs_rbyd_p_pop(
|
||||||
@@ -1462,44 +1449,14 @@ static void lfs_rbyd_p_red(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
static int lfs_rbyd_append(lfs_t *lfs, lfs_rbyd_t *rbyd_,
|
||||||
const struct lfs_rattr *attrs) {
|
lfs_rtag_t tag, const void *buffer, lfs_size_t size) {
|
||||||
printf("commit()\n");
|
|
||||||
LFS_ASSERT(rbyd->erased);
|
|
||||||
|
|
||||||
// setup commit state
|
|
||||||
const lfs_block_t block = rbyd->block;
|
|
||||||
lfs_off_t trunk = rbyd->trunk;
|
|
||||||
lfs_off_t off = rbyd->off;
|
|
||||||
uint32_t crc = rbyd->crc;
|
|
||||||
uint16_t count = rbyd->count;
|
|
||||||
bool erased = false;
|
|
||||||
|
|
||||||
// mark as unerased in case we fail
|
|
||||||
rbyd->erased = false;
|
|
||||||
|
|
||||||
// include revision count?
|
|
||||||
if (!off) {
|
|
||||||
uint32_t rev;
|
|
||||||
lfs_tole32_(rbyd->rev, &rev);
|
|
||||||
int err = lfs_rbyd_prog(lfs,
|
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off, &rev, sizeof(uint32_t), &crc);
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
off += sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// append each tag to the tree
|
|
||||||
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
|
|
||||||
printf("append()\n");
|
printf("append()\n");
|
||||||
LFS_ASSERT(lfs_rtag_id(attr->tag) <= count+1);
|
LFS_ASSERT(lfs_rtag_id(tag) <= rbyd_->count+1);
|
||||||
|
|
||||||
// assume we'll update our trunk
|
// assume we'll update our trunk
|
||||||
lfs_off_t branch = trunk;
|
lfs_off_t branch = rbyd_->trunk;
|
||||||
trunk = off;
|
rbyd_->trunk = rbyd_->off;
|
||||||
|
|
||||||
// no trunk yet?
|
// no trunk yet?
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
@@ -1509,7 +1466,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// weights for pruning
|
// weights for pruning
|
||||||
lfs_srtag_t lt;
|
lfs_srtag_t lt;
|
||||||
lfs_srtag_t gt;
|
lfs_srtag_t gt;
|
||||||
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
|
||||||
// inserting a new id? align down
|
// inserting a new id? align down
|
||||||
// TODO special function for this?
|
// TODO special function for this?
|
||||||
// if (lfs_rtag_id(attr->tag) == count+1) {
|
// if (lfs_rtag_id(attr->tag) == count+1) {
|
||||||
@@ -1519,11 +1476,11 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
|
// lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
|
||||||
// gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1);
|
// gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1);
|
||||||
// }
|
// }
|
||||||
lt = lfs_rtag_weight_lt(attr->tag & ~0x7fff, count+1);
|
lt = lfs_rtag_weight_lt(tag & ~0x7fff, rbyd_->count+1);
|
||||||
gt = lfs_rtag_weight_gt(attr->tag & ~0x7fff, count+1) + 1;
|
gt = lfs_rtag_weight_gt(tag & ~0x7fff, rbyd_->count+1) + 1;
|
||||||
} else {
|
} else {
|
||||||
lt = lfs_rtag_weight_lt(attr->tag, count+1);
|
lt = lfs_rtag_weight_lt(tag, rbyd_->count+1);
|
||||||
gt = lfs_rtag_weight_gt(attr->tag, count+1);
|
gt = lfs_rtag_weight_gt(tag, rbyd_->count+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("lt, gt = (%x, %x)\n", lt, gt);
|
printf("lt, gt = (%x, %x)\n", lt, gt);
|
||||||
@@ -1531,7 +1488,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// queue of pending alts we can emulate rotations with
|
// queue of pending alts we can emulate rotations with
|
||||||
lfs_rtag_t p_alts[3] = {0, 0, 0};
|
lfs_rtag_t p_alts[3] = {0, 0, 0};
|
||||||
lfs_off_t p_jumps[3] = {0, 0, 0};
|
lfs_off_t p_jumps[3] = {0, 0, 0};
|
||||||
lfs_off_t xylem = 0;
|
lfs_off_t graft = 0;
|
||||||
|
|
||||||
// descend down tree, building alt pointers
|
// descend down tree, building alt pointers
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -1539,7 +1496,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
lfs_off_t jump;
|
lfs_off_t jump;
|
||||||
lfs_ssize_t delta = lfs_rbyd_readtag(lfs,
|
lfs_ssize_t delta = lfs_rbyd_readtag(lfs,
|
||||||
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
|
&lfs->pcache, &lfs->rcache, lfs->cfg->block_size,
|
||||||
block, branch, &alt, &jump, NULL);
|
rbyd_->block, branch, &alt, &jump, NULL);
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
@@ -1591,12 +1548,12 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
printf("ysplit nofollow\n");
|
printf("ysplit nofollow\n");
|
||||||
p_alts[0] = lfs_rtag_black(
|
p_alts[0] = lfs_rtag_black(
|
||||||
lfs_rtag_merge(alt, p_alts[0]));
|
lfs_rtag_merge(alt, p_alts[0]));
|
||||||
p_jumps[0] = xylem;
|
p_jumps[0] = graft;
|
||||||
|
|
||||||
lfs_rtag_trim(alt, <, >);
|
lfs_rtag_trim(alt, <, >);
|
||||||
lfs_rbyd_p_red(p_alts, p_jumps);
|
lfs_rbyd_p_red(p_alts, p_jumps);
|
||||||
|
|
||||||
xylem = branch;
|
graft = branch;
|
||||||
branch = branch_;
|
branch = branch_;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1641,19 +1598,16 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// push alt onto queue
|
// push alt onto queue
|
||||||
lfs_ssize_t delta = lfs_rbyd_p_push(lfs,
|
int err = lfs_rbyd_p_push(lfs, rbyd_,
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off,
|
|
||||||
p_alts, p_jumps,
|
p_alts, p_jumps,
|
||||||
alt, jump, &crc);
|
alt, jump);
|
||||||
if (delta < 0) {
|
if (err) {
|
||||||
return delta;
|
return err;
|
||||||
}
|
}
|
||||||
off += delta;
|
|
||||||
|
|
||||||
// continue to next alt
|
// continue to next alt
|
||||||
lfs_rtag_trim(alt, <, >);
|
lfs_rtag_trim(alt, <, >);
|
||||||
xylem = branch;
|
graft = branch;
|
||||||
branch = branch_;
|
branch = branch_;
|
||||||
|
|
||||||
// found end of tree?
|
// found end of tree?
|
||||||
@@ -1663,9 +1617,9 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// TODO alternatively can we do this a bit more directly here
|
// TODO alternatively can we do this a bit more directly here
|
||||||
// lfs_rtag_t tag_ = lfs_rtag_setid(alt,
|
// lfs_rtag_t tag_ = lfs_rtag_setid(alt,
|
||||||
// lfs_min(lfs_rtag_id(attr->tag), count));
|
// lfs_min(lfs_rtag_id(attr->tag), count));
|
||||||
lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(attr->tag));
|
lfs_rtag_t tag_ = lfs_rtag_setid(alt, lfs_rtag_id(tag));
|
||||||
// TODO I don't really know why this works
|
// TODO I don't really know why this works
|
||||||
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE && gt == 0) {
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE && gt == 0) {
|
||||||
tag_ = lfs_rtag_decid(tag_);
|
tag_ = lfs_rtag_decid(tag_);
|
||||||
}
|
}
|
||||||
//gt == 0 ? lfs_rtag_id(attr->tag)-1 : lfs_rtag_id(attr->tag));
|
//gt == 0 ? lfs_rtag_id(attr->tag)-1 : lfs_rtag_id(attr->tag));
|
||||||
@@ -1673,14 +1627,14 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
|
|
||||||
// split leaf?
|
// split leaf?
|
||||||
// TODO we might be able to rearrange this a bit better
|
// TODO we might be able to rearrange this a bit better
|
||||||
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE
|
||||||
|| tag_ != attr->tag) {
|
|| tag_ != tag) {
|
||||||
// inserting a new id?
|
// inserting a new id?
|
||||||
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
|
||||||
// bias the weights so that lookups always find the
|
// bias the weights so that lookups always find the
|
||||||
// next biggest tag
|
// next biggest tag
|
||||||
if (lfs_rtag_weight(tag_)
|
if (lfs_rtag_weight(tag_)
|
||||||
< lfs_rtag_weight(attr->tag & ~0x7fff)) {
|
< lfs_rtag_weight(tag & ~0x7fff)) {
|
||||||
printf("lt insert\n");
|
printf("lt insert\n");
|
||||||
//
|
//
|
||||||
// lt gt
|
// lt gt
|
||||||
@@ -1691,12 +1645,12 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// a old new d e
|
// a old new d e
|
||||||
//
|
//
|
||||||
alt = LFS_MKRALT(B, LT, lt
|
alt = LFS_MKRALT(B, LT, lt
|
||||||
- (lfs_rtag_weight(attr->tag & ~0x7fff)-1
|
- (lfs_rtag_weight(tag & ~0x7fff)-1
|
||||||
- lfs_rtag_weight(tag_))
|
- lfs_rtag_weight(tag_))
|
||||||
+ 1);
|
+ 1);
|
||||||
} else {
|
} else {
|
||||||
printf("gt insert\n");
|
printf("gt insert\n");
|
||||||
printf("hmmm? %08x %08x\n", lfs_rtag_weight(tag_), lfs_rtag_weight(attr->tag & ~0x7fff));
|
printf("hmmm? %08x %08x\n", lfs_rtag_weight(tag_), lfs_rtag_weight(tag & ~0x7fff));
|
||||||
//
|
//
|
||||||
// lt gt
|
// lt gt
|
||||||
// .-----'--. .-'.
|
// .-----'--. .-'.
|
||||||
@@ -1708,13 +1662,13 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
alt = LFS_MKRALT(B, GT,
|
alt = LFS_MKRALT(B, GT,
|
||||||
// TODO hm, can this be done differently?
|
// TODO hm, can this be done differently?
|
||||||
lfs_rtag_weight(lfs_rtag_incid(tag_))
|
lfs_rtag_weight(lfs_rtag_incid(tag_))
|
||||||
- lfs_rtag_weight(attr->tag));
|
- lfs_rtag_weight(tag));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// bias the weights so that lookups always find the
|
// bias the weights so that lookups always find the
|
||||||
// next biggest tag
|
// next biggest tag
|
||||||
if (lfs_rtag_weight(tag_)
|
if (lfs_rtag_weight(tag_)
|
||||||
< lfs_rtag_weight(attr->tag)) {
|
< lfs_rtag_weight(tag)) {
|
||||||
//
|
//
|
||||||
// lt gt
|
// lt gt
|
||||||
// .-----'-----. .--'--.
|
// .-----'-----. .--'--.
|
||||||
@@ -1725,7 +1679,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
//
|
//
|
||||||
alt = LFS_MKRALT(B, LT, lt
|
alt = LFS_MKRALT(B, LT, lt
|
||||||
+ 1
|
+ 1
|
||||||
- (lfs_rtag_weight(attr->tag)
|
- (lfs_rtag_weight(tag)
|
||||||
- lfs_rtag_weight(tag_)));
|
- lfs_rtag_weight(tag_)));
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
@@ -1740,65 +1694,82 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lfs_ssize_t delta = lfs_rbyd_p_push(lfs,
|
int err = lfs_rbyd_p_push(lfs, rbyd_,
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off,
|
|
||||||
p_alts, p_jumps,
|
p_alts, p_jumps,
|
||||||
alt, branch, &crc);
|
alt, branch);
|
||||||
if (delta < 0) {
|
if (err) {
|
||||||
return delta;
|
return err;
|
||||||
}
|
}
|
||||||
off += delta;
|
|
||||||
|
|
||||||
lfs_rbyd_p_red(p_alts, p_jumps);
|
lfs_rbyd_p_red(p_alts, p_jumps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush any pending alts
|
// flush any pending alts
|
||||||
delta = lfs_rbyd_p_flush(lfs,
|
int err = lfs_rbyd_p_flush(lfs, rbyd_,
|
||||||
&lfs->pcache, &lfs->rcache,
|
p_alts, p_jumps, 3);
|
||||||
block, off,
|
if (err) {
|
||||||
p_alts, p_jumps, 3, &crc);
|
return err;
|
||||||
if (delta < 0) {
|
|
||||||
return delta;
|
|
||||||
}
|
}
|
||||||
off += delta;
|
|
||||||
|
|
||||||
// done! lets get out of here
|
// done! lets get out of here
|
||||||
goto leaf;
|
goto leaf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf:;
|
leaf:;
|
||||||
// write the tag
|
// write the tag
|
||||||
lfs_ssize_t delta = lfs_rbyd_progtag(lfs,
|
int err = lfs_rbyd_progtag(lfs, rbyd_, tag, size, &rbyd_->crc);
|
||||||
&lfs->pcache, &lfs->rcache,
|
if (err) {
|
||||||
block, off,
|
return err;
|
||||||
attr->tag, attr->size, &crc);
|
}
|
||||||
if (delta < 0) {
|
|
||||||
return delta;
|
// don't forget the actual data!
|
||||||
}
|
err = lfs_rbyd_prog(lfs, rbyd_, buffer, size, &rbyd_->crc);
|
||||||
off += delta;
|
|
||||||
|
|
||||||
// don't forget the actual data!
|
|
||||||
int err = lfs_rbyd_prog(lfs,
|
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off,
|
|
||||||
attr->buffer, attr->size, &crc);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
off += attr->size;
|
|
||||||
|
|
||||||
// if we're inserting, increase the id count, indirectly shifting
|
// if we're inserting, increase the id count, indirectly shifting
|
||||||
// all ids >= over one
|
// all ids >= over one
|
||||||
//
|
//
|
||||||
// note we do this here since it is possible to insert into an
|
// note we do this here since it is possible to insert into an
|
||||||
// empty tree
|
// empty tree
|
||||||
if (lfs_rtag_type1(attr->tag) == LFS_TYPE1_CREATE) {
|
if (lfs_rtag_type1(tag) == LFS_TYPE1_CREATE) {
|
||||||
count += 1;
|
rbyd_->count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
||||||
|
const struct lfs_rattr *attrs) {
|
||||||
|
printf("commit()\n");
|
||||||
|
LFS_ASSERT(rbyd->erased);
|
||||||
|
|
||||||
|
// mark as unerased in case we fail
|
||||||
|
rbyd->erased = false;
|
||||||
|
|
||||||
|
// setup commit state
|
||||||
|
lfs_rbyd_t rbyd_ = *rbyd;
|
||||||
|
|
||||||
|
// include revision count?
|
||||||
|
if (!rbyd_.off) {
|
||||||
|
uint32_t rev;
|
||||||
|
lfs_tole32_(rbyd_.rev, &rev);
|
||||||
|
int err = lfs_rbyd_prog(lfs, &rbyd_,
|
||||||
|
&rev, sizeof(uint32_t), &rbyd_.crc);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append each tag to the tree
|
||||||
|
for (const struct lfs_rattr *attr = attrs; attr; attr = attr->next) {
|
||||||
|
int err = lfs_rbyd_append(lfs, &rbyd_,
|
||||||
|
attr->tag, attr->buffer, attr->size);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// align to the next prog unit
|
// align to the next prog unit
|
||||||
@@ -1820,7 +1791,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// = 9 bytes
|
// = 9 bytes
|
||||||
//
|
//
|
||||||
const lfs_off_t aligned = lfs_alignup(
|
const lfs_off_t aligned = lfs_alignup(
|
||||||
off + 1+1+4+4 + 1+4+4,
|
rbyd_.off + 1+1+4+4 + 1+4+4,
|
||||||
lfs->cfg->prog_size);
|
lfs->cfg->prog_size);
|
||||||
|
|
||||||
// space for fcrc?
|
// space for fcrc?
|
||||||
@@ -1830,7 +1801,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// value of the next tag's valid bit
|
// value of the next tag's valid bit
|
||||||
int err = lfs_bd_read(lfs,
|
int err = lfs_bd_read(lfs,
|
||||||
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
|
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
|
||||||
block, aligned, &perturb, 1);
|
rbyd_.block, aligned, &perturb, 1);
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1840,31 +1811,25 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
struct lfs_rfcrc fcrc = {.crc=0, .size=lfs->cfg->prog_size};
|
struct lfs_rfcrc fcrc = {.crc=0, .size=lfs->cfg->prog_size};
|
||||||
err = lfs_bd_crc32c(lfs,
|
err = lfs_bd_crc32c(lfs,
|
||||||
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
|
&lfs->pcache, &lfs->rcache, lfs->cfg->prog_size,
|
||||||
block, aligned, fcrc.size, &fcrc.crc);
|
rbyd_.block, aligned, fcrc.size, &fcrc.crc);
|
||||||
if (err && err != LFS_ERR_CORRUPT) {
|
if (err && err != LFS_ERR_CORRUPT) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfs_size_t fcrc_delta = lfs_rfcrc_todisk(&fcrc);
|
lfs_size_t fcrc_delta = lfs_rfcrc_todisk(&fcrc);
|
||||||
lfs_ssize_t delta = lfs_rbyd_progtag(lfs,
|
err = lfs_rbyd_progtag(lfs, &rbyd_,
|
||||||
&lfs->pcache, &lfs->rcache,
|
LFS_MKRTAG(FCRC, 0, 0), fcrc_delta, &rbyd_.crc);
|
||||||
block, off,
|
|
||||||
LFS_MKRTAG(FCRC, 0, 0), fcrc_delta, &crc);
|
|
||||||
if (delta < 0) {
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
off += delta;
|
|
||||||
|
|
||||||
err = lfs_rbyd_prog(lfs,
|
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off,
|
|
||||||
&fcrc, fcrc_delta, &crc);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
off += fcrc_delta;
|
|
||||||
|
|
||||||
erased = true;
|
err = lfs_rbyd_prog(lfs, &rbyd_,
|
||||||
|
&fcrc, fcrc_delta, &rbyd_.crc);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rbyd_.erased = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// build end-of-commit crc
|
// build end-of-commit crc
|
||||||
@@ -1873,32 +1838,29 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// get around this catch-22 we just always write a fully-expanded leb128
|
// get around this catch-22 we just always write a fully-expanded leb128
|
||||||
// encoding
|
// encoding
|
||||||
uint8_t buffer[1+4+4];
|
uint8_t buffer[1+4+4];
|
||||||
buffer[0] = (LFS_MKRTAG(CRC, 0, 0) << 1) | (lfs_popc(crc) & 1);
|
buffer[0] = (LFS_MKRTAG(CRC, 0, 0) << 1) | (lfs_popc(rbyd_.crc) & 1);
|
||||||
|
|
||||||
lfs_off_t padding = aligned - (off + 1+4);
|
lfs_off_t padding = aligned - (rbyd_.off + 1+4);
|
||||||
buffer[1] = 0x80 | (0x7f & (padding >> 0));
|
buffer[1] = 0x80 | (0x7f & (padding >> 0));
|
||||||
buffer[2] = 0x80 | (0x7f & (padding >> 7));
|
buffer[2] = 0x80 | (0x7f & (padding >> 7));
|
||||||
buffer[3] = 0x80 | (0x7f & (padding >> 14));
|
buffer[3] = 0x80 | (0x7f & (padding >> 14));
|
||||||
buffer[4] = 0x00 | (0x7f & (padding >> 21));
|
buffer[4] = 0x00 | (0x7f & (padding >> 21));
|
||||||
|
|
||||||
crc = lfs_crc32c(crc, buffer, 1+4);
|
rbyd_.crc = lfs_crc32c(rbyd_.crc, buffer, 1+4);
|
||||||
// we can't let the next tag appear as valid, so intentionally perturb the
|
// we can't let the next tag appear as valid, so intentionally perturb the
|
||||||
// commit if this happens, note parity(crc(m)) == parity(m) with crc32c,
|
// commit if this happens, note parity(crc(m)) == parity(m) with crc32c,
|
||||||
// so we can really change any bit to make this happen, we've reserved a bit
|
// so we can really change any bit to make this happen, we've reserved a bit
|
||||||
// in crc tags just for this purpose
|
// in crc tags just for this purpose
|
||||||
if ((lfs_popc(crc) & 1) == (perturb & 1)) {
|
if ((lfs_popc(rbyd_.crc) & 1) == (perturb & 1)) {
|
||||||
buffer[0] ^= 0x2;
|
buffer[0] ^= 0x2;
|
||||||
crc ^= 0x7022df58; // note crc(a ^ b) == crc(a) ^ crc(b)
|
rbyd_.crc ^= 0x7022df58; // note crc(a ^ b) == crc(a) ^ crc(b)
|
||||||
}
|
}
|
||||||
lfs_tole32_(crc, &buffer[1+4]);
|
lfs_tole32_(rbyd_.crc, &buffer[1+4]);
|
||||||
|
|
||||||
int err = lfs_rbyd_prog(lfs,
|
int err = lfs_rbyd_prog(lfs, &rbyd_, buffer, 1+4+4, NULL);
|
||||||
&lfs->pcache, &lfs->rcache,
|
|
||||||
block, off, buffer, 1+4+4, NULL);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
off += 1+4+4;
|
|
||||||
|
|
||||||
// flush our caches, finalizing the commit on-disk
|
// flush our caches, finalizing the commit on-disk
|
||||||
err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
|
err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false);
|
||||||
@@ -1909,24 +1871,21 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd,
|
|||||||
// succesful commit, check checksum to make sure
|
// succesful commit, check checksum to make sure
|
||||||
uint32_t crc_ = rbyd->crc;
|
uint32_t crc_ = rbyd->crc;
|
||||||
err = lfs_bd_crc32c(lfs,
|
err = lfs_bd_crc32c(lfs,
|
||||||
NULL, &lfs->rcache, off-4,
|
NULL, &lfs->rcache, rbyd_.off-4,
|
||||||
block, rbyd->off, off-4 - rbyd->off, &crc_);
|
rbyd_.block, rbyd->off, rbyd_.off-4 - rbyd->off, &crc_);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crc_ != crc) {
|
if (crc_ != rbyd_.crc) {
|
||||||
// oh no, something went wrong
|
// oh no, something went wrong
|
||||||
printf("oh no %08x != %08x\n", crc_, crc);
|
printf("oh no %08x != %08x\n", crc_, rbyd_.crc);
|
||||||
return LFS_ERR_CORRUPT;
|
return LFS_ERR_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok, everything is good, save what we've committed
|
// ok, everything is good, save what we've committed
|
||||||
rbyd->trunk = trunk;
|
rbyd_.off = aligned;
|
||||||
rbyd->off = aligned;
|
*rbyd = rbyd_;
|
||||||
rbyd->crc = crc;
|
|
||||||
rbyd->count = count;
|
|
||||||
rbyd->erased = erased;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user