Report grmed mids as orphaned at the mdir level

By moving this to such a low-level, this ensures consistent reporting of
grms without needed special cases in every high-level function.

The use of the orphan type is very convenient here, as it avoids a whole
category of potential bugs around mismatched mids<->mdir weights.

Also added lfsr_grm_isrm, though ironically it has less use after these
changes.

This required duplication of some rbyd/mdir lookup convenience
functions, so unfortunately it's not a win code-wise, but I think the
resilience to future bugs is worth it.

Heck, it already revealed one minor bug in the return value of
lfsr_mtree_pathlookup when an intermediary path name is grmed/orphaned:

            code          stack
  before:  33812           2944
  after:   33944 (+0.4%)   2944 (+0.0%)
This commit is contained in:
Christopher Haster
2024-01-18 12:34:55 -06:00
parent 033d5545e9
commit a17b5e3cd6
+72 -40
View File
@@ -1842,6 +1842,10 @@ static inline void lfsr_grm_poprm(lfsr_grm_t *grm) {
grm->rms[1] = -1; grm->rms[1] = -1;
} }
static inline bool lfsr_grm_isrm(const lfsr_grm_t *grm, lfsr_smid_t mid) {
return grm->rms[0] == mid || grm->rms[1] == mid;
}
static inline bool lfsr_grm_iszero( static inline bool lfsr_grm_iszero(
const uint8_t gdelta[static LFSR_GRM_DSIZE]) { const uint8_t gdelta[static LFSR_GRM_DSIZE]) {
return lfsr_gdelta_iszero(gdelta, LFSR_GRM_DSIZE); return lfsr_gdelta_iszero(gdelta, LFSR_GRM_DSIZE);
@@ -5088,14 +5092,17 @@ static int lfsr_mdir_lookupnext(lfs_t *lfs, const lfsr_mdir_t *mdir,
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
if (tag_) {
// intercept pending grms here and pretend they're orphaned files // intercept pending grms here and pretend they're orphaned files
// //
// fortunately pending grms/orphaned files have roughly the same // fortunately pending grms/orphaned files have roughly the same
// semantics, and it's easier to manage the implied mid gap in // semantics, and it's easier to manage the implied mid gap in
// higher-levels // higher-levels
// TODO if (lfsr_tag_suptype(tag__) == LFSR_TAG_NAME
&& lfsr_grm_isrm(&lfs->grm, mid)) {
tag__ = LFSR_TAG_ORPHAN;
}
if (tag_) {
*tag_ = tag__; *tag_ = tag__;
} }
return 0; return 0;
@@ -5104,17 +5111,45 @@ static int lfsr_mdir_lookupnext(lfs_t *lfs, const lfsr_mdir_t *mdir,
static int lfsr_mdir_lookup(lfs_t *lfs, const lfsr_mdir_t *mdir, static int lfsr_mdir_lookup(lfs_t *lfs, const lfsr_mdir_t *mdir,
lfsr_smid_t mid, lfsr_tag_t tag, lfsr_smid_t mid, lfsr_tag_t tag,
lfsr_data_t *data_) { lfsr_data_t *data_) {
return lfsr_rbyd_lookup(lfs, &mdir->rbyd, lfsr_tag_t tag_;
lfsr_mid_rid(lfs, mid), tag, int err = lfsr_mdir_lookupnext(lfs, mdir, mid, tag,
data_); &tag_, data_);
if (err) {
return err;
}
// lookup finds the next-smallest tag, all we need to do is fail if it
// picks up the wrong tag
if (tag_ != tag) {
return LFS_ERR_NOENT;
}
return 0;
} }
static int lfsr_mdir_lookupwide(lfs_t *lfs, const lfsr_mdir_t *mdir, static int lfsr_mdir_lookupwide(lfs_t *lfs, const lfsr_mdir_t *mdir,
lfsr_smid_t mid, lfsr_tag_t tag, lfsr_smid_t mid, lfsr_tag_t tag,
lfsr_tag_t *tag_, lfsr_data_t *data_) { lfsr_tag_t *tag_, lfsr_data_t *data_) {
return lfsr_rbyd_lookupwide(lfs, &mdir->rbyd, // looking up a wide tag with subtype is probably a mistake
lfsr_mid_rid(lfs, mid), tag, LFS_ASSERT(lfsr_tag_subtype(tag) == 0);
tag_, data_);
lfsr_tag_t tag__;
int err = lfsr_mdir_lookupnext(lfs, mdir, mid, tag,
&tag__, data_);
if (err) {
return err;
}
// the difference between lookup and lookupwide is we accept any
// subtype of the requested tag
if (lfsr_tag_suptype(tag__) != tag) {
return LFS_ERR_NOENT;
}
if (tag_) {
*tag_ = tag__;
}
return 0;
} }
// track opened mdirs to keep state in-sync // track opened mdirs to keep state in-sync
@@ -5261,13 +5296,6 @@ static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) {
} }
mdir->mid = bid-(lfsr_mweight(lfs)-1) + rid; mdir->mid = bid-(lfsr_mweight(lfs)-1) + rid;
// wait are we grmed? pretend this mid doesn't exist
if (mdir->mid == lfs->grm.rms[0]
|| mdir->mid == lfs->grm.rms[1]) {
continue;
}
return 0; return 0;
} }
} }
@@ -6772,11 +6800,11 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// if not found, rid will be the best place to insert // if not found, rid will be the best place to insert
static int lfsr_mdir_namelookup(lfs_t *lfs, const lfsr_mdir_t *mdir, static int lfsr_mdir_namelookup(lfs_t *lfs, const lfsr_mdir_t *mdir,
lfsr_did_t did, const char *name, lfs_size_t name_size, lfsr_did_t did, const char *name, lfs_size_t name_size,
lfsr_srid_t *rid_, lfsr_tag_t *tag_, lfsr_data_t *data_) { lfsr_smid_t *mid_, lfsr_tag_t *tag_, lfsr_data_t *data_) {
// default to rid_ = 0, this blanket assignment is the only way to // default to mid_ = 0, this blanket assignment is the only way to
// keep GCC happy // keep GCC happy
if (rid_) { if (mid_) {
*rid_ = 0; *mid_ = 0;
} }
// empty mdir? // empty mdir?
@@ -6785,21 +6813,35 @@ static int lfsr_mdir_namelookup(lfs_t *lfs, const lfsr_mdir_t *mdir,
} }
lfsr_srid_t rid; lfsr_srid_t rid;
lfsr_tag_t tag;
lfs_scmp_t cmp = lfsr_rbyd_namelookup(lfs, &mdir->rbyd, lfs_scmp_t cmp = lfsr_rbyd_namelookup(lfs, &mdir->rbyd,
did, name, name_size, did, name, name_size,
&rid, tag_, NULL, data_); &rid, &tag, NULL, data_);
if (cmp < 0) { if (cmp < 0) {
LFS_ASSERT(cmp != LFS_ERR_NOENT); LFS_ASSERT(cmp != LFS_ERR_NOENT);
return cmp; return cmp;
} }
// adjust rid if necessary // adjust mid if necessary
if (lfs_cmp(cmp) < 0) { if (lfs_cmp(cmp) < 0) {
rid += 1; rid += 1;
} }
lfsr_smid_t mid = lfsr_mdir_bid(lfs, mdir)-(lfsr_mweight(lfs)-1) + rid;
if (rid_) { // intercept pending grms here and pretend they're orphaned files
*rid_ = rid; //
// fortunately pending grms/orphaned files have roughly the same
// semantics, and it's easier to manage the implied mid gap in
// higher-levels
if (lfsr_grm_isrm(&lfs->grm, mid)) {
tag = LFSR_TAG_ORPHAN;
}
if (mid_) {
*mid_ = mid;
}
if (tag_) {
*tag_ = tag;
} }
return (lfs_cmp(cmp) == 0) ? 0 : LFS_ERR_NOENT; return (lfs_cmp(cmp) == 0) ? 0 : LFS_ERR_NOENT;
} }
@@ -6855,33 +6897,23 @@ static int lfsr_mtree_namelookup(lfs_t *lfs,
} }
// and finally lookup name in our mdir // and finally lookup name in our mdir
lfsr_srid_t rid; lfsr_smid_t mid;
int err = lfsr_mdir_namelookup(lfs, &mdir, int err = lfsr_mdir_namelookup(lfs, &mdir,
did, name, name_size, did, name, name_size,
&rid, tag_, data_); &mid, tag_, data_);
if (err && err != LFS_ERR_NOENT) { if (err && err != LFS_ERR_NOENT) {
return err; return err;
} }
// update mdir with best place to insert even if we fail // update mdir with best place to insert even if we fail
mdir.mid += rid; mdir.mid = mid;
if (mdir_) { if (mdir_) {
*mdir_ = mdir; *mdir_ = mdir;
} }
if (err) {
return err; return err;
} }
// wait are we grmed? pretend this mid doesn't exist
if (mdir.mid == lfs->grm.rms[0]
|| mdir.mid == lfs->grm.rms[1]) {
return LFS_ERR_NOENT;
}
return 0;
}
// special directory-ids // special directory-ids
enum { enum {
@@ -6961,7 +6993,9 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path,
// only continue if we hit a directory // only continue if we hit a directory
if (tag != LFSR_TAG_DIR) { if (tag != LFSR_TAG_DIR) {
return LFS_ERR_NOTDIR; return (tag == LFSR_TAG_ORPHAN)
? LFS_ERR_NOENT
: LFS_ERR_NOTDIR;
} }
// read the next did from the mdir if this is not the root // read the next did from the mdir if this is not the root
@@ -8765,9 +8799,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
opened; opened;
opened = opened->next) { opened = opened->next) {
if (opened->type == LFS_TYPE_REG if (opened->type == LFS_TYPE_REG
// TODO should we have lfsr_grm_isrm or something? && lfsr_grm_isrm(&lfs->grm, opened->mdir.mid)) {
&& (opened->mdir.mid == lfs->grm.rms[0]
|| opened->mdir.mid == lfs->grm.rms[1])) {
opened->mdir = new_mdir; opened->mdir = new_mdir;
} }
} }