blob: 729ce3f2f5c8de919e74eba029c93d30216dce9b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
;;; Guix Build Coordinator
;;;
;;; Copyright © 2020 Christopher Baines <mail@cbaines.net>
;;;
;;; This file is part of the guix-build-coordinator.
;;;
;;; The Guix Build Coordinator is free software; you can redistribute
;;; it and/or modify it under the terms of the GNU General Public
;;; License as published by the Free Software Foundation; either
;;; version 3 of the License, or (at your option) any later version.
;;;
;;; The Guix Build Coordinator is distributed in the hope that it will
;;; be useful, but WITHOUT ANY WARRANTY; without even the implied
;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
;;; See the GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with the guix-data-service. If not, see
;;; <http://www.gnu.org/licenses/>.
(define-module (guix-build-coordinator build-allocator)
#:use-module (srfi srfi-1)
#:use-module (guix memoization)
#:use-module (guix-build-coordinator datastore)
#:use-module (guix-build-coordinator coordinator)
#:export (basic-build-allocation-strategy))
(define* (basic-build-allocation-strategy datastore
#:key
(planned-builds-for-agent-limit 2048))
(define (log . args)
(when #f
(simple-format #t "allocator: ~A\n"
(string-join (map (lambda (arg)
(simple-format #f "~A" arg))
args)
" "))))
(let ((agents (datastore-list-agents datastore))
(builds (datastore-list-unprocessed-builds datastore))
(setup-failures-hash
(datastore-fetch-setup-failures datastore)))
(define (filter-builds-for-agent agent-id)
(define output-has-successful-build?
(mlambda (output)
(log "considering missing input:" output)
(any (lambda (output-build)
(let ((build-successful?
(string=? (or (assq-ref output-build 'result)
"unknown")
"success")))
(when build-successful?
(log "found successful build:" (assq-ref output-build 'uuid)))
build-successful?))
(datastore-list-builds-for-output datastore output))))
(define (relevant-setup-failure? setup-failure)
(log "setup failure:" setup-failure)
(let ((failure-reason
(assq-ref setup-failure 'failure-reason)))
(cond
((string=? failure-reason "missing_inputs")
;; If all outputs have had at least one successful build, then the
;; inputs should be available. Otherwise, treat the setup failure
;; as still relevant (return #t)
(not
(every output-has-successful-build?
(datastore-list-setup-failure-missing-inputs
datastore
(assq-ref setup-failure 'id)))))
((string=? failure-reason "could_not_delete_outputs")
;; This problem might go away, but just don't try the same agent
;; again for now.
(string=? (assq-ref setup-failure 'agent-id)
agent-id))
(else
(error "Unknown setup failure " failure-reason)))))
(lambda (build)
(log "build:" (assq-ref build 'uuid))
(let* ((build-id (assq-ref build 'uuid))
(setup-failures-for-build
(or (hash-ref setup-failures-hash build-id)
'()))
(relevant-setup-failures
(filter relevant-setup-failure?
setup-failures-for-build)))
(log "relevant setup failures:" relevant-setup-failures)
(if (null? relevant-setup-failures)
#t
#f))))
(define (build-sorting-function-for-agent agent-id)
(lambda (a b)
(let ((a-priority (assq-ref a 'priority))
(b-priority (assq-ref b 'priority)))
(< b-priority a-priority))))
(define (limit-planned-builds builds)
(if planned-builds-for-agent-limit
(if (> (length builds) planned-builds-for-agent-limit)
(take builds planned-builds-for-agent-limit)
builds)
builds))
(let ((result
(append-map
(lambda (agent-id)
(log "considering builds for" agent-id)
(let ((builds-for-agent
(limit-planned-builds
(sort (filter (filter-builds-for-agent agent-id)
builds)
(build-sorting-function-for-agent agent-id)))))
(map (lambda (build-id ordering)
(list build-id
agent-id
ordering))
(map (lambda (build)
(assq-ref build 'uuid))
builds-for-agent)
(iota (length builds-for-agent)))))
(map (lambda (agent)
(assq-ref agent 'uuid))
agents))))
(log "finished")
result)))
|