@@ -29,6 +29,8 @@ const (
29
29
EventAdd EventType = iota
30
30
EventDel
31
31
EventErr
32
+ EventPause
33
+ EventResume
32
34
)
33
35
34
36
func (t EventType ) String () string {
@@ -39,6 +41,10 @@ func (t EventType) String() string {
39
41
return "Del"
40
42
case EventErr :
41
43
return "Err"
44
+ case EventPause :
45
+ return "Pause"
46
+ case EventResume :
47
+ return "Resume"
42
48
}
43
49
return "Unknown"
44
50
}
@@ -70,29 +76,47 @@ func errorEvent(err error) TaskEvent {
70
76
}
71
77
72
78
func (t AdvancerExt ) toTaskEvent (ctx context.Context , event * clientv3.Event ) (TaskEvent , error ) {
73
- if ! bytes .HasPrefix (event .Kv .Key , []byte (PrefixOfTask ())) {
74
- return TaskEvent {}, errors .Annotatef (berrors .ErrInvalidArgument ,
75
- "the path isn't a task path (%s)" , string (event .Kv .Key ))
79
+ te := TaskEvent {}
80
+ var prefix string
81
+
82
+ if bytes .HasPrefix (event .Kv .Key , []byte (PrefixOfTask ())) {
83
+ prefix = PrefixOfTask ()
84
+ te .Name = strings .TrimPrefix (string (event .Kv .Key ), prefix )
85
+ } else if bytes .HasPrefix (event .Kv .Key , []byte (PrefixOfPause ())) {
86
+ prefix = PrefixOfPause ()
87
+ te .Name = strings .TrimPrefix (string (event .Kv .Key ), prefix )
88
+ } else {
89
+ return TaskEvent {},
90
+ errors .Annotatef (berrors .ErrInvalidArgument , "the path isn't a task/pause path (%s)" ,
91
+ string (event .Kv .Key ))
76
92
}
77
93
78
- te := TaskEvent {}
79
- te .Name = strings .TrimPrefix (string (event .Kv .Key ), PrefixOfTask ())
80
- if event .Type == clientv3 .EventTypeDelete {
81
- te .Type = EventDel
82
- } else if event .Type == clientv3 .EventTypePut {
94
+ switch {
95
+ case event .Type == clientv3 .EventTypePut && prefix == PrefixOfTask ():
83
96
te .Type = EventAdd
84
- } else {
85
- return TaskEvent {}, errors .Annotatef (berrors .ErrInvalidArgument , "event type is wrong (%s)" , event .Type )
97
+ case event .Type == clientv3 .EventTypeDelete && prefix == PrefixOfTask ():
98
+ te .Type = EventDel
99
+ case event .Type == clientv3 .EventTypePut && prefix == PrefixOfPause ():
100
+ te .Type = EventPause
101
+ case event .Type == clientv3 .EventTypeDelete && prefix == PrefixOfPause ():
102
+ te .Type = EventResume
103
+ default :
104
+ return TaskEvent {},
105
+ errors .Annotatef (berrors .ErrInvalidArgument ,
106
+ "invalid event type or prefix: type=%s, prefix=%s" , event .Type , prefix )
86
107
}
108
+
87
109
te .Info = new (backuppb.StreamBackupTaskInfo )
88
110
if err := proto .Unmarshal (event .Kv .Value , te .Info ); err != nil {
89
111
return TaskEvent {}, err
90
112
}
113
+
91
114
var err error
92
115
te .Ranges , err = t .MetaDataClient .TaskByInfo (* te .Info ).Ranges (ctx )
93
116
if err != nil {
94
117
return TaskEvent {}, err
95
118
}
119
+
96
120
return te , nil
97
121
}
98
122
@@ -113,7 +137,10 @@ func (t AdvancerExt) eventFromWatch(ctx context.Context, resp clientv3.WatchResp
113
137
}
114
138
115
139
func (t AdvancerExt ) startListen (ctx context.Context , rev int64 , ch chan <- TaskEvent ) {
116
- c := t .Client .Watcher .Watch (ctx , PrefixOfTask (), clientv3 .WithPrefix (), clientv3 .WithRev (rev ))
140
+ taskCh := t .Client .Watcher .Watch (ctx , PrefixOfTask (), clientv3 .WithPrefix (), clientv3 .WithRev (rev ))
141
+ pauseCh := t .Client .Watcher .Watch (ctx , PrefixOfPause (), clientv3 .WithPrefix (), clientv3 .WithRev (rev ))
142
+
143
+ // inner function def
117
144
handleResponse := func (resp clientv3.WatchResponse ) bool {
118
145
events , err := t .eventFromWatch (ctx , resp )
119
146
if err != nil {
@@ -127,21 +154,26 @@ func (t AdvancerExt) startListen(ctx context.Context, rev int64, ch chan<- TaskE
127
154
}
128
155
return true
129
156
}
157
+
158
+ // inner function def
130
159
collectRemaining := func () {
131
160
log .Info ("Start collecting remaining events in the channel." , zap .String ("category" , "log backup advancer" ),
132
- zap .Int ("remained" , len (c )))
161
+ zap .Int ("remained" , len (taskCh )))
133
162
defer log .Info ("Finish collecting remaining events in the channel." , zap .String ("category" , "log backup advancer" ))
134
163
for {
164
+ if taskCh == nil && pauseCh == nil {
165
+ return
166
+ }
167
+
135
168
select {
136
- case resp , ok := <- c :
137
- if ! ok {
138
- return
169
+ case resp , ok := <- taskCh :
170
+ if ! ok || ! handleResponse ( resp ) {
171
+ taskCh = nil
139
172
}
140
- if ! handleResponse (resp ) {
141
- return
173
+ case resp , ok := <- pauseCh :
174
+ if ! ok || ! handleResponse (resp ) {
175
+ pauseCh = nil
142
176
}
143
- default :
144
- return
145
177
}
146
178
}
147
179
}
@@ -150,7 +182,7 @@ func (t AdvancerExt) startListen(ctx context.Context, rev int64, ch chan<- TaskE
150
182
defer close (ch )
151
183
for {
152
184
select {
153
- case resp , ok := <- c :
185
+ case resp , ok := <- taskCh :
154
186
failpoint .Inject ("advancer_close_channel" , func () {
155
187
// We cannot really close the channel, just simulating it.
156
188
ok = false
@@ -162,6 +194,18 @@ func (t AdvancerExt) startListen(ctx context.Context, rev int64, ch chan<- TaskE
162
194
if ! handleResponse (resp ) {
163
195
return
164
196
}
197
+ case resp , ok := <- pauseCh :
198
+ failpoint .Inject ("advancer_close_pause_channel" , func () {
199
+ // We cannot really close the channel, just simulating it.
200
+ ok = false
201
+ })
202
+ if ! ok {
203
+ ch <- errorEvent (io .EOF )
204
+ return
205
+ }
206
+ if ! handleResponse (resp ) {
207
+ return
208
+ }
165
209
case <- ctx .Done ():
166
210
collectRemaining ()
167
211
ch <- errorEvent (ctx .Err ())
0 commit comments