WIP cleaned up commit logic

This commit is contained in:
Christopher Haster
2018-07-14 04:26:05 -05:00
parent 37cf030445
commit f1719e3310
2 changed files with 79 additions and 87 deletions

163
lfs.c
View File

@@ -457,16 +457,13 @@ static inline lfs_size_t lfs_tagsize(uint32_t tag) {
}
// operations on globals
static lfs_globals_t lfs_globals_xor(
const lfs_globals_t *a, const lfs_globals_t *b) {
lfs_globals_t res;
res.move.pair[0] = a->move.pair[0] ^ b->move.pair[0];
res.move.pair[1] = a->move.pair[1] ^ b->move.pair[1];
res.move.id = a->move.id ^ b->move.id;
return res;
static void lfs_globalsxor(lfs_globals_t *a, const lfs_globals_t *b) {
a->move.pair[0] ^= b->move.pair[0];
a->move.pair[1] ^= b->move.pair[1];
a->move.id ^= b->move.id;
}
static bool lfs_globals_iszero(const lfs_globals_t *a) {
static bool lfs_globalsiszero(const lfs_globals_t *a) {
return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0);
}
@@ -488,18 +485,8 @@ struct lfs_diskoff {
};
static int32_t lfs_commitget(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
uint32_t tag, uint32_t getmask, uint32_t gettag, void *buffer,
bool stopatcommit) {
uint16_t id = lfs_tagid(gettag);
lfs_size_t size = lfs_tagsize(gettag);
// synthetic moves
if ((block == lfs->globals.move.pair[0] ||
block == lfs->globals.move.pair[1])
&& lfs_tagid(gettag) <= lfs->globals.move.id) {
gettag += LFS_MKTAG(0, 1, 0);
}
uint32_t tag, uint32_t getmask, uint32_t gettag, int32_t difftag,
void *buffer, bool stopatcommit) {
// iterate over dir block backwards (for faster lookups)
while (off > sizeof(tag)) {
LFS_ASSERT(off > sizeof(tag)+lfs_tagsize(tag));
@@ -508,22 +495,24 @@ static int32_t lfs_commitget(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
if (lfs_tagtype(tag) == LFS_TYPE_CRC && stopatcommit) {
break;
} else if (lfs_tagtype(tag) == LFS_TYPE_DELETE) {
if (lfs_tagid(tag) <= lfs_tagid(gettag)) {
gettag += LFS_MKTAG(0, 1, 0);
if (lfs_tagid(tag) <= lfs_tagid(gettag + difftag)) {
difftag += LFS_MKTAG(0, 1, 0);
}
} else if ((tag & getmask) == (gettag & getmask)) {
} else if ((tag & getmask) == ((gettag + difftag) & getmask)) {
if (buffer) {
lfs_size_t diff = lfs_min(size, lfs_tagsize(tag));
lfs_size_t diff = lfs_min(
lfs_tagsize(gettag), lfs_tagsize(tag));
int err = lfs_bd_read(lfs, block,
off+sizeof(tag), buffer, diff);
if (err) {
return err;
}
memset((uint8_t*)buffer + diff, 0, size - diff);
memset((uint8_t*)buffer + diff, 0,
lfs_tagsize(gettag) - diff);
}
return (tag & 0xffc00fff) | LFS_MKTAG(0, id, 0);
return tag - difftag;
}
uint32_t ntag;
@@ -640,7 +629,8 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
int32_t res = lfs_commitget(lfs, commit->block,
commit->off, commit->ptag,
lfs_tagisuser(tag) ? 0x7ffff000 : 0x7c3ff000,
LFS_MKTAG(lfs_tagtype(tag), toid, 0), NULL, true);
LFS_MKTAG(lfs_tagtype(tag), toid, 0),
0, NULL, true);
if (res < 0 && res != LFS_ERR_NOENT) {
return res;
}
@@ -661,20 +651,16 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
}
static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit,
const lfs_globals_t *source, const lfs_globals_t *diff) {
if (lfs_globals_iszero(diff)) {
lfs_globals_t *locals) {
if (lfs_globalsiszero(&lfs->diff)) {
return 0;
}
// TODO check performance/complexity of different strategies here
lfs_globals_t res = lfs_globals_xor(source, diff);
lfs_globalsxor(locals, &lfs->diff);
int err = lfs_commitattr(lfs, commit,
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(res)), &res);
if (err) {
return err;
}
return 0;
LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(*locals)), locals);
lfs_globalsxor(locals, &lfs->diff);
return err;
}
static int lfs_commitcrc(lfs_t *lfs, struct lfs_commit *commit) {
@@ -754,7 +740,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
dir->tail[1] = tail[1];
dir->erased = false;
dir->split = split;
dir->globals = (lfs_globals_t){0};
dir->locals = (lfs_globals_t){0};
// don't write out yet, let caller take care of that
return 0;
@@ -769,11 +755,8 @@ static int lfs_dir_compact(lfs_t *lfs,
// There's nothing special about our global delta, so feed it back
// into the global global delta
// TODO IMMENSE HMM globals get bleed into from above, need to be fixed after commits due to potential moves
lfs_globals_t gtemp = dir->globals; // TODO hmm, why did we have different variables then?
lfs->diff = lfs_globals_xor(&lfs->diff, &dir->globals);
dir->globals = (lfs_globals_t){0};
lfs_globalsxor(&lfs->diff, &dir->locals);
dir->locals = (lfs_globals_t){0};
// increment revision count
dir->rev += 1;
@@ -812,27 +795,14 @@ static int lfs_dir_compact(lfs_t *lfs,
.crc = crc,
.ptag = 0,
// space is complicated, we need room for tail, crc, and we
// keep cap at around half a block
// space is complicated, we need room for tail, crc, globals,
// and we cap at half a block to give room for metadata updates
.begin = 0,
.end = lfs_min(
lfs_alignup(lfs->cfg->block_size/2, lfs->cfg->prog_size),
lfs->cfg->block_size - 5*sizeof(uint32_t)),
lfs->cfg->block_size - 34),
};
if (!relocated) {
err = lfs_commitglobals(lfs, &commit,
&dir->globals, &lfs->diff);
if (err) {
if (err == LFS_ERR_NOSPC) {
goto split;
} else if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
}
// commit with a move
for (uint16_t id = begin; id < end; id++) {
err = lfs_commitmove(lfs, &commit,
@@ -850,7 +820,17 @@ static int lfs_dir_compact(lfs_t *lfs,
}
// reopen reserved space at the end
commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t);
commit.end = lfs->cfg->block_size - 8;
if (!relocated) {
err = lfs_commitglobals(lfs, &commit, &dir->locals);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
}
if (!lfs_pairisnull(dir->tail)) {
// commit tail, which may be new after last size check
@@ -929,7 +909,11 @@ relocate:
continue;
}
if (relocated) {
if (!relocated) {
// successful commit, update globals
lfs_globalsxor(&dir->locals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
} else {
// update references if we relocated
LFS_DEBUG("Relocating %d %d to %d %d",
oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]);
@@ -937,13 +921,8 @@ relocate:
if (err) {
return err;
}
} else {
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
}
lfs->globals = lfs_globals_xor(&lfs->globals, &gtemp); // TODO hmm, why did we have different variables then?
return 0;
}
@@ -962,7 +941,7 @@ static int lfs_dir_commit(lfs_t *lfs,
.ptag = dir->etag,
.begin = dir->off,
.end = lfs->cfg->block_size - 2*sizeof(uint32_t),
.end = lfs->cfg->block_size - 8,
};
for (const lfs_mattr_t *a = attrs; a; a = a->next) {
@@ -975,7 +954,7 @@ static int lfs_dir_commit(lfs_t *lfs,
}
}
int err = lfs_commitglobals(lfs, &commit, &dir->globals, &lfs->diff);
int err = lfs_commitglobals(lfs, &commit, &dir->locals);
if (err) {
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
goto compact;
@@ -991,12 +970,11 @@ static int lfs_dir_commit(lfs_t *lfs,
return err;
}
// successful commit, lets update dir
// successful commit, update dir
dir->off = commit.off;
dir->etag = commit.ptag;
// // TODO hm
// dir->globals = lfs_globals_xor(&dir->globals, &lfs->diff);
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
// successful commit, update globals
lfs_globalsxor(&dir->locals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
break;
@@ -1053,7 +1031,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
dir->tail[1] = 0xffffffff;
dir->count = 0;
dir->split = false;
dir->globals = (lfs_globals_t){0};
dir->locals = (lfs_globals_t){0};
dir->rev = lfs_tole32(rev[0]);
lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
@@ -1131,7 +1109,7 @@ static int32_t lfs_dir_find(lfs_t *lfs,
}
} else if (lfs_tagtype(tag) == LFS_TYPE_GLOBALS) {
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
&tempdir.globals, sizeof(tempdir.globals));
&tempdir.locals, sizeof(tempdir.locals));
if (err) {
return err;
}
@@ -1196,8 +1174,15 @@ static int lfs_dir_fetch(lfs_t *lfs,
static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
uint32_t getmask, uint32_t gettag, void *buffer) {
int32_t difftag = 0;
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0 &&
lfs_tagid(gettag) <= lfs->globals.move.id) {
// synthetic moves
difftag = LFS_MKTAG(0, 1, 0);
}
return lfs_commitget(lfs, dir->pair[0], dir->off, dir->etag,
getmask, gettag, buffer, false);
getmask, gettag, difftag, buffer, false);
}
static int lfs_dir_append(lfs_t *lfs, lfs_mdir_t *dir, uint16_t *id) {
@@ -1218,12 +1203,11 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
}
if (err != LFS_ERR_NOENT && pdir.split) {
// steal tail, and global state
// steal tail and global state
pdir.split = dir->split;
pdir.tail[0] = dir->tail[0];
pdir.tail[1] = dir->tail[1];
lfs->diff = dir->globals;
lfs->globals = lfs_globals_xor(&lfs->globals, &dir->globals);
lfs_globalsxor(&lfs->diff, &dir->locals);
return lfs_dir_commit(lfs, &pdir,
LFS_MKATTR(LFS_TYPE_TAIL + pdir.split, 0x3ff,
@@ -2617,6 +2601,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0];
lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1];
lfs->diff.move.id = lfs_tagid(oldtag) ^ lfs->globals.move.id;
lfs->globals.move.pair[0] = oldcwd.pair[0];
lfs->globals.move.pair[1] = oldcwd.pair[1];
lfs->globals.move.id = lfs_tagid(oldtag);
// move over all attributes
int err = lfs_dir_commit(lfs, &newcwd,
@@ -2639,9 +2626,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
return err;
}
// TODO test for global state stealing?
// steal global state
lfs->globals = lfs_globals_xor(&lfs->globals, &prevdir.globals);
// TODO test for global state stealing?
lfs_globalsxor(&lfs->diff, &prevdir.locals);
newcwd.tail[0] = prevdir.tail[0];
newcwd.tail[1] = prevdir.tail[1];
@@ -2792,8 +2779,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->deorphaned = false;
lfs->globals.move.pair[0] = 0xffffffff;
lfs->globals.move.pair[1] = 0xffffffff;
lfs->globals.move.id = 0x3ff;
lfs->diff = (lfs_globals_t){0};
lfs->globals.move.id = 0x3ff;
// scan for any global updates
// TODO rm me? need to grab any inits
@@ -3202,6 +3188,7 @@ static int lfs_relocate(lfs_t *lfs,
return err;
}
// if we can't find dir, it must be new
if (err != LFS_ERR_NOENT) {
// just replace bad pair, no desync can occur
parent.tail[0] = newpair[0];
@@ -3226,7 +3213,6 @@ static int lfs_relocate(lfs_t *lfs,
}
}
// couldn't find dir, must be new
return 0;
}
@@ -3236,7 +3222,7 @@ int lfs_scan(lfs_t *lfs) {
}
lfs_mdir_t dir = {.tail = {0, 1}};
lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}};
lfs->diff = (lfs_globals_t){0};
// iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) {
@@ -3246,11 +3232,13 @@ int lfs_scan(lfs_t *lfs) {
}
// xor together indirect deletes
globals = lfs_globals_xor(&globals, &dir.globals);
lfs_globalsxor(&lfs->diff, &dir.locals);
}
// update littlefs with globals
lfs->globals = globals;
// TODO does this only run once?
// TODO Should we inline this into init??
lfs_globalsxor(&lfs->globals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
if (!lfs_pairisnull(lfs->globals.move.pair)) {
LFS_DEBUG("Found move %d %d %d",
@@ -3285,6 +3273,9 @@ int lfs_fixmove(lfs_t *lfs) {
return err;
}
lfs->globals.move.pair[0] = 0xffffffff;
lfs->globals.move.pair[1] = 0xffffffff;
lfs->globals.move.id = 0x3ff;
return 0;
}

3
lfs.h
View File

@@ -284,7 +284,7 @@ typedef struct lfs_mdir {
uint16_t count;
bool erased;
bool split;
lfs_globals_t globals;
lfs_globals_t locals;
} lfs_mdir_t;
typedef struct lfs_cache {
@@ -353,6 +353,7 @@ typedef struct lfs {
lfs_free_t free;
bool deorphaned;
lfs_globals_t globals2;
lfs_globals_t globals;
lfs_globals_t diff;