| 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 |