mirror of
https://github.com/NixOS/nix.git
synced 2025-11-10 12:36:01 +01:00
Show which PID is causing a temp root
Example:
error: Cannot delete path '/nix/store/klyng5rpdkwi5kbxkncy4gjwb490dlhb-foo.drv' because it's in use by Nix process '{nix-process:3605324}'.
This commit is contained in:
parent
cae732f7a1
commit
31b00218fe
6 changed files with 35 additions and 20 deletions
|
|
@ -208,7 +208,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
|
|||
while ((end = contents.find((char) 0, pos)) != std::string::npos) {
|
||||
Path root(contents, pos, end - pos);
|
||||
debug("got temporary root '%s'", root);
|
||||
tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{temp:%d}", pid));
|
||||
tempRoots[parseStorePath(root)].emplace(censor ? censored : fmt("{nix-process:%d}", pid));
|
||||
pos = end + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -465,7 +465,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||
{
|
||||
// The temp roots only store the hash part to make it easier to
|
||||
// ignore suffixes like '.lock', '.chroot' and '.check'.
|
||||
std::unordered_set<std::string> tempRoots;
|
||||
std::unordered_map<std::string, GcRootInfo> tempRoots;
|
||||
|
||||
// Hash part of the store path currently being deleted, if
|
||||
// any.
|
||||
|
|
@ -574,7 +574,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||
debug("got new GC root '%s'", path);
|
||||
auto hashPart = std::string(storePath->hashPart());
|
||||
auto shared(_shared.lock());
|
||||
shared->tempRoots.insert(hashPart);
|
||||
// FIXME: could get the PID from the socket.
|
||||
shared->tempRoots.insert_or_assign(hashPart, "{nix-process:unknown}");
|
||||
/* If this path is currently being
|
||||
deleted, then we have to wait until
|
||||
deletion is finished to ensure that
|
||||
|
|
@ -618,10 +619,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||
|
||||
/* Read the temporary roots created before we acquired the global
|
||||
GC root. Any new roots will be sent to our socket. */
|
||||
{
|
||||
Roots tempRoots;
|
||||
findTempRoots(tempRoots, options.censor);
|
||||
for (auto & root : tempRoots)
|
||||
_shared.lock()->tempRoots.insert(std::string(root.first.hashPart()));
|
||||
_shared.lock()->tempRoots.insert_or_assign(
|
||||
std::string(root.first.hashPart()),
|
||||
*root.second.begin());
|
||||
}
|
||||
|
||||
/* Synchronisation point for testing, see tests/functional/gc-non-blocking.sh. */
|
||||
if (auto p = getEnv("_NIX_TEST_GC_SYNC_2"))
|
||||
|
|
@ -735,11 +740,12 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||
{
|
||||
auto hashPart = std::string(path->hashPart());
|
||||
auto shared(_shared.lock());
|
||||
if (shared->tempRoots.count(hashPart)) {
|
||||
if (auto i = shared->tempRoots.find(hashPart); i != shared->tempRoots.end()) {
|
||||
if (options.action == GCOptions::gcDeleteSpecific)
|
||||
throw Error(
|
||||
"Cannot delete path '%s' because it's in use by a Nix process.",
|
||||
printStorePath(start));
|
||||
"Cannot delete path '%s' because it's in use by '%s'.",
|
||||
printStorePath(start),
|
||||
i->second);
|
||||
return markAlive();
|
||||
}
|
||||
shared->pending = hashPart;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
// FIXME: should turn this into an std::variant to represent the
|
||||
// several root types.
|
||||
using GcRootInfo = std::string;
|
||||
|
||||
typedef std::unordered_map<StorePath, std::unordered_set<std::string>> Roots;
|
||||
typedef std::unordered_map<StorePath, std::unordered_set<GcRootInfo>> Roots;
|
||||
|
||||
|
||||
struct GCOptions
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ mkDerivation {
|
|||
|
||||
cat > $out/program <<EOF
|
||||
#! ${shell}
|
||||
echo x > \$TEST_ROOT/fifo
|
||||
sleep 10000
|
||||
EOF
|
||||
|
||||
|
|
|
|||
|
|
@ -21,11 +21,16 @@ nix-env -p "$profiles/test" -f ./gc-runtime.nix -i gc-runtime
|
|||
outPath=$(nix-env -p "$profiles/test" -q --no-name --out-path gc-runtime)
|
||||
echo "$outPath"
|
||||
|
||||
fifo="$TEST_ROOT/fifo"
|
||||
mkfifo "$fifo"
|
||||
|
||||
echo "backgrounding program..."
|
||||
"$profiles"/test/program &
|
||||
sleep 2 # hack - wait for the program to get started
|
||||
"$profiles"/test/program "$fifo" &
|
||||
child=$!
|
||||
echo PID=$child
|
||||
cat "$fifo"
|
||||
|
||||
expectStderr 1 nix-store --delete "$outPath" | grepQuiet "Cannot delete path.*because it's referenced by the GC root '/proc/"
|
||||
|
||||
nix-env -p "$profiles/test" -e gc-runtime
|
||||
nix-env -p "$profiles/test" --delete-generations old
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ if nix-store --gc --print-dead | grep -E "$outPath"$; then false; fi
|
|||
nix-store --gc --print-dead
|
||||
|
||||
inUse=$(readLink "$outPath/reference-to-input-2")
|
||||
if nix-store --delete "$inUse"; then false; fi
|
||||
expectStderr 1 nix-store --delete "$inUse" | grepQuiet "Cannot delete path.*because it's referenced by the GC root "
|
||||
test -e "$inUse"
|
||||
|
||||
if nix-store --delete "$outPath"; then false; fi
|
||||
expectStderr 1 nix-store --delete "$outPath" | grepQuiet "Cannot delete path.*because it's referenced by the GC root "
|
||||
test -e "$outPath"
|
||||
|
||||
for i in "$NIX_STORE_DIR"/*; do
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ input2=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg
|
|||
input3=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg withFinalRefs true --arg seed 2 -A passthru.input3 -j0)
|
||||
|
||||
# Can't delete because referenced
|
||||
expectStderr 1 nix-store --delete $input1 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --delete $input2 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --delete $input3 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --delete $input1 | grepQuiet "Cannot delete path.*because it's referenced by path"
|
||||
expectStderr 1 nix-store --delete $input2 | grepQuiet "Cannot delete path.*because it's referenced by path"
|
||||
expectStderr 1 nix-store --delete $input3 | grepQuiet "Cannot delete path.*because it's referenced by path"
|
||||
|
||||
# These same paths are referenced in the lower layer (by the seed 1
|
||||
# build done in `initLowerStore`).
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input2 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input3 | grepQuiet "Cannot delete path"
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input2 | grepQuiet "Cannot delete path.*because it's referenced by path"
|
||||
expectStderr 1 nix-store --store "$storeA" --delete $input3 | grepQuiet "Cannot delete path.*because it's referenced by path"
|
||||
|
||||
# Can delete
|
||||
nix-store --delete $hermetic
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue