Skip to content

Commit

Permalink
cmd/coordinator, internal/coordinator/schedule: create schedule pkg
Browse files Browse the repository at this point in the history
This moves the coordinator scheduler into a package. The span has also
been moved into the schedule package. It also adds a mostly
uimplemented fake scheduler.

Updates golang/go#38337
Updates golang/go#48742

Change-Id: I980241e8e8ba2acafa38f732fe480e66d9d3a4f3
Reviewed-on: https://go-review.googlesource.com/c/build/+/368676
Trust: Carlos Amedee <[email protected]>
Run-TryBot: Carlos Amedee <[email protected]>
Reviewed-by: Heschi Kreinick <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
cagedmantis committed Dec 13, 2021
1 parent f45690d commit c4e615e
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 107 deletions.
37 changes: 19 additions & 18 deletions cmd/coordinator/buildstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"golang.org/x/build/internal/buildstats"
clog "golang.org/x/build/internal/coordinator/log"
"golang.org/x/build/internal/coordinator/pool"
"golang.org/x/build/internal/coordinator/schedule"
"golang.org/x/build/internal/singleflight"
"golang.org/x/build/internal/sourcecache"
"golang.org/x/build/internal/spanlog"
Expand Down Expand Up @@ -102,14 +103,14 @@ type buildStatus struct {

hasBuildlet int32 // atomic: non-zero if this build has a buildlet; for status.go.

mu sync.Mutex // guards following
canceled bool // whether this build was forcefully canceled, so errors should be ignored
schedItem *SchedItem // for the initial buildlet (ignoring helpers for now)
logURL string // if non-empty, permanent URL of log
bc *buildlet.Client // nil initially, until pool returns one
done time.Time // finished running
succeeded bool // set when done
output livelog.Buffer // stdout and stderr
mu sync.Mutex // guards following
canceled bool // whether this build was forcefully canceled, so errors should be ignored
schedItem *schedule.SchedItem // for the initial buildlet (ignoring helpers for now)
logURL string // if non-empty, permanent URL of log
bc *buildlet.Client // nil initially, until pool returns one
done time.Time // finished running
succeeded bool // set when done
output livelog.Buffer // stdout and stderr
events []eventAndTime
useSnapshotMemo *bool // if non-nil, memoized result of useSnapshot
}
Expand Down Expand Up @@ -293,7 +294,7 @@ func (st *buildStatus) getHelpers() <-chan *buildlet.Client {
}

