gc: Use the trace helper
This commit is contained in:
@@ -31,6 +31,7 @@ namespace nix {
|
||||
|
||||
|
||||
static std::string gcSocketPath = "/gc-socket/socket";
|
||||
static std::string rootsSocketPath = "/gc-roots-socket/socket";
|
||||
static std::string gcRootsDir = "gcroots";
|
||||
|
||||
|
||||
@@ -143,7 +144,7 @@ void LocalStore::addTempRoot(const StorePath & path)
|
||||
auto fdRootsSocket(_fdRootsSocket.lock());
|
||||
|
||||
if (!*fdRootsSocket) {
|
||||
auto socketPath = stateDir.get() + gcSocketPath;
|
||||
auto socketPath = stateDir.get() + rootsSocketPath;
|
||||
debug("connecting to '%s'", socketPath);
|
||||
*fdRootsSocket = createUnixDomainSocket();
|
||||
try {
|
||||
@@ -304,8 +305,10 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||
}
|
||||
|
||||
|
||||
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
|
||||
void LocalStore::findRootsNoTempNoExternalDaemon(Roots & roots, bool censor)
|
||||
{
|
||||
debug("Can’t connect to the tracing daemon socket, fallback to the internal trace");
|
||||
|
||||
/* Process direct roots in {gcroots,profiles}. */
|
||||
findRoots(stateDir + "/" + gcRootsDir, DT_UNKNOWN, roots);
|
||||
findRoots(stateDir + "/profiles", DT_UNKNOWN, roots);
|
||||
@@ -322,11 +325,57 @@ Roots LocalStore::findRoots(bool censor)
|
||||
Roots roots;
|
||||
findRootsNoTemp(roots, censor);
|
||||
|
||||
findTempRoots(roots, censor);
|
||||
FDs fds;
|
||||
findTempRoots(fds, roots, censor);
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
void LocalStore::findRootsNoTemp(Roots & roots, bool censor)
|
||||
{
|
||||
|
||||
auto fd = createUnixDomainSocket();
|
||||
|
||||
std::string socketPath = settings.gcSocketPath.get() != "auto"
|
||||
? settings.gcSocketPath.get()
|
||||
: stateDir.get() + gcSocketPath;
|
||||
|
||||
try {
|
||||
nix::connect(fd.get(), socketPath);
|
||||
} catch (SysError & e) {
|
||||
return findRootsNoTempNoExternalDaemon(roots, censor);
|
||||
}
|
||||
|
||||
experimentalFeatureSettings.require(Xp::ExternalGCDaemon);
|
||||
|
||||
try {
|
||||
StringMap unescapes = {
|
||||
{ "\\n", "\n"},
|
||||
{ "\\t", "\t"},
|
||||
};
|
||||
while (true) {
|
||||
auto line = readLine(fd.get());
|
||||
if (line.empty()) break; // TODO: Handle the broken symlinks
|
||||
auto parsedLine = tokenizeString<std::vector<std::string>>(line, "\t");
|
||||
if (parsedLine.size() != 2)
|
||||
throw Error("Invalid result from the gc helper");
|
||||
auto rawDestPath = rewriteStrings(parsedLine[0], unescapes);
|
||||
auto retainer = rewriteStrings(parsedLine[1], unescapes);
|
||||
if (!isInStore(rawDestPath)) continue;
|
||||
try {
|
||||
auto destPath = toStorePath(rawDestPath).first;
|
||||
if (!isValidPath(destPath)) continue;
|
||||
roots[destPath].insert(
|
||||
(!censor || isInDir(retainer, stateDir)) ? retainer : censored);
|
||||
} catch (Error &) {
|
||||
}
|
||||
}
|
||||
} catch (EndOfFile &) {
|
||||
}
|
||||
|
||||
findRuntimeRoots(roots, censor);
|
||||
}
|
||||
|
||||
typedef std::unordered_map<Path, std::unordered_set<std::string>> UncheckedRoots;
|
||||
|
||||
static void readProcLink(const std::string & file, UncheckedRoots & roots)
|
||||
@@ -516,7 +565,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
readFile(*p);
|
||||
|
||||
/* Start the server for receiving new roots. */
|
||||
auto socketPath = stateDir.get() + gcSocketPath;
|
||||
auto socketPath = stateDir.get() + rootsSocketPath;
|
||||
createDirs(dirOf(socketPath));
|
||||
auto fdServer = createUnixDomainSocket(socketPath, 0666);
|
||||
|
||||
@@ -625,7 +674,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
||||
printInfo("finding garbage collector roots...");
|
||||
Roots rootMap;
|
||||
if (!options.ignoreLiveness)
|
||||
findRootsNoTemp(rootMap, true);
|
||||
rootMap = findRoots(true);
|
||||
|
||||
for (auto & i : rootMap) roots.insert(i.first);
|
||||
|
||||
|
||||
@@ -124,6 +124,13 @@ public:
|
||||
section of the manual for supported store types and settings.
|
||||
)"};
|
||||
|
||||
Setting<std::string> gcSocketPath {
|
||||
this,
|
||||
getEnv("NIX_GC_SOCKET_PATH").value_or("auto"),
|
||||
"gc-socket-path",
|
||||
"Path to the socket used to communicate with an external GC."
|
||||
};
|
||||
|
||||
Setting<bool> keepFailed{this, false, "keep-failed",
|
||||
"Whether to keep temporary directories of failed builds."};
|
||||
|
||||
|
||||
@@ -328,6 +328,8 @@ private:
|
||||
|
||||
void findRootsNoTemp(Roots & roots, bool censor);
|
||||
|
||||
void findRootsNoTempNoExternalDaemon(Roots & roots, bool censor);
|
||||
|
||||
void findRuntimeRoots(Roots & roots, bool censor);
|
||||
|
||||
std::pair<Path, AutoCloseFD> createTempDirInStore();
|
||||
|
||||
@@ -268,6 +268,20 @@ constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails
|
||||
Allow the use of the [`mounted SSH store`](@docroot@/command-ref/new-cli/nix3-help-stores.html#experimental-ssh-store-with-filesytem-mounted).
|
||||
)",
|
||||
},
|
||||
{
|
||||
.tag = Xp::ExternalGCDaemon,
|
||||
.name = "external-gc-daemon",
|
||||
.description = R"(
|
||||
Make the garbage collector use an external daemon for the tracing.
|
||||
|
||||
This makes it possible to run a multi-user Nix daemon as a non-root
|
||||
user (only the tracing daemon needs to be root), reducing the attack
|
||||
surface a lot.
|
||||
|
||||
This requires more infrastructure and isn't directly supported by the
|
||||
installer.
|
||||
)"
|
||||
},
|
||||
{
|
||||
.tag = Xp::VerifiedFetches,
|
||||
.name = "verified-fetches",
|
||||
|
||||
@@ -35,6 +35,7 @@ enum struct ExperimentalFeature
|
||||
ReadOnlyLocalStore,
|
||||
ConfigurableImpureEnv,
|
||||
MountedSSHStore,
|
||||
ExternalGCDaemon,
|
||||
VerifiedFetches,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user