@@ -28,57 +28,96 @@ import (
28
28
29
29
type runningJobs struct {
30
30
sync.RWMutex
31
- ids map [int64 ]struct {}
32
- runningSchema map [string ]map [string ]struct {} // database -> table -> struct{}
33
- runningJobIDs string
31
+ // processingIDs records the IDs of the jobs that are being processed by a worker.
32
+ processingIDs map [int64 ]struct {}
33
+ processingIDsStr string
34
+
35
+ // unfinishedIDs records the IDs of the jobs that are not finished yet.
36
+ // It is not necessarily being processed by a worker.
37
+ unfinishedIDs map [int64 ]struct {}
38
+ unfinishedSchema map [string ]map [string ]struct {} // database -> table -> struct{}
34
39
}
35
40
36
41
func newRunningJobs () * runningJobs {
37
42
return & runningJobs {
38
- ids : make (map [int64 ]struct {}),
39
- runningSchema : make (map [string ]map [string ]struct {}),
43
+ processingIDs : make (map [int64 ]struct {}),
44
+ unfinishedSchema : make (map [string ]map [string ]struct {}),
45
+ unfinishedIDs : make (map [int64 ]struct {}),
40
46
}
41
47
}
42
48
43
49
func (j * runningJobs ) add (job * model.Job ) {
44
50
j .Lock ()
45
51
defer j .Unlock ()
46
- j .ids [job .ID ] = struct {}{}
52
+ j .processingIDs [job .ID ] = struct {}{}
47
53
j .updateInternalRunningJobIDs ()
54
+
55
+ if _ , ok := j .unfinishedIDs [job .ID ]; ok {
56
+ // Already exists, no need to add it again.
57
+ return
58
+ }
59
+ j .unfinishedIDs [job .ID ] = struct {}{}
48
60
for _ , info := range job .GetInvolvingSchemaInfo () {
49
- if _ , ok := j .runningSchema [info .Database ]; ! ok {
50
- j .runningSchema [info .Database ] = make (map [string ]struct {})
61
+ if _ , ok := j .unfinishedSchema [info .Database ]; ! ok {
62
+ j .unfinishedSchema [info .Database ] = make (map [string ]struct {})
51
63
}
52
- j.runningSchema [info.Database ][info.Table ] = struct {}{}
64
+ j.unfinishedSchema [info.Database ][info.Table ] = struct {}{}
53
65
}
54
66
}
55
67
56
68
func (j * runningJobs ) remove (job * model.Job ) {
57
69
j .Lock ()
58
70
defer j .Unlock ()
59
- delete (j .ids , job .ID )
71
+ delete (j .processingIDs , job .ID )
60
72
j .updateInternalRunningJobIDs ()
61
- for _ , info := range job .GetInvolvingSchemaInfo () {
62
- if db , ok := j .runningSchema [info .Database ]; ok {
63
- delete (db , info .Table )
73
+
74
+ if job .IsFinished () || job .IsSynced () {
75
+ delete (j .unfinishedIDs , job .ID )
76
+ for _ , info := range job .GetInvolvingSchemaInfo () {
77
+ if db , ok := j .unfinishedSchema [info .Database ]; ok {
78
+ delete (db , info .Table )
79
+ }
80
+ if len (j .unfinishedSchema [info .Database ]) == 0 {
81
+ delete (j .unfinishedSchema , info .Database )
82
+ }
64
83
}
65
- if len (j .runningSchema [info .Database ]) == 0 {
66
- delete (j .runningSchema , info .Database )
84
+ }
85
+ }
86
+
87
+ func (j * runningJobs ) allIDs () string {
88
+ j .RLock ()
89
+ defer j .RUnlock ()
90
+ return j .processingIDsStr
91
+ }
92
+
93
+ func (j * runningJobs ) updateInternalRunningJobIDs () {
94
+ var sb strings.Builder
95
+ i := 0
96
+ for id := range j .processingIDs {
97
+ sb .WriteString (strconv .Itoa (int (id )))
98
+ if i != len (j .processingIDs )- 1 {
99
+ sb .WriteString ("," )
67
100
}
101
+ i ++
68
102
}
103
+ j .processingIDsStr = sb .String ()
69
104
}
70
105
71
106
func (j * runningJobs ) checkRunnable (job * model.Job ) bool {
72
107
j .RLock ()
73
108
defer j .RUnlock ()
109
+ if _ , ok := j .processingIDs [job .ID ]; ok {
110
+ // Already processing by a worker. Skip running it again.
111
+ return false
112
+ }
74
113
for _ , info := range job .GetInvolvingSchemaInfo () {
75
- if _ , ok := j .runningSchema [model .InvolvingAll ]; ok {
114
+ if _ , ok := j .unfinishedSchema [model .InvolvingAll ]; ok {
76
115
return false
77
116
}
78
117
if info .Database == model .InvolvingNone {
79
118
continue
80
119
}
81
- if tbls , ok := j .runningSchema [info .Database ]; ok {
120
+ if tbls , ok := j .unfinishedSchema [info .Database ]; ok {
82
121
if _ , ok := tbls [model .InvolvingAll ]; ok {
83
122
return false
84
123
}
@@ -92,22 +131,3 @@ func (j *runningJobs) checkRunnable(job *model.Job) bool {
92
131
}
93
132
return true
94
133
}
95
-
96
- func (j * runningJobs ) allIDs () string {
97
- j .RLock ()
98
- defer j .RUnlock ()
99
- return j .runningJobIDs
100
- }
101
-
102
- func (j * runningJobs ) updateInternalRunningJobIDs () {
103
- var sb strings.Builder
104
- i := 0
105
- for id := range j .ids {
106
- sb .WriteString (strconv .Itoa (int (id )))
107
- if i != len (j .ids )- 1 {
108
- sb .WriteString ("," )
109
- }
110
- i ++
111
- }
112
- j .runningJobIDs = sb .String ()
113
- }
0 commit comments