Changed namelookup functions to include a directory-id
The plan is that names in littlefs now include a directory-id prefixed
as a single leb128.
01 66 69 6c 65 2e 74 78 74 .file.txt
^ '----------+----------'
'------------|------------ leb128 directory-id
'------------ ascii/utf8 name
Unfortunately, while this is easy for read/compare operations to implement,
it creates a bit of a problem for writes. We can't allocate a new buffer
for each name, so we need some sort of extra mechanism.
The solution here is to just add a did member to lfsr_data_t that is
written when non-negative. This works, though it does introduce some
complexity.
Fortunately, did in lfsr_data_t is somewhat free when
sizeof(void*) == sizeof(lfs_size_t), due to the union with disk
references.
This commit is contained in:
@@ -1001,6 +1001,7 @@ typedef union lfsr_data {
|
||||
struct {
|
||||
lfs_size_t size;
|
||||
const uint8_t *buffer;
|
||||
lfs_ssize_t did;
|
||||
} buf;
|
||||
struct {
|
||||
lfs_size_t size;
|
||||
@@ -1009,13 +1010,20 @@ typedef union lfsr_data {
|
||||
} disk;
|
||||
} lfsr_data_t;
|
||||
|
||||
#define LFSR_DATA_NULL \
|
||||
((lfsr_data_t){.size=0})
|
||||
#define LFSR_DATA_NULL LFSR_DATA_BUF(NULL, 0)
|
||||
|
||||
#define LFSR_DATA_BUF(_buffer, _size) \
|
||||
((lfsr_data_t){.buf={ \
|
||||
.size=_size, \
|
||||
.buffer=(const void*)(_buffer)}})
|
||||
.buffer=(const void*)(_buffer), \
|
||||
.did=-1}})
|
||||
|
||||
#define LFSR_DATA_DNAME(_did, _buffer, _size) \
|
||||
((lfsr_data_t){.buf={ \
|
||||
/* note this find the effective leb128 size */ \
|
||||
.size=_size + lfs_min32(lfs_nlog2(_did)/7, 1), \
|
||||
.buffer=(const void*)(_buffer), \
|
||||
.did=_did}})
|
||||
|
||||
#define LFSR_DATA_DISK(_block, _off, _size) \
|
||||
((lfsr_data_t){.disk={ \
|
||||
@@ -1114,7 +1122,26 @@ static lfs_scmp_t lfsr_data_cmp(lfs_t *lfs, lfsr_data_t data,
|
||||
}
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfsr_bd_progdata(lfs_t *lfs,
|
||||
static lfs_scmp_t lfsr_data_dnamecmp(lfs_t *lfs, lfsr_data_t data,
|
||||
lfs_off_t off, lfs_size_t did, const char *name, lfs_size_t name_size) {
|
||||
// first compare the did
|
||||
lfs_size_t did_;
|
||||
lfs_ssize_t d = lfsr_data_readleb128(lfs, data, off, &did_);
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if (did_ < did) {
|
||||
return LFS_CMP_LT;
|
||||
} else if (did_ > did) {
|
||||
return LFS_CMP_GT;
|
||||
}
|
||||
|
||||
// next compare the actual name
|
||||
return lfsr_data_cmp(lfs, data, off+d, name, name_size);
|
||||
}
|
||||
|
||||
static int lfsr_bd_progdata(lfs_t *lfs,
|
||||
lfs_block_t block, lfs_off_t off,
|
||||
lfsr_data_t data,
|
||||
uint32_t *csum_) {
|
||||
@@ -1140,6 +1167,25 @@ static lfs_ssize_t lfsr_bd_progdata(lfs_t *lfs,
|
||||
}
|
||||
|
||||
} else {
|
||||
// this is kind of a hack, but when lfsr_data_t is in buffer mode, it
|
||||
// can also contain a leb128 encoded directory-id prefix
|
||||
if (data.buf.did != -1) {
|
||||
// TODO should progleb128 be its own function? rely on caching?
|
||||
uint8_t buf[5];
|
||||
lfs_ssize_t d = lfs_toleb128(data.buf.did, buf, 5);
|
||||
if (d < 0) {
|
||||
return d;
|
||||
}
|
||||
|
||||
int err = lfsr_bd_prog(lfs, block, off, buf, d, csum_);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
off += d;
|
||||
data.buf.size -= d;
|
||||
}
|
||||
|
||||
int err = lfsr_bd_prog(lfs, block, off,
|
||||
data.buf.buffer, lfsr_data_size(data),
|
||||
csum_);
|
||||
@@ -3068,10 +3114,16 @@ static int lfsr_rbyd_isdegenerate(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// some low-level dname things
|
||||
//
|
||||
// dnames in littlefs are tuples of directory-ids + ascii/utf8 strings
|
||||
|
||||
|
||||
// binary search an rbyd for a name, leaving the id_/weight_ with the best
|
||||
// matching name if not found
|
||||
static int lfsr_rbyd_namelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
const char *name, lfs_size_t name_size,
|
||||
static int lfsr_rbyd_dnamelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
lfs_size_t did, const char *name, lfs_size_t name_size,
|
||||
lfs_ssize_t *id_, lfsr_tag_t *tag_, lfs_size_t *weight_,
|
||||
lfsr_data_t *data_) {
|
||||
// binary search for our name
|
||||
@@ -3101,7 +3153,7 @@ static int lfsr_rbyd_namelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd,
|
||||
|
||||
// compare names
|
||||
} else {
|
||||
cmp = lfsr_data_cmp(lfs, data__, 0, name, name_size);
|
||||
cmp = lfsr_data_dnamecmp(lfs, data__, 0, did, name, name_size);
|
||||
if (cmp < 0) {
|
||||
return cmp;
|
||||
}
|
||||
@@ -3505,8 +3557,8 @@ static int lfsr_btree_parent(lfs_t *lfs,
|
||||
}
|
||||
}
|
||||
|
||||
static lfs_ssize_t lfsr_btree_namelookup(lfs_t *lfs, const lfsr_btree_t *btree,
|
||||
const char *name, lfs_size_t name_size,
|
||||
static lfs_ssize_t lfsr_btree_dnamelookup(lfs_t *lfs, const lfsr_btree_t *btree,
|
||||
lfs_size_t did, const char *name, lfs_size_t name_size,
|
||||
lfs_size_t *bid_, lfsr_tag_t *tag_, lfs_size_t *weight_,
|
||||
lfsr_data_t *data_) {
|
||||
// an empty tree?
|
||||
@@ -3539,7 +3591,7 @@ static lfs_ssize_t lfsr_btree_namelookup(lfs_t *lfs, const lfsr_btree_t *btree,
|
||||
// lookup our name in the rbyd via binary search
|
||||
lfs_ssize_t rid__;
|
||||
lfs_size_t weight__;
|
||||
int err = lfsr_rbyd_namelookup(lfs, &branch, name, name_size,
|
||||
int err = lfsr_rbyd_dnamelookup(lfs, &branch, did, name, name_size,
|
||||
&rid__, NULL, &weight__, NULL);
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user