Limited block merging to only merge when fits
This is similar to fragment coalescing, except we may need to merge multiple fragments/blocks, so we check for merges in a loop (need to determine if this is the best strategy). This prevents runaway block allocations when writing to a file backwards. I'm not really sure why you would write to a file backwards, but this also has an impact on random writes.
This commit is contained in:
@@ -9523,7 +9523,8 @@ static int lfsr_file_flushbuffer(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
// can we coalesce?
|
// can we coalesce?
|
||||||
if (pos+lfsr_data_size(&data)
|
if (pos+lfsr_data_size(&data)
|
||||||
< rid_-(weight_-1) + lfsr_data_size(&data_)
|
< rid_-(weight_-1) + lfsr_data_size(&data_)
|
||||||
&& lfsr_data_size(&data) + lfsr_data_size(&data_)
|
&& lfsr_data_size(&data)
|
||||||
|
+ lfsr_data_size(&data_)
|
||||||
- (pos+lfsr_data_size(&data) - (rid_-(weight_-1)))
|
- (pos+lfsr_data_size(&data) - (rid_-(weight_-1)))
|
||||||
<= lfs->cfg->fragment_size) {
|
<= lfs->cfg->fragment_size) {
|
||||||
datas[data_count++] = lfsr_data_fruncate(data_,
|
datas[data_count++] = lfsr_data_fruncate(data_,
|
||||||
@@ -9974,20 +9975,15 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
// before we can compact we need to figure out the best block
|
// before we can compact we need to figure out the best block
|
||||||
// alignment, we use the entry immediately to the left of our
|
// alignment, we use the entry immediately to the left of our
|
||||||
// crystal for this
|
// crystal for this
|
||||||
lfs_off_t block_off;
|
lfs_off_t block_start = crystal_start;
|
||||||
// some corner cases where we align arbitrarily
|
if (block_start > 0 && lfsr_tree_size(&file->tree) > 0) {
|
||||||
if (crystal_start == 0 || lfsr_tree_size(&file->tree) == 0) {
|
|
||||||
block_off = crystal_start;
|
|
||||||
|
|
||||||
// find left block neighbor
|
|
||||||
} else {
|
|
||||||
lfsr_bid_t bid_;
|
lfsr_bid_t bid_;
|
||||||
lfsr_tag_t tag_;
|
lfsr_tag_t tag_;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight_;
|
||||||
lfsr_data_t data_;
|
lfsr_data_t data_;
|
||||||
int err = lfsr_tree_lookupnext(lfs, &file->tree,
|
int err = lfsr_tree_lookupnext(lfs, &file->tree,
|
||||||
lfs_min32(
|
lfs_min32(
|
||||||
crystal_start-1,
|
block_start-1,
|
||||||
lfsr_tree_size(&file->tree)-1),
|
lfsr_tree_size(&file->tree)-1),
|
||||||
&bid_, &tag_, &weight_, &data_);
|
&bid_, &tag_, &weight_, &data_);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -9998,23 +9994,51 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
|| tag_ == LFSR_TAG_BLOCK);
|
|| tag_ == LFSR_TAG_BLOCK);
|
||||||
|
|
||||||
// is our left neighbor in the same block?
|
// is our left neighbor in the same block?
|
||||||
if (crystal_start - (bid_-(weight_-1)) < lfs->cfg->block_size
|
if (block_start - (bid_-(weight_-1)) < lfs->cfg->block_size
|
||||||
&& lfsr_data_size(&data_) > 0) {
|
&& lfsr_data_size(&data_) > 0) {
|
||||||
block_off = bid_-(weight_-1);
|
block_start = bid_-(weight_-1);
|
||||||
|
|
||||||
// no? is our left neighbor at least our left block neighbor?
|
// no? is our left neighbor at least our left block neighbor?
|
||||||
// align to block alignment
|
// align to block alignment
|
||||||
} else if (crystal_start - (bid_-(weight_-1))
|
} else if (block_start - (bid_-(weight_-1))
|
||||||
< 2*lfs->cfg->block_size
|
< 2*lfs->cfg->block_size
|
||||||
&& lfsr_data_size(&data_) > 0) {
|
&& lfsr_data_size(&data_) > 0) {
|
||||||
block_off = bid_-(weight_-1) + lfs->cfg->block_size;
|
block_start = bid_-(weight_-1) + lfs->cfg->block_size;
|
||||||
|
|
||||||
// no!? file is sparse, align arbitrarily
|
|
||||||
} else {
|
|
||||||
block_off = crystal_start;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we have space in our block, lookup right block neighbors
|
||||||
|
// to see if we can merge
|
||||||
|
lfs_off_t block_end = lfs_min32(
|
||||||
|
crystal_end,
|
||||||
|
block_start + lfs->cfg->block_size);
|
||||||
|
while (block_end - block_start < lfs->cfg->block_size
|
||||||
|
&& block_end < lfsr_tree_size(&file->tree)) {
|
||||||
|
lfsr_bid_t bid_;
|
||||||
|
lfsr_tag_t tag_;
|
||||||
|
lfsr_bid_t weight_;
|
||||||
|
lfsr_data_t data_;
|
||||||
|
int err = lfsr_tree_lookupnext(lfs, &file->tree,
|
||||||
|
block_end,
|
||||||
|
&bid_, &tag_, &weight_, &data_);
|
||||||
|
if (err) {
|
||||||
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
LFS_ASSERT(tag_ == LFSR_TAG_DATA
|
||||||
|
|| tag_ == LFSR_TAG_BLOCK);
|
||||||
|
|
||||||
|
// can we merge?
|
||||||
|
if (bid_-(weight_-1)+lfsr_data_size(&data_) <= block_end
|
||||||
|
|| bid_-(weight_-1)+lfsr_data_size(&data_)
|
||||||
|
- block_start
|
||||||
|
> lfs->cfg->block_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_end = bid_-(weight_-1)+lfsr_data_size(&data_);
|
||||||
|
}
|
||||||
|
|
||||||
// allocate a new block
|
// allocate a new block
|
||||||
lfs_block_t block;
|
lfs_block_t block;
|
||||||
int err = lfs_alloc(lfs, &block);
|
int err = lfs_alloc(lfs, &block);
|
||||||
@@ -10029,11 +10053,10 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copy any data underneath our block into our block
|
// copy any data underneath our block into our block
|
||||||
lfs_off_t pos_ = block_off;
|
lfs_off_t pos_ = block_start;
|
||||||
while (pos_ < block_off + lfs->cfg->block_size) {
|
while (pos_ < block_end) {
|
||||||
lfsr_data_t data;
|
lfsr_data_t data;
|
||||||
err = lfsr_file_readnext(lfs, file, pos_,
|
err = lfsr_file_readnext(lfs, file, pos_, block_end - pos_,
|
||||||
block_off + lfs->cfg->block_size - pos_,
|
|
||||||
&data);
|
&data);
|
||||||
if (err) {
|
if (err) {
|
||||||
// end of file?
|
// end of file?
|
||||||
@@ -10044,16 +10067,8 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
}
|
}
|
||||||
LFS_ASSERT(lfsr_data_size(&data) > 0);
|
LFS_ASSERT(lfsr_data_size(&data) > 0);
|
||||||
|
|
||||||
// found a hole that goes all the way to the end? terminate
|
|
||||||
// early
|
|
||||||
if (lfsr_data_ishole(&data)
|
|
||||||
&& pos_ + lfsr_data_size(&data)
|
|
||||||
>= block_off + lfs->cfg->block_size) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prog data/hole
|
// prog data/hole
|
||||||
err = lfsr_bd_progdata(lfs, block, pos_ - block_off,
|
err = lfsr_bd_progdata(lfs, block, pos_ - block_start,
|
||||||
data,
|
data,
|
||||||
NULL);
|
NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -10062,7 +10077,6 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
|
|
||||||
pos_ += lfsr_data_size(&data);
|
pos_ += lfsr_data_size(&data);
|
||||||
}
|
}
|
||||||
lfs_off_t block_size = pos_ - block_off;
|
|
||||||
|
|
||||||
// TODO validate?
|
// TODO validate?
|
||||||
// finalize our write
|
// finalize our write
|
||||||
@@ -10075,13 +10089,13 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
lfsr_bptr_t bptr = {
|
lfsr_bptr_t bptr = {
|
||||||
.block = block,
|
.block = block,
|
||||||
.off = 0,
|
.off = 0,
|
||||||
.size = block_size,
|
.size = block_end - block_start,
|
||||||
};
|
};
|
||||||
|
|
||||||
// and write it into our tree
|
// and write it into our tree
|
||||||
uint8_t bptr_buf[LFSR_BPTR_DSIZE];
|
uint8_t bptr_buf[LFSR_BPTR_DSIZE];
|
||||||
err = lfsr_tree_carve(lfs, &file->tree,
|
err = lfsr_tree_carve(lfs, &file->tree,
|
||||||
block_off, block_size, 0,
|
block_start, block_end - block_start, 0,
|
||||||
LFSR_TAG_BLOCK, lfsr_data_frombptr(&bptr, bptr_buf));
|
LFSR_TAG_BLOCK, lfsr_data_frombptr(&bptr, bptr_buf));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -10089,7 +10103,7 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
|
|
||||||
// note due to block alignment we may not actually make progress
|
// note due to block alignment we may not actually make progress
|
||||||
// here until a second pass
|
// here until a second pass
|
||||||
pos = lfs_max32(pos, block_off + block_size);
|
pos = lfs_max32(pos, block_end);
|
||||||
|
|
||||||
// fits in crystallization threshold? just append a fragment
|
// fits in crystallization threshold? just append a fragment
|
||||||
} else {
|
} else {
|
||||||
@@ -10168,7 +10182,7 @@ static int lfsr_file_flushshrub(lfs_t *lfs, lfsr_file_t *file) {
|
|||||||
if (pos+lfsr_data_size(&data)
|
if (pos+lfsr_data_size(&data)
|
||||||
< bid_-(weight_-1) + lfsr_data_size(&data_)
|
< bid_-(weight_-1) + lfsr_data_size(&data_)
|
||||||
&& lfsr_data_size(&data)
|
&& lfsr_data_size(&data)
|
||||||
+ lfsr_data_size(&data_)
|
+ lfsr_data_size(&data_)
|
||||||
- (pos+lfsr_data_size(&data)
|
- (pos+lfsr_data_size(&data)
|
||||||
- (bid_-(weight_-1)))
|
- (bid_-(weight_-1)))
|
||||||
<= lfs->cfg->fragment_size) {
|
<= lfs->cfg->fragment_size) {
|
||||||
|
|||||||
Reference in New Issue
Block a user