libstore: add async path locking
just single path locks for now since we don't need more. Change-Id: I0f1be156e762fbe7355dc1381295a7b276bad720
This commit is contained in:
@@ -2301,7 +2301,7 @@ try {
|
||||
worker.store.printStorePath(*optFixedPath) != finalDestPath)
|
||||
{
|
||||
assert(newInfo.ca);
|
||||
dynamicOutputLock = lockPath(worker.store.toRealPath(finalDestPath));
|
||||
dynamicOutputLock = TRY_AWAIT(lockPathAsync(worker.store.toRealPath(finalDestPath)));
|
||||
}
|
||||
|
||||
/* Move files, if needed */
|
||||
|
||||
+36
-13
@@ -132,6 +132,25 @@ void unlockFile(int fd)
|
||||
}
|
||||
|
||||
|
||||
static bool isPathLockValid(AutoCloseFD & fd, const Path & lockPath)
|
||||
{
|
||||
/* Check that the lock file hasn't become stale (i.e.,
|
||||
hasn't been unlinked). */
|
||||
struct stat st;
|
||||
if (fstat(fd.get(), &st) == -1)
|
||||
throw SysError("statting lock file '%1%'", lockPath);
|
||||
if (st.st_nlink == 0) {
|
||||
/* This lock file has been unlinked, so we're holding
|
||||
a lock on a deleted file. This means that other
|
||||
processes may create and acquire a lock on
|
||||
`lockPath', and proceed. So we must retry. */
|
||||
debug("open lock file '%1%' has become stale", lockPath);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<PathLock>
|
||||
PathLock::lockImpl(const Path & path, std::string_view waitMsg, bool wait)
|
||||
{
|
||||
@@ -155,23 +174,27 @@ PathLock::lockImpl(const Path & path, std::string_view waitMsg, bool wait)
|
||||
}
|
||||
|
||||
debug("lock acquired on '%1%'", lockPath);
|
||||
|
||||
/* Check that the lock file hasn't become stale (i.e.,
|
||||
hasn't been unlinked). */
|
||||
struct stat st;
|
||||
if (fstat(fd.get(), &st) == -1)
|
||||
throw SysError("statting lock file '%1%'", lockPath);
|
||||
if (st.st_nlink == 0)
|
||||
/* This lock file has been unlinked, so we're holding
|
||||
a lock on a deleted file. This means that other
|
||||
processes may create and acquire a lock on
|
||||
`lockPath', and proceed. So we must retry. */
|
||||
debug("open lock file '%1%' has become stale", lockPath);
|
||||
else
|
||||
if (isPathLockValid(fd, lockPath))
|
||||
return PathLock{std::move(fd), lockPath};
|
||||
}
|
||||
}
|
||||
|
||||
kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg)
|
||||
try {
|
||||
Path lockPath = path + ".lock";
|
||||
debug("locking path '%1%'", path);
|
||||
|
||||
while (1) {
|
||||
auto fd = openLockFile(lockPath, true);
|
||||
TRY_AWAIT(lockFileAsync(fd.get(), ltWrite));
|
||||
debug("lock acquired on '%1%'", lockPath);
|
||||
if (isPathLockValid(fd, lockPath))
|
||||
co_return PathLock{std::move(fd), lockPath};
|
||||
}
|
||||
} catch (...) {
|
||||
co_return result::current_exception();
|
||||
}
|
||||
|
||||
PathLock lockPath(const Path & path, std::string_view waitMsg)
|
||||
{
|
||||
return std::move(*PathLock::lockImpl(path, waitMsg, true));
|
||||
|
||||
@@ -33,6 +33,7 @@ void unlockFile(int fd);
|
||||
|
||||
class PathLock
|
||||
{
|
||||
friend kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg);
|
||||
friend PathLock lockPath(const Path & path, std::string_view waitMsg);
|
||||
friend std::optional<PathLock> tryLockPath(const Path & path);
|
||||
|
||||
@@ -52,6 +53,7 @@ public:
|
||||
void unlock();
|
||||
};
|
||||
|
||||
kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg = "");
|
||||
PathLock lockPath(const Path & path, std::string_view waitMsg = "");
|
||||
std::optional<PathLock> tryLockPath(const Path & path);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user