forked from TrueCloudLab/restic
Merge pull request #3512 from MichaelEischer/cleaner-lock-refresh
Prevent lock refresh from leaving behind lots of stale locks
This commit is contained in:
commit
0b8b524f12
4 changed files with 22 additions and 10 deletions
11
changelog/unreleased/issue-2452
Normal file
11
changelog/unreleased/issue-2452
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Bugfix: Improve error handling of repository locking
|
||||||
|
|
||||||
|
When the lock refresh failed to delete the old lock file, it forgot about the
|
||||||
|
newly created one. Instead it continued trying to delete the old (usually no
|
||||||
|
longer existing) lock file and thus over time lots of lock files accumulated.
|
||||||
|
This has been fixed.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/2452
|
||||||
|
https://github.com/restic/restic/issues/2473
|
||||||
|
https://github.com/restic/restic/issues/2562
|
||||||
|
https://github.com/restic/restic/pull/3512
|
|
@ -98,6 +98,8 @@ func init() {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
globalOptions.ctx, cancel = context.WithCancel(context.Background())
|
globalOptions.ctx, cancel = context.WithCancel(context.Background())
|
||||||
AddCleanupHandler(func() error {
|
AddCleanupHandler(func() error {
|
||||||
|
// Must be called before the unlock cleanup handler to ensure that the latter is
|
||||||
|
// not blocked due to limited number of backend connections, see #1434
|
||||||
cancel()
|
cancel()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,6 +16,7 @@ var globalLocks struct {
|
||||||
cancelRefresh chan struct{}
|
cancelRefresh chan struct{}
|
||||||
refreshWG sync.WaitGroup
|
refreshWG sync.WaitGroup
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func lockRepo(ctx context.Context, repo *repository.Repository) (*restic.Lock, error) {
|
func lockRepo(ctx context.Context, repo *repository.Repository) (*restic.Lock, error) {
|
||||||
|
@ -27,6 +28,12 @@ func lockRepoExclusive(ctx context.Context, repo *repository.Repository) (*resti
|
||||||
}
|
}
|
||||||
|
|
||||||
func lockRepository(ctx context.Context, repo *repository.Repository, exclusive bool) (*restic.Lock, error) {
|
func lockRepository(ctx context.Context, repo *repository.Repository, exclusive bool) (*restic.Lock, error) {
|
||||||
|
// make sure that a repository is unlocked properly and after cancel() was
|
||||||
|
// called by the cleanup handler in global.go
|
||||||
|
globalLocks.Do(func() {
|
||||||
|
AddCleanupHandler(unlockAll)
|
||||||
|
})
|
||||||
|
|
||||||
lockFn := restic.NewLock
|
lockFn := restic.NewLock
|
||||||
if exclusive {
|
if exclusive {
|
||||||
lockFn = restic.NewExclusiveLock
|
lockFn = restic.NewExclusiveLock
|
||||||
|
@ -128,7 +135,3 @@ func unlockAll() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
AddCleanupHandler(unlockAll)
|
|
||||||
}
|
|
||||||
|
|
|
@ -223,15 +223,11 @@ func (l *Lock) Refresh(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: l.lockID.String()})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
debug.Log("new lock ID %v", id)
|
debug.Log("new lock ID %v", id)
|
||||||
|
oldLockID := l.lockID
|
||||||
l.lockID = &id
|
l.lockID = &id
|
||||||
|
|
||||||
return nil
|
return l.repo.Backend().Remove(context.TODO(), Handle{Type: LockFile, Name: oldLockID.String()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Lock) String() string {
|
func (l Lock) String() string {
|
||||||
|
|
Loading…
Reference in a new issue