@@ -176,8 +176,6 @@ func (cfg *ReplayConfig) Validate() ([]storage.ExternalStorage, error) {
176176 now := time .Now ()
177177 if cfg .StartTime .IsZero () {
178178 return storages , errors .New ("start time is not specified" )
179- } else if now .Add (time .Minute ).Before (cfg .StartTime ) {
180- return storages , errors .New ("start time should not be in the future" )
181179 } else if cfg .StartTime .Add (time .Minute ).Before (now ) {
182180 return storages , errors .New ("start time should not be in the past" )
183181 }
@@ -269,7 +267,7 @@ type replay struct {
269267 exceptionCh chan conn.Exception
270268 closeConnCh chan uint64
271269 execInfoCh chan conn.ExecInfo
272- gracefulStop atomic. Bool
270+ gracefulStopCh chan struct {}
273271 wg waitgroup.WaitGroup
274272 cancel context.CancelFunc
275273 connCreator conn.ConnCreator
@@ -309,7 +307,7 @@ func (r *replay) Start(cfg ReplayConfig, backendTLSConfig *tls.Config, hsHandler
309307 r .cfg = cfg
310308 r .storages = storages
311309 r .meta = * r .readMeta ()
312- r .gracefulStop . Store ( false )
310+ r .gracefulStopCh = make ( chan struct {} )
313311 r .startTime = cfg .StartTime
314312 r .endTime = time.Time {}
315313 r .progress = 0
@@ -395,7 +393,45 @@ func (r *replay) Start(cfg ReplayConfig, backendTLSConfig *tls.Config, hsHandler
395393 return nil
396394}
397395
396+ // waitUntilStartTime waits until the configured start time and returns whether the replay has stopped
397+ func (r * replay ) waitUntilStartTime (ctx context.Context ) bool {
398+ waitDuration := time .Until (r .cfg .StartTime )
399+ if waitDuration > 0 {
400+ r .lg .Info ("wait until the specified time to start replaying" , zap .Time ("until" , r .cfg .StartTime ),
401+ zap .Duration ("duration" , waitDuration ))
402+ select {
403+ case <- ctx .Done ():
404+ return true
405+ case <- time .After (waitDuration ):
406+ return false
407+ case <- r .gracefulStopCh :
408+ return true
409+ }
410+ }
411+
412+ return false
413+ }
414+
415+ // isGracefulStopped returns whether the replay is gracefully stopped.
416+ func (r * replay ) isGracefulStopped () bool {
417+ select {
418+ case _ , ok := <- r .gracefulStopCh :
419+ if ! ok {
420+ return true
421+ } else {
422+ return false
423+ }
424+ default :
425+ return false
426+ }
427+ }
428+
398429func (r * replay ) readCommands (ctx context.Context ) {
430+ if r .waitUntilStartTime (ctx ) {
431+ r .stop (nil )
432+ return
433+ }
434+
399435 var decoder decoder
400436 var err error
401437
@@ -429,7 +465,7 @@ func (r *replay) readCommands(ctx context.Context) {
429465 connCount := 0 // alive connection count
430466 maxPendingCmds := int64 (0 )
431467 extraWaitTime := time .Duration (0 )
432- for ctx .Err () == nil && ! r .gracefulStop . Load () {
468+ for ctx .Err () == nil && ! r .isGracefulStopped () {
433469 for hasCloseEvent := true ; hasCloseEvent ; {
434470 select {
435471 case id := <- r .closeConnCh :
@@ -501,6 +537,7 @@ func (r *replay) readCommands(ctx context.Context) {
501537 select {
502538 case <- ctx .Done ():
503539 case <- time .After (expectedInterval ):
540+ case <- r .gracefulStopCh :
504541 }
505542 }
506543 }
@@ -513,7 +550,7 @@ func (r *replay) readCommands(ctx context.Context) {
513550 zap .Int ("alive_conns" , connCount ),
514551 zap .Time ("last_cmd_start_ts" , time .Unix (0 , r .replayStats .CurCmdTs .Load ())),
515552 zap .Time ("last_cmd_end_ts" , time .Unix (0 , r .replayStats .CurCmdEndTs .Load ())),
516- zap .Bool ("graceful_stop" , r .gracefulStop . Load ()),
553+ zap .Bool ("graceful_stop" , r .isGracefulStopped ()),
517554 zap .Error (err ),
518555 zap .NamedError ("ctx_err" , ctx .Err ()))
519556
@@ -980,6 +1017,10 @@ func (r *replay) Wait() {
9801017 r .wg .Wait ()
9811018}
9821019
1020+ func (r * replay ) gracefulStop () {
1021+ close (r .gracefulStopCh )
1022+ }
1023+
9831024func (r * replay ) Stop (err error , graceful bool ) {
9841025 r .Lock ()
9851026 // already stopped
@@ -989,7 +1030,7 @@ func (r *replay) Stop(err error, graceful bool) {
9891030 }
9901031 r .err = err
9911032 if graceful {
992- r .gracefulStop . Store ( true )
1033+ r .gracefulStop ( )
9931034 } else if r .cancel != nil {
9941035 r .cancel ()
9951036 r .cancel = nil
0 commit comments