forked from TrueCloudLab/restic
Merge pull request #4166 from MichaelEischer/cache-mkdirall
cache: Create missing intermediate directories when caching a file
This commit is contained in:
commit
41cc320145
3 changed files with 44 additions and 16 deletions
7
changelog/unreleased/pull-4166
Normal file
7
changelog/unreleased/pull-4166
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Enhancement: Cancel current command if cache becomes unusable
|
||||||
|
|
||||||
|
If the cache directory was removed or ran out of space while restic was
|
||||||
|
running, this caused further caching attempts to fail and drastically slow down
|
||||||
|
the command execution. Now, the currently running command is canceled instead.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/pull/4166
|
35
internal/cache/backend.go
vendored
35
internal/cache/backend.go
vendored
|
@ -83,7 +83,7 @@ func (b *Backend) Save(ctx context.Context, h restic.Handle, rd restic.RewindRea
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Log("unable to save %v to cache: %v", h, err)
|
debug.Log("unable to save %v to cache: %v", h, err)
|
||||||
_ = b.Cache.remove(h)
|
_ = b.Cache.remove(h)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -106,11 +106,19 @@ func (b *Backend) cacheFile(ctx context.Context, h restic.Handle) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
// signal other waiting goroutines that the file may now be cached
|
||||||
|
close(finish)
|
||||||
|
|
||||||
|
// remove the finish channel from the map
|
||||||
|
b.inProgressMutex.Lock()
|
||||||
|
delete(b.inProgress, h)
|
||||||
|
b.inProgressMutex.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
// test again, maybe the file was cached in the meantime
|
// test again, maybe the file was cached in the meantime
|
||||||
if !b.Cache.Has(h) {
|
if !b.Cache.Has(h) {
|
||||||
|
|
||||||
// nope, it's still not in the cache, pull it from the repo and save it
|
// nope, it's still not in the cache, pull it from the repo and save it
|
||||||
|
|
||||||
err := b.Backend.Load(ctx, h, 0, 0, func(rd io.Reader) error {
|
err := b.Backend.Load(ctx, h, 0, 0, func(rd io.Reader) error {
|
||||||
return b.Cache.Save(h, rd)
|
return b.Cache.Save(h, rd)
|
||||||
})
|
})
|
||||||
|
@ -118,16 +126,9 @@ func (b *Backend) cacheFile(ctx context.Context, h restic.Handle) error {
|
||||||
// try to remove from the cache, ignore errors
|
// try to remove from the cache, ignore errors
|
||||||
_ = b.Cache.remove(h)
|
_ = b.Cache.remove(h)
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// signal other waiting goroutines that the file may now be cached
|
|
||||||
close(finish)
|
|
||||||
|
|
||||||
// remove the finish channel from the map
|
|
||||||
b.inProgressMutex.Lock()
|
|
||||||
delete(b.inProgress, h)
|
|
||||||
b.inProgressMutex.Unlock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,11 +179,13 @@ func (b *Backend) Load(ctx context.Context, h restic.Handle, length int, offset
|
||||||
|
|
||||||
debug.Log("auto-store %v in the cache", h)
|
debug.Log("auto-store %v in the cache", h)
|
||||||
err = b.cacheFile(ctx, h)
|
err = b.cacheFile(ctx, h)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
inCache, err = b.loadFromCache(ctx, h, length, offset, consumer)
|
return err
|
||||||
if inCache {
|
}
|
||||||
return err
|
|
||||||
}
|
inCache, err = b.loadFromCache(ctx, h, length, offset, consumer)
|
||||||
|
if inCache {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.Log("error caching %v: %v, falling back to backend", h, err)
|
debug.Log("error caching %v: %v, falling back to backend", h, err)
|
||||||
|
|
18
internal/cache/file_test.go
vendored
18
internal/cache/file_test.go
vendored
|
@ -11,8 +11,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/errors"
|
"github.com/restic/restic/internal/errors"
|
||||||
|
"github.com/restic/restic/internal/fs"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
"github.com/restic/restic/internal/test"
|
"github.com/restic/restic/internal/test"
|
||||||
|
rtest "github.com/restic/restic/internal/test"
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
@ -266,3 +268,19 @@ func TestFileSaveConcurrent(t *testing.T) {
|
||||||
saved := load(t, c, h)
|
saved := load(t, c, h)
|
||||||
test.Equals(t, data, saved)
|
test.Equals(t, data, saved)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFileSaveAfterDamage(t *testing.T) {
|
||||||
|
c := TestNewCache(t)
|
||||||
|
rtest.OK(t, fs.RemoveAll(c.path))
|
||||||
|
|
||||||
|
// save a few bytes of data in the cache
|
||||||
|
data := test.Random(123456789, 42)
|
||||||
|
id := restic.Hash(data)
|
||||||
|
h := restic.Handle{
|
||||||
|
Type: restic.PackFile,
|
||||||
|
Name: id.String(),
|
||||||
|
}
|
||||||
|
if err := c.Save(h, bytes.NewReader(data)); err == nil {
|
||||||
|
t.Fatal("Missing error when saving to deleted cache directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue