nar: 'finalize-store-file' follows proper store lock protocol.
authorCaleb Ristvedt <caleb.ristvedt@cune.org>
Wed, 6 May 2020 16:48:21 +0000 (11:48 -0500)
committerCaleb Ristvedt <caleb.ristvedt@cune.org>
Thu, 7 May 2020 10:56:01 +0000 (05:56 -0500)
* guix/nar.scm (finalize-store-file): check for deletion token when acquiring
  lock, write deletion token and delete lock file before releasing lock.

guix/nar.scm

index 29636aa..0a6f59b 100644 (file)
 REFERENCES and DERIVER.  When LOCK? is true, acquire exclusive locks on TARGET
 before attempting to register it; otherwise, assume TARGET's locks are already
 held."
+  ;; TODO: make this reusable
+  (define (acquire-lock file)
+    (let ((port (lock-file file)))
+      ;; There is an inherent race condition between opening the lock file and
+      ;; attempting to acquire the lock on it, and because we like deleting
+      ;; these lock files when we release them, only the first successful
+      ;; acquisition on a given lock file matters.  To make it easier to tell
+      ;; when an acquisition is and isn't the first, the first to acquire it
+      ;; writes a deletion token (arbitrary character) prior to releasing the
+      ;; lock.
+      (if (zero? (stat:size (stat port)))
+          port
+          ;; if FILE is non-empty, that's because it contains the deletion
+          ;; token, so we aren't the first to acquire it.  So try again!
+          (begin
+            (close port)
+            (acquire-lock file)))))
+
   (with-database %default-database-file db
     (unless (path-id db target)
       (let ((lock (and lock?
-                       (lock-file (string-append target ".lock")))))
+                       (acquire-lock (string-append target ".lock")))))
 
         (unless (path-id db target)
           ;; If FILE already exists, delete it (it's invalid anyway.)
@@ -102,6 +120,12 @@ held."
                          #:deriver deriver))
 
         (when lock?
+          (delete-file (string-append target ".lock"))
+          ;; Write the deletion token to inform anyone who acquires the lock
+          ;; on this particular file next that they aren't the first to
+          ;; acquire it, so they should retry.
+          (display "d" lock)
+          (force-output lock)
           (unlock-file lock))))))
 
 (define (temporary-store-file)