libstore: simplify LocalStore::createTempRootsFile

we now create a temporary file, lock it, move it into place, and return.
if any of these steps (except creation) fails the GC must have found and
deleted our new file before we got the chance to use it. we don't need a
lock around file creation anymore, we especially don't need a mutex that
covers an flock call, and we don't need the GC to clobber what it finds.
(clobbering *is* kept for compatibility with older nix implementations.)

if we ever leave trash around it'll be cleaned up by some future gc run.

Change-Id: I078ae55fb7a9dfcdae28d6917d138842188ed528
This commit is contained in:
eldritch horrors
2025-02-14 15:28:50 +00:00
parent 406f4fed35
commit 84dd5864f3
+28 -24
View File
@@ -82,32 +82,36 @@ try {
void LocalStore::createTempRootsFile()
{
auto fdTempRoots(_fdTempRoots.lock());
if (auto fdTempRoots(_fdTempRoots.lock()); *fdTempRoots) {
return;
}
/* Create the temporary roots file for this process. */
if (*fdTempRoots) return;
while (1) {
if (pathExists(fnTempRoots))
/* It *must* be stale, since there can be no two
processes with the same pid. */
unlink(fnTempRoots.c_str());
*fdTempRoots = openLockFile(fnTempRoots, true);
debug("acquiring write lock on '%s'", fnTempRoots);
lockFile(fdTempRoots->get(), ltWrite);
/* Check whether the garbage collector didn't get in our
way. */
struct stat st;
if (fstat(fdTempRoots->get(), &st) == -1)
throw SysError("statting '%1%'", fnTempRoots);
if (st.st_size == 0) break;
/* The garbage collector deleted this file before we could get
a lock. (It won't delete the file after we get a lock.)
Try again. */
while (true) {
auto tmp = makeTempPath(fnTempRoots, ".tmp");
AutoCloseFD fd{open(tmp.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600)};
if (!fd && errno != EEXIST) {
throw SysError("opening lock file '%1%'", tmp);
}
// if we can't lock it then GC must've found and deleted it, so we try again.
// if we *can* lock it GC may have still deleted it, and rename will tell us.
if (!tryLockFile(fd.get(), ltWrite)) {
unlink(tmp.c_str()); // just to be sure it's gone
continue;
} else if (auto fdTempRoots(_fdTempRoots.lock()); *fdTempRoots) {
if (unlink(tmp.c_str()) == -1) {
throw SysError("deleting lock file '%1%'", tmp);
}
break;
} else if (rename(tmp.c_str(), fnTempRoots.c_str()) == -1) {
if (errno != ENOENT) {
throw SysError("moving lock file '%1%'", tmp);
}
} else {
debug("acquired write lock on '%s'", fnTempRoots);
*fdTempRoots = std::move(fd);
break;
}
}
}