libstore: bind FdLock to AutoCloseFD and make resource-safe
Change-Id: I2451c15bd0e7d3a5a537bbb65502fd4a18ae0c22
This commit is contained in:
+3
-3
@@ -129,9 +129,9 @@ void LocalStore::addTempRoot(const StorePath & path)
|
||||
/* Try to acquire a shared global GC lock (non-blocking). This
|
||||
only succeeds if the garbage collector is not currently
|
||||
running. */
|
||||
FdLock gcLock(_fdGCLock.lock()->get(), ltRead);
|
||||
FdLock gcLock(*_fdGCLock.lock(), ltRead, FdLock::dont_wait);
|
||||
|
||||
if (!gcLock.acquired) {
|
||||
if (!gcLock.valid()) {
|
||||
/* We couldn't get a shared global GC lock, so the garbage
|
||||
collector is running. So we have to connect to the garbage
|
||||
collector and inform it about our root. */
|
||||
@@ -583,7 +583,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
here because then in auto-gc mode, another thread could
|
||||
downgrade our exclusive lock. */
|
||||
auto fdGCLock = openGCLock();
|
||||
FdLock gcLock(fdGCLock.get(), ltWrite, "waiting for the big garbage collector lock...");
|
||||
FdLock gcLock(fdGCLock, ltWrite, "waiting for the big garbage collector lock...");
|
||||
|
||||
/* Synchronisation point to test ENOENT handling in
|
||||
addTempRoot(), see tests/gc-non-blocking.sh. */
|
||||
|
||||
@@ -1527,7 +1527,7 @@ try {
|
||||
/* Acquire the global GC lock to get a consistent snapshot of
|
||||
existing and valid paths. */
|
||||
auto fdGCLock = openGCLock();
|
||||
FdLock gcLock(fdGCLock.get(), ltRead, "waiting for the big garbage collector lock...");
|
||||
FdLock gcLock(fdGCLock, ltRead, "waiting for the big garbage collector lock...");
|
||||
|
||||
StorePathSet validPaths;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "lix/libstore/pathlocks.hh"
|
||||
#include "lix/libutil/file-descriptor.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
|
||||
@@ -208,19 +209,19 @@ void PathLocks::setDeletion(bool deletePaths)
|
||||
}
|
||||
|
||||
|
||||
FdLock::FdLock(int fd, LockType lockType)
|
||||
: fd(fd)
|
||||
FdLock::FdLock(AutoCloseFD & fd, LockType lockType, DontWait)
|
||||
{
|
||||
acquired = tryLockFile(fd, lockType);
|
||||
if (tryLockFile(fd.get(), lockType)) {
|
||||
this->fd.reset(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
FdLock::FdLock(int fd, LockType lockType, std::string_view waitMsg)
|
||||
: fd(fd)
|
||||
FdLock::FdLock(AutoCloseFD & fd, LockType lockType, std::string_view waitMsg)
|
||||
{
|
||||
if (!tryLockFile(fd, lockType)) {
|
||||
if (!tryLockFile(fd.get(), lockType)) {
|
||||
printInfo("%s", waitMsg);
|
||||
lockFile(fd, lockType);
|
||||
acquired = true;
|
||||
lockFile(fd.get(), lockType);
|
||||
this->fd.reset(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-14
@@ -57,23 +57,29 @@ public:
|
||||
void setDeletion(bool deletePaths);
|
||||
};
|
||||
|
||||
struct FdLock
|
||||
class FdLock
|
||||
{
|
||||
int fd;
|
||||
bool acquired = false;
|
||||
|
||||
FdLock(int fd, LockType lockType);
|
||||
FdLock(int fd, LockType lockType, std::string_view waitMsg);
|
||||
|
||||
~FdLock()
|
||||
struct Unlocker
|
||||
{
|
||||
try {
|
||||
if (acquired)
|
||||
unlockFile(fd);
|
||||
} catch (SysError &) {
|
||||
ignoreExceptionInDestructor();
|
||||
void operator()(AutoCloseFD * fd)
|
||||
{
|
||||
try {
|
||||
unlockFile(fd->get());
|
||||
} catch (SysError &) {
|
||||
ignoreExceptionInDestructor();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<AutoCloseFD, Unlocker> fd;
|
||||
|
||||
public:
|
||||
static constexpr struct DontWait { explicit DontWait() = default; } dont_wait;
|
||||
|
||||
FdLock(AutoCloseFD & fd, LockType lockType, DontWait);
|
||||
FdLock(AutoCloseFD & fd, LockType lockType, std::string_view waitMsg);
|
||||
|
||||
bool valid() const { return bool(fd); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user