* Move addTempRoot() to the store API, and add another function
syncWithGC() to allow clients to register GC roots without needing write access to the global roots directory or the GC lock.
This commit is contained in:
parent
30bf547f4f
commit
e25fad691a
11 changed files with 81 additions and 17 deletions
|
@ -642,7 +642,7 @@ void DerivationGoal::haveStoreExpr()
|
||||||
|
|
||||||
for (DerivationOutputs::iterator i = drv.outputs.begin();
|
for (DerivationOutputs::iterator i = drv.outputs.begin();
|
||||||
i != drv.outputs.end(); ++i)
|
i != drv.outputs.end(); ++i)
|
||||||
addTempRoot(i->second.path);
|
store->addTempRoot(i->second.path);
|
||||||
|
|
||||||
/* Check what outputs paths are not already valid. */
|
/* Check what outputs paths are not already valid. */
|
||||||
PathSet invalidOutputs = checkPathValidity(false);
|
PathSet invalidOutputs = checkPathValidity(false);
|
||||||
|
@ -1714,7 +1714,7 @@ void SubstitutionGoal::init()
|
||||||
{
|
{
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
addTempRoot(storePath);
|
store->addTempRoot(storePath);
|
||||||
|
|
||||||
/* If the path already exists we're done. */
|
/* If the path already exists we're done. */
|
||||||
if (store->isValidPath(storePath)) {
|
if (store->isValidPath(storePath)) {
|
||||||
|
|
|
@ -76,6 +76,12 @@ void createSymlink(const Path & link, const Path & target, bool careful)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LocalStore::syncWithGC()
|
||||||
|
{
|
||||||
|
AutoCloseFD fdGCLock = openGCLock(ltRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
||||||
bool indirect, bool allowOutsideRootsDir)
|
bool indirect, bool allowOutsideRootsDir)
|
||||||
{
|
{
|
||||||
|
@ -83,10 +89,6 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
||||||
Path gcRoot(canonPath(_gcRoot));
|
Path gcRoot(canonPath(_gcRoot));
|
||||||
assertStorePath(storePath);
|
assertStorePath(storePath);
|
||||||
|
|
||||||
/* Grab the global GC root. This prevents the set of permanent
|
|
||||||
roots from increasing while a GC is in progress. */
|
|
||||||
AutoCloseFD fdGCLock = openGCLock(ltRead);
|
|
||||||
|
|
||||||
if (indirect) {
|
if (indirect) {
|
||||||
string hash = printHash32(hashString(htSHA1, gcRoot));
|
string hash = printHash32(hashString(htSHA1, gcRoot));
|
||||||
Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
|
Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
|
||||||
|
@ -110,6 +112,11 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
|
||||||
createSymlink(gcRoot, storePath, false);
|
createSymlink(gcRoot, storePath, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Grab the global GC root, causing us to block while a GC is in
|
||||||
|
progress. This prevents the set of permanent roots from
|
||||||
|
increasing while a GC is in progress. */
|
||||||
|
store->syncWithGC();
|
||||||
|
|
||||||
return gcRoot;
|
return gcRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +126,7 @@ static Path fnTempRoots;
|
||||||
static AutoCloseFD fdTempRoots;
|
static AutoCloseFD fdTempRoots;
|
||||||
|
|
||||||
|
|
||||||
void addTempRoot(const Path & path)
|
void LocalStore::addTempRoot(const Path & path)
|
||||||
{
|
{
|
||||||
/* Create the temporary roots file for this process. */
|
/* Create the temporary roots file for this process. */
|
||||||
if (fdTempRoots == -1) {
|
if (fdTempRoots == -1) {
|
||||||
|
|
|
@ -26,12 +26,6 @@ typedef enum {
|
||||||
void collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
void collectGarbage(GCAction action, const PathSet & pathsToDelete,
|
||||||
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
|
bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
|
||||||
|
|
||||||
/* Register a temporary GC root. This root will automatically
|
|
||||||
disappear when this process exits. WARNING: this function should
|
|
||||||
not be called inside a BDB transaction, otherwise we can
|
|
||||||
deadlock. */
|
|
||||||
void addTempRoot(const Path & path);
|
|
||||||
|
|
||||||
/* Remove the temporary roots file for this process. Any temporary
|
/* Remove the temporary roots file for this process. Any temporary
|
||||||
root becomes garbage after this point unless it has been registered
|
root becomes garbage after this point unless it has been registered
|
||||||
as a (permanent) root. */
|
as a (permanent) root. */
|
||||||
|
|
|
@ -58,6 +58,10 @@ public:
|
||||||
void buildDerivations(const PathSet & drvPaths);
|
void buildDerivations(const PathSet & drvPaths);
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
void ensurePath(const Path & path);
|
||||||
|
|
||||||
|
void addTempRoot(const Path & path);
|
||||||
|
|
||||||
|
void syncWithGC();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -170,4 +170,19 @@ void RemoteStore::ensurePath(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RemoteStore::addTempRoot(const Path & path)
|
||||||
|
{
|
||||||
|
writeInt(wopAddTempRoot, to);
|
||||||
|
writeString(path, to);
|
||||||
|
readInt(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RemoteStore::syncWithGC()
|
||||||
|
{
|
||||||
|
writeInt(wopSyncWithGC, to);
|
||||||
|
readInt(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,10 @@ public:
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
void ensurePath(const Path & path);
|
||||||
|
|
||||||
|
void addTempRoot(const Path & path);
|
||||||
|
|
||||||
|
void syncWithGC();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pipe toChild;
|
Pipe toChild;
|
||||||
Pipe fromChild;
|
Pipe fromChild;
|
||||||
|
|
|
@ -86,6 +86,31 @@ public:
|
||||||
may be made valid by running a substitute (if defined for the
|
may be made valid by running a substitute (if defined for the
|
||||||
path). */
|
path). */
|
||||||
virtual void ensurePath(const Path & path) = 0;
|
virtual void ensurePath(const Path & path) = 0;
|
||||||
|
|
||||||
|
/* Add a store path as a temporary root of the garbage collector.
|
||||||
|
The root disappears as soon as we exit. */
|
||||||
|
virtual void addTempRoot(const Path & path) = 0;
|
||||||
|
|
||||||
|
/* Acquire the global GC lock, then immediately release it. This
|
||||||
|
function must be called after registering a new permanent root,
|
||||||
|
but before exiting. Otherwise, it is possible that a running
|
||||||
|
garbage collector doesn't see the new root and deletes the
|
||||||
|
stuff we've just built. By acquiring the lock briefly, we
|
||||||
|
ensure that either:
|
||||||
|
|
||||||
|
- The collector is already running, and so we block until the
|
||||||
|
collector is finished. The collector will know about our
|
||||||
|
*temporary* locks, which should include whatever it is we
|
||||||
|
want to register as a permanent lock.
|
||||||
|
|
||||||
|
- The collector isn't running, or it's just started but hasn't
|
||||||
|
acquired the GC lock yet. In that case we get and release
|
||||||
|
the lock right away, then exit. The collector scans the
|
||||||
|
permanent root and sees our's.
|
||||||
|
|
||||||
|
In either case the permanent root is seen by the collector. */
|
||||||
|
virtual void syncWithGC() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ typedef enum {
|
||||||
wopAddTextToStore,
|
wopAddTextToStore,
|
||||||
wopBuildDerivations,
|
wopBuildDerivations,
|
||||||
wopEnsurePath,
|
wopEnsurePath,
|
||||||
|
wopAddTempRoot,
|
||||||
|
wopSyncWithGC
|
||||||
} WorkerOp;
|
} WorkerOp;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ Path dirOf(const Path & path)
|
||||||
{
|
{
|
||||||
Path::size_type pos = path.rfind('/');
|
Path::size_type pos = path.rfind('/');
|
||||||
if (pos == string::npos)
|
if (pos == string::npos)
|
||||||
throw Error(format("invalid file name: %1%") % path);
|
throw Error(format("invalid file name `%1%'") % path);
|
||||||
return pos == 0 ? "/" : Path(path, 0, pos);
|
return pos == 0 ? "/" : Path(path, 0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ string baseNameOf(const Path & path)
|
||||||
{
|
{
|
||||||
Path::size_type pos = path.rfind('/');
|
Path::size_type pos = path.rfind('/');
|
||||||
if (pos == string::npos)
|
if (pos == string::npos)
|
||||||
throw Error(format("invalid file name %1% ") % path);
|
throw Error(format("invalid file name `%1%'") % path);
|
||||||
return string(path, pos + 1);
|
return string(path, pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
addTempRoot(i->queryOutPath(state));
|
store->addTempRoot(i->queryOutPath(state));
|
||||||
store->ensurePath(i->queryOutPath(state));
|
store->ensurePath(i->queryOutPath(state));
|
||||||
|
|
||||||
references.insert(i->queryOutPath(state));
|
references.insert(i->queryOutPath(state));
|
||||||
|
@ -940,7 +940,7 @@ static void opSwitchProfile(Globals & globals,
|
||||||
if (opArgs.size() != 1)
|
if (opArgs.size() != 1)
|
||||||
throw UsageError(format("exactly one argument expected"));
|
throw UsageError(format("exactly one argument expected"));
|
||||||
|
|
||||||
Path profile = opArgs.front();
|
Path profile = absPath(opArgs.front());
|
||||||
Path profileLink = getHomeDir() + "/.nix-profile";
|
Path profileLink = getHomeDir() + "/.nix-profile";
|
||||||
|
|
||||||
switchLink(profileLink, profile);
|
switchLink(profileLink, profile);
|
||||||
|
|
|
@ -127,6 +127,19 @@ void processConnection(Source & from, Sink & to)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case wopAddTempRoot: {
|
||||||
|
Path path = readStorePath(from);
|
||||||
|
store->addTempRoot(path);
|
||||||
|
writeInt(1, to);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case wopSyncWithGC: {
|
||||||
|
store->syncWithGC();
|
||||||
|
writeInt(1, to);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw Error(format("invalid operation %1%") % op);
|
throw Error(format("invalid operation %1%") % op);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue