summary refs log tree commit diff
path: root/tests/store-deduplication.scm
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2018-12-14 11:10:25 +0100
committerLudovic Courtès <ludo@gnu.org>2018-12-14 12:07:24 +0100
commitadb158b7396cbdcda347fa298978408e531a03fd (patch)
treefd6877e72a20840cd3962f80a89618bd08fcf04b /tests/store-deduplication.scm
parentea49fbdea3bbb9b55951b7bff9d9cf768fd23161 (diff)
downloadguix-adb158b7396cbdcda347fa298978408e531a03fd.tar.gz
deduplication: Gracefully handle ENOSPC raised by 'link' calls.
Reported by Andreas Enge <andreas@enge.fr>
in <https://bugs.gnu.org/33676>.

* guix/store/deduplication.scm (replace-with-link): Catch ENOSPC around
'get-temp-link'.  Do nothing when 'get-temp-link' throws ENOSPC.  Move
code to restore PARENT's permissions outside of 'catch'.
* tests/store-deduplication.scm ("deduplicate, ENOSPC"): New test.
Diffstat (limited to 'tests/store-deduplication.scm')
-rw-r--r--tests/store-deduplication.scm44
1 files changed, 43 insertions, 1 deletions
diff --git a/tests/store-deduplication.scm b/tests/store-deduplication.scm
index e438aa84c6..e2870a363d 100644
--- a/tests/store-deduplication.scm
+++ b/tests/store-deduplication.scm
@@ -48,7 +48,7 @@
                        (put-bytevector port data))))
                  identical)
        ;; Make the parent of IDENTICAL read-only.  This should not prevent
-       ;; deduplication for inserting its hard link.
+       ;; deduplication from inserting its hard link.
        (chmod (dirname (second identical)) #o544)
 
        (call-with-output-file unique
@@ -64,4 +64,46 @@
               (stat:nlink (stat unique))
               (map (compose stat:nlink stat) identical))))))
 
+(test-equal "deduplicate, ENOSPC"
+  (cons* #f                                       ;inode comparison
+         (append (make-list 3 4)
+                 (make-list 7 1)))                ;'nlink' values
+
+  ;; In this scenario the first 3 files are properly deduplicated and then we
+  ;; simulate a full '.links' directory where link(2) gets ENOSPC, thereby
+  ;; preventing deduplication of the subsequent files.
+  (call-with-temporary-directory
+   (lambda (store)
+     (let ((true-link link)
+           (links     0)
+           (data1     (string->utf8 "Hello, world!"))
+           (data2     (string->utf8 "Hi, world!"))
+           (identical (map (lambda (n)
+                             (string-append store "/" (number->string n)
+                                            "/a/b/c"))
+                           (iota 10)))
+           (populate  (lambda (data)
+                        (lambda (file)
+                          (mkdir-p (dirname file))
+                          (call-with-output-file file
+                            (lambda (port)
+                              (put-bytevector port data)))))))
+       (for-each (populate data1) (take identical 5))
+       (for-each (populate data2) (drop identical 5))
+       (dynamic-wind
+         (lambda ()
+           (set! link (lambda (old new)
+                        (set! links (+ links 1))
+                        (if (<= links 3)
+                            (true-link old new)
+                            (throw 'system-error "link" "~A" '("Whaaat?!")
+                                   (list ENOSPC))))))
+         (lambda ()
+           (deduplicate store (nar-sha256 store) #:store store))
+         (lambda ()
+           (set! link true-link)))
+
+       (cons (apply = (map (compose stat:ino stat) identical))
+             (map (compose stat:nlink stat) identical))))))
+
 (test-end "store-deduplication")