@@ -28,14 +28,14 @@ use super::{Command, Scheduled};
28
28
use crate :: hummock:: HummockManagerRef ;
29
29
use crate :: rpc:: metrics:: MetaMetrics ;
30
30
use crate :: storage:: MetaStore ;
31
- use crate :: MetaResult ;
31
+ use crate :: { MetaError , MetaResult } ;
32
32
33
33
/// A queue for scheduling barriers.
34
34
///
35
35
/// We manually implement one here instead of using channels since we may need to update the front
36
36
/// of the queue to add some notifiers for instant flushes.
37
37
struct Inner {
38
- queue : RwLock < VecDeque < Scheduled > > ,
38
+ queue : RwLock < ScheduledQueue > ,
39
39
40
40
/// When `queue` is not empty anymore, all subscribers of this watcher will be notified.
41
41
changed_tx : watch:: Sender < ( ) > ,
@@ -52,6 +52,47 @@ struct Inner {
52
52
metrics : Arc < MetaMetrics > ,
53
53
}
54
54
55
+ enum QueueStatus {
56
+ /// The queue is ready to accept new command.
57
+ Ready ,
58
+ /// The queue is blocked to accept new command with the given reason.
59
+ Blocked ( String ) ,
60
+ }
61
+
62
+ struct ScheduledQueue {
63
+ queue : VecDeque < Scheduled > ,
64
+ status : QueueStatus ,
65
+ }
66
+
67
+ impl ScheduledQueue {
68
+ fn new ( ) -> Self {
69
+ Self {
70
+ queue : VecDeque :: new ( ) ,
71
+ status : QueueStatus :: Ready ,
72
+ }
73
+ }
74
+
75
+ fn mark_blocked ( & mut self , reason : String ) {
76
+ self . status = QueueStatus :: Blocked ( reason) ;
77
+ }
78
+
79
+ fn mark_ready ( & mut self ) {
80
+ self . status = QueueStatus :: Ready ;
81
+ }
82
+
83
+ fn len ( & self ) -> usize {
84
+ self . queue . len ( )
85
+ }
86
+
87
+ fn push_back ( & mut self , scheduled : Scheduled ) -> MetaResult < ( ) > {
88
+ if let QueueStatus :: Blocked ( reason) = & self . status {
89
+ return Err ( MetaError :: unavailable ( reason. clone ( ) ) ) ;
90
+ }
91
+ self . queue . push_back ( scheduled) ;
92
+ Ok ( ( ) )
93
+ }
94
+ }
95
+
55
96
impl Inner {
56
97
/// Create a new scheduled barrier with the given `checkpoint`, `command` and `notifiers`.
57
98
fn new_scheduled (
@@ -100,7 +141,7 @@ impl<S: MetaStore> BarrierScheduler<S> {
100
141
checkpoint_frequency,
101
142
) ;
102
143
let inner = Arc :: new ( Inner {
103
- queue : RwLock :: new ( VecDeque :: new ( ) ) ,
144
+ queue : RwLock :: new ( ScheduledQueue :: new ( ) ) ,
104
145
changed_tx : watch:: channel ( ( ) ) . 0 ,
105
146
num_uncheckpointed_barrier : AtomicUsize :: new ( 0 ) ,
106
147
checkpoint_frequency : AtomicUsize :: new ( checkpoint_frequency) ,
@@ -118,20 +159,21 @@ impl<S: MetaStore> BarrierScheduler<S> {
118
159
}
119
160
120
161
/// Push a scheduled barrier into the queue.
121
- async fn push ( & self , scheduleds : impl IntoIterator < Item = Scheduled > ) {
162
+ async fn push ( & self , scheduleds : impl IntoIterator < Item = Scheduled > ) -> MetaResult < ( ) > {
122
163
let mut queue = self . inner . queue . write ( ) . await ;
123
164
for scheduled in scheduleds {
124
- queue. push_back ( scheduled) ;
165
+ queue. push_back ( scheduled) ? ;
125
166
if queue. len ( ) == 1 {
126
167
self . inner . changed_tx . send ( ( ) ) . ok ( ) ;
127
168
}
128
169
}
170
+ Ok ( ( ) )
129
171
}
130
172
131
173
/// Try to cancel scheduled cmd for create streaming job, return true if cancelled.
132
174
pub async fn try_cancel_scheduled_create ( & self , table_id : TableId ) -> bool {
133
- let mut queue = self . inner . queue . write ( ) . await ;
134
- if let Some ( idx) = queue. iter ( ) . position ( |scheduled| {
175
+ let queue = & mut self . inner . queue . write ( ) . await ;
176
+ if let Some ( idx) = queue. queue . iter ( ) . position ( |scheduled| {
135
177
if let Command :: CreateStreamingJob {
136
178
table_fragments, ..
137
179
} = & scheduled. command
@@ -142,7 +184,7 @@ impl<S: MetaStore> BarrierScheduler<S> {
142
184
false
143
185
}
144
186
} ) {
145
- queue. remove ( idx) . unwrap ( ) ;
187
+ queue. queue . remove ( idx) . unwrap ( ) ;
146
188
true
147
189
} else {
148
190
false
@@ -152,9 +194,13 @@ impl<S: MetaStore> BarrierScheduler<S> {
152
194
/// Attach `new_notifiers` to the very first scheduled barrier. If there's no one scheduled, a
153
195
/// default barrier will be created. If `new_checkpoint` is true, the barrier will become a
154
196
/// checkpoint.
155
- async fn attach_notifiers ( & self , new_notifiers : Vec < Notifier > , new_checkpoint : bool ) {
197
+ async fn attach_notifiers (
198
+ & self ,
199
+ new_notifiers : Vec < Notifier > ,
200
+ new_checkpoint : bool ,
201
+ ) -> MetaResult < ( ) > {
156
202
let mut queue = self . inner . queue . write ( ) . await ;
157
- match queue. front_mut ( ) {
203
+ match queue. queue . front_mut ( ) {
158
204
Some ( Scheduled {
159
205
notifiers,
160
206
checkpoint,
@@ -169,10 +215,11 @@ impl<S: MetaStore> BarrierScheduler<S> {
169
215
new_checkpoint,
170
216
Command :: barrier ( ) ,
171
217
new_notifiers,
172
- ) ) ;
218
+ ) ) ? ;
173
219
self . inner . changed_tx . send ( ( ) ) . ok ( ) ;
174
220
}
175
221
}
222
+ Ok ( ( ) )
176
223
}
177
224
178
225
/// Wait for the next barrier to collect. Note that the barrier flowing in our stream graph is
@@ -183,7 +230,7 @@ impl<S: MetaStore> BarrierScheduler<S> {
183
230
collected : Some ( tx) ,
184
231
..Default :: default ( )
185
232
} ;
186
- self . attach_notifiers ( vec ! [ notifier] , checkpoint) . await ;
233
+ self . attach_notifiers ( vec ! [ notifier] , checkpoint) . await ? ;
187
234
rx. await . unwrap ( )
188
235
}
189
236
@@ -219,7 +266,7 @@ impl<S: MetaStore> BarrierScheduler<S> {
219
266
) ) ;
220
267
}
221
268
222
- self . push ( scheduleds) . await ;
269
+ self . push ( scheduleds) . await ? ;
223
270
224
271
for Context {
225
272
collect_rx,
@@ -278,7 +325,7 @@ impl ScheduledBarriers {
278
325
pub ( super ) async fn pop_or_default ( & self ) -> Scheduled {
279
326
let mut queue = self . inner . queue . write ( ) . await ;
280
327
let checkpoint = self . try_get_checkpoint ( ) ;
281
- let scheduled = match queue. pop_front ( ) {
328
+ let scheduled = match queue. queue . pop_front ( ) {
282
329
Some ( mut scheduled) => {
283
330
scheduled. checkpoint = scheduled. checkpoint || checkpoint;
284
331
scheduled
@@ -305,16 +352,24 @@ impl ScheduledBarriers {
305
352
rx. changed ( ) . await . unwrap ( ) ;
306
353
}
307
354
308
- /// Clear all queued scheduled barriers, and notify their subscribers with failed as aborted.
309
- pub ( super ) async fn abort ( & self ) {
355
+ /// Mark command scheduler as blocked and abort all queued scheduled command and notify with
356
+ /// specific reason.
357
+ pub ( super ) async fn abort_and_mark_blocked ( & self , reason : impl Into < String > + Copy ) {
310
358
let mut queue = self . inner . queue . write ( ) . await ;
311
- while let Some ( Scheduled { notifiers, .. } ) = queue. pop_front ( ) {
312
- notifiers. into_iter ( ) . for_each ( |notify| {
313
- notify. notify_collection_failed ( anyhow ! ( "Scheduled barrier abort." ) . into ( ) )
314
- } )
359
+ queue. mark_blocked ( reason. into ( ) ) ;
360
+ while let Some ( Scheduled { notifiers, .. } ) = queue. queue . pop_front ( ) {
361
+ notifiers
362
+ . into_iter ( )
363
+ . for_each ( |notify| notify. notify_collection_failed ( anyhow ! ( reason. into( ) ) . into ( ) ) )
315
364
}
316
365
}
317
366
367
+ /// Mark command scheduler as ready to accept new command.
368
+ pub ( super ) async fn mark_ready ( & self ) {
369
+ let mut queue = self . inner . queue . write ( ) . await ;
370
+ queue. mark_ready ( ) ;
371
+ }
372
+
318
373
/// Whether the barrier(checkpoint = true) should be injected.
319
374
fn try_get_checkpoint ( & self ) -> bool {
320
375
self . inner
0 commit comments