8
8
"context"
9
9
"fmt"
10
10
"sync"
11
+ "sync/atomic"
11
12
"time"
12
13
13
14
"code.gitea.io/gitea/modules/log"
@@ -52,8 +53,7 @@ func NewByteFIFOQueue(typ Type, byteFIFO ByteFIFO, handle HandlerFunc, cfg, exem
52
53
terminateCtx , terminateCtxCancel := context .WithCancel (context .Background ())
53
54
shutdownCtx , shutdownCtxCancel := context .WithCancel (terminateCtx )
54
55
55
- return & ByteFIFOQueue {
56
- WorkerPool : NewWorkerPool (handle , config .WorkerPoolConfiguration ),
56
+ q := & ByteFIFOQueue {
57
57
byteFIFO : byteFIFO ,
58
58
typ : typ ,
59
59
shutdownCtx : shutdownCtx ,
@@ -65,7 +65,17 @@ func NewByteFIFOQueue(typ Type, byteFIFO ByteFIFO, handle HandlerFunc, cfg, exem
65
65
name : config .Name ,
66
66
waitOnEmpty : config .WaitOnEmpty ,
67
67
pushed : make (chan struct {}, 1 ),
68
- }, nil
68
+ }
69
+ q .WorkerPool = NewWorkerPool (func (data ... Data ) (failed []Data ) {
70
+ for _ , unhandled := range handle (data ... ) {
71
+ if fail := q .PushBack (unhandled ); fail != nil {
72
+ failed = append (failed , fail )
73
+ }
74
+ }
75
+ return
76
+ }, config .WorkerPoolConfiguration )
77
+
78
+ return q , nil
69
79
}
70
80
71
81
// Name returns the name of this queue
@@ -78,6 +88,25 @@ func (q *ByteFIFOQueue) Push(data Data) error {
78
88
return q .PushFunc (data , nil )
79
89
}
80
90
91
+ // PushBack pushes data to the fifo
92
+ func (q * ByteFIFOQueue ) PushBack (data Data ) error {
93
+ if ! assignableTo (data , q .exemplar ) {
94
+ return fmt .Errorf ("Unable to assign data: %v to same type as exemplar: %v in %s" , data , q .exemplar , q .name )
95
+ }
96
+ json := jsoniter .ConfigCompatibleWithStandardLibrary
97
+ bs , err := json .Marshal (data )
98
+ if err != nil {
99
+ return err
100
+ }
101
+ defer func () {
102
+ select {
103
+ case q .pushed <- struct {}{}:
104
+ default :
105
+ }
106
+ }()
107
+ return q .byteFIFO .PushBack (q .terminateCtx , bs )
108
+ }
109
+
81
110
// PushFunc pushes data to the fifo
82
111
func (q * ByteFIFOQueue ) PushFunc (data Data , fn func () error ) error {
83
112
if ! assignableTo (data , q .exemplar ) {
@@ -88,14 +117,12 @@ func (q *ByteFIFOQueue) PushFunc(data Data, fn func() error) error {
88
117
if err != nil {
89
118
return err
90
119
}
91
- if q .waitOnEmpty {
92
- defer func () {
93
- select {
94
- case q .pushed <- struct {}{}:
95
- default :
96
- }
97
- }()
98
- }
120
+ defer func () {
121
+ select {
122
+ case q .pushed <- struct {}{}:
123
+ default :
124
+ }
125
+ }()
99
126
return q .byteFIFO .PushFunc (q .terminateCtx , bs , fn )
100
127
}
101
128
@@ -109,6 +136,15 @@ func (q *ByteFIFOQueue) IsEmpty() bool {
109
136
return q .byteFIFO .Len (q .terminateCtx ) == 0
110
137
}
111
138
139
+ // Flush flushes the ByteFIFOQueue
140
+ func (q * ByteFIFOQueue ) Flush (timeout time.Duration ) error {
141
+ select {
142
+ case q .pushed <- struct {}{}:
143
+ default :
144
+ }
145
+ return q .WorkerPool .Flush (timeout )
146
+ }
147
+
112
148
// Run runs the bytefifo queue
113
149
func (q * ByteFIFOQueue ) Run (atShutdown , atTerminate func (func ())) {
114
150
atShutdown (q .Shutdown )
@@ -143,47 +179,89 @@ func (q *ByteFIFOQueue) readToChan() {
143
179
144
180
// Default backoff values
145
181
backOffTime := time .Millisecond * 100
182
+ backOffTimer := time .NewTimer (0 )
183
+ if ! backOffTimer .Stop () {
184
+ select {
185
+ case <- backOffTimer .C :
186
+ default :
187
+ }
188
+ }
146
189
147
190
loop:
148
191
for {
149
- err := q .doPop ()
150
- if err == errQueueEmpty {
151
- log .Trace ("%s: %s Waiting on Empty" , q . typ , q .name )
192
+ paused , resumed := q .IsPausedIsResumed ()
193
+ if paused {
194
+ log .Trace ("Queue %s pausing" , q .name )
152
195
select {
153
- case <- q .pushed :
154
- // reset backOffTime
155
- backOffTime = 100 * time .Millisecond
156
- continue loop
196
+ case <- resumed :
197
+ log .Trace ("Queue %s resuming" , q .name )
157
198
case <- q .shutdownCtx .Done ():
158
- // Oops we've been shutdown whilst waiting
159
- // Make sure the worker pool is shutdown too
199
+ // tell the pool to shutdown.
160
200
q .baseCtxCancel ()
161
201
return
202
+ case data := <- q .dataChan :
203
+ if err := q .PushBack (data ); err != nil {
204
+ log .Error ("Unable to push back data into queue %s" , q .name )
205
+ }
206
+ atomic .AddInt64 (& q .numInQueue , - 1 )
162
207
}
163
208
}
164
209
165
- // Reset the backOffTime if there is no error or an unmarshalError
166
- if err == nil || err == errUnmarshal {
167
- backOffTime = 100 * time .Millisecond
210
+ // empty the pushed channel
211
+ select {
212
+ case <- q .pushed :
213
+ default :
214
+ }
215
+
216
+ err := q .doPop ()
217
+
218
+ if ! backOffTimer .Stop () {
219
+ select {
220
+ case <- backOffTimer .C :
221
+ default :
222
+ }
168
223
}
169
224
170
225
if err != nil {
226
+ if err == errQueueEmpty && q .waitOnEmpty {
227
+ log .Trace ("%s: %s Waiting on Empty" , q .typ , q .name )
228
+
229
+ // reset the backoff time but don't set the timer
230
+ backOffTime = 100 * time .Millisecond
231
+ } else if err == errUnmarshal {
232
+ // reset the timer and backoff
233
+ backOffTime = 100 * time .Millisecond
234
+ backOffTimer .Reset (backOffTime )
235
+ } else {
236
+ // backoff
237
+ backOffTimer .Reset (backOffTime )
238
+ }
239
+
171
240
// Need to Backoff
172
241
select {
173
242
case <- q .shutdownCtx .Done ():
174
243
// Oops we've been shutdown whilst backing off
175
244
// Make sure the worker pool is shutdown too
176
245
q .baseCtxCancel ()
177
246
return
178
- case <- time .After (backOffTime ):
179
- // OK we've waited - so backoff a bit
247
+ case <- q .pushed :
248
+ // Data has been pushed to the fifo (or flush has been called)
249
+ // reset the backoff time
250
+ backOffTime = 100 * time .Millisecond
251
+ continue loop
252
+ case <- backOffTimer .C :
253
+ // Calculate the next backoff time
180
254
backOffTime += backOffTime / 2
181
255
if backOffTime > maxBackOffTime {
182
256
backOffTime = maxBackOffTime
183
257
}
184
258
continue loop
185
259
}
186
260
}
261
+
262
+ // Reset the backoff time
263
+ backOffTime = 100 * time .Millisecond
264
+
187
265
select {
188
266
case <- q .shutdownCtx .Done ():
189
267
// Oops we've been shutdown
@@ -288,9 +366,8 @@ func NewByteFIFOUniqueQueue(typ Type, byteFIFO UniqueByteFIFO, handle HandlerFun
288
366
terminateCtx , terminateCtxCancel := context .WithCancel (context .Background ())
289
367
shutdownCtx , shutdownCtxCancel := context .WithCancel (terminateCtx )
290
368
291
- return & ByteFIFOUniqueQueue {
369
+ q := & ByteFIFOUniqueQueue {
292
370
ByteFIFOQueue : ByteFIFOQueue {
293
- WorkerPool : NewWorkerPool (handle , config .WorkerPoolConfiguration ),
294
371
byteFIFO : byteFIFO ,
295
372
typ : typ ,
296
373
shutdownCtx : shutdownCtx ,
@@ -301,7 +378,17 @@ func NewByteFIFOUniqueQueue(typ Type, byteFIFO UniqueByteFIFO, handle HandlerFun
301
378
workers : config .Workers ,
302
379
name : config .Name ,
303
380
},
304
- }, nil
381
+ }
382
+ q .WorkerPool = NewWorkerPool (func (data ... Data ) (failed []Data ) {
383
+ for _ , unhandled := range handle (data ... ) {
384
+ if fail := q .PushBack (unhandled ); fail != nil {
385
+ failed = append (failed , fail )
386
+ }
387
+ }
388
+ return
389
+ }, config .WorkerPoolConfiguration )
390
+
391
+ return q , nil
305
392
}
306
393
307
394
// Has checks if the provided data is in the queue
0 commit comments