diff --git a/changelog/unreleased/issue-3897 b/changelog/unreleased/issue-3897 new file mode 100644 index 000000000..45596c326 --- /dev/null +++ b/changelog/unreleased/issue-3897 @@ -0,0 +1,7 @@ +Bugfix: Fix stuck `copy` command when setting backend connections to 1 + +When calling the copy command using `copy -o .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 diff --git a/internal/repository/repack.go b/internal/repository/repack.go index bf6b65c8f..92be33952 100644 --- a/internal/repository/repack.go +++ b/internal/repository/repack.go @@ -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) } diff --git a/internal/repository/repack_test.go b/internal/repository/repack_test.go index f8cefc00b..f21dbddf7 100644 --- a/internal/repository/repack_test.go +++ b/internal/repository/repack_test.go @@ -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) }