From e638b46a1303ace658a3f4dc6239dd5ddbb774b4 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Tue, 6 Oct 2020 15:59:00 +0200 Subject: [PATCH] Embed context into ReaderAt The io.Reader interface does not support contexts, such that it is necessary to embed the context into the backendReaderAt struct. This has the problem that a reader might suddenly stop working when it's contained context is canceled. However, this is now problem here as the reader instances never escape the calling function. --- cmd/restic/cmd_debug.go | 2 +- internal/pack/pack_test.go | 4 ++-- internal/repository/repository.go | 2 +- internal/restic/readerat.go | 15 +++++++++------ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/restic/cmd_debug.go b/cmd/restic/cmd_debug.go index c242d0a25..b36eefa07 100644 --- a/cmd/restic/cmd_debug.go +++ b/cmd/restic/cmd_debug.go @@ -87,7 +87,7 @@ func printPacks(ctx context.Context, repo *repository.Repository, wr io.Writer) return repo.List(ctx, restic.PackFile, func(id restic.ID, size int64) error { h := restic.Handle{Type: restic.PackFile, Name: id.String()} - blobs, err := pack.List(repo.Key(), restic.ReaderAt(repo.Backend(), h), size) + blobs, err := pack.List(repo.Key(), restic.ReaderAt(ctx, repo.Backend(), h), size) if err != nil { Warnf("error for pack %v: %v\n", id.Str(), err) return nil diff --git a/internal/pack/pack_test.go b/internal/pack/pack_test.go index 71aac082d..e40e5bd2a 100644 --- a/internal/pack/pack_test.go +++ b/internal/pack/pack_test.go @@ -128,7 +128,7 @@ func TestUnpackReadSeeker(t *testing.T) { handle := restic.Handle{Type: restic.PackFile, Name: id.String()} rtest.OK(t, b.Save(context.TODO(), handle, restic.NewByteReader(packData))) - verifyBlobs(t, bufs, k, restic.ReaderAt(b, handle), packSize) + verifyBlobs(t, bufs, k, restic.ReaderAt(context.TODO(), b, handle), packSize) } func TestShortPack(t *testing.T) { @@ -141,5 +141,5 @@ func TestShortPack(t *testing.T) { handle := restic.Handle{Type: restic.PackFile, Name: id.String()} rtest.OK(t, b.Save(context.TODO(), handle, restic.NewByteReader(packData))) - verifyBlobs(t, bufs, k, restic.ReaderAt(b, handle), packSize) + verifyBlobs(t, bufs, k, restic.ReaderAt(context.TODO(), b, handle), packSize) } diff --git a/internal/repository/repository.go b/internal/repository/repository.go index fc58a660e..635b15253 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -679,7 +679,7 @@ func (r *Repository) List(ctx context.Context, t restic.FileType, fn func(restic func (r *Repository) ListPack(ctx context.Context, id restic.ID, size int64) ([]restic.Blob, int64, error) { h := restic.Handle{Type: restic.PackFile, Name: id.String()} - blobs, err := pack.List(r.Key(), restic.ReaderAt(r.Backend(), h), size) + blobs, err := pack.List(r.Key(), restic.ReaderAt(ctx, r.Backend(), h), size) if err != nil { return nil, 0, err } diff --git a/internal/restic/readerat.go b/internal/restic/readerat.go index 6e945b43a..6ed2e83f5 100644 --- a/internal/restic/readerat.go +++ b/internal/restic/readerat.go @@ -9,17 +9,20 @@ import ( ) type backendReaderAt struct { - be Backend - h Handle + ctx context.Context + be Backend + h Handle } func (brd backendReaderAt) ReadAt(p []byte, offset int64) (n int, err error) { - return ReadAt(context.TODO(), brd.be, brd.h, offset, p) + return ReadAt(brd.ctx, brd.be, brd.h, offset, p) } -// ReaderAt returns an io.ReaderAt for a file in the backend. -func ReaderAt(be Backend, h Handle) io.ReaderAt { - return backendReaderAt{be: be, h: h} +// ReaderAt returns an io.ReaderAt for a file in the backend. The returned reader +// should not escape the caller function to avoid unexpected interactions with the +// embedded context +func ReaderAt(ctx context.Context, be Backend, h Handle) io.ReaderAt { + return backendReaderAt{ctx: ctx, be: be, h: h} } // ReadAt reads from the backend handle h at the given position.