OLD | NEW |
1 package db | 1 package db |
2 | 2 |
3 import ( | 3 import ( |
4 "bytes" | 4 "bytes" |
5 "encoding/gob" | 5 "encoding/gob" |
6 "fmt" | 6 "fmt" |
7 "time" | 7 "time" |
8 | 8 |
9 "go.skia.org/infra/go/util" | 9 "go.skia.org/infra/go/util" |
10 | 10 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 // that can not be executed on Swarming, but can be added to the DB and | 49 // that can not be executed on Swarming, but can be added to the DB and |
50 // displayed as if it were a real TaskSpec. | 50 // displayed as if it were a real TaskSpec. |
51 type Task struct { | 51 type Task struct { |
52 // Commits are the commits which were tested in this Task. The list may | 52 // Commits are the commits which were tested in this Task. The list may |
53 // change due to backfilling/bisecting. | 53 // change due to backfilling/bisecting. |
54 Commits []string | 54 Commits []string |
55 | 55 |
56 // Created is the creation timestamp. | 56 // Created is the creation timestamp. |
57 Created time.Time | 57 Created time.Time |
58 | 58 |
59 » // Id is a generated unique identifier for this Task instance. Must be U
RL-safe. | 59 » // Id is a generated unique identifier for this Task instance. Must be |
| 60 » // URL-safe. |
60 Id string | 61 Id string |
61 | 62 |
62 // IsolatedOutput is the isolated hash of any outputs produced by this | 63 // IsolatedOutput is the isolated hash of any outputs produced by this |
63 // Task. Filled in when the task is completed. | 64 // Task. Filled in when the task is completed. |
64 IsolatedOutput string | 65 IsolatedOutput string |
65 | 66 |
66 // Name is a human-friendly descriptive name for this Task. All Tasks | 67 // Name is a human-friendly descriptive name for this Task. All Tasks |
67 // generated from the same TaskSpec have the same name. | 68 // generated from the same TaskSpec have the same name. |
68 Name string | 69 Name string |
69 | 70 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 return fmt.Errorf("Unable to parse task creation time for task %
s. %v %v", t.Id, err, s) | 143 return fmt.Errorf("Unable to parse task creation time for task %
s. %v %v", t.Id, err, s) |
143 } | 144 } |
144 | 145 |
145 switch s.TaskResult.State { | 146 switch s.TaskResult.State { |
146 case SWARMING_STATE_BOT_DIED, SWARMING_STATE_CANCELED, SWARMING_STATE_EX
PIRED, SWARMING_STATE_TIMED_OUT: | 147 case SWARMING_STATE_BOT_DIED, SWARMING_STATE_CANCELED, SWARMING_STATE_EX
PIRED, SWARMING_STATE_TIMED_OUT: |
147 t.Status = TASK_STATUS_MISHAP | 148 t.Status = TASK_STATUS_MISHAP |
148 case SWARMING_STATE_PENDING, SWARMING_STATE_RUNNING: | 149 case SWARMING_STATE_PENDING, SWARMING_STATE_RUNNING: |
149 t.Status = TASK_STATUS_PENDING | 150 t.Status = TASK_STATUS_PENDING |
150 case SWARMING_STATE_COMPLETED: | 151 case SWARMING_STATE_COMPLETED: |
151 if s.TaskResult.Failure { | 152 if s.TaskResult.Failure { |
152 » » » // TODO(benjaminwagner): Choose FAILURE or MISHAP depend
ing on ExitCode? | 153 » » » // TODO(benjaminwagner): Choose FAILURE or MISHAP depend
ing on |
| 154 » » » // ExitCode? |
153 t.Status = TASK_STATUS_FAILURE | 155 t.Status = TASK_STATUS_FAILURE |
154 } else { | 156 } else { |
155 t.Status = TASK_STATUS_SUCCESS | 157 t.Status = TASK_STATUS_SUCCESS |
156 } | 158 } |
157 default: | 159 default: |
158 return fmt.Errorf("Unknown Swarming State %v in %v", s.TaskResul
t.State, s) | 160 return fmt.Errorf("Unknown Swarming State %v in %v", s.TaskResul
t.State, s) |
159 } | 161 } |
160 | 162 |
161 if s.TaskResult.OutputsRef == nil { | 163 if s.TaskResult.OutputsRef == nil { |
162 t.IsolatedOutput = "" | 164 t.IsolatedOutput = "" |
(...skipping 19 matching lines...) Expand all Loading... |
182 if err := gob.NewEncoder(&buf).Encode(t); err != nil { | 184 if err := gob.NewEncoder(&buf).Encode(t); err != nil { |
183 glog.Fatal(err) | 185 glog.Fatal(err) |
184 } | 186 } |
185 var rv Task | 187 var rv Task |
186 if err := gob.NewDecoder(&buf).Decode(&rv); err != nil { | 188 if err := gob.NewDecoder(&buf).Decode(&rv); err != nil { |
187 glog.Fatal(err) | 189 glog.Fatal(err) |
188 } | 190 } |
189 return &rv | 191 return &rv |
190 } | 192 } |
191 | 193 |
| 194 // TaskSlice implements sort.Interface. To sort tasks []*Task, use |
| 195 // sort.Sort(TaskSlice(tasks)). |
192 type TaskSlice []*Task | 196 type TaskSlice []*Task |
193 | 197 |
194 func (s TaskSlice) Len() int { return len(s) } | 198 func (s TaskSlice) Len() int { return len(s) } |
195 | 199 |
196 func (s TaskSlice) Less(i, j int) bool { | 200 func (s TaskSlice) Less(i, j int) bool { |
197 return s[i].Created.Before(s[j].Created) | 201 return s[i].Created.Before(s[j].Created) |
198 } | 202 } |
199 | 203 |
200 func (s TaskSlice) Swap(i, j int) { | 204 func (s TaskSlice) Swap(i, j int) { |
201 s[i], s[j] = s[j], s[i] | 205 s[i], s[j] = s[j], s[i] |
202 } | 206 } |
| 207 |
| 208 // TaskEncoder encodes Tasks into bytes via GOB encoding. Not safe for |
| 209 // concurrent use. |
| 210 // TODO(benjaminwagner): Encode in parallel. |
| 211 type TaskEncoder struct { |
| 212 err error |
| 213 tasks []*Task |
| 214 result [][]byte |
| 215 } |
| 216 |
| 217 // Process encodes the Task into a byte slice that will be returned from Next() |
| 218 // (in arbitrary order). Returns false if Next is certain to return an error. |
| 219 // Caller must ensure t does not change until after the first call to Next(). |
| 220 // May not be called after calling Next(). |
| 221 func (e *TaskEncoder) Process(t *Task) bool { |
| 222 if e.err != nil { |
| 223 return false |
| 224 } |
| 225 var buf bytes.Buffer |
| 226 if err := gob.NewEncoder(&buf).Encode(t); err != nil { |
| 227 e.err = err |
| 228 e.tasks = nil |
| 229 e.result = nil |
| 230 return false |
| 231 } |
| 232 e.tasks = append(e.tasks, t) |
| 233 e.result = append(e.result, buf.Bytes()) |
| 234 return true |
| 235 } |
| 236 |
| 237 // Next returns one of the Tasks provided to Process (in arbitrary order) and |
| 238 // its serialized bytes. If any tasks remain, returns the task, the serialized |
| 239 // bytes, nil. If all tasks have been returned, returns nil, nil, nil. If an |
| 240 // error is encountered, returns nil, nil, error. |
| 241 func (e *TaskEncoder) Next() (*Task, []byte, error) { |
| 242 if e.err != nil { |
| 243 return nil, nil, e.err |
| 244 } |
| 245 if len(e.tasks) == 0 { |
| 246 return nil, nil, nil |
| 247 } |
| 248 t := e.tasks[0] |
| 249 e.tasks = e.tasks[1:] |
| 250 serialized := e.result[0] |
| 251 e.result = e.result[1:] |
| 252 return t, serialized, nil |
| 253 } |
| 254 |
| 255 // TaskDecoder decodes bytes into Tasks via GOB decoding. Not safe for |
| 256 // concurrent use. |
| 257 // TODO(benjaminwagner): Decode in parallel. |
| 258 type TaskDecoder struct { |
| 259 err error |
| 260 result []*Task |
| 261 } |
| 262 |
| 263 // Process decodes the byte slice into a Task and includes it in Result() (in |
| 264 // arbitrary order). Returns false if Result is certain to return an error. |
| 265 // Caller must ensure b does not change until after Result() returns. |
| 266 func (d *TaskDecoder) Process(b []byte) bool { |
| 267 if d.err != nil { |
| 268 return false |
| 269 } |
| 270 var t Task |
| 271 if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&t); err != nil { |
| 272 d.err = err |
| 273 d.result = nil |
| 274 return false |
| 275 } |
| 276 d.result = append(d.result, &t) |
| 277 return true |
| 278 } |
| 279 |
| 280 // Result returns all decoded Tasks provided to Process (in arbitrary order), or |
| 281 // any error encountered. |
| 282 func (d *TaskDecoder) Result() ([]*Task, error) { |
| 283 // Allow TaskDecoder to be used without initialization. |
| 284 if d.err == nil && d.result == nil { |
| 285 return []*Task{}, nil |
| 286 } |
| 287 return d.result, d.err |
| 288 } |
OLD | NEW |