4
4
"fmt"
5
5
"math"
6
6
"sync"
7
+ "sync/atomic"
7
8
"time"
8
9
9
10
"github.com/iotaledger/hive.go/core/safemath"
@@ -44,6 +45,8 @@ type Scheduler struct {
44
45
45
46
workersWg sync.WaitGroup
46
47
shutdownSignal chan struct {}
48
+ // isShutdown is true if the scheduler was shutdown.
49
+ isShutdown atomic.Bool
47
50
48
51
blockCache * blocks.Blocks
49
52
@@ -69,6 +72,11 @@ func NewProvider(opts ...options.Option[Scheduler]) module.Provider[*engine.Engi
69
72
e .Events .Notarization .LatestCommitmentUpdated .Hook (func (commitment * model.Commitment ) {
70
73
// when the last slot of an epoch is committed, remove the queues of validators that are no longer in the committee.
71
74
if s .apiProvider .APIForSlot (commitment .Slot ()).TimeProvider ().SlotsBeforeNextEpoch (commitment .Slot ()) == 0 {
75
+ if s .IsShutdown () {
76
+ // if the scheduler is already shutdown, we don't need to do anything.
77
+ return
78
+ }
79
+
72
80
s .bufferMutex .Lock ()
73
81
defer s .bufferMutex .Unlock ()
74
82
@@ -102,12 +110,22 @@ func NewProvider(opts ...options.Option[Scheduler]) module.Provider[*engine.Engi
102
110
s .selectBlockToScheduleWithLocking ()
103
111
})
104
112
e .Events .Ledger .AccountCreated .Hook (func (accountID iotago.AccountID ) {
113
+ if s .IsShutdown () {
114
+ // if the scheduler is already shutdown, we don't need to do anything.
115
+ return
116
+ }
117
+
105
118
s .bufferMutex .Lock ()
106
119
defer s .bufferMutex .Unlock ()
107
120
108
121
s .createIssuer (accountID )
109
122
})
110
123
e .Events .Ledger .AccountDestroyed .Hook (func (accountID iotago.AccountID ) {
124
+ if s .IsShutdown () {
125
+ // if the scheduler is already shutdown, we don't need to do anything.
126
+ return
127
+ }
128
+
111
129
s .bufferMutex .Lock ()
112
130
defer s .bufferMutex .Unlock ()
113
131
@@ -142,10 +160,13 @@ func New(subModule module.Module, apiProvider iotago.APIProvider, opts ...option
142
160
}
143
161
144
162
func (s * Scheduler ) shutdown () {
145
- s .bufferMutex .Lock ()
146
- defer s .bufferMutex .Unlock ()
163
+ if s .isShutdown .Swap (true ) {
164
+ return
165
+ }
147
166
167
+ s .bufferMutex .Lock ()
148
168
s .validatorBuffer .Clear ()
169
+ s .bufferMutex .Unlock ()
149
170
150
171
close (s .shutdownSignal )
151
172
@@ -154,6 +175,10 @@ func (s *Scheduler) shutdown() {
154
175
s .StoppedEvent ().Trigger ()
155
176
}
156
177
178
+ func (s * Scheduler ) IsShutdown () bool {
179
+ return s .isShutdown .Load ()
180
+ }
181
+
157
182
// Start starts the scheduler.
158
183
func (s * Scheduler ) Start () {
159
184
s .shutdownSignal = make (chan struct {}, 1 )
@@ -200,13 +225,23 @@ func (s *Scheduler) MaxBufferSize() int {
200
225
201
226
// ReadyBlocksCount returns the number of ready blocks.
202
227
func (s * Scheduler ) ReadyBlocksCount () int {
228
+ if s .IsShutdown () {
229
+ // if the scheduler is already shutdown, we return 0.
230
+ return 0
231
+ }
232
+
203
233
s .bufferMutex .RLock ()
204
234
defer s .bufferMutex .RUnlock ()
205
235
206
236
return s .basicBuffer .ReadyBlocksCount ()
207
237
}
208
238
209
239
func (s * Scheduler ) IsBlockIssuerReady (accountID iotago.AccountID , workScores ... iotago.WorkScore ) bool {
240
+ if s .IsShutdown () {
241
+ // if the scheduler is already shutdown, we return false.
242
+ return false
243
+ }
244
+
210
245
s .bufferMutex .RLock ()
211
246
defer s .bufferMutex .RUnlock ()
212
247
@@ -243,6 +278,11 @@ func (s *Scheduler) AddBlock(block *blocks.Block) {
243
278
244
279
// Reset resets the component to a clean state as if it was created at the last commitment.
245
280
func (s * Scheduler ) Reset () {
281
+ if s .IsShutdown () {
282
+ // if the scheduler is already shutdown, we don't need to do anything.
283
+ return
284
+ }
285
+
246
286
s .bufferMutex .Lock ()
247
287
defer s .bufferMutex .Unlock ()
248
288
@@ -251,6 +291,11 @@ func (s *Scheduler) Reset() {
251
291
}
252
292
253
293
func (s * Scheduler ) enqueueBasicBlock (block * blocks.Block ) {
294
+ if s .IsShutdown () {
295
+ // if the scheduler is already shutdown, we don't need to do anything.
296
+ return
297
+ }
298
+
254
299
s .bufferMutex .Lock ()
255
300
defer s .bufferMutex .Unlock ()
256
301
@@ -289,6 +334,11 @@ func (s *Scheduler) enqueueBasicBlock(block *blocks.Block) {
289
334
}
290
335
291
336
func (s * Scheduler ) enqueueValidationBlock (block * blocks.Block ) {
337
+ if s .IsShutdown () {
338
+ // if the scheduler is already shutdown, we don't need to do anything.
339
+ return
340
+ }
341
+
292
342
s .bufferMutex .Lock ()
293
343
defer s .bufferMutex .Unlock ()
294
344
@@ -338,6 +388,9 @@ loop:
338
388
for {
339
389
select {
340
390
// on close, exit the loop
391
+ case <- s .shutdownSignal :
392
+ break loop
393
+ // on close, exit the loop
341
394
case <- validatorQueue .shutdownSignal :
342
395
break loop
343
396
// when a block is pushed by this validator queue.
@@ -384,6 +437,11 @@ func (s *Scheduler) scheduleValidationBlock(block *blocks.Block, validatorQueue
384
437
}
385
438
386
439
func (s * Scheduler ) selectBlockToScheduleWithLocking () {
440
+ if s .IsShutdown () {
441
+ // if the scheduler is already shutdown, we don't need to do anything.
442
+ return
443
+ }
444
+
387
445
s .bufferMutex .Lock ()
388
446
defer s .bufferMutex .Unlock ()
389
447
@@ -424,8 +482,14 @@ func (s *Scheduler) selectBasicBlockWithoutLocking() {
424
482
})
425
483
}
426
484
485
+ start := s .basicBuffer .Current ()
486
+ if start == nil {
487
+ // if there are no queues in the buffer, we cannot schedule anything
488
+ return
489
+ }
490
+
427
491
// increment the deficit for all issuers before schedulingIssuer one more time
428
- for q := s . basicBuffer . Current () ; q != schedulingIssuer ; q = s .basicBuffer .Next () {
492
+ for q := start ; q != schedulingIssuer ; q = s .basicBuffer .Next () {
429
493
issuerID := q .IssuerID ()
430
494
newDeficit , err := s .incrementDeficit (issuerID , 1 , slot )
431
495
if err != nil {
@@ -652,6 +716,11 @@ func (s *Scheduler) tryReadyValidationBlock(block *blocks.Block) {
652
716
// updateChildrenWithLocking locks the buffer mutex and iterates over the direct children of the given blockID and
653
717
// tries to mark them as ready.
654
718
func (s * Scheduler ) updateChildrenWithLocking (block * blocks.Block ) {
719
+ if s .IsShutdown () {
720
+ // if the scheduler is already shutdown, we don't need to do anything.
721
+ return
722
+ }
723
+
655
724
s .bufferMutex .Lock ()
656
725
defer s .bufferMutex .Unlock ()
657
726
0 commit comments