Skip to content

Commit ff18cb3

Browse files
committed
cmd/coordinator: plumb commit time and branch from findWork down into scheduler
The branch is not yet used in this CL, but the scheduler has it now and can use it easily in the future. Updates golang/go#19178 Change-Id: I6abab826a8668cb091d0face8184f28d08421722 Reviewed-on: https://go-review.googlesource.com/c/build/+/208277 Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent d6dec9c commit ff18cb3

File tree

4 files changed

+100
-32
lines changed

4 files changed

+100
-32
lines changed

cmd/coordinator/coordinator.go

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,24 @@ func main() {
357357
var ignoreAllNewWork bool
358358

359359
// addWorkTestHook is optionally set by tests.
360-
var addWorkTestHook func(work buildgo.BuilderRev)
360+
var addWorkTestHook func(buildgo.BuilderRev, *commitDetail)
361+
362+
type commitDetail struct {
363+
CommitTime string // in time.RFC3339 format
364+
Branch string
365+
}
361366

362367
func addWork(work buildgo.BuilderRev) {
368+
addWorkDetail(work, nil)
369+
}
370+
371+
// addWorkDetail adds some work to (maybe) do, if it's not already
372+
// enqueued and the builders are configured to run the given repo. The
373+
// detail argument is optional and used for scheduling. It's currently
374+
// only used for post-submit builds.
375+
func addWorkDetail(work buildgo.BuilderRev, detail *commitDetail) {
363376
if f := addWorkTestHook; f != nil {
364-
f(work)
377+
f(work, detail)
365378
return
366379
}
367380
if ignoreAllNewWork || isBuilding(work) {
@@ -375,12 +388,12 @@ func addWork(work buildgo.BuilderRev) {
375388
}
376389
return
377390
}
378-
st, err := newBuild(work)
391+
st, err := newBuild(work, detail)
379392
if err != nil {
380393
log.Printf("Bad build work params %v: %v", work, err)
381-
} else {
382-
st.start()
394+
return
383395
}
396+
st.start()
384397
}
385398

386399
// httpToHTTPSRedirector redirects all requests from http to https.
@@ -872,12 +885,28 @@ func findWork() error {
872885

873886
var goRevisions []string // revisions of repo "go", branch "master" revisions
874887
seenSubrepo := make(map[string]bool)
888+
commitTime := make(map[string]string) // git rev => "2019-11-20T22:54:54Z" (time.RFC3339 from build.golang.org's JSON)
889+
commitBranch := make(map[string]string) // git rev => "master"
890+
891+
add := func(br buildgo.BuilderRev) {
892+
rev := br.SubRev
893+
if br.SubRev == "" {
894+
rev = br.Rev
895+
}
896+
addWorkDetail(br, &commitDetail{
897+
CommitTime: commitTime[rev],
898+
Branch: commitBranch[rev],
899+
})
900+
}
901+
875902
for _, br := range bs.Revisions {
876903
if br.Repo == "grpc-review" {
877904
// Skip the grpc repo. It's only for reviews
878905
// for now (using LetsUseGerrit).
879906
continue
880907
}
908+
commitTime[br.Revision] = br.Date
909+
commitBranch[br.Revision] = br.Branch
881910
awaitSnapshot := false
882911
if br.Repo == "go" {
883912
if br.Branch == "master" {
@@ -938,7 +967,7 @@ func findWork() error {
938967
}
939968
}
940969

941-
addWork(rev)
970+
add(rev)
942971
}
943972
}
944973

@@ -950,7 +979,7 @@ func findWork() error {
950979
continue
951980
}
952981
for _, rev := range goRevisions {
953-
addWork(buildgo.BuilderRev{Name: b, Rev: rev})
982+
add(buildgo.BuilderRev{Name: b, Rev: rev})
954983
}
955984
}
956985
return nil
@@ -1160,7 +1189,7 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
11601189
continue
11611190
}
11621191
brev := tryKeyToBuilderRev(bconf.Name, key, goRev)
1163-
bs, err := newBuild(brev)
1192+
bs, err := newBuild(brev, noCommitDetail)
11641193
if err != nil {
11651194
log.Printf("can't create build for %q: %v", brev, err)
11661195
continue
@@ -1190,7 +1219,7 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
11901219
continue
11911220
}
11921221
brev := tryKeyToBuilderRev(linuxBuilder.Name, key, goRev)
1193-
bs, err := newBuild(brev)
1222+
bs, err := newBuild(brev, noCommitDetail)
11941223
if err != nil {
11951224
log.Printf("can't create build for %q: %v", brev, err)
11961225
continue
@@ -1221,7 +1250,7 @@ func newTrySet(work *apipb.GerritTryWorkItem) *trySet {
12211250
SubName: project,
12221251
SubRev: rev,
12231252
}
1224-
bs, err := newBuild(brev)
1253+
bs, err := newBuild(brev, noCommitDetail)
12251254
if err != nil {
12261255
log.Printf("can't create x/%s trybot build for go/master commit %s: %v", project, rev, err)
12271256
return nil
@@ -1338,7 +1367,7 @@ func (ts *trySet) awaitTryBuild(idx int, bs *buildStatus, brev buildgo.BuilderRe
13381367
if !ts.wanted() {
13391368
return
13401369
}
1341-
bs, _ = newBuild(brev)
1370+
bs, _ = newBuild(brev, noCommitDetail)
13421371
bs.trySet = ts
13431372
bs.goBranch = old.goBranch
13441373
go bs.start()
@@ -1588,7 +1617,12 @@ func poolForConf(conf *dashboard.HostConfig) BuildletPool {
15881617
}
15891618
}
15901619

1591-
func newBuild(rev buildgo.BuilderRev) (*buildStatus, error) {
1620+
// noCommitDetail is just a nice name for nil at call sites.
1621+
var noCommitDetail *commitDetail = nil
1622+
1623+
// newBuild constructs a new *buildStatus from rev and an optional detail.
1624+
// If detail is nil, the scheduler just has less information to work with.
1625+
func newBuild(rev buildgo.BuilderRev, detail *commitDetail) (*buildStatus, error) {
15921626
// Note: can't acquire statusMu in newBuild, as this is called
15931627
// from findTryWork -> newTrySet, which holds statusMu.
15941628

@@ -1600,6 +1634,19 @@ func newBuild(rev buildgo.BuilderRev) (*buildStatus, error) {
16001634
return nil, fmt.Errorf("required field Rev is empty; got %+v", rev)
16011635
}
16021636

1637+
var branch string
1638+
var commitTime time.Time
1639+
if detail != nil {
1640+
branch = detail.Branch
1641+
if detail.CommitTime != "" {
1642+
var err error
1643+
commitTime, err = time.Parse(time.RFC3339, detail.CommitTime)
1644+
if err != nil {
1645+
return nil, fmt.Errorf("invalid commit time %q, for %+v: %err", detail.CommitTime, rev, err)
1646+
}
1647+
}
1648+
}
1649+
16031650
ctx, cancel := context.WithCancel(context.Background())
16041651
return &buildStatus{
16051652
buildID: "B" + randHex(9),
@@ -1608,6 +1655,8 @@ func newBuild(rev buildgo.BuilderRev) (*buildStatus, error) {
16081655
startTime: time.Now(),
16091656
ctx: ctx,
16101657
cancel: cancel,
1658+
commitTime: commitTime,
1659+
branch: branch,
16111660
}, nil
16121661
}
16131662

@@ -1717,6 +1766,8 @@ func (st *buildStatus) onceInitHelpersFunc() {
17171766
BuilderRev: st.BuilderRev,
17181767
HostType: st.conf.HostType,
17191768
IsTry: st.isTry(),
1769+
CommitTime: st.commitTime,
1770+
Branch: st.branch,
17201771
}
17211772
st.helpers = getBuildlets(st.ctx, st.conf.NumTestHelpers(st.isTry()), schedTmpl, st)
17221773
}
@@ -1799,6 +1850,8 @@ func (st *buildStatus) getBuildlet() (*buildlet.Client, error) {
17991850
HostType: st.conf.HostType,
18001851
IsTry: st.trySet != nil,
18011852
BuilderRev: st.BuilderRev,
1853+
CommitTime: st.commitTime,
1854+
Branch: st.branch,
18021855
}
18031856
st.mu.Lock()
18041857
st.schedItem = schedItem
@@ -2110,6 +2163,8 @@ func (st *buildStatus) crossCompileMakeAndSnapshot(config *dashboard.CrossCompil
21102163
HostType: config.CompileHostType,
21112164
IsTry: st.trySet != nil,
21122165
BuilderRev: st.BuilderRev,
2166+
CommitTime: st.commitTime,
2167+
Branch: st.branch,
21132168
})
21142169
sp.Done(err)
21152170
if err != nil {
@@ -3370,11 +3425,13 @@ type eventAndTime struct {
33703425
type buildStatus struct {
33713426
// Immutable:
33723427
buildgo.BuilderRev
3373-
buildID string // "B" + 9 random hex
3374-
goBranch string // non-empty for subrepo trybots if not go master branch
3375-
conf *dashboard.BuildConfig
3376-
startTime time.Time // actually time of newBuild (~same thing); TODO(bradfitz): rename this createTime
3377-
trySet *trySet // or nil
3428+
buildID string // "B" + 9 random hex
3429+
goBranch string // non-empty for subrepo trybots if not go master branch
3430+
conf *dashboard.BuildConfig
3431+
startTime time.Time // actually time of newBuild (~same thing)
3432+
trySet *trySet // or nil
3433+
commitTime time.Time // non-zero for post-submit builders
3434+
branch string // non-empty for post-submit work
33783435

33793436
onceInitHelpers sync.Once // guards call of onceInitHelpersFunc
33803437
helpers <-chan *buildlet.Client

cmd/coordinator/coordinator_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ func TestFindWork(t *testing.T) {
189189
return false
190190
}
191191

192-
addWorkTestHook = func(work buildgo.BuilderRev) {
193-
t.Logf("Got: %v", work)
192+
addWorkTestHook = func(work buildgo.BuilderRev, d *commitDetail) {
193+
t.Logf("Got: %v, %+v", work, d)
194194
}
195195
defer func() { addWorkTestHook = nil }()
196196

cmd/coordinator/sched.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,19 @@ func (s *Scheduler) waiterState(waiter *SchedItem) (ws types.BuildletWaitStatus)
284284
return ws
285285
}
286286

287-
// schedLess reports whether scheduled item ia is "less" (more
288-
// important) than scheduled item ib.
287+
// schedLess reports whether the scheduler item ia is "less" (more
288+
// important) than scheduler item ib.
289289
func schedLess(ia, ib *SchedItem) bool {
290290
// TODO: flesh out this policy more. For now this is much
291291
// better than the old random policy.
292292
// For example, consider IsHelper? Figure out a policy.
293+
// TODO: consider SchedItem.Branch.
294+
// TODO: pass in a context to schedLess that includes current time and current
295+
// top of various branches. Then we can use that in decisions rather than doing
296+
// lookups or locks in a less function.
293297

294-
// Gomote is most important, then TryBots, then FIFO for
295-
// either Gomote/Try, else LIFO for post-submit builds.
298+
// Gomote is most important, then TryBots (FIFO for either), then
299+
// post-submit builds (LIFO, by commit time)
296300
if ia.IsGomote != ib.IsGomote {
297301
return ia.IsGomote
298302
}
@@ -307,8 +311,11 @@ func schedLess(ia, ib *SchedItem) bool {
307311
// time. But time works for now.
308312
return ia.requestTime.Before(ib.requestTime)
309313
}
310-
// Post-submit builds are LIFO.
311-
return ib.requestTime.Before(ia.requestTime)
314+
315+
// Post-submit builds are LIFO by commit time, not necessarily
316+
// when the coordinator's findWork loop threw them at the
317+
// scheduler.
318+
return ia.CommitTime.After(ib.CommitTime)
312319
}
313320

314321
// SchedItem is a specification of a requested buildlet in its
@@ -320,15 +327,15 @@ type SchedItem struct {
320327
IsGomote bool
321328
IsTry bool
322329
IsHelper bool
330+
CommitTime time.Time
331+
Branch string
323332

324333
// The following unexported fields are set by the Scheduler in
325334
// Scheduler.GetBuildlet.
326335

327336
s *Scheduler
328337
requestTime time.Time
329-
commitTime time.Time // TODO: populate post-submit commit time from maintnerd
330-
branch string // TODO: populate from maintnerd
331-
tryFor string // TODO: which user. (user with 1 trybot >> user with 50 trybots)
338+
tryFor string // TODO: which user. (user with 1 trybot >> user with 50 trybots)
332339
pool BuildletPool
333340
ctxDone <-chan struct{}
334341

cmd/coordinator/sched_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,24 @@ func TestSchedLess(t *testing.T) {
8787
{
8888
name: "reg LIFO, less",
8989
a: &SchedItem{
90-
requestTime: t2,
90+
CommitTime: t2,
91+
requestTime: t1, // shouldn't be used
9192
},
9293
b: &SchedItem{
93-
requestTime: t1,
94+
CommitTime: t1,
95+
requestTime: t2, // shouldn't be used
9496
},
9597
want: true,
9698
},
9799
{
98100
name: "reg LIFO, greater",
99101
a: &SchedItem{
100-
requestTime: t1,
102+
CommitTime: t1,
103+
requestTime: t2, // shouldn't be used
101104
},
102105
b: &SchedItem{
103-
requestTime: t2,
106+
CommitTime: t2,
107+
requestTime: t1, // shouldn't be used
104108
},
105109
want: false,
106110
},

0 commit comments

Comments
 (0)