cmd/coordinator: support limiting number of builds at once

Change-Id: Icd0054f2b943abf2e8a15c32d358ff06541f75f7
Reviewed-on: https://go-review.googlesource.com/41130
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/cmd/coordinator/coordinator.go b/cmd/coordinator/coordinator.go
index 6ec0bb0..456261d 100644
--- a/cmd/coordinator/coordinator.go
+++ b/cmd/coordinator/coordinator.go
@@ -377,6 +377,17 @@
 	return len(status)
 }
 
+func numCurrentBuildsOfType(typ string) (n int) {
+	statusMu.Lock()
+	defer statusMu.Unlock()
+	for rev := range status {
+		if rev.name == typ {
+			n++
+		}
+	}
+	return
+}
+
 func isBuilding(work builderRev) bool {
 	statusMu.Lock()
 	defer statusMu.Unlock()
@@ -406,6 +417,9 @@
 		}
 		return false
 	}
+	if buildConf.MaxAtOnce > 0 && numCurrentBuildsOfType(rev.name) >= buildConf.MaxAtOnce {
+		return false
+	}
 	if buildConf.IsReverse() && !reversePool.CanBuild(buildConf.HostType) {
 		return false
 	}
diff --git a/dashboard/builders.go b/dashboard/builders.go
index 7a37dae..0689024 100644
--- a/dashboard/builders.go
+++ b/dashboard/builders.go
@@ -417,6 +417,12 @@
 	CompileOnly bool // if true, compile tests, but don't run them
 	FlakyNet    bool // network tests are flaky (try anyway, but ignore some failures)
 
+	// MaxAtOnce optionally specifies a cap of how many builds of
+	// this type can run at once. Zero means unlimited. This is a
+	// temporary measure until the build scheduler
+	// (golang.org/issue/19178) is done.
+	MaxAtOnce int
+
 	// SkipSnapshot, if true, means to not fetch a tarball
 	// snapshot of the world post-make.bash from the buildlet (and
 	// thus to not write it to Google Cloud Storage). This is