Merge pull request #3898 from MichaelEischer/fix-copy-hang

don't hang when `copy` uses a single connection
This commit is contained in:
Michael Eischer 2022-08-30 20:23:39 +02:00 committed by GitHub
commit 3e70bac56e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 2 deletions

View File

@ -0,0 +1,7 @@
Bugfix: Fix stuck `copy` command when setting backend connections to 1
When calling the copy command using `copy -o <backend>.connections=1` this
caused the command to be stuck permanently. This has been fixed.
https://github.com/restic/restic/issues/3897
https://github.com/restic/restic/pull/3898

View File

@ -22,7 +22,7 @@ import (
func Repack(ctx context.Context, repo restic.Repository, dstRepo restic.Repository, packs restic.IDSet, keepBlobs restic.BlobSet, p *progress.Counter) (obsoletePacks restic.IDSet, err error) {
debug.Log("repacking %d packs while keeping %d blobs", len(packs), len(keepBlobs))
if repo == dstRepo && dstRepo.Backend().Connections() < 2 {
if repo == dstRepo && dstRepo.Connections() < 2 {
return nil, errors.Fatal("repack step requires a backend connection limit of at least two")
}
@ -114,6 +114,10 @@ func repack(ctx context.Context, repo restic.Repository, dstRepo restic.Reposito
// as packs are streamed the concurrency is limited by IO
// reduce by one to ensure that uploading is always possible
repackWorkerCount := int(repo.Connections() - 1)
if repo != dstRepo {
// no need to share the upload and download connections for different repositories
repackWorkerCount = int(repo.Connections())
}
for i := 0; i < repackWorkerCount; i++ {
wg.Go(worker)
}

View File

@ -292,12 +292,24 @@ func TestRepackCopy(t *testing.T) {
repository.TestAllVersions(t, testRepackCopy)
}
type oneConnectionRepo struct {
restic.Repository
}
func (r oneConnectionRepo) Connections() uint {
return 1
}
func testRepackCopy(t *testing.T, version uint) {
repo, cleanup := repository.TestRepositoryWithVersion(t, version)
defer cleanup()
dstRepo, dstCleanup := repository.TestRepositoryWithVersion(t, version)
defer dstCleanup()
// test with minimal possible connection count
repoWrapped := &oneConnectionRepo{repo}
dstRepoWrapped := &oneConnectionRepo{dstRepo}
seed := time.Now().UnixNano()
rand.Seed(seed)
t.Logf("rand seed is %v", seed)
@ -308,7 +320,7 @@ func testRepackCopy(t *testing.T, version uint) {
_, keepBlobs := selectBlobs(t, repo, 0.2)
copyPacks := findPacksForBlobs(t, repo, keepBlobs)
_, err := repository.Repack(context.TODO(), repo, dstRepo, copyPacks, keepBlobs, nil)
_, err := repository.Repack(context.TODO(), repoWrapped, dstRepoWrapped, copyPacks, keepBlobs, nil)
if err != nil {
t.Fatal(err)
}