Fixed/implemented renaming open files

This requires two things:

1. Any opened file handles need to have their mid/mdir updated after the
   rename succeeds.

2. Any shrubs/sprouts need to be copied over to the new mdir, even if
   they aren't in-tree.

The LFSR_TAG_MOVE operation is starting to look an awfully lot like
lfsr_mdir_compact... Unfortunately lfsr_mdir_compact, uh, compacts,
whereas LFSR_TAG_MOVE appends to the rbyd like normal, so it's not clear
exactly _how_ to deduplicate.
This commit is contained in:
Christopher Haster
2024-01-15 16:41:08 -06:00
parent f51dc5c5af
commit 7385d84df5
2 changed files with 113 additions and 54 deletions
+111 -52
View File
@@ -4723,15 +4723,17 @@ static lfs_ssize_t lfsr_sprout_estimate(lfs_t *lfs,
return LFSR_TAG_DSIZE + lfsr_data_size(sprout); return LFSR_TAG_DSIZE + lfsr_data_size(sprout);
} }
static int lfsr_sprout_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_, static int lfsr_sprout_compact(lfs_t *lfs, const lfsr_rbyd_t *rbyd_,
lfsr_data_t *sprout_, const lfsr_data_t *sprout, bool orphan) { lfsr_data_t *sprout_, const lfsr_data_t *sprout) {
// write out bsprout // this gets a bit weird, since upper layers need to do the actual
int err = lfsr_rbyd_appendcompactattr(lfs, rbyd_, // compaction, we just update internal state here
(orphan) ? LFSR_TAG_SHRUB(DATA) : LFSR_TAG_DATA, 0,
*sprout); // this is a bit tricky since we don't know the tag size,
if (err) { // but we have just enough info
return err; lfsr_data_t sprout__ = LFSR_DATA_DISK(
} rbyd_->blocks[0],
rbyd_->eoff - lfsr_data_size(sprout),
lfsr_data_size(sprout));
// stage any opened inlined files with their new location so we // stage any opened inlined files with their new location so we
// can update these later if our commit is a success // can update these later if our commit is a success
@@ -4744,21 +4746,11 @@ static int lfsr_sprout_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_,
&& lfsr_sprout_cmp( && lfsr_sprout_cmp(
&file_->ftree.u.bsprout, &file_->ftree.u.bsprout,
sprout) == 0) { sprout) == 0) {
// this is a bit tricky since we don't know the tag size, file_->ftree_.u.bsprout = sprout__;
// but we have just enough info
file_->ftree_.u.bsprout = LFSR_DATA_DISK(
rbyd_->blocks[0],
rbyd_->eoff - lfsr_data_size(sprout),
lfsr_data_size(sprout));
} }
} }
// this is a bit tricky since we don't know the tag size, *sprout_ = sprout__;
// but we have just enough info
*sprout_ = LFSR_DATA_DISK(
rbyd_->blocks[0],
rbyd_->eoff - lfsr_data_size(sprout),
lfsr_data_size(sprout));
return 0; return 0;
} }
@@ -5427,6 +5419,8 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
// do nothing // do nothing
// move tags copy over any tags associated with the source's rid // move tags copy over any tags associated with the source's rid
// TODO can this be deduplicated with lfsr_mdir_compact__ more?
// it _really_ wants to be deduplicated
} else if (attrs[i].tag == LFSR_TAG_MOVE) { } else if (attrs[i].tag == LFSR_TAG_MOVE) {
// weighted moves are not supported // weighted moves are not supported
LFS_ASSERT(attrs[i].delta == 0); LFS_ASSERT(attrs[i].delta == 0);
@@ -5447,8 +5441,25 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
return err; return err;
} }
// special case for bshrubs, we need to copy these over // found an inlined sprout? we can just copy this like
if (tag == LFSR_TAG_BSHRUB) { // normal but we need to update any opened inlined files
if (tag == LFSR_TAG_DATA) {
err = lfsr_rbyd_appendattr(lfs, &rbyd_,
rid - lfs_smax32(start_rid, 0),
tag, 0, data);
if (err) {
return err;
}
err = lfsr_sprout_compact(lfs, &rbyd_, &data,
&data);
if (err) {
return err;
}
// found an inlined shrub? we need to compact the shrub
// as well to bring it along with us
} else if (tag == LFSR_TAG_BSHRUB) {
lfsr_shrub_t shrub; lfsr_shrub_t shrub;
err = lfsr_data_readshrub(lfs, &data, mdir__, err = lfsr_data_readshrub(lfs, &data, mdir__,
&shrub); &shrub);
@@ -5484,6 +5495,55 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
} }
// we're not quite done! we also need to bring over any
// unsynced files
for (lfsr_opened_t *opened = lfs->opened;
opened;
opened = opened->next) {
lfsr_file_t *file = (lfsr_file_t*)opened;
// belongs to our mid?
if (file->type != LFS_TYPE_REG
|| file->mdir.mid != mdir__->mid) {
continue;
}
// inlined sprout?
if (lfsr_ftree_isbsprout(&file->mdir, &file->ftree)
// only compact once, first compact should stage
// the new block
&& file->ftree_.u.bsprout.u.disk.block
!= rbyd_.blocks[0]) {
int err = lfsr_rbyd_appendcompactattr(lfs, &rbyd_,
LFSR_TAG_SHRUB(DATA), 0,
file->ftree.u.bsprout);
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
return err;
}
err = lfsr_sprout_compact(lfs, &rbyd_,
&file->ftree_.u.bsprout,
&file->ftree.u.bsprout);
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
return err;
}
// inlined shrub?
} else if (lfsr_ftree_isbshrub(&file->mdir, &file->ftree)
// only compact once, first compact should stage
// the new block
&& file->ftree.u.bshrub.blocks[0]
!= rbyd_.blocks[0]) {
int err = lfsr_shrub_compact(lfs, &rbyd_,
&file->ftree_.u.bshrub, &file->ftree.u.bshrub);
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
return err;
}
}
}
// shrub tags append a set of attributes to an unrelated trunk // shrub tags append a set of attributes to an unrelated trunk
// in our rbyd // in our rbyd
} else if (attrs[i].tag == LFSR_TAG_SHRUBALLOC } else if (attrs[i].tag == LFSR_TAG_SHRUBALLOC
@@ -5753,9 +5813,15 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
// found an inlined sprout? we can just copy this like normal but // found an inlined sprout? we can just copy this like normal but
// we need to update any opened inlined files // we need to update any opened inlined files
if (tag == LFSR_TAG_DATA) { if (tag == LFSR_TAG_DATA) {
LFS_ASSERT(weight == 0); err = lfsr_rbyd_appendcompactattr(lfs, &mdir_->rbyd,
tag, weight, data);
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
return err;
}
err = lfsr_sprout_compact(lfs, &mdir_->rbyd, &data, err = lfsr_sprout_compact(lfs, &mdir_->rbyd, &data,
&data, false); &data);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
@@ -5825,9 +5891,15 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_,
// only compact once, first compact should stage the new block // only compact once, first compact should stage the new block
&& file->ftree_.u.bsprout.u.disk.block && file->ftree_.u.bsprout.u.disk.block
!= mdir_->rbyd.blocks[0]) { != mdir_->rbyd.blocks[0]) {
err = lfsr_rbyd_appendcompactattr(lfs, &mdir_->rbyd,
LFSR_TAG_SHRUB(DATA), 0, file->ftree.u.bsprout);
if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE);
return err;
}
err = lfsr_sprout_compact(lfs, &mdir_->rbyd, err = lfsr_sprout_compact(lfs, &mdir_->rbyd,
&file->ftree_.u.bsprout, &file->ftree_.u.bsprout, &file->ftree.u.bsprout);
&file->ftree.u.bsprout, true);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
@@ -6591,7 +6663,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
if (opened->mdir.mid < attrs[i].rid - attrs[i].delta) { if (opened->mdir.mid < attrs[i].rid - attrs[i].delta) {
// mark as zombied and move onto the next rid, upper // mark as zombied and move onto the next rid, upper
// layers should handle the repercussions // layers should handle the repercussions
opened->flags |= LFS_F_ZOMBIE; opened->flags |= LFS_F_ZOMBIE | LFS_F_UNSYNC | LFS_O_DESYNC;
opened->flags &= ~LFS_F_UNCREAT;
opened->mdir.mid = attrs[i].rid; opened->mdir.mid = attrs[i].rid;
} else { } else {
opened->mdir.mid += attrs[i].delta; opened->mdir.mid += attrs[i].delta;
@@ -8396,7 +8469,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
? LFSR_ATTR(mdir.mid, RM, -1, NULL()) ? LFSR_ATTR(mdir.mid, RM, -1, NULL())
: LFSR_ATTR_NOOP(), : LFSR_ATTR_NOOP(),
LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{ LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{
mdir.mid + ((exists) ? 1 : 0), mdir.mid,
-1}}))))); -1}})))));
if (err) { if (err) {
goto failed_with_bookmark; goto failed_with_bookmark;
@@ -8413,18 +8486,6 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
return err; return err;
} }
// mark any zombied files as created to avoid a remove from beyond
// the grave
for (lfsr_opened_t *opened = lfs->opened;
opened;
opened = opened->next) {
if (opened->type == LFS_TYPE_REG
&& opened->mdir.mid == mdir.mid) {
LFS_ASSERT(lfsr_f_iszombie(opened->flags));
opened->flags &= ~LFS_F_UNCREAT;
}
}
return 0; return 0;
failed_with_bookmark: failed_with_bookmark:
@@ -8712,15 +8773,15 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
return err; return err;
} }
// mark any zombied files as created to avoid a remove from beyond // update moved files with the new mdir
// the grave
for (lfsr_opened_t *opened = lfs->opened; for (lfsr_opened_t *opened = lfs->opened;
opened; opened;
opened = opened->next) { opened = opened->next) {
if (opened->type == LFS_TYPE_REG if (opened->type == LFS_TYPE_REG
&& opened->mdir.mid == new_mdir.mid) { // TODO should we have lfsr_grm_isrm or something?
LFS_ASSERT(lfsr_f_iszombie(opened->flags)); && (opened->mdir.mid == lfs->grm.rms[0]
opened->flags &= ~LFS_F_UNCREAT; || opened->mdir.mid == lfs->grm.rms[1])) {
opened->mdir = new_mdir;
} }
} }
@@ -9308,11 +9369,10 @@ int lfsr_file_open(lfs_t *lfs, lfsr_file_t *file,
int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file); int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file);
int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) { int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file) {
// don't call lfsr_file_sync if we're readonly, desynced, or zombied // don't call lfsr_file_sync if we're readonly or desynced
int err = 0; int err = 0;
if (!lfsr_o_isrdonly(file->flags) if (!lfsr_o_isrdonly(file->flags)
&& !lfsr_o_isdesync(file->flags) && !lfsr_o_isdesync(file->flags)) {
&& !lfsr_f_iszombie(file->flags)) {
err = lfsr_file_sync(lfs, file); err = lfsr_file_sync(lfs, file);
} }
@@ -11034,9 +11094,8 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
// notify all files of creation // notify all files of creation
file_->flags &= ~LFS_F_UNCREAT; file_->flags &= ~LFS_F_UNCREAT;
// mark desynced/zombied files an unsynced // mark desynced files an unsynced
if (lfsr_o_isdesync(file_->flags) if (lfsr_o_isdesync(file_->flags)) {
|| lfsr_f_iszombie(file_->flags)) {
file_->flags |= LFS_F_UNSYNC; file_->flags |= LFS_F_UNSYNC;
// update synced files // update synced files
+2 -2
View File
@@ -578,7 +578,7 @@ code = '''
# one purpose of this test is to check that data is not hidden # one purpose of this test is to check that data is not hidden
# and then revealed by truncate, that would be bad # and then revealed by truncate, that would be bad
[cases.test_fwrite_truncate_2] [cases.test_fwrite_truncate_truncate]
defines.FROM = [ defines.FROM = [
'0', '0',
'CACHE_SIZE/2', 'CACHE_SIZE/2',
@@ -832,7 +832,7 @@ code = '''
# one purpose of this test is to check that data is not hidden # one purpose of this test is to check that data is not hidden
# and then revealed by fruncate, that would be bad # and then revealed by fruncate, that would be bad
[cases.test_fwrite_fruncate_2] [cases.test_fwrite_fruncate_fruncate]
defines.FROM = [ defines.FROM = [
'0', '0',
'CACHE_SIZE/2', 'CACHE_SIZE/2',