func (st *buildStatus) onceInitHelpersFunc() {
schedTmpl := &SchedItem{
schedTmpl := &schedule.SchedItem{
BuilderRev: st.BuilderRev,
HostType: st.conf.HostType,
IsTry: st.isTry(),
Expand Down Expand Up @@ -377,7 +378,7 @@ func (st *buildStatus) checkDep(ctx context.Context, dep string) (have bool, err
var errSkipBuildDueToDeps = errors.New("build was skipped due to missing deps")

func (st *buildStatus) getBuildlet() (*buildlet.Client, error) {
schedItem := &SchedItem{
schedItem := &schedule.SchedItem{
HostType: st.conf.HostType,
IsTry: st.trySet != nil,
BuilderRev: st.BuilderRev,
Expand Down Expand Up @@ -610,7 +611,7 @@ func (st *buildStatus) buildRecord() *types.BuildRecord {
return rec
}

func (st *buildStatus) spanRecord(sp *span, err error) *types.SpanRecord {
func (st *buildStatus) SpanRecord(sp *schedule.Span, err error) *types.SpanRecord {
rec := &types.SpanRecord{
BuildID: st.buildID,
IsTry: st.isTry(),
Expand All @@ -621,11 +622,11 @@ func (st *buildStatus) spanRecord(sp *span, err error) *types.SpanRecord {
OS: st.conf.GOOS(),
Arch: st.conf.GOARCH(),

Event: sp.event,
Detail: sp.optText,
StartTime: sp.start,
EndTime: sp.end,
Seconds: sp.end.Sub(sp.start).Seconds(),
Event: sp.Event(),
Detail: sp.OptText(),
StartTime: sp.Start(),
EndTime: sp.End(),
Seconds: sp.End().Sub(sp.Start()).Seconds(),
}
if err != nil {
rec.Error = err.Error()
Expand Down Expand Up @@ -700,7 +701,7 @@ func (st *buildStatus) crossCompileMakeAndSnapshot(config *dashboard.CrossCompil
ctx, cancel := context.WithCancel(st.ctx)
defer cancel()
sp := st.CreateSpan("get_buildlet_cross")
kubeBC, err := sched.GetBuildlet(ctx, &SchedItem{
kubeBC, err := sched.GetBuildlet(ctx, &schedule.SchedItem{
HostType: config.CompileHostType,
IsTry: st.trySet != nil,
BuilderRev: st.BuilderRev,
Expand Down Expand Up @@ -1576,7 +1577,7 @@ func (st *buildStatus) runTestsOnBuildlet(bc *buildlet.Client, tis []*testItem,
}

func (st *buildStatus) CreateSpan(event string, optText ...string) spanlog.Span {
return createSpan(st, event, optText...)
return schedule.CreateSpan(st, event, optText...)
}

func (st *buildStatus) LogEventTime(event string, optText ...string) {
Expand Down
60 changes: 3 additions & 57 deletions cmd/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import (
clog "golang.org/x/build/internal/coordinator/log"
"golang.org/x/build/internal/coordinator/pool"
"golang.org/x/build/internal/coordinator/remote"
"golang.org/x/build/internal/coordinator/schedule"
"golang.org/x/build/internal/https"
"golang.org/x/build/internal/secret"
"golang.org/x/build/maintner/maintnerd/apipb"
Expand Down Expand Up @@ -88,7 +89,7 @@ var (
processID = "P" + randHex(9)
)

var sched = NewScheduler()
var sched = schedule.NewScheduler()

var Version string // set by linker -X

Expand Down Expand Up @@ -1746,7 +1747,7 @@ func (ts *trySet) noteBuildComplete(bs *buildStatus) {

// getBuildlets creates up to n buildlets and sends them on the returned channel
// before closing the channel.
func getBuildlets(ctx context.Context, n int, schedTmpl *SchedItem, lg pool.Logger) <-chan *buildlet.Client {
func getBuildlets(ctx context.Context, n int, schedTmpl *schedule.SchedItem, lg pool.Logger) <-chan *buildlet.Client {
ch := make(chan *buildlet.Client) // NOT buffered
var wg sync.WaitGroup
wg.Add(n)
Expand Down Expand Up @@ -1975,61 +1976,6 @@ type eventAndTime struct {
text string // optional detail text
}

// span is an event covering a region of time.
// A span ultimately ends in an error or success, and will eventually
// be visualized and logged.
type span struct {
event string // event name like "get_foo" or "write_bar"
optText string // optional details for event
start time.Time
end time.Time
el pool.EventTimeLogger // where we log to at the end; TODO: this will change
}

func createSpan(el pool.EventTimeLogger, event string, optText ...string) *span {
if len(optText) > 1 {
panic("usage")
}
start := time.Now()
var opt string
if len(optText) > 0 {
opt = optText[0]
}
el.LogEventTime(event, opt)
return &span{
el: el,
event: event,
start: start,
optText: opt,
}
}

// Done ends a span.
// It is legal to call Done multiple times. Only the first call
// logs.
// Done always returns its input argument.
func (s *span) Done(err error) error {
if !s.end.IsZero() {
return err
}
t1 := time.Now()
s.end = t1
td := t1.Sub(s.start)
var text bytes.Buffer
fmt.Fprintf(&text, "after %s", friendlyDuration(td))
if err != nil {
fmt.Fprintf(&text, "; err=%v", err)
}
if s.optText != "" {
fmt.Fprintf(&text, "; %v", s.optText)
}
if st, ok := s.el.(*buildStatus); ok {
clog.CoordinatorProcess().PutSpanRecord(st.spanRecord(s, err))
}
s.el.LogEventTime("finish_"+s.event, text.String())
return err
}

var nl = []byte("\n")

// getRepoHead returns the commit hash of the latest master HEAD
Expand Down
5 changes: 3 additions & 2 deletions cmd/coordinator/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"golang.org/x/build/buildlet"
"golang.org/x/build/dashboard"
"golang.org/x/build/internal/coordinator/pool"
"golang.org/x/build/internal/coordinator/schedule"
"golang.org/x/build/internal/envutil"
"golang.org/x/build/internal/gophers"
"golang.org/x/build/internal/secret"
Expand Down Expand Up @@ -167,7 +168,7 @@ func handleBuildletCreate(w http.ResponseWriter, r *http.Request) {
w.(http.Flusher).Flush()
}

si := &SchedItem{
si := &schedule.SchedItem{
HostType: bconf.HostType,
IsGomote: true,
}
Expand Down Expand Up @@ -237,7 +238,7 @@ func handleBuildletCreate(w http.ResponseWriter, r *http.Request) {
for {
select {
case <-ticker:
st := sched.waiterState(si)
st := sched.WaiterState(si)
sendJSONLine(msg{Status: &st})
case bc := <-resc:
now := timeNow()
Expand Down
5 changes: 3 additions & 2 deletions cmd/coordinator/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"golang.org/x/build/cmd/coordinator/internal"
"golang.org/x/build/dashboard"
"golang.org/x/build/internal/coordinator/pool"
"golang.org/x/build/internal/coordinator/schedule"
"golang.org/x/build/internal/secret"
"golang.org/x/build/kubernetes/api"
"golang.org/x/oauth2"
Expand Down Expand Up @@ -718,7 +719,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
pool.ReversePool().WriteHTMLStatus(&buf)
data.ReversePoolStatus = template.HTML(buf.String())

data.SchedState = sched.state()
data.SchedState = sched.State()

buf.Reset()
if err := statusTmpl.Execute(&buf, data); err != nil {
Expand Down Expand Up @@ -783,7 +784,7 @@ type statusData struct {
KubePoolStatus template.HTML // TODO: embed template
ReversePoolStatus template.HTML // TODO: embed template
RemoteBuildlets template.HTML
SchedState schedulerState
SchedState schedule.SchedulerState
DiskFree string
Version string
HealthCheckers []*healthChecker
Expand Down
24 changes: 13 additions & 11 deletions cmd/coordinator/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"strings"
"testing"
"time"

"golang.org/x/build/internal/coordinator/schedule"
)

var durationTests = []struct {
Expand Down Expand Up @@ -108,27 +110,27 @@ func TestHandleStatus_HealthFormatting(t *testing.T) {

func TestStatusSched(t *testing.T) {
data := statusData{
SchedState: schedulerState{
HostTypes: []schedulerHostState{
SchedState: schedule.SchedulerState{
HostTypes: []schedule.SchedulerHostState{
{
HostType: "no-special",
LastProgress: 5 * time.Minute,
Total: schedulerWaitingState{Count: 10, Newest: 5 * time.Minute, Oldest: 61 * time.Minute},
Regular: schedulerWaitingState{Count: 1},
Total: schedule.SchedulerWaitingState{Count: 10, Newest: 5 * time.Minute, Oldest: 61 * time.Minute},
Regular: schedule.SchedulerWaitingState{Count: 1},
},
{
HostType: "with-try",
LastProgress: 5 * time.Minute,
Total: schedulerWaitingState{Count: 3},
Try: schedulerWaitingState{Count: 1, Newest: 2 * time.Second, Oldest: 5 * time.Minute},
Regular: schedulerWaitingState{Count: 2},
Total: schedule.SchedulerWaitingState{Count: 3},
Try: schedule.SchedulerWaitingState{Count: 1, Newest: 2 * time.Second, Oldest: 5 * time.Minute},
Regular: schedule.SchedulerWaitingState{Count: 2},
},
{
HostType: "gomote-and-try",
Total: schedulerWaitingState{Count: 6, Newest: 3 * time.Second, Oldest: 4 * time.Minute},
Gomote: schedulerWaitingState{Count: 2, Newest: 3 * time.Second, Oldest: 4 * time.Minute},
Try: schedulerWaitingState{Count: 1},
Regular: schedulerWaitingState{Count: 3},
Total: schedule.SchedulerWaitingState{Count: 6, Newest: 3 * time.Second, Oldest: 4 * time.Minute},
Gomote: schedule.SchedulerWaitingState{Count: 2, Newest: 3 * time.Second, Oldest: 4 * time.Minute},
Try: schedule.SchedulerWaitingState{Count: 1},
Regular: schedule.SchedulerWaitingState{Count: 3},
},
},
},
Expand Down
35 changes: 35 additions & 0 deletions internal/coordinator/schedule/fake_schedule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.13 && (linux || darwin)
// +build go1.13
// +build linux darwin

package schedule

import (
"context"

"golang.org/x/build/buildlet"
"golang.org/x/build/types"
)

// Fake is a fake scheduler.
type Fake struct{}

// NewFake returns a fake scheduler.
func NewFake() *Fake { return &Fake{} }

// State returns the state of the fake scheduler.
func (f *Fake) State() (st SchedulerState) { return SchedulerState{} }

// WaiterState is the waiter state of the fake scheduler.
func (f *Fake) WaiterState(waiter *SchedItem) (ws types.BuildletWaitStatus) {
return types.BuildletWaitStatus{}
}

// GetBuildlet returns a fake buildlet client for the requested buildlet.
func (f *Fake) GetBuildlet(ctx context.Context, si *SchedItem) (*buildlet.Client, error) {
return &buildlet.Client{}, nil
}
Loading

0 comments on commit c4e615e

Please sign in to comment.