@@ -150,14 +150,40 @@ type Client struct {
150
150
vaultClient vaultclient.VaultClient
151
151
152
152
// migratingAllocs is the set of allocs whose data migration is in flight
153
- migratingAllocs map [string ]chan struct {}
153
+ migratingAllocs map [string ]* migrateAllocCtrl
154
154
migratingAllocsLock sync.Mutex
155
155
156
156
// garbageCollector is used to garbage collect terminal allocations present
157
157
// in the node automatically
158
158
garbageCollector * AllocGarbageCollector
159
159
}
160
160
161
+ // migrateAllocCtrl indicates whether migration is complete
162
+ type migrateAllocCtrl struct {
163
+ ch chan struct {}
164
+ closed bool
165
+ chLock sync.Mutex
166
+ }
167
+
168
+ func newMigrateAllocCtrl () * migrateAllocCtrl {
169
+ return & migrateAllocCtrl {
170
+ ch : make (chan struct {}),
171
+ }
172
+ }
173
+
174
+ func (m * migrateAllocCtrl ) closeCh () {
175
+ m .chLock .Lock ()
176
+ defer m .chLock .Unlock ()
177
+
178
+ if m .closed {
179
+ return
180
+ }
181
+
182
+ // If channel is not closed then close it
183
+ m .closed = true
184
+ close (m .ch )
185
+ }
186
+
161
187
var (
162
188
// noServersErr is returned by the RPC method when the client has no
163
189
// configured servers. This is used to trigger Consul discovery if
@@ -188,7 +214,7 @@ func NewClient(cfg *config.Config, consulSyncer *consul.Syncer, logger *log.Logg
188
214
blockedAllocations : make (map [string ]* structs.Allocation ),
189
215
allocUpdates : make (chan * structs.Allocation , 64 ),
190
216
shutdownCh : make (chan struct {}),
191
- migratingAllocs : make (map [string ]chan struct {} ),
217
+ migratingAllocs : make (map [string ]* migrateAllocCtrl ),
192
218
servers : newServerList (),
193
219
triggerDiscoveryCh : make (chan struct {}),
194
220
serversDiscoveredCh : make (chan struct {}),
@@ -1420,7 +1446,7 @@ func (c *Client) runAllocs(update *allocUpdates) {
1420
1446
// Stopping the migration if the allocation doesn't need any
1421
1447
// migration
1422
1448
if ! update .updated .ShouldMigrate () {
1423
- close ( ch )
1449
+ ch . closeCh ( )
1424
1450
}
1425
1451
}
1426
1452
}
@@ -1455,7 +1481,7 @@ func (c *Client) runAllocs(update *allocUpdates) {
1455
1481
// prevents a race between a finishing blockForRemoteAlloc and
1456
1482
// another invocation of runAllocs
1457
1483
if _ , ok := c .getAllocRunners ()[add .PreviousAllocation ]; ! ok {
1458
- c .migratingAllocs [add .ID ] = make ( chan struct {} )
1484
+ c .migratingAllocs [add .ID ] = newMigrateAllocCtrl ( )
1459
1485
go c .blockForRemoteAlloc (add )
1460
1486
}
1461
1487
}
@@ -1533,7 +1559,7 @@ ADDALLOC:
1533
1559
1534
1560
// waitForAllocTerminal waits for an allocation with the given alloc id to
1535
1561
// transition to terminal state and blocks the caller until then.
1536
- func (c * Client ) waitForAllocTerminal (allocID string , stopCh chan struct {} ) (* structs.Allocation , error ) {
1562
+ func (c * Client ) waitForAllocTerminal (allocID string , stopCh * migrateAllocCtrl ) (* structs.Allocation , error ) {
1537
1563
req := structs.AllocSpecificRequest {
1538
1564
AllocID : allocID ,
1539
1565
QueryOptions : structs.QueryOptions {
@@ -1551,7 +1577,7 @@ func (c *Client) waitForAllocTerminal(allocID string, stopCh chan struct{}) (*st
1551
1577
select {
1552
1578
case <- time .After (retry ):
1553
1579
continue
1554
- case <- stopCh :
1580
+ case <- stopCh . ch :
1555
1581
return nil , fmt .Errorf ("giving up waiting on alloc %v since migration is not needed" , allocID )
1556
1582
case <- c .shutdownCh :
1557
1583
return nil , fmt .Errorf ("aborting because client is shutting down" )
@@ -1665,7 +1691,7 @@ func (c *Client) unarchiveAllocDir(resp io.ReadCloser, allocID string, pathToAll
1665
1691
for {
1666
1692
// See if the alloc still needs migration
1667
1693
select {
1668
- case <- stopMigrating :
1694
+ case <- stopMigrating . ch :
1669
1695
os .RemoveAll (pathToAllocDir )
1670
1696
c .logger .Printf ("[INFO] client: stopping migration of allocdir for alloc: %v" , allocID )
1671
1697
return nil
0 commit comments