From 122406ede6afc26d489afa60eae81f4df6ac0da7 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Thu, 4 Jun 2026 22:21:38 +0200 Subject: [PATCH] repository: require *Repository for CopyBlobs Prepare `CopyBlobs` to allow access to unexported methods of the Repository struct. This requires changing the test to inject the number of backend connections via a wrapped backend instead of a wrapped repository. --- cmd/restic/cmd_copy.go | 4 ++-- internal/repository/repack.go | 4 ++-- internal/repository/repack_test.go | 31 ++++++++++++++++++------------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/cmd/restic/cmd_copy.go b/cmd/restic/cmd_copy.go index d17ded7c9..908a61768 100644 --- a/cmd/restic/cmd_copy.go +++ b/cmd/restic/cmd_copy.go @@ -189,7 +189,7 @@ func similarSnapshots(sna *data.Snapshot, snb *data.Snapshot) bool { // copyTreeBatched copies multiple snapshots in one go. Snapshots are written after // data equivalent to at least 10 packfiles was written. -func copyTreeBatched(ctx context.Context, srcRepo restic.Repository, dstRepo restic.Repository, +func copyTreeBatched(ctx context.Context, srcRepo *repository.Repository, dstRepo restic.Repository, selectedSnapshots iter.Seq[*data.Snapshot], printer progress.Printer) error { // remember already processed trees across all snapshots @@ -254,7 +254,7 @@ func copyTreeBatched(ctx context.Context, srcRepo restic.Repository, dstRepo res return nil } -func copyTree(ctx context.Context, srcRepo restic.Repository, dstRepo restic.Repository, +func copyTree(ctx context.Context, srcRepo *repository.Repository, dstRepo restic.Repository, visitedTrees restic.AssociatedBlobSet, rootTreeID restic.ID, printer progress.Printer, uploader restic.BlobSaverWithAsync) (uint64, error) { copyBlobs := srcRepo.NewAssociatedBlobSet() diff --git a/internal/repository/repack.go b/internal/repository/repack.go index 2793348b8..431aefd69 100644 --- a/internal/repository/repack.go +++ b/internal/repository/repack.go @@ -30,7 +30,7 @@ type LogFunc func(msg string, args ...interface{}) // blobs have been processed. func CopyBlobs( ctx context.Context, - repo restic.Repository, + repo *Repository, dstRepo restic.Repository, dstUploader restic.BlobSaverWithAsync, packs restic.IDSet, @@ -55,7 +55,7 @@ func CopyBlobs( func repack( ctx context.Context, - repo restic.Repository, + repo *Repository, dstRepo restic.Repository, uploader restic.BlobSaverWithAsync, packs restic.IDSet, diff --git a/internal/repository/repack_test.go b/internal/repository/repack_test.go index fc7d86900..13ba63315 100644 --- a/internal/repository/repack_test.go +++ b/internal/repository/repack_test.go @@ -149,7 +149,7 @@ func findPacksForBlobs(t *testing.T, repo restic.Repository, blobs restic.BlobSe return packs } -func repack(t *testing.T, repo restic.Repository, be backend.Backend, packs restic.IDSet, blobs restic.BlobSet) { +func repack(t *testing.T, repo *repository.Repository, be backend.Backend, packs restic.IDSet, blobs restic.BlobSet) { rtest.OK(t, repo.WithBlobUploader(context.TODO(), func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { return repository.CopyBlobs(ctx, repo, repo, uploader, packs, blobs, nil, nil) })) @@ -238,21 +238,28 @@ func TestRepackCopy(t *testing.T) { repository.TestAllVersions(t, testRepackCopy) } -type oneConnectionRepo struct { - restic.Repository +// oneConnectionBackend limits concurrent backend operations to test repack with +// the minimum connection count required by CopyBlobs. +type oneConnectionBackend struct { + backend.Backend } -func (r oneConnectionRepo) Connections() uint { - return 1 +func (be *oneConnectionBackend) Properties() backend.Properties { + p := be.Backend.Properties() + p.Connections = 1 + return p +} + +func (be *oneConnectionBackend) Unwrap() backend.Backend { + return be.Backend } func testRepackCopy(t *testing.T, version uint) { - repo, _, _ := repository.TestRepositoryWithVersion(t, version) - dstRepo, _, _ := repository.TestRepositoryWithVersion(t, version) - // test with minimal possible connection count - repoWrapped := &oneConnectionRepo{repo} - dstRepoWrapped := &oneConnectionRepo{dstRepo} + repo, _ := repository.TestRepositoryWithBackend(t, &oneConnectionBackend{Backend: repository.TestBackend(t)}, version, repository.Options{}) + dstRepo, _ := repository.TestRepositoryWithBackend(t, &oneConnectionBackend{Backend: repository.TestBackend(t)}, version, repository.Options{}) + rtest.Equals(t, repo.Connections(), 1) + rtest.Equals(t, dstRepo.Connections(), 1) seed := time.Now().UnixNano() random := rand.New(rand.NewSource(seed)) @@ -265,8 +272,8 @@ func testRepackCopy(t *testing.T, version uint) { _, keepBlobs := selectBlobs(t, random, repo, 0.2) copyPacks := findPacksForBlobs(t, repo, keepBlobs) - rtest.OK(t, repoWrapped.WithBlobUploader(context.TODO(), func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { - return repository.CopyBlobs(ctx, repoWrapped, dstRepoWrapped, uploader, copyPacks, keepBlobs, nil, nil) + rtest.OK(t, repo.WithBlobUploader(context.TODO(), func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { + return repository.CopyBlobs(ctx, repo, dstRepo, uploader, copyPacks, keepBlobs, nil, nil) })) rebuildAndReloadIndex(t, dstRepo)