From 49126796d03213a8b57d4a5a344f09d55a16cb51 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 10 Sep 2022 19:25:06 +0200 Subject: [PATCH] lock: fix timer expiry monitoring during standby Monotonic timers are paused during standby. Thus these timers won't fire after waking up. Fall back to periodic polling to detect too large clock jumps. See https://github.com/golang/go/issues/35012 for a discussion of go timers during standby. --- cmd/restic/lock.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/cmd/restic/lock.go b/cmd/restic/lock.go index 03d880670..1a8386de5 100644 --- a/cmd/restic/lock.go +++ b/cmd/restic/lock.go @@ -119,7 +119,18 @@ func refreshLocks(ctx context.Context, lock *restic.Lock, lockInfo *lockContext, } func monitorLockRefresh(ctx context.Context, lock *restic.Lock, lockInfo *lockContext, refreshed <-chan struct{}) { - timer := time.NewTimer(refreshabilityTimeout) + // time.Now() might use a monotonic timer which is paused during standby + // convert to unix time to ensure we compare real time values + lastRefresh := time.Now().Unix() + pollDuration := 1 * time.Second + if refreshInterval < pollDuration { + // require for TestLockFailedRefresh + pollDuration = refreshInterval / 5 + } + // timers are paused during standby, which is a problem as the refresh timeout + // _must_ expire if the host was too long in standby. Thus fall back to periodic checks + // https://github.com/golang/go/issues/35012 + timer := time.NewTimer(pollDuration) defer func() { timer.Stop() lockInfo.cancel() @@ -132,9 +143,14 @@ func monitorLockRefresh(ctx context.Context, lock *restic.Lock, lockInfo *lockCo debug.Log("terminate expiry monitoring") return case <-refreshed: - // reset timer once the lock was refreshed successfully - timer.Reset(refreshabilityTimeout) + lastRefresh = time.Now().Unix() case <-timer.C: + if float64(time.Now().Unix()-lastRefresh) < refreshInterval.Seconds() { + // restart timer + timer.Reset(pollDuration) + continue + } + Warnf("Fatal: failed to refresh lock in time\n") return }