319
// could be lingering on a shard that this instance should own, but this
320
// instance's acquireShards concurrency slots are filled with lingering shards.
322
return
323
}
324
326
>
defer c.endLinger(shard)
327
>
c.doLinger(ctx, shard)
328
>
}()
329
}
330
331
>
func (c *ControllerImpl) beginLinger(shard historyi.ControllableContext) bool {
controller_impl.go
332
>
c.lingerState.Lock()
333
>
defer c.lingerState.Unlock()
334
>
if _, ok := c.lingerState.shards[shard]; ok {
335
return false
336
}
338
>
return true
339
}
340
341
>
func (c *ControllerImpl) endLinger(shard historyi.ControllableContext) {
controller_impl.go
342
>
c.lingerState.Lock()
343
>
defer c.lingerState.Unlock()
344
>
delete(c.lingerState.shards, shard)
345
>
}
346
347
>
func (c *ControllerImpl) doLinger(ctx context.Context, shard historyi.ControllableContext) {
controller_impl.go
348
>
startTime := time.Now()
349
>
// Enforce a max limit to ensure we close the shard in a reasonable time,
350
>
// and to indirectly limit the number of lingering shards.
351
>
timeLimit := min(c.config.ShardLingerTimeLimit(), shardLingerMaxTimeLimit)
352
>
ctx, cancel := context.WithTimeout(ctx, timeLimit)
353
>
defer cancel()
354
>
355
>
qps := c.config.ShardLingerOwnershipCheckQPS()
356
>
// The limiter must be configured with burst>=1. With burst=1,
357
>
// the first call to Wait() won't be delayed.
358
>
limiter := rate.NewLimiter(rate.Limit(qps), 1)
359
>
360
>
for {
361
>
if !shard.IsValid() {
362
metrics.ShardLingerSuccess.With(c.taggedMetricsHandler).Record(time.Since(startTime))
363
break
364
}
365
367
c.contextTaggedLogger.Info("shardLinger: wait timed out",
368
tag.ShardID(shard.GetShardID()),