about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstore/gc.cc26
-rw-r--r--src/libstore/gc.hh4
-rw-r--r--src/libstore/pathlocks.cc5
3 files changed, 31 insertions, 4 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 4c6a944b89ce..e7321449e7a1 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -194,9 +194,35 @@ void collectGarbage(const PathSet & roots, GCAction action,
         debug(format("dead path `%1%'") % path);
         result.insert(path);
 
+        AutoCloseFD fdLock;
+
         if (action == gcDeleteDead) {
             printMsg(lvlInfo, format("deleting `%1%'") % path);
+
+            /* Only delete a lock file if we can acquire a write lock
+               on it.  That means that it's either stale, or the
+               process that created it hasn't locked it yet.  In the
+               latter case the other process will detect that we
+               deleted the lock, and retry (see pathlocks.cc). */
+            if (path.size() >= 5 && string(path, path.size() - 5) == ".lock") {
+
+                fdLock = open(path.c_str(), O_RDWR);
+                if (fdLock == -1) {
+                    if (errno == ENOENT) continue;
+                    throw SysError(format("opening lock file `%1%'") % path);
+                }
+
+                if (!lockFile(fdLock, ltWrite, false)) {
+                    debug(format("skipping active lock `%1%'") % path);
+                    continue;
+                }
+            }
+            
             deleteFromStore(path);
+
+            if (fdLock != -1)
+                /* Write token to stale (deleted) lock file. */
+                writeFull(fdLock, (const unsigned char *) "d", 1);
         }
 
         /* Only delete lock files if the path is belongs to doesn't
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index 838188adeb82..c8f908b152aa 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -16,7 +16,9 @@ void collectGarbage(const PathSet & roots, GCAction action,
     PathSet & result);
 
 /* Register a temporary GC root.  This root will automatically
-   disappear when this process exits. */
+   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);
 
 
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index a92b2225a51c..3beb49aac803 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -127,9 +127,8 @@ PathLocks::~PathLocks()
             /* Write a (meaningless) token to the file to indicate to
                other processes waiting on this lock that the lock is
                stale (deleted). */
-            if (write(i->first, "d", 1) == 1) {
-                unlink(i->second.c_str());
-            }
+            unlink(i->second.c_str());
+            writeFull(i->first, (const unsigned char *) "d", 1);
             /* Note that the result of unlink() is ignored; removing
                the lock file is an optimisation, not a necessity. */
         }