From 38a8a48a2590af03bb951557f47130d1704098e8 Mon Sep 17 00:00:00 2001 From: Alexander Weiss Date: Tue, 23 Feb 2021 16:09:29 +0100 Subject: [PATCH] Simplify dry run backend --- internal/backend/dryrun/dry_backend.go | 183 ++++---------------- internal/backend/dryrun/dry_backend_test.go | 35 ++-- 2 files changed, 52 insertions(+), 166 deletions(-) diff --git a/internal/backend/dryrun/dry_backend.go b/internal/backend/dryrun/dry_backend.go index add7c4b45..2b0735d66 100644 --- a/internal/backend/dryrun/dry_backend.go +++ b/internal/backend/dryrun/dry_backend.go @@ -3,186 +3,77 @@ package dryrun import ( "context" "io" - "io/ioutil" - "sync" - - "github.com/restic/restic/internal/errors" - "github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/debug" + "github.com/restic/restic/internal/restic" ) -type sizeMap map[restic.Handle]int - -var errNotFound = errors.New("not found") - -// Backend passes reads through to an underlying layer and only records -// metadata about writes. This is used for `backup --dry-run`. -// It is directly derivted from the mem backend. +// Backend passes reads through to an underlying layer and accepts writes, but +// doesn't do anything. Also removes are ignored. +// So in fact, this backend silently ignores all operations that would modify +// the repo and does normal operations else. +// This is used for `backup --dry-run`. type Backend struct { - be restic.Backend - data sizeMap - m sync.Mutex + b restic.Backend } +// statically ensure that RetryBackend implements restic.Backend. +var _ restic.Backend = &Backend{} + // New returns a new backend that saves all data in a map in memory. func New(be restic.Backend) *Backend { - b := &Backend{ - be: be, - data: make(sizeMap), - } - + b := &Backend{b: be} debug.Log("created new dry backend") - return b } -// Test returns whether a file exists. -func (be *Backend) Test(ctx context.Context, h restic.Handle) (bool, error) { - be.m.Lock() - defer be.m.Unlock() - - debug.Log("Test %v", h) - - if _, ok := be.data[h]; ok { - return true, nil - } - - return be.be.Test(ctx, h) -} - -// IsNotExist returns true if the file does not exist. -func (be *Backend) IsNotExist(err error) bool { - return errors.Cause(err) == errNotFound || be.be.IsNotExist(err) -} - // Save adds new Data to the backend. func (be *Backend) Save(ctx context.Context, h restic.Handle, rd restic.RewindReader) error { if err := h.Valid(); err != nil { return err } - be.m.Lock() - defer be.m.Unlock() - - if h.Type == restic.ConfigFile { - h.Name = "" - } - - if _, ok := be.data[h]; ok { - return errors.New("file already exists") - } - - buf, err := ioutil.ReadAll(rd) - if err != nil { - return err - } - - be.data[h] = len(buf) - debug.Log("faked saving %v bytes at %v", len(buf), h) + debug.Log("faked saving %v bytes at %v", rd.Length(), h) + // don't save anything, just return ok return nil } -// Load runs fn with a reader that yields the contents of the file at h at the -// given offset. -func (be *Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64, fn func(rd io.Reader) error) error { - be.m.Lock() - defer be.m.Unlock() - - if _, ok := be.data[h]; ok { - return errors.New("can't read file saved on dry backend") - } - return be.be.Load(ctx, h, length, offset, fn) -} - -// Stat returns information about a file in the backend. -func (be *Backend) Stat(ctx context.Context, h restic.Handle) (restic.FileInfo, error) { - if err := h.Valid(); err != nil { - return restic.FileInfo{}, err - } - - be.m.Lock() - defer be.m.Unlock() - - if h.Type == restic.ConfigFile { - h.Name = "" - } - - debug.Log("stat %v", h) - - s, ok := be.data[h] - if !ok { - return be.be.Stat(ctx, h) - } - - return restic.FileInfo{Size: int64(s), Name: h.Name}, nil -} - // Remove deletes a file from the backend. func (be *Backend) Remove(ctx context.Context, h restic.Handle) error { - be.m.Lock() - defer be.m.Unlock() - - debug.Log("Remove %v", h) - - if _, ok := be.data[h]; !ok { - return errNotFound - } - - delete(be.data, h) - return nil } -// List returns a channel which yields entries from the backend. -func (be *Backend) List(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) error { - entries := []restic.FileInfo{} - be.m.Lock() - for entry, size := range be.data { - if entry.Type != t { - continue - } - entries = append(entries, restic.FileInfo{ - Name: entry.Name, - Size: int64(size), - }) - } - be.m.Unlock() - - for _, entry := range entries { - if ctx.Err() != nil { - return ctx.Err() - } - - err := fn(entry) - if err != nil { - return err - } - - if ctx.Err() != nil { - return ctx.Err() - } - } - - if ctx.Err() != nil { - return ctx.Err() - } - - return be.be.List(ctx, t, fn) -} - -// Location returns the location of the backend (RAM). +// Location returns the location of the backend. func (be *Backend) Location() string { - return "DRY:" + be.be.Location() + return "DRY:" + be.b.Location() } // Delete removes all data in the backend. func (be *Backend) Delete(ctx context.Context) error { - return errors.New("dry-run doesn't support Delete()") + return nil } -// Close closes the backend. func (be *Backend) Close() error { - return be.be.Close() + return be.b.Close() +} + +func (be *Backend) IsNotExist(err error) bool { + return be.b.IsNotExist(err) +} + +func (be *Backend) List(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) error { + return be.b.List(ctx, t, fn) +} + +func (be *Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64, fn func(io.Reader) error) error { + return be.b.Load(ctx, h, length, offset, fn) +} + +func (be *Backend) Stat(ctx context.Context, h restic.Handle) (restic.FileInfo, error) { + return be.b.Stat(ctx, h) +} + +func (be *Backend) Test(ctx context.Context, h restic.Handle) (bool, error) { + return be.b.Test(ctx, h) } diff --git a/internal/backend/dryrun/dry_backend_test.go b/internal/backend/dryrun/dry_backend_test.go index f62703866..c3cabf801 100644 --- a/internal/backend/dryrun/dry_backend_test.go +++ b/internal/backend/dryrun/dry_backend_test.go @@ -24,11 +24,9 @@ func newBackends() (*dryrun.Backend, restic.Backend) { } func TestDry(t *testing.T) { - d, m := newBackends() - m.Save(context.TODO(), restic.Handle{}, restic.NewByteReader([]byte("foo"))) - ctx := context.TODO() + d, m := newBackends() // Since the dry backend is a mostly write-only overlay, the standard backend test suite // won't pass. Instead, perform a series of operations over the backend, testing the state // at each step. @@ -40,26 +38,28 @@ func TestDry(t *testing.T) { wantErr string }{ {d, "loc", "", "DRY:RAM", ""}, - {d, "delete", "", "", "doesn't support"}, + {d, "delete", "", "", ""}, {d, "stat", "a", "", "not found"}, {d, "list", "", "", ""}, {d, "save", "", "", "invalid"}, {d, "test", "a", "", ""}, - {m, "save", "a", "baz", ""}, - {d, "save", "b", "foob", ""}, - {d, "save", "b", "asdf", "already exists"}, + {m, "save", "a", "baz", ""}, // save a directly to the mem backend + {d, "save", "b", "foob", ""}, // b is not saved + {d, "save", "b", "xxx", ""}, // no error as b is not saved {d, "test", "a", "1", ""}, - {d, "test", "b", "1", ""}, + {d, "test", "b", "", ""}, {d, "stat", "", "", "invalid"}, {d, "stat", "a", "a 3", ""}, - {d, "stat", "b", "b 4", ""}, {d, "load", "a", "baz", ""}, - {d, "load", "b", "", "can't read file"}, - {d, "list", "", "a b", ""}, - {d, "remove", "c", "", "not found"}, - {d, "remove", "b", "", ""}, + {d, "load", "b", "", "not found"}, + {d, "list", "", "a", ""}, + {d, "remove", "c", "", ""}, {d, "stat", "b", "", "not found"}, {d, "list", "", "a", ""}, + {d, "remove", "a", "", ""}, // a is in fact not removed + {d, "list", "", "a", ""}, + {m, "remove", "a", "", ""}, // remove a from the mem backend + {d, "list", "", "", ""}, {d, "close", "", "", ""}, {d, "close", "", "", ""}, } @@ -68,7 +68,7 @@ func TestDry(t *testing.T) { var err error var boolRes bool - handle := restic.Handle{Type: restic.DataFile, Name: step.fname} + handle := restic.Handle{Type: restic.PackFile, Name: step.fname} switch step.op { case "save": err = step.be.Save(ctx, handle, restic.NewByteReader([]byte(step.content))) @@ -79,12 +79,7 @@ func TestDry(t *testing.T) { } case "list": fileList := []string{} - err = step.be.List(ctx, restic.DataFile, func(fi restic.FileInfo) error { - for _, n := range fileList { - if n == fi.Name { - return nil - } - } + err = step.be.List(ctx, restic.PackFile, func(fi restic.FileInfo) error { fileList = append(fileList, fi.Name) return nil })