@@ -55,8 +55,10 @@ const (
55
55
56
56
defaultPort = 27017
57
57
58
- tryConnCount = 5
59
- tryConnTimeout = 5 * time .Minute
58
+ tryConnCount = 5
59
+ tryConnTimeout = 5 * time .Minute
60
+ mongodLockTimeout = 30 * time .Minute
61
+ mongodPortTimeout = 5 * time .Minute
60
62
61
63
internalMongodLog = "pbm.restore.log"
62
64
)
@@ -452,22 +454,53 @@ func nodeShutdown(ctx context.Context, m *mongo.Client) error {
452
454
return err
453
455
}
454
456
457
+ // waitMgoShutdown waits until mongod releases mongod.lock file within dbpath dir.
458
+ // In case of timeout or unexpected error it'll return error.
455
459
func waitMgoShutdown (dbpath string ) error {
456
460
tk := time .NewTicker (time .Second )
457
461
defer tk .Stop ()
458
462
459
- for range tk .C {
460
- f , err := os .Stat (path .Join (dbpath , mongofslock ))
461
- if err != nil {
462
- return errors .Wrapf (err , "check for lock file %s" , path .Join (dbpath , mongofslock ))
463
- }
463
+ to := time .After (mongodLockTimeout )
464
464
465
- if f .Size () == 0 {
466
- return nil
465
+ for {
466
+ select {
467
+ case <- tk .C :
468
+ f , err := os .Stat (path .Join (dbpath , mongofslock ))
469
+ if err != nil {
470
+ return errors .Wrapf (err , "check for lock file %s" , path .Join (dbpath , mongofslock ))
471
+ }
472
+
473
+ if f .Size () == 0 {
474
+ return nil
475
+ }
476
+
477
+ case <- to :
478
+ return errors .Errorf ("timeout during waiting for lock file %s" , path .Join (dbpath , mongofslock ))
467
479
}
468
480
}
481
+ }
469
482
470
- return nil
483
+ // waitMgoFreePort waits for port p to be free.
484
+ // It case of timeout it'll return error.
485
+ func waitMgoFreePort (p int ) error {
486
+ tk := time .NewTicker (time .Second )
487
+ defer tk .Stop ()
488
+
489
+ to := time .After (mongodPortTimeout )
490
+
491
+ for {
492
+ select {
493
+ case <- tk .C :
494
+ ln , err := net .Listen ("tcp" , ":" + strconv .Itoa (p ))
495
+ if err == nil {
496
+ ln .Close ()
497
+ return nil
498
+ }
499
+
500
+ case <- to :
501
+ return errors .Errorf ("timeout during waiting for mongod free port %d" , p )
502
+ }
503
+ }
471
504
}
472
505
473
506
// waitToBecomePrimary pause execution until RS member becomes primary node.
@@ -1450,11 +1483,11 @@ func (r *PhysRestore) prepareData() error {
1450
1483
}
1451
1484
1452
1485
func (r * PhysRestore ) shutdown (c * mongo.Client ) error {
1453
- err := shutdownImpl (c , r .dbpath , false )
1486
+ err := shutdownImpl (c , r .dbpath , false , r . tmpPort )
1454
1487
if err != nil {
1455
1488
if strings .Contains (err .Error (), "ConflictingOperationInProgress" ) {
1456
1489
r .log .Warning ("try force shutdown. reason: %v" , err )
1457
- err = shutdownImpl (c , r .dbpath , true )
1490
+ err = shutdownImpl (c , r .dbpath , true , r . tmpPort )
1458
1491
return errors .Wrap (err , "force shutdown mongo" )
1459
1492
}
1460
1493
@@ -1464,7 +1497,7 @@ func (r *PhysRestore) shutdown(c *mongo.Client) error {
1464
1497
return nil
1465
1498
}
1466
1499
1467
- func shutdownImpl (c * mongo.Client , dbpath string , force bool ) error {
1500
+ func shutdownImpl (c * mongo.Client , dbpath string , force bool , port int ) error {
1468
1501
res := c .Database ("admin" ).RunCommand (context .TODO (),
1469
1502
bson.D {{"shutdown" , 1 }, {"force" , force }})
1470
1503
err := res .Err ()
@@ -1474,7 +1507,11 @@ func shutdownImpl(c *mongo.Client, dbpath string, force bool) error {
1474
1507
1475
1508
err = waitMgoShutdown (dbpath )
1476
1509
if err != nil {
1477
- return errors .Wrap (err , "wait" )
1510
+ return errors .Wrap (err , "wait mongod shutdown" )
1511
+ }
1512
+ err = waitMgoFreePort (port )
1513
+ if err != nil {
1514
+ return errors .Wrap (err , "wait mongod free port" )
1478
1515
}
1479
1516
1480
1517
return nil
0 commit comments