mirror of
https://github.com/restic/restic.git
synced 2025-12-03 20:11:52 +00:00
move Backend interface to backend package
This commit is contained in:
34
internal/cache/backend.go
vendored
34
internal/cache/backend.go
vendored
@@ -5,35 +5,35 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/restic/restic/internal/backend"
|
||||
"github.com/restic/restic/internal/debug"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
)
|
||||
|
||||
// Backend wraps a restic.Backend and adds a cache.
|
||||
type Backend struct {
|
||||
restic.Backend
|
||||
backend.Backend
|
||||
*Cache
|
||||
|
||||
// inProgress contains the handle for all files that are currently
|
||||
// downloaded. The channel in the value is closed as soon as the download
|
||||
// is finished.
|
||||
inProgressMutex sync.Mutex
|
||||
inProgress map[restic.Handle]chan struct{}
|
||||
inProgress map[backend.Handle]chan struct{}
|
||||
}
|
||||
|
||||
// ensure Backend implements restic.Backend
|
||||
var _ restic.Backend = &Backend{}
|
||||
// ensure Backend implements backend.Backend
|
||||
var _ backend.Backend = &Backend{}
|
||||
|
||||
func newBackend(be restic.Backend, c *Cache) *Backend {
|
||||
func newBackend(be backend.Backend, c *Cache) *Backend {
|
||||
return &Backend{
|
||||
Backend: be,
|
||||
Cache: c,
|
||||
inProgress: make(map[restic.Handle]chan struct{}),
|
||||
inProgress: make(map[backend.Handle]chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deletes a file from the backend and the cache if it has been cached.
|
||||
func (b *Backend) Remove(ctx context.Context, h restic.Handle) error {
|
||||
func (b *Backend) Remove(ctx context.Context, h backend.Handle) error {
|
||||
debug.Log("cache Remove(%v)", h)
|
||||
err := b.Backend.Remove(ctx, h)
|
||||
if err != nil {
|
||||
@@ -43,18 +43,18 @@ func (b *Backend) Remove(ctx context.Context, h restic.Handle) error {
|
||||
return b.Cache.remove(h)
|
||||
}
|
||||
|
||||
func autoCacheTypes(h restic.Handle) bool {
|
||||
func autoCacheTypes(h backend.Handle) bool {
|
||||
switch h.Type {
|
||||
case restic.IndexFile, restic.SnapshotFile:
|
||||
case backend.IndexFile, backend.SnapshotFile:
|
||||
return true
|
||||
case restic.PackFile:
|
||||
case backend.PackFile:
|
||||
return h.IsMetadata
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Save stores a new file in the backend and the cache.
|
||||
func (b *Backend) Save(ctx context.Context, h restic.Handle, rd restic.RewindReader) error {
|
||||
func (b *Backend) Save(ctx context.Context, h backend.Handle, rd backend.RewindReader) error {
|
||||
if !autoCacheTypes(h) {
|
||||
return b.Backend.Save(ctx, h, rd)
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (b *Backend) Save(ctx context.Context, h restic.Handle, rd restic.RewindRea
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Backend) cacheFile(ctx context.Context, h restic.Handle) error {
|
||||
func (b *Backend) cacheFile(ctx context.Context, h backend.Handle) error {
|
||||
finish := make(chan struct{})
|
||||
|
||||
b.inProgressMutex.Lock()
|
||||
@@ -133,7 +133,7 @@ func (b *Backend) cacheFile(ctx context.Context, h restic.Handle) error {
|
||||
}
|
||||
|
||||
// loadFromCache will try to load the file from the cache.
|
||||
func (b *Backend) loadFromCache(h restic.Handle, length int, offset int64, consumer func(rd io.Reader) error) (bool, error) {
|
||||
func (b *Backend) loadFromCache(h backend.Handle, length int, offset int64, consumer func(rd io.Reader) error) (bool, error) {
|
||||
rd, err := b.Cache.load(h, length, offset)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -148,7 +148,7 @@ func (b *Backend) loadFromCache(h restic.Handle, length int, offset int64, consu
|
||||
}
|
||||
|
||||
// Load loads a file from the cache or the backend.
|
||||
func (b *Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64, consumer func(rd io.Reader) error) error {
|
||||
func (b *Backend) Load(ctx context.Context, h backend.Handle, length int, offset int64, consumer func(rd io.Reader) error) error {
|
||||
b.inProgressMutex.Lock()
|
||||
waitForFinish, inProgress := b.inProgress[h]
|
||||
b.inProgressMutex.Unlock()
|
||||
@@ -194,7 +194,7 @@ func (b *Backend) Load(ctx context.Context, h restic.Handle, length int, offset
|
||||
|
||||
// Stat tests whether the backend has a file. If it does not exist but still
|
||||
// exists in the cache, it is removed from the cache.
|
||||
func (b *Backend) Stat(ctx context.Context, h restic.Handle) (restic.FileInfo, error) {
|
||||
func (b *Backend) Stat(ctx context.Context, h backend.Handle) (backend.FileInfo, error) {
|
||||
debug.Log("cache Stat(%v)", h)
|
||||
|
||||
fi, err := b.Backend.Stat(ctx, h)
|
||||
@@ -215,6 +215,6 @@ func (b *Backend) IsNotExist(err error) bool {
|
||||
return b.Backend.IsNotExist(err)
|
||||
}
|
||||
|
||||
func (b *Backend) Unwrap() restic.Backend {
|
||||
func (b *Backend) Unwrap() backend.Backend {
|
||||
return b.Backend
|
||||
}
|
||||
|
||||
20
internal/cache/backend_test.go
vendored
20
internal/cache/backend_test.go
vendored
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/restic/restic/internal/test"
|
||||
)
|
||||
|
||||
func loadAndCompare(t testing.TB, be restic.Backend, h restic.Handle, data []byte) {
|
||||
func loadAndCompare(t testing.TB, be backend.Backend, h backend.Handle, data []byte) {
|
||||
buf, err := backend.LoadAll(context.TODO(), nil, be, h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -31,25 +31,25 @@ func loadAndCompare(t testing.TB, be restic.Backend, h restic.Handle, data []byt
|
||||
}
|
||||
}
|
||||
|
||||
func save(t testing.TB, be restic.Backend, h restic.Handle, data []byte) {
|
||||
err := be.Save(context.TODO(), h, restic.NewByteReader(data, be.Hasher()))
|
||||
func save(t testing.TB, be backend.Backend, h backend.Handle, data []byte) {
|
||||
err := be.Save(context.TODO(), h, backend.NewByteReader(data, be.Hasher()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func remove(t testing.TB, be restic.Backend, h restic.Handle) {
|
||||
func remove(t testing.TB, be backend.Backend, h backend.Handle) {
|
||||
err := be.Remove(context.TODO(), h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func randomData(n int) (restic.Handle, []byte) {
|
||||
func randomData(n int) (backend.Handle, []byte) {
|
||||
data := test.Random(rand.Int(), n)
|
||||
id := restic.Hash(data)
|
||||
h := restic.Handle{
|
||||
Type: restic.IndexFile,
|
||||
h := backend.Handle{
|
||||
Type: backend.IndexFile,
|
||||
Name: id.String(),
|
||||
}
|
||||
return h, data
|
||||
@@ -114,11 +114,11 @@ func TestBackend(t *testing.T) {
|
||||
}
|
||||
|
||||
type loadErrorBackend struct {
|
||||
restic.Backend
|
||||
backend.Backend
|
||||
loadError error
|
||||
}
|
||||
|
||||
func (be loadErrorBackend) Load(_ context.Context, _ restic.Handle, _ int, _ int64, _ func(rd io.Reader) error) error {
|
||||
func (be loadErrorBackend) Load(_ context.Context, _ backend.Handle, _ int, _ int64, _ func(rd io.Reader) error) error {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return be.loadError
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func TestErrorBackend(t *testing.T) {
|
||||
loadError: testErr,
|
||||
}
|
||||
|
||||
loadTest := func(wg *sync.WaitGroup, be restic.Backend) {
|
||||
loadTest := func(wg *sync.WaitGroup, be backend.Backend) {
|
||||
defer wg.Done()
|
||||
|
||||
buf, err := backend.LoadAll(context.TODO(), nil, be, h)
|
||||
|
||||
3
internal/cache/cache.go
vendored
3
internal/cache/cache.go
vendored
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/restic/restic/internal/backend"
|
||||
"github.com/restic/restic/internal/debug"
|
||||
"github.com/restic/restic/internal/fs"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
@@ -234,7 +235,7 @@ func IsOld(t time.Time, maxAge time.Duration) bool {
|
||||
}
|
||||
|
||||
// Wrap returns a backend with a cache.
|
||||
func (c *Cache) Wrap(be restic.Backend) restic.Backend {
|
||||
func (c *Cache) Wrap(be backend.Backend) backend.Backend {
|
||||
return newBackend(be, c)
|
||||
}
|
||||
|
||||
|
||||
14
internal/cache/file.go
vendored
14
internal/cache/file.go
vendored
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/restic/restic/internal/restic"
|
||||
)
|
||||
|
||||
func (c *Cache) filename(h restic.Handle) string {
|
||||
func (c *Cache) filename(h backend.Handle) string {
|
||||
if len(h.Name) < 2 {
|
||||
panic("Name is empty or too short")
|
||||
}
|
||||
@@ -22,7 +22,7 @@ func (c *Cache) filename(h restic.Handle) string {
|
||||
return filepath.Join(c.path, cacheLayoutPaths[h.Type], subdir, h.Name)
|
||||
}
|
||||
|
||||
func (c *Cache) canBeCached(t restic.FileType) bool {
|
||||
func (c *Cache) canBeCached(t backend.FileType) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (c *Cache) canBeCached(t restic.FileType) bool {
|
||||
// Load returns a reader that yields the contents of the file with the
|
||||
// given handle. rd must be closed after use. If an error is returned, the
|
||||
// ReadCloser is nil.
|
||||
func (c *Cache) load(h restic.Handle, length int, offset int64) (io.ReadCloser, error) {
|
||||
func (c *Cache) load(h backend.Handle, length int, offset int64) (io.ReadCloser, error) {
|
||||
debug.Log("Load(%v, %v, %v) from cache", h, length, offset)
|
||||
if !c.canBeCached(h.Type) {
|
||||
return nil, errors.New("cannot be cached")
|
||||
@@ -78,7 +78,7 @@ func (c *Cache) load(h restic.Handle, length int, offset int64) (io.ReadCloser,
|
||||
}
|
||||
|
||||
// Save saves a file in the cache.
|
||||
func (c *Cache) Save(h restic.Handle, rd io.Reader) error {
|
||||
func (c *Cache) Save(h backend.Handle, rd io.Reader) error {
|
||||
debug.Log("Save to cache: %v", h)
|
||||
if rd == nil {
|
||||
return errors.New("Save() called with nil reader")
|
||||
@@ -139,7 +139,7 @@ func (c *Cache) Save(h restic.Handle, rd io.Reader) error {
|
||||
}
|
||||
|
||||
// Remove deletes a file. When the file is not cache, no error is returned.
|
||||
func (c *Cache) remove(h restic.Handle) error {
|
||||
func (c *Cache) remove(h backend.Handle) error {
|
||||
if !c.Has(h) {
|
||||
return nil
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func (c *Cache) Clear(t restic.FileType, valid restic.IDSet) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = fs.Remove(c.filename(restic.Handle{Type: t, Name: id.String()})); err != nil {
|
||||
if err = fs.Remove(c.filename(backend.Handle{Type: t, Name: id.String()})); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ func (c *Cache) list(t restic.FileType) (restic.IDSet, error) {
|
||||
}
|
||||
|
||||
// Has returns true if the file is cached.
|
||||
func (c *Cache) Has(h restic.Handle) bool {
|
||||
func (c *Cache) Has(h backend.Handle) bool {
|
||||
if !c.canBeCached(h.Type) {
|
||||
return false
|
||||
}
|
||||
|
||||
15
internal/cache/file_test.go
vendored
15
internal/cache/file_test.go
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/restic/restic/internal/backend"
|
||||
"github.com/restic/restic/internal/errors"
|
||||
"github.com/restic/restic/internal/fs"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
@@ -18,12 +19,12 @@ import (
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func generateRandomFiles(t testing.TB, tpe restic.FileType, c *Cache) restic.IDSet {
|
||||
func generateRandomFiles(t testing.TB, tpe backend.FileType, c *Cache) restic.IDSet {
|
||||
ids := restic.NewIDSet()
|
||||
for i := 0; i < rand.Intn(15)+10; i++ {
|
||||
buf := test.Random(rand.Int(), 1<<19)
|
||||
id := restic.Hash(buf)
|
||||
h := restic.Handle{Type: tpe, Name: id.String()}
|
||||
h := backend.Handle{Type: tpe, Name: id.String()}
|
||||
|
||||
if c.Has(h) {
|
||||
t.Errorf("index %v present before save", id)
|
||||
@@ -46,7 +47,7 @@ func randomID(s restic.IDSet) restic.ID {
|
||||
panic("set is empty")
|
||||
}
|
||||
|
||||
func load(t testing.TB, c *Cache, h restic.Handle) []byte {
|
||||
func load(t testing.TB, c *Cache, h backend.Handle) []byte {
|
||||
rd, err := c.load(h, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -101,7 +102,7 @@ func TestFiles(t *testing.T) {
|
||||
ids := generateRandomFiles(t, tpe, c)
|
||||
id := randomID(ids)
|
||||
|
||||
h := restic.Handle{Type: tpe, Name: id.String()}
|
||||
h := backend.Handle{Type: tpe, Name: id.String()}
|
||||
id2 := restic.Hash(load(t, c, h))
|
||||
|
||||
if !id.Equal(id2) {
|
||||
@@ -146,7 +147,7 @@ func TestFileLoad(t *testing.T) {
|
||||
data := test.Random(rand.Int(), 5234142)
|
||||
id := restic.ID{}
|
||||
copy(id[:], data)
|
||||
h := restic.Handle{
|
||||
h := backend.Handle{
|
||||
Type: restic.PackFile,
|
||||
Name: id.String(),
|
||||
}
|
||||
@@ -230,7 +231,7 @@ func TestFileSaveConcurrent(t *testing.T) {
|
||||
)
|
||||
rand.Read(id[:])
|
||||
|
||||
h := restic.Handle{
|
||||
h := backend.Handle{
|
||||
Type: restic.PackFile,
|
||||
Name: id.String(),
|
||||
}
|
||||
@@ -275,7 +276,7 @@ func TestFileSaveAfterDamage(t *testing.T) {
|
||||
// save a few bytes of data in the cache
|
||||
data := test.Random(123456789, 42)
|
||||
id := restic.Hash(data)
|
||||
h := restic.Handle{
|
||||
h := backend.Handle{
|
||||
Type: restic.PackFile,
|
||||
Name: id.String(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user