From 34c1a83340a681424bdecb317c566f9e600bf25d Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 20 Sep 2021 22:12:00 +0200 Subject: [PATCH] cache: Drop cache entry if it cannot be processed Failing to process data requested from the cache usually indicates a problem with the returned data. Assume that the cache entry is somehow damaged and retry downloading it once. --- internal/cache/backend.go | 7 ++++++- internal/cache/backend_test.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/internal/cache/backend.go b/internal/cache/backend.go index fa8aedc40..a707f8243 100644 --- a/internal/cache/backend.go +++ b/internal/cache/backend.go @@ -161,7 +161,12 @@ func (b *Backend) Load(ctx context.Context, h restic.Handle, length int, offset // try loading from cache without checking that the handle is actually cached inCache, err := b.loadFromCache(ctx, h, length, offset, consumer) if inCache { - return err + if err == nil { + return nil + } + + // drop from cache and retry once + _ = b.Cache.remove(h) } debug.Log("error loading %v from cache: %v", h, err) diff --git a/internal/cache/backend_test.go b/internal/cache/backend_test.go index e9f0c4d2b..da935b9a0 100644 --- a/internal/cache/backend_test.go +++ b/internal/cache/backend_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "io" + "io/ioutil" "math/rand" "sync" "testing" @@ -171,3 +172,37 @@ func TestErrorBackend(t *testing.T) { wg.Wait() } + +func TestBackendRemoveBroken(t *testing.T) { + be := mem.New() + + c, cleanup := TestNewCache(t) + defer cleanup() + + h, data := randomData(5234142) + // save directly in backend + save(t, be, h, data) + + // prime cache with broken copy + broken := append([]byte{}, data...) + broken[0] ^= 0xff + err := c.Save(h, bytes.NewReader(broken)) + test.OK(t, err) + + // loadall retries if broken data was returned + buf, err := backend.LoadAll(context.TODO(), nil, c.Wrap(be), h) + test.OK(t, err) + + if !bytes.Equal(buf, data) { + t.Fatalf("wrong data returned") + } + + // check that the cache now contains the correct data + rd, err := c.load(h, 0, 0) + test.OK(t, err) + cached, err := ioutil.ReadAll(rd) + test.OK(t, err) + if !bytes.Equal(cached, data) { + t.Fatalf("wrong data cache") + } +}