forked from TrueCloudLab/restic
Merge pull request #4981 from konidev20/fix-gh-4934-cleanup-removed-snaphots-from-cache
cache: clear snapshot files from cache during load index
This commit is contained in:
commit
5cca6e66be
4 changed files with 111 additions and 10 deletions
8
changelog/unreleased/issue-4934
Normal file
8
changelog/unreleased/issue-4934
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Enhancement: Clear removed snapshots from local cache of the current host
|
||||||
|
|
||||||
|
Restic only removed snapshots from the cache on the host that runs the `forget` command.
|
||||||
|
On other hosts that use the same repository, the old snapshots remained in the cache.
|
||||||
|
Restic now, automatically clears old snapshots from the local cache of the current host.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/4934
|
||||||
|
https://github.com/restic/restic/pull/4981
|
44
internal/backend/cache/backend.go
vendored
44
internal/backend/cache/backend.go
vendored
|
@ -2,11 +2,14 @@ package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/debug"
|
"github.com/restic/restic/internal/debug"
|
||||||
|
"github.com/restic/restic/internal/restic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Backend wraps a restic.Backend and adds a cache.
|
// Backend wraps a restic.Backend and adds a cache.
|
||||||
|
@ -215,3 +218,44 @@ func (b *Backend) IsNotExist(err error) bool {
|
||||||
func (b *Backend) Unwrap() backend.Backend {
|
func (b *Backend) Unwrap() backend.Backend {
|
||||||
return b.Backend
|
return b.Backend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Backend) List(ctx context.Context, t backend.FileType, fn func(f backend.FileInfo) error) error {
|
||||||
|
if !b.Cache.canBeCached(t) {
|
||||||
|
return b.Backend.List(ctx, t, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// will contain the IDs of the files that are in the repository
|
||||||
|
ids := restic.NewIDSet()
|
||||||
|
|
||||||
|
// wrap the original function to also add the file to the ids set
|
||||||
|
wrapFn := func(f backend.FileInfo) error {
|
||||||
|
id, err := restic.ParseID(f.Name)
|
||||||
|
if err != nil {
|
||||||
|
// returning error here since, if we cannot parse the ID, the file
|
||||||
|
// is invalid and the list must exit.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ids.Insert(id)
|
||||||
|
|
||||||
|
// execute the original function
|
||||||
|
return fn(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := b.Backend.List(ctx, t, wrapFn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the cache for files that are not in the repo anymore, ignore errors
|
||||||
|
err = b.Cache.Clear(t, ids)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error clearing %s files in cache: %v\n", t.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
58
internal/backend/cache/backend_test.go
vendored
58
internal/backend/cache/backend_test.go
vendored
|
@ -57,6 +57,13 @@ func randomData(n int) (backend.Handle, []byte) {
|
||||||
return h, data
|
return h, data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func list(t testing.TB, be backend.Backend, fn func(backend.FileInfo) error) {
|
||||||
|
err := be.List(context.TODO(), backend.IndexFile, fn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackend(t *testing.T) {
|
func TestBackend(t *testing.T) {
|
||||||
be := mem.New()
|
be := mem.New()
|
||||||
c := TestNewCache(t)
|
c := TestNewCache(t)
|
||||||
|
@ -238,3 +245,54 @@ func TestErrorBackend(t *testing.T) {
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAutomaticCacheClear(t *testing.T) {
|
||||||
|
be := mem.New()
|
||||||
|
c := TestNewCache(t)
|
||||||
|
wbe := c.Wrap(be)
|
||||||
|
|
||||||
|
// add two handles h1 and h2
|
||||||
|
h1, data := randomData(2000)
|
||||||
|
// save h1 directly to the backend
|
||||||
|
save(t, be, h1, data)
|
||||||
|
if c.Has(h1) {
|
||||||
|
t.Errorf("cache has file1 too early")
|
||||||
|
}
|
||||||
|
|
||||||
|
h2, data2 := randomData(3000)
|
||||||
|
|
||||||
|
// save h2 directly to the backend
|
||||||
|
save(t, be, h2, data2)
|
||||||
|
if c.Has(h2) {
|
||||||
|
t.Errorf("cache has file2 too early")
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAndCompare(t, wbe, h1, data)
|
||||||
|
if !c.Has(h1) {
|
||||||
|
t.Errorf("cache doesn't have file1 after load")
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAndCompare(t, wbe, h2, data2)
|
||||||
|
if !c.Has(h2) {
|
||||||
|
t.Errorf("cache doesn't have file2 after load")
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove h1 directly from the backend
|
||||||
|
remove(t, be, h1)
|
||||||
|
if !c.Has(h1) {
|
||||||
|
t.Errorf("file1 not in cache any more, should be removed from cache only after list")
|
||||||
|
}
|
||||||
|
|
||||||
|
// list all files in the backend
|
||||||
|
list(t, wbe, func(_ backend.FileInfo) error { return nil })
|
||||||
|
|
||||||
|
// h1 should be removed from the cache
|
||||||
|
if c.Has(h1) {
|
||||||
|
t.Errorf("cache has file1 after remove")
|
||||||
|
}
|
||||||
|
|
||||||
|
// h2 should still be in the cache
|
||||||
|
if !c.Has(h2) {
|
||||||
|
t.Errorf("cache doesn't have file2 after list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -706,19 +706,10 @@ func (r *Repository) prepareCache() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
indexIDs := r.idx.IDs()
|
|
||||||
debug.Log("prepare cache with %d index files", len(indexIDs))
|
|
||||||
|
|
||||||
// clear old index files
|
|
||||||
err := r.Cache.Clear(restic.IndexFile, indexIDs)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error clearing index files in cache: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
packs := r.idx.Packs(restic.NewIDSet())
|
packs := r.idx.Packs(restic.NewIDSet())
|
||||||
|
|
||||||
// clear old packs
|
// clear old packs
|
||||||
err = r.Cache.Clear(restic.PackFile, packs)
|
err := r.Cache.Clear(restic.PackFile, packs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "error clearing pack files in cache: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error clearing pack files in cache: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue