WIP Moved findscan into fetch as primitive

This commit is contained in:
Christopher Haster
2018-07-10 13:07:47 -05:00
parent 43e6aadef6
commit 5152b973f0

207
lfs.c
View File

@@ -507,8 +507,11 @@ static int lfs_commit_commit(lfs_t *lfs,
attr.u.dir, NULL); attr.u.dir, NULL);
} }
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin; if (lfs_tag_id(attr.tag) != 0x3ff) {
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff); // TODO eh?
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin;
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff);
}
// check if we fit // check if we fit
lfs_size_t size = lfs_tag_size(attr.tag); lfs_size_t size = lfs_tag_size(attr.tag);
@@ -757,12 +760,14 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
return 0; return 0;
} }
static int lfs_dir_fetchwith(lfs_t *lfs, static int lfs_dir_find(lfs_t *lfs,
lfs_mdir_t *dir, const lfs_block_t pair[2], lfs_mdir_t *dir, const lfs_block_t pair[2],
int (*cb)(lfs_t *lfs, void *data, lfs_mattr_t attr), void *data) { uint32_t findmask, lfs_tag_t findtag,
const void *findbuffer, lfs_tag_t *foundtag) {
dir->pair[0] = pair[0]; dir->pair[0] = pair[0];
dir->pair[1] = pair[1]; dir->pair[1] = pair[1];
dir->stop_at_commit = false; dir->stop_at_commit = false;
*foundtag = 0xffffffff;
// find the block with the most recent revision // find the block with the most recent revision
uint32_t rev[2]; uint32_t rev[2];
@@ -794,12 +799,14 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
lfs_crc(&crc, &dir->rev, sizeof(dir->rev)); lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
dir->rev = lfs_fromle32(dir->rev); dir->rev = lfs_fromle32(dir->rev);
lfs_mdir_t temp = *dir; lfs_mdir_t tempdir = *dir;
lfs_tag_t tempfoundtag = *foundtag;
while (true) { while (true) {
// extract next tag // extract next tag
lfs_tag_t tag; lfs_tag_t tag;
int err = lfs_bd_read(lfs, temp.pair[0], off, &tag, sizeof(tag)); int err = lfs_bd_read(lfs, tempdir.pair[0],
off, &tag, sizeof(tag));
if (err) { if (err) {
return err; return err;
} }
@@ -809,19 +816,8 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
// next commit not yet programmed // next commit not yet programmed
if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_isvalid(tag)) { if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_isvalid(tag)) {
// synthetic move
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
&& cb) {
int err = cb(lfs, data, (lfs_mattr_t){
lfs_mktag(LFS_TYPE_DELETE,
lfs->globals.move.id, 0)});
if (err) {
return err;
}
}
dir->erased = true; dir->erased = true;
return 0; goto done;
} }
// check we're in valid range // check we're in valid range
@@ -829,93 +825,75 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
break; break;
} }
//printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, temp.pair[0], off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
if (lfs_tag_type(tag) == LFS_TYPE_CRC) { if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
// check the crc attr // check the crc attr
uint32_t dcrc; uint32_t dcrc;
int err = lfs_bd_read(lfs, temp.pair[0], int err = lfs_bd_read(lfs, tempdir.pair[0],
off+sizeof(tag), &dcrc, sizeof(dcrc)); off+sizeof(tag), &dcrc, sizeof(dcrc));
if (err) { if (err) {
return err; return err;
} }
if (crc != lfs_fromle32(dcrc)) { if (crc != lfs_fromle32(dcrc)) {
if (off == sizeof(temp.rev)) { if (off == sizeof(tempdir.rev)) {
// try other block // try other block
break; break;
} else { } else {
// snythetic move
// TODO combine with above?
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
&& cb) {
int err = cb(lfs, data, (lfs_mattr_t){
lfs_mktag(LFS_TYPE_DELETE,
lfs->globals.move.id, 0)});
if (err) {
return err;
}
}
// consider what we have good enough // consider what we have good enough
dir->erased = false; dir->erased = false;
return 0; goto done;
} }
} }
temp.off = off + sizeof(tag)+lfs_tag_size(tag); tempdir.off = off + sizeof(tag)+lfs_tag_size(tag);
temp.etag = tag; tempdir.etag = tag;
crc = 0xffffffff; crc = 0xffffffff;
*dir = temp; *dir = tempdir;
*foundtag = tempfoundtag;
// TODO simplify this?
if (cb) {
err = cb(lfs, data, (lfs_mattr_t){
(tag | 0x80000000),
.u.d.block=temp.pair[0],
.u.d.off=off+sizeof(tag)});
if (err) {
return err;
}
}
} else { } else {
// TODO crc before callback??? err = lfs_bd_crc(lfs, tempdir.pair[0],
err = lfs_bd_crc(lfs, temp.pair[0],
off+sizeof(tag), lfs_tag_size(tag), &crc); off+sizeof(tag), lfs_tag_size(tag), &crc);
if (err) { if (err) {
return err; return err;
} }
if (lfs_tag_id(tag) < 0x3ff &&
lfs_tag_id(tag) >= tempdir.count) {
tempdir.count = lfs_tag_id(tag)+1;
}
if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) { if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) {
temp.split = (lfs_tag_type(tag) & 1); tempdir.split = (lfs_tag_type(tag) & 1);
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag), err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
temp.tail, sizeof(temp.tail)); tempdir.tail, sizeof(tempdir.tail));
if (err) { if (err) {
return err; return err;
} }
} else if (lfs_tag_type(tag) == LFS_TYPE_GLOBALS) { } else if (lfs_tag_type(tag) == LFS_TYPE_GLOBALS) {
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag), err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
&temp.globals, sizeof(temp.globals)); &tempdir.globals, sizeof(tempdir.globals));
if (err) { if (err) {
return err; return err;
} }
} else { } else if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
if (lfs_tag_id(tag) < 0x3ff && tempdir.count -= 1;
lfs_tag_id(tag) >= temp.count) {
temp.count = lfs_tag_id(tag)+1; if (lfs_tag_id(tag) == lfs_tag_id(tempfoundtag)) {
tempfoundtag = 0xffffffff;
} else if (lfs_tag_id(tempfoundtag) < 0x3ff &&
lfs_tag_id(tag) < lfs_tag_id(tempfoundtag)) {
tempfoundtag -= lfs_mktag(0, 1, 0);
}
} else if ((tag & findmask) == (findtag & findmask)) {
int res = lfs_bd_cmp(lfs, tempdir.pair[0], off+sizeof(tag),
findbuffer, lfs_tag_size(tag));
if (res < 0) {
return res;
} }
if (lfs_tag_type(tag) == LFS_TYPE_DELETE) { if (res) {
temp.count -= 1; // found a match
} tempfoundtag = tag;
if (cb) {
err = cb(lfs, data, (lfs_mattr_t){
(tag | 0x80000000),
.u.d.block=temp.pair[0],
.u.d.off=off+sizeof(tag)});
if (err) {
return err;
}
} }
} }
} }
@@ -931,11 +909,34 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]); LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
return LFS_ERR_CORRUPT; return LFS_ERR_CORRUPT;
done:
// synthetic move
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) {
if (lfs->globals.move.id == lfs_tag_id(*foundtag)) {
*foundtag = 0xffffffff;
} else if (lfs_tag_id(*foundtag) < 0x3ff &&
lfs->globals.move.id < lfs_tag_id(*foundtag)) {
*foundtag -= lfs_mktag(0, 1, 0);
}
}
if (*foundtag == 0xffffffff) {
return LFS_ERR_NOENT;
}
return 0;
} }
static int lfs_dir_fetch(lfs_t *lfs, static int lfs_dir_fetch(lfs_t *lfs,
lfs_mdir_t *dir, const lfs_block_t pair[2]) { lfs_mdir_t *dir, const lfs_block_t pair[2]) {
return lfs_dir_fetchwith(lfs, dir, pair, NULL, NULL); int err = lfs_dir_find(lfs, dir, pair,
0xffffffff, 0xffffffff, NULL, &(lfs_tag_t){0});
if (err && err != LFS_ERR_NOENT) {
return err;
}
return 0;
} }
static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir, static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
@@ -1115,6 +1116,8 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
break; break;
split: split:
// TODO update dirs that get split here?
// commit no longer fits, need to split dir, // commit no longer fits, need to split dir,
// drop caches and create tail // drop caches and create tail
lfs->pcache.block = 0xffffffff; lfs->pcache.block = 0xffffffff;
@@ -1414,66 +1417,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
return 0; return 0;
} }
struct lfs_dir_find {
uint32_t mask;
lfs_tag_t tag;
const void *buffer;
lfs_tag_t foundtag;
lfs_tag_t temptag;
};
static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
struct lfs_dir_find *find = p;
if ((attr.tag & find->mask) == (find->tag & find->mask)) {
int res = lfs_bd_cmp(lfs, attr.u.d.block, attr.u.d.off,
find->buffer, lfs_tag_size(attr.tag));
if (res < 0) {
return res;
}
if (res) {
// found a match
find->temptag = attr.tag;
}
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_DELETE) {
if (lfs_tag_id(attr.tag) == lfs_tag_id(find->temptag)) {
find->temptag = 0xffffffff;
} else if (lfs_tag_id(find->temptag) < 0x3ff &&
lfs_tag_id(attr.tag) < lfs_tag_id(find->temptag)) {
find->temptag -= lfs_mktag(0, 1, 0);
}
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_CRC) {
find->foundtag = find->temptag;
}
return 0;
}
static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, const lfs_block_t *pair,
uint32_t mask, lfs_tag_t tag,
const void *buffer, lfs_tag_t *foundtag) {
struct lfs_dir_find find = {
.mask = mask,
.tag = tag,
.buffer = buffer,
.foundtag = 0xffffffff,
.temptag = 0xffffffff,
};
int err = lfs_dir_fetchwith(lfs, dir, pair, lfs_dir_findscan, &find);
if (err) {
return err;
}
if (find.foundtag == 0xffffffff) {
return LFS_ERR_NOENT;
}
*foundtag = find.foundtag;
return 0;
}
// TODO drop others, make this only return id, also make get take in only entry to populate (with embedded tag) // TODO drop others, make this only return id, also make get take in only entry to populate (with embedded tag)
static int lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, static int lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir,