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.
This commit is contained in:
Michael Eischer 2021-09-20 22:12:00 +02:00
parent aa3b1925b4
commit 34c1a83340
2 changed files with 41 additions and 1 deletions

View file

@ -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)

View file

@ -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")
}
}