From 461064da9e169df3dd939b734bb2860598d113f4 Mon Sep 17 00:00:00 2001 From: Caleb Ristvedt Date: Wed, 24 Jun 2020 00:56:50 -0500 Subject: [PATCH 1/2] deduplication: retry on ENOENT. It's possible for the garbage collector to remove the "canonical" link after it's been detected as existing by 'deduplicate'. This would cause an ENOENT error when replace-with-link attempts to create the temporary link. This changes it so that it will properly handle that by retrying. * guix/store/deduplication.scm (deduplicate): retry on ENOENT. --- guix/store/deduplication.scm | 64 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm index 6784ee0b92..b6d94e49c2 100644 --- a/guix/store/deduplication.scm +++ b/guix/store/deduplication.scm @@ -161,26 +161,44 @@ under STORE." (scandir* path)) (let ((link-file (string-append links-directory "/" (bytevector->nix-base32-string hash)))) - (if (file-exists? link-file) - (replace-with-link link-file path - #:swap-directory links-directory) - (catch 'system-error - (lambda () - (link path link-file)) - (lambda args - (let ((errno (system-error-errno args))) - (cond ((= errno EEXIST) - ;; Someone else put an entry for PATH in - ;; LINKS-DIRECTORY before we could. Let's use it. - (replace-with-link path link-file - #:swap-directory links-directory)) - ((= errno ENOSPC) - ;; There's not enough room in the directory index for - ;; more entries in .links, but that's fine: we can - ;; just stop. - #f) - ((= errno EMLINK) - ;; PATH has reached the maximum number of links, but - ;; that's OK: we just can't deduplicate it more. - #f) - (else (apply throw args))))))))))) + (let retry () + (if (file-exists? link-file) + (catch 'system-error + (lambda () + (replace-with-link link-file path + #:swap-directory links-directory)) + (lambda args + (if (and (= (system-error-errno args) ENOENT) + ;; ENOENT can be produced because: + ;; - LINK-FILE has missing directory components + ;; - LINKS-DIRECTORY has missing directory + ;; components + ;; - PATH has missing directory components + ;; + ;; the last two are errors, the first just + ;; requires a retry. + (file-exists? (dirname path)) + (file-exists? links-directory)) + (retry) + (apply throw args)))) + (catch 'system-error + (lambda () + (link path link-file)) + (lambda args + (let ((errno (system-error-errno args))) + (cond ((= errno EEXIST) + ;; Someone else put an entry for PATH in + ;; LINKS-DIRECTORY before we could. Let's use + ;; it. + (retry)) + ((= errno ENOSPC) + ;; There's not enough room in the directory index + ;; for more entries in .links, but that's fine: + ;; we can just stop. + #f) + ((= errno EMLINK) + ;; PATH has reached the maximum number of links, + ;; but that's OK: we just can't deduplicate it + ;; more. + #f) + (else (apply throw args)))))))))))) -- 2.26.2