| OLD | NEW |
| (Empty) |
| 1 package task_scheduler | |
| 2 | |
| 3 import ( | |
| 4 "fmt" | |
| 5 "path" | |
| 6 "strings" | |
| 7 | |
| 8 swarming_api "github.com/luci/luci-go/common/api/swarming/swarming/v1" | |
| 9 "go.skia.org/infra/build_scheduler/go/db" | |
| 10 "go.skia.org/infra/go/isolate" | |
| 11 "go.skia.org/infra/go/swarming" | |
| 12 ) | |
| 13 | |
| 14 // taskCandidate is a struct used for determining which tasks to schedule. | |
| 15 type taskCandidate struct { | |
| 16 Commits []string | |
| 17 IsolatedInput string | |
| 18 IsolatedHashes []string | |
| 19 Name string | |
| 20 Repo string | |
| 21 Revision string | |
| 22 Score float64 | |
| 23 StealingFromId string | |
| 24 TaskSpec *TaskSpec | |
| 25 } | |
| 26 | |
| 27 // Copy returns a copy of the taskCandidate. | |
| 28 func (c *taskCandidate) Copy() *taskCandidate { | |
| 29 commits := make([]string, len(c.Commits)) | |
| 30 copy(commits, c.Commits) | |
| 31 isolatedHashes := make([]string, len(c.IsolatedHashes)) | |
| 32 copy(isolatedHashes, c.IsolatedHashes) | |
| 33 return &taskCandidate{ | |
| 34 Commits: commits, | |
| 35 IsolatedInput: c.IsolatedInput, | |
| 36 IsolatedHashes: isolatedHashes, | |
| 37 Name: c.Name, | |
| 38 Repo: c.Repo, | |
| 39 Revision: c.Revision, | |
| 40 Score: c.Score, | |
| 41 StealingFromId: c.StealingFromId, | |
| 42 TaskSpec: c.TaskSpec.Copy(), | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 // MakeId generates a string ID for the taskCandidate. | |
| 47 func (c *taskCandidate) MakeId() string { | |
| 48 return fmt.Sprintf("taskCandidate|%s|%s|%s", c.Repo, c.Name, c.Revision) | |
| 49 } | |
| 50 | |
| 51 // ParseId generates taskCandidate information from the ID. | |
| 52 func parseId(id string) (string, string, string, error) { | |
| 53 split := strings.Split(id, "|") | |
| 54 if len(split) != 4 { | |
| 55 return "", "", "", fmt.Errorf("Invalid ID: %q", id) | |
| 56 } | |
| 57 if split[0] != "taskCandidate" { | |
| 58 return "", "", "", fmt.Errorf("Invalid ID: %q", id) | |
| 59 } | |
| 60 for _, s := range split[1:] { | |
| 61 if s == "" { | |
| 62 return "", "", "", fmt.Errorf("Invalid ID: %q", id) | |
| 63 } | |
| 64 } | |
| 65 return split[1], split[2], split[3], nil | |
| 66 } | |
| 67 | |
| 68 // MakeTask instantiates a db.Task from the taskCandidate. | |
| 69 func (c *taskCandidate) MakeTask() *db.Task { | |
| 70 commits := make([]string, len(c.Commits)) | |
| 71 copy(commits, c.Commits) | |
| 72 return &db.Task{ | |
| 73 Commits: commits, | |
| 74 Id: "", // Filled in when the task is inserted into the DB
. | |
| 75 Name: c.Name, | |
| 76 Repo: c.Repo, | |
| 77 Revision: c.Revision, | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 // MakeIsolateTask creates an isolate.Task from this taskCandidate. | |
| 82 func (c *taskCandidate) MakeIsolateTask(infraBotsDir, baseDir string) *isolate.T
ask { | |
| 83 return &isolate.Task{ | |
| 84 BaseDir: baseDir, | |
| 85 Blacklist: isolate.DEFAULT_BLACKLIST, | |
| 86 Deps: c.IsolatedHashes, | |
| 87 IsolateFile: path.Join(infraBotsDir, c.TaskSpec.Isolate), | |
| 88 OsType: "linux", // TODO(borenet) | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 // MakeTaskRequest creates a SwarmingRpcsNewTaskRequest object from the taskCand
idate. | |
| 93 func (c *taskCandidate) MakeTaskRequest(id string) *swarming_api.SwarmingRpcsNew
TaskRequest { | |
| 94 cipdPackages := make([]*swarming_api.SwarmingRpcsCipdPackage, 0, len(c.T
askSpec.CipdPackages)) | |
| 95 for _, p := range c.TaskSpec.CipdPackages { | |
| 96 cipdPackages = append(cipdPackages, &swarming_api.SwarmingRpcsCi
pdPackage{ | |
| 97 PackageName: p.Name, | |
| 98 Path: p.Path, | |
| 99 Version: fmt.Sprintf("%d", p.Version), | |
| 100 }) | |
| 101 } | |
| 102 | |
| 103 dims := make([]*swarming_api.SwarmingRpcsStringPair, 0, len(c.TaskSpec.D
imensions)) | |
| 104 dimsMap := make(map[string]string, len(c.TaskSpec.Dimensions)) | |
| 105 for _, d := range c.TaskSpec.Dimensions { | |
| 106 split := strings.SplitN(d, ":", 2) | |
| 107 key := split[0] | |
| 108 val := split[1] | |
| 109 dims = append(dims, &swarming_api.SwarmingRpcsStringPair{ | |
| 110 Key: key, | |
| 111 Value: val, | |
| 112 }) | |
| 113 dimsMap[key] = val | |
| 114 } | |
| 115 | |
| 116 return &swarming_api.SwarmingRpcsNewTaskRequest{ | |
| 117 ExpirationSecs: int64(swarming.RECOMMENDED_EXPIRATION.Seconds())
, | |
| 118 Name: c.Name, | |
| 119 Priority: int64(100.0 * c.TaskSpec.Priority), | |
| 120 Properties: &swarming_api.SwarmingRpcsTaskProperties{ | |
| 121 CipdInput: &swarming_api.SwarmingRpcsCipdInput{ | |
| 122 Packages: cipdPackages, | |
| 123 }, | |
| 124 Dimensions: dims, | |
| 125 ExecutionTimeoutSecs: int64(swarming.RECOMMENDED_HARD_TI
MEOUT.Seconds()), | |
| 126 InputsRef: &swarming_api.SwarmingRpcsFilesRef{ | |
| 127 Isolated: c.IsolatedInput, | |
| 128 Isolatedserver: isolate.ISOLATE_SERVER_URL, | |
| 129 Namespace: isolate.DEFAULT_NAMESPACE, | |
| 130 }, | |
| 131 IoTimeoutSecs: int64(swarming.RECOMMENDED_IO_TIMEOUT.Sec
onds()), | |
| 132 }, | |
| 133 Tags: db.TagsForTask(c.Name, id, c.TaskSpec.Priority, c.Repo, c.
Revision, dimsMap), | |
| 134 User: "skia-build-scheduler", | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 // allDepsMet determines whether all dependencies for the given task candidate | |
| 139 // have been satisfied, and if so, returns their isolated outputs. | |
| 140 func (c *taskCandidate) allDepsMet(cache db.TaskCache) (bool, []string, error) { | |
| 141 isolatedHashes := make([]string, 0, len(c.TaskSpec.Dependencies)) | |
| 142 for _, depName := range c.TaskSpec.Dependencies { | |
| 143 d, err := cache.GetTaskForCommit(c.Repo, c.Revision, depName) | |
| 144 if err != nil { | |
| 145 return false, nil, err | |
| 146 } | |
| 147 if d == nil { | |
| 148 return false, nil, nil | |
| 149 } | |
| 150 if !d.Done() || !d.Success() || d.IsolatedOutput == "" { | |
| 151 return false, nil, nil | |
| 152 } | |
| 153 isolatedHashes = append(isolatedHashes, d.IsolatedOutput) | |
| 154 } | |
| 155 return true, isolatedHashes, nil | |
| 156 } | |
| 157 | |
| 158 // taskCandidateSlice is an alias used for sorting a slice of taskCandidates. | |
| 159 type taskCandidateSlice []*taskCandidate | |
| 160 | |
| 161 func (s taskCandidateSlice) Len() int { return len(s) } | |
| 162 func (s taskCandidateSlice) Swap(i, j int) { | |
| 163 s[i], s[j] = s[j], s[i] | |
| 164 } | |
| 165 func (s taskCandidateSlice) Less(i, j int) bool { | |
| 166 return s[i].Score > s[j].Score // candidates sort in decreasing order. | |
| 167 } | |
| OLD | NEW |