-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtaskstat.go
More file actions
140 lines (121 loc) · 3.71 KB
/
taskstat.go
File metadata and controls
140 lines (121 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package taskengine
import "fmt"
// TaskStat type object tracks the number of workers dealing with the task.
// It is used to dynamically choose the next task to execute.
type TaskStat struct {
Todo int // how many workers have to do the task.
Doing int // how many workers are doing the task.
Done int // how many workers have done the task.
Success int // how many workers have done the task with success.
}
// func (stat *TaskStat) Todo() int { return stat.todo }
// func (stat *TaskStat) Doing() int { return stat.doing }
// func (stat *TaskStat) Done() int { return stat.done }
// func (stat *TaskStat) Success() int { return stat.success }
// Completed returns if no worker has to do or is doing the task.
func (stat *TaskStat) Completed() bool {
return (stat.Todo == 0) && (stat.Doing == 0)
}
// String representation of a TaskStat object.
func (stat TaskStat) String() string {
return fmt.Sprintf("[%d %d %d(%d)]",
stat.Todo, stat.Doing, stat.Done, stat.Success)
}
// taskStatMap maps TaskID -> taskInfo.
type taskStatMap map[TaskID]*TaskStat
// // total returns how many workers have assigned the task.
// func (stat *taskStat) total() int {
// return stat.todo + stat.doing + stat.done
// }
// // total returns how many workers have done the task with error.
// func (stat *taskStat) error() int {
// return stat.done - stat.success
// }
// newTaskStatusMap init a new taskInfoMap from a WorkerTasks object.
func newTaskStatusMap(widtasks WorkerTasks) taskStatMap {
statmap := taskStatMap{}
for _, ts := range widtasks {
for _, t := range ts {
statmap.todo(t.TaskID())
}
}
return statmap
}
// completed returns true if all the tasks are completed:
// no worker has to do or is doing some task.
func (statmap taskStatMap) completed() bool {
for _, stat := range statmap {
if !stat.Completed() {
return false
}
}
return true
}
// todo increments the number workers that can perform the given task.
func (statmap taskStatMap) todo(tid TaskID) {
stat := statmap[tid]
if stat == nil {
stat = &TaskStat{}
statmap[tid] = stat
}
stat.Todo++
}
// doing increments the doing number and decrements the todo number.
// WARN: it doesn't check that task exists and todo > 0.
func (statmap taskStatMap) doing(tid TaskID) {
stat := statmap[tid]
stat.Todo--
stat.Doing++
}
// done increments the done number and decrements the doing number.
// It also increments the success number, if needed.
// WARN: it doesn't check task exists and doing > 0.
func (statmap taskStatMap) done(tid TaskID, success bool) {
stat := statmap[tid]
stat.Doing--
stat.Done++
if success {
stat.Success++
}
}
// pick choose among the tasks list the best task to execute next.
// The task is chosen so to maximize the thoughput of the tasks successfully executed.
// It returns -1 if the tasks list is empty, or the index of the choosen task in the list.
// It doesn't updates neither the Tasks nor the taskInfoMap.
// WARN: it doesn't check every TaskID exists in taskStatMap.
func (statmap taskStatMap) pick(ts Tasks) int {
L := len(ts)
if L == 0 {
return -1
}
j0 := 0
s0 := statmap[ts[0].TaskID()]
for j := 1; j < L; j++ {
s := statmap[ts[j].TaskID()]
if s.Success > s0.Success {
// prefer task with fewer success
continue
} else if s.Success == s0.Success {
if s.Doing > s0.Doing {
// else prefer task with fewer doing
continue
} else if s.Doing == s0.Doing {
if s.Todo > s0.Todo {
// else prefer task with fewer todo
continue
} else if s.Todo == s0.Todo {
// else prefer task with lower TaskID
// NOTE: only needed to be deterministic
tid0 := ts[j0].TaskID()
tid := ts[j].TaskID()
if tid >= tid0 {
continue
}
}
}
}
j0 = j
s0 = s
}
return j0
}