Skip to content

Commit

Permalink
Merge pull request #4709 from MichaelEischer/refactor-locking
Browse files Browse the repository at this point in the history
Refactor locking into repository package
  • Loading branch information
MichaelEischer committed Mar 28, 2024
2 parents 7f9ad1c + 07eb6c3 commit 510f6f0
Show file tree
Hide file tree
Showing 42 changed files with 582 additions and 784 deletions.
10 changes: 10 additions & 0 deletions changelog/unreleased/pull-4709
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Bugfix: Correct `--no-lock` handling of `ls` and `tag` command

The `ls` command never locked the repository. This has been fixed. The old
behavior is still supported using `ls --no-lock`. The latter invocation also
works with older restic versions.

The `tag` command erroneously accepted the `--no-lock` command. The command
now always requires an exclusive lock.

https://github.com/restic/restic/pull/4709
19 changes: 2 additions & 17 deletions cmd/restic/cmd_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,10 +463,11 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
Verbosef("open repository\n")
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, opts.DryRun)
if err != nil {
return err
}
defer unlock()

var progressPrinter backup.ProgressPrinter
if gopts.JSON {
Expand All @@ -478,22 +479,6 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
calculateProgressInterval(!gopts.Quiet, gopts.JSON))
defer progressReporter.Done()

if opts.DryRun {
repo.SetDryRun()
}

if !gopts.JSON {
progressPrinter.V("lock repository")
}
if !opts.DryRun {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}

// rejectByNameFuncs collect functions that can reject items from the backup based on path only
rejectByNameFuncs, err := collectRejectByNameFuncs(opts, repo)
if err != nil {
Expand Down
18 changes: 3 additions & 15 deletions cmd/restic/cmd_backup_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"runtime"
"testing"

"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
Expand Down Expand Up @@ -250,29 +249,18 @@ func TestBackupTreeLoadError(t *testing.T) {
opts := BackupOptions{}
// Backup a subdirectory first, such that we can remove the tree pack for the subdirectory
testRunBackup(t, env.testdata, []string{"test"}, opts, env.gopts)

r, err := OpenRepository(context.TODO(), env.gopts)
rtest.OK(t, err)
rtest.OK(t, r.LoadIndex(context.TODO(), nil))
treePacks := restic.NewIDSet()
r.Index().Each(context.TODO(), func(pb restic.PackedBlob) {
if pb.Type == restic.TreeBlob {
treePacks.Insert(pb.PackID)
}
})
treePacks := listTreePacks(env.gopts, t)

testRunBackup(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
testRunCheck(t, env.gopts)

// delete the subdirectory pack first
for id := range treePacks {
rtest.OK(t, r.Backend().Remove(context.TODO(), backend.Handle{Type: restic.PackFile, Name: id.String()}))
}
removePacks(env.gopts, t, treePacks)
testRunRebuildIndex(t, env.gopts)
// now the repo is missing the tree blob in the index; check should report this
testRunCheckMustFail(t, env.gopts)
// second backup should report an error but "heal" this situation
err = testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
err := testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
rtest.Assert(t, err != nil, "backup should have reported an error for the subdirectory")
testRunCheck(t, env.gopts)

Expand Down
12 changes: 2 additions & 10 deletions cmd/restic/cmd_cat.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,11 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
return err
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

tpe := args[0]

Expand Down
16 changes: 5 additions & 11 deletions cmd/restic/cmd_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,20 +204,14 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
return code, nil
})

repo, err := OpenRepository(ctx, gopts)
if err != nil {
return err
}

if !gopts.NoLock {
Verbosef("create exclusive lock for repository\n")
var lock *restic.Lock
lock, ctx, err = lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}
defer unlock()

chkr := checker.New(repo, opts.CheckUnused)
err = chkr.LoadSnapshots(ctx)
Expand Down
21 changes: 4 additions & 17 deletions cmd/restic/cmd_copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,30 +62,17 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
gopts, secondaryGopts = secondaryGopts, gopts
}

srcRepo, err := OpenRepository(ctx, gopts)
ctx, srcRepo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}
defer unlock()

dstRepo, err := OpenRepository(ctx, secondaryGopts)
if err != nil {
return err
}

if !gopts.NoLock {
var srcLock *restic.Lock
srcLock, ctx, err = lockRepo(ctx, srcRepo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(srcLock)
if err != nil {
return err
}
}

dstLock, ctx, err := lockRepo(ctx, dstRepo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(dstLock)
ctx, dstRepo, unlock, err := openWithAppendLock(ctx, secondaryGopts, false)
if err != nil {
return err
}
defer unlock()

srcSnapshotLister, err := restic.MemorizeList(ctx, srcRepo, restic.SnapshotFile)
if err != nil {
Expand Down
28 changes: 8 additions & 20 deletions cmd/restic/cmd_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,11 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string) error
return errors.Fatal("type not specified")
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

tpe := args[0]

Expand Down Expand Up @@ -442,10 +434,15 @@ func storePlainBlob(id restic.ID, prefix string, plain []byte) error {
}

func runDebugExamine(ctx context.Context, gopts GlobalOptions, opts DebugExamineOptions, args []string) error {
repo, err := OpenRepository(ctx, gopts)
if opts.ExtractPack && gopts.NoLock {
return fmt.Errorf("--extract-pack and --no-lock are mutually exclusive")
}

ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}
defer unlock()

ids := make([]restic.ID, 0)
for _, name := range args {
Expand All @@ -464,15 +461,6 @@ func runDebugExamine(ctx context.Context, gopts GlobalOptions, opts DebugExamine
return errors.Fatal("no pack files to examine")
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}

bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
Expand Down
12 changes: 2 additions & 10 deletions cmd/restic/cmd_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,19 +344,11 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
return errors.Fatalf("specify two snapshot IDs")
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

// cache snapshots listing
be, err := restic.MemorizeList(ctx, repo, restic.SnapshotFile)
Expand Down
12 changes: 2 additions & 10 deletions cmd/restic/cmd_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,11 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []

splittedPath := splitPath(path.Clean(pathToPrint))

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

sn, subfolder, err := (&restic.SnapshotFilter{
Hosts: opts.Hosts,
Expand Down
12 changes: 2 additions & 10 deletions cmd/restic/cmd_find.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,19 +563,11 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
return errors.Fatal("cannot have several ID types")
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

snapshotLister, err := restic.MemorizeList(ctx, repo, restic.SnapshotFile)
if err != nil {
Expand Down
16 changes: 4 additions & 12 deletions cmd/restic/cmd_forget.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,23 +163,15 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
return err
}

repo, err := OpenRepository(ctx, gopts)
if err != nil {
return err
}

if gopts.NoLock && !opts.DryRun {
return errors.Fatal("--no-lock is only applicable in combination with --dry-run for forget command")
}

if !opts.DryRun || !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun && gopts.NoLock)
if err != nil {
return err
}
defer unlock()

var snapshots restic.Snapshots
removeSnIDs := restic.NewIDSet()
Expand Down
9 changes: 2 additions & 7 deletions cmd/restic/cmd_key_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,11 @@ func runKeyAdd(ctx context.Context, gopts GlobalOptions, opts KeyAddOptions, arg
return fmt.Errorf("the key add command expects no arguments, only options - please see `restic help key add` for usage and flags")
}

repo, err := OpenRepository(ctx, gopts)
if err != nil {
return err
}

lock, ctx, err := lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, false)
if err != nil {
return err
}
defer unlock()

return addKey(ctx, repo, gopts, opts)
}
Expand Down
12 changes: 2 additions & 10 deletions cmd/restic/cmd_key_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,11 @@ func runKeyList(ctx context.Context, gopts GlobalOptions, args []string) error {
return fmt.Errorf("the key list command expects no arguments, only options - please see `restic help key list` for usage and flags")
}

repo, err := OpenRepository(ctx, gopts)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
if err != nil {
return err
}

if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
defer unlock()

return listKeys(ctx, repo, gopts)
}
Expand Down
9 changes: 2 additions & 7 deletions cmd/restic/cmd_key_passwd.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,11 @@ func runKeyPasswd(ctx context.Context, gopts GlobalOptions, opts KeyPasswdOption
return fmt.Errorf("the key passwd command expects no arguments, only options - please see `restic help key passwd` for usage and flags")
}

repo, err := OpenRepository(ctx, gopts)
if err != nil {
return err
}

lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
if err != nil {
return err
}
defer unlock()

return changePassword(ctx, repo, gopts, opts)
}
Expand Down

0 comments on commit 510f6f0

Please sign in to comment.