store: 'map/accumulate-builds' processes the whole list in case of cutoff.
Fixes <https://issues.guix.gnu.org/50264>.
Reported by Lars-Dominik Braun <lars@6xq.net>.
This fixes a regression introduced in
fa81971cba
whereby 'map/accumulate-builds'
would return REST (the tail of LST) without applying PROC on it. The
effect would be that 'lower-inputs' in (guix gexp) would dismiss those
elements, leading to derivations with correct builders but only a subset
of the inputs they should have had.
* guix/store.scm (map/accumulate-builds): Add #:cutoff parameter and
remove 'accumulation-cutoff' variable. Call PROC on the elements of
REST.
* tests/store.scm ("map/accumulate-builds cutoff"): New test.
master
parent
a840caccae
commit
f72f4b48c6
|
@ -1355,14 +1355,16 @@ on the build output of a previous derivation."
|
||||||
(unresolved things continue)
|
(unresolved things continue)
|
||||||
(continue #t)))
|
(continue #t)))
|
||||||
|
|
||||||
(define (map/accumulate-builds store proc lst)
|
(define* (map/accumulate-builds store proc lst
|
||||||
|
#:key (cutoff 30))
|
||||||
"Apply PROC over each element of LST, accumulating 'build-things' calls and
|
"Apply PROC over each element of LST, accumulating 'build-things' calls and
|
||||||
coalescing them into a single call."
|
coalescing them into a single call.
|
||||||
(define accumulation-cutoff
|
|
||||||
;; Threshold above which we stop accumulating unresolved nodes to avoid
|
CUTOFF is the threshold above which we stop accumulating unresolved nodes."
|
||||||
;; pessimal behavior where we keep stumbling upon the same .drv build
|
|
||||||
;; requests with many incoming edges. See <https://bugs.gnu.org/49439>.
|
;; The CUTOFF parameter helps avoid pessimal behavior where we keep
|
||||||
30)
|
;; stumbling upon the same .drv build requests with many incoming edges.
|
||||||
|
;; See <https://bugs.gnu.org/49439>.
|
||||||
|
|
||||||
(define-values (result rest)
|
(define-values (result rest)
|
||||||
(let loop ((lst lst)
|
(let loop ((lst lst)
|
||||||
|
@ -1373,7 +1375,7 @@ coalescing them into a single call."
|
||||||
(match (with-build-handler build-accumulator
|
(match (with-build-handler build-accumulator
|
||||||
(proc head))
|
(proc head))
|
||||||
((? unresolved? obj)
|
((? unresolved? obj)
|
||||||
(if (> unresolved accumulation-cutoff)
|
(if (>= unresolved cutoff)
|
||||||
(values (reverse (cons obj result)) tail)
|
(values (reverse (cons obj result)) tail)
|
||||||
(loop tail (cons obj result) (+ 1 unresolved))))
|
(loop tail (cons obj result) (+ 1 unresolved))))
|
||||||
(obj
|
(obj
|
||||||
|
@ -1390,17 +1392,20 @@ coalescing them into a single call."
|
||||||
;; REST is necessarily empty.
|
;; REST is necessarily empty.
|
||||||
result)
|
result)
|
||||||
(to-build
|
(to-build
|
||||||
;; We've accumulated things TO-BUILD. Actually build them and resume the
|
;; We've accumulated things TO-BUILD; build them.
|
||||||
;; corresponding continuations.
|
|
||||||
(build-things store (delete-duplicates to-build))
|
(build-things store (delete-duplicates to-build))
|
||||||
(map/accumulate-builds store
|
|
||||||
(lambda (obj)
|
;; Resume the continuations corresponding to TO-BUILD, and then process
|
||||||
(if (unresolved? obj)
|
;; REST.
|
||||||
;; Pass #f because 'build-things' is now
|
(append (map/accumulate-builds store
|
||||||
;; unnecessary.
|
(lambda (obj)
|
||||||
((unresolved-continuation obj) #f)
|
(if (unresolved? obj)
|
||||||
obj))
|
;; Pass #f because 'build-things' is now
|
||||||
(append result rest)))))
|
;; unnecessary.
|
||||||
|
((unresolved-continuation obj) #f)
|
||||||
|
obj))
|
||||||
|
result #:cutoff cutoff)
|
||||||
|
(map/accumulate-builds store proc rest #:cutoff cutoff)))))
|
||||||
|
|
||||||
(define build-things
|
(define build-things
|
||||||
(let ((build (operation (build-things (string-list things)
|
(let ((build (operation (build-things (string-list things)
|
||||||
|
|
|
@ -454,6 +454,42 @@
|
||||||
(derivation->output-path drv)))
|
(derivation->output-path drv)))
|
||||||
(list d1 d2)))))
|
(list d1 d2)))))
|
||||||
|
|
||||||
|
(test-equal "map/accumulate-builds cutoff" ;https://issues.guix.gnu.org/50264
|
||||||
|
(iota 20)
|
||||||
|
|
||||||
|
;; Make sure that, when the cutoff is reached, 'map/accumulate-builds' still
|
||||||
|
;; returns the right result and calls the build handler by batches.
|
||||||
|
(let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
|
||||||
|
(s (add-to-store %store "bash" #t "sha256"
|
||||||
|
(search-bootstrap-binary "bash"
|
||||||
|
(%current-system))))
|
||||||
|
(d (map (lambda (i)
|
||||||
|
(derivation %store (string-append "the-thing-"
|
||||||
|
(number->string i))
|
||||||
|
s `("-e" ,b)
|
||||||
|
#:env-vars `(("foo" . ,(random-text)))
|
||||||
|
#:sources (list b s)
|
||||||
|
#:properties `((n . ,i))))
|
||||||
|
(iota 20)))
|
||||||
|
(calls '()))
|
||||||
|
(define lst
|
||||||
|
(with-build-handler (lambda (continue store things mode)
|
||||||
|
(set! calls (cons things calls))
|
||||||
|
(continue #f))
|
||||||
|
(map/accumulate-builds %store
|
||||||
|
(lambda (d)
|
||||||
|
(build-derivations %store (list d))
|
||||||
|
(assq-ref (derivation-properties d) 'n))
|
||||||
|
d
|
||||||
|
#:cutoff 7)))
|
||||||
|
|
||||||
|
(match (reverse calls)
|
||||||
|
(((batch1 ...) (batch2 ...) (batch3 ...))
|
||||||
|
(and (equal? (map derivation-file-name (take d 8)) batch1)
|
||||||
|
(equal? (map derivation-file-name (take (drop d 8) 8)) batch2)
|
||||||
|
(equal? (map derivation-file-name (drop d 16)) batch3)
|
||||||
|
lst)))))
|
||||||
|
|
||||||
(test-assert "mapm/accumulate-builds"
|
(test-assert "mapm/accumulate-builds"
|
||||||
(let* ((d1 (run-with-store %store
|
(let* ((d1 (run-with-store %store
|
||||||
(gexp->derivation "foo" #~(mkdir #$output))))
|
(gexp->derivation "foo" #~(mkdir #$output))))
|
||||||
|
|
Reference in New Issue