Files
lix/lix/libstore/pathlocks.hh
T
eldritch horrors 280772583f libutil: remote unsafeLockFileSingleThreaded
while this does require spawning a thread for every contended lock now
we don't expect performance to be impacted. only build-remote used the
synchronous method, and it only used it to serialize uploads to remote
builders. these uploads are expensive enough to dwarf the thread cost.

Change-Id: Iad0aa0cd738bc96fd06a90d655803dadffa09c47
2025-07-14 17:02:30 +00:00

90 lines
2.5 KiB
C++

#pragma once
///@file
#include "lix/libutil/error.hh"
#include "lix/libutil/file-descriptor.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/types.hh"
#include <chrono>
#include <kj/async.h>
#include <kj/common.h>
namespace nix {
/**
* Open (possibly create) a lock file and return the file descriptor.
* -1 is returned if create is false and the lock could not be opened
* because it doesn't exist. Any other error throws an exception.
*/
AutoCloseFD openLockFile(const Path & path, bool create);
enum LockType { ltRead, ltWrite };
void lockFile(int fd, LockType lockType, NeverAsync = {});
kj::Promise<Result<void>> lockFileAsync(int fd, LockType lockType);
bool tryLockFile(int fd, LockType lockType);
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, NeverAsync);
friend std::optional<PathLock> tryLockPath(const Path & path);
AutoCloseFD fd;
Path path;
PathLock(AutoCloseFD fd, const Path & path): fd(std::move(fd)), path(path) {}
static std::optional<PathLock>
lockImpl(const Path & path, std::string_view waitMsg, bool wait, NeverAsync = {});
public:
PathLock(PathLock &&) = default;
PathLock & operator=(PathLock &&) = default;
~PathLock();
void unlock();
};
kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg = "");
PathLock lockPath(const Path & path, std::string_view waitMsg = "", NeverAsync = {});
std::optional<PathLock> tryLockPath(const Path & path);
using PathLocks = std::list<PathLock>;
PathLocks lockPaths(const PathSet & paths, std::string_view waitMsg = "", NeverAsync = {});
std::optional<PathLocks> tryLockPaths(const PathSet & paths);
class FdLock
{
struct Unlocker
{
void operator()(AutoCloseFD * fd)
{
try {
unlockFile(fd->get());
} catch (SysError &) {
ignoreExceptionInDestructor();
}
}
};
std::unique_ptr<AutoCloseFD, Unlocker> fd;
explicit FdLock(AutoCloseFD & fd): fd(&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, NeverAsync = {});
static kj::Promise<Result<FdLock>>
lockAsync(AutoCloseFD & fd, LockType lockType, std::string_view waitMsg);
bool valid() const { return bool(fd); }
};
}