From 2ec0f3303a8b588c816ff72d485d14130f871af9 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 6 Nov 2021 00:32:46 +0100 Subject: [PATCH] backup/diff/dump/restore/stats: List snapshots before index During a backup the index is written before the corresponding snapshots. To ensure that a concurrent/later restic run can read a snapshot's data, restic thus must first load the snapshots and only afterwards the index. Otherwise it is not possible to ensure that the loaded index is recent enough to cover all of the snapshot's data. --- cmd/restic/cmd_backup.go | 16 ++++++++-------- cmd/restic/cmd_diff.go | 8 ++++---- cmd/restic/cmd_dump.go | 10 +++++----- cmd/restic/cmd_prune.go | 1 + cmd/restic/cmd_restore.go | 10 +++++----- cmd/restic/cmd_stats.go | 8 ++++---- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 873fce163..a899fb013 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -571,14 +571,6 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina return err } - if !gopts.JSON { - progressPrinter.V("load index files") - } - err = repo.LoadIndex(gopts.ctx) - if err != nil { - return err - } - var parentSnapshotID *restic.ID if !opts.Stdin { parentSnapshotID, err = findParentSnapshot(gopts.ctx, repo, opts, targets, timeStamp) @@ -595,6 +587,14 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina } } + if !gopts.JSON { + progressPrinter.V("load index files") + } + err = repo.LoadIndex(gopts.ctx) + if err != nil { + return err + } + selectByNameFilter := func(item string) bool { for _, reject := range rejectByNameFuncs { if reject(item) { diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index f83c87132..60a50a21f 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -334,10 +334,6 @@ func runDiff(opts DiffOptions, gopts GlobalOptions, args []string) error { return err } - if err = repo.LoadIndex(ctx); err != nil { - return err - } - if !gopts.NoLock { lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) @@ -360,6 +356,10 @@ func runDiff(opts DiffOptions, gopts GlobalOptions, args []string) error { Verbosef("comparing snapshot %v to %v:\n\n", sn1.ID().Str(), sn2.ID().Str()) } + if err = repo.LoadIndex(ctx); err != nil { + return err + } + if sn1.Tree == nil { return errors.Errorf("snapshot %v has nil tree", sn1.ID().Str()) } diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go index 4449af5ce..cadc05476 100644 --- a/cmd/restic/cmd_dump.go +++ b/cmd/restic/cmd_dump.go @@ -144,11 +144,6 @@ func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error { } } - err = repo.LoadIndex(ctx) - if err != nil { - return err - } - var id restic.ID if snapshotIDString == "latest" { @@ -168,6 +163,11 @@ func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error { Exitf(2, "loading snapshot %q failed: %v", snapshotIDString, err) } + err = repo.LoadIndex(ctx) + if err != nil { + return err + } + tree, err := repo.LoadTree(ctx, *sn.Tree) if err != nil { Exitf(2, "loading tree for snapshot %q failed: %v", snapshotIDString, err) diff --git a/cmd/restic/cmd_prune.go b/cmd/restic/cmd_prune.go index 76d7d7ea9..4bbd6d2fd 100644 --- a/cmd/restic/cmd_prune.go +++ b/cmd/restic/cmd_prune.go @@ -150,6 +150,7 @@ func runPruneWithRepo(opts PruneOptions, gopts GlobalOptions, repo *repository.R } Verbosef("loading indexes...\n") + // loading the index before the snapshots is ok, as we use an exclusive lock here err := repo.LoadIndex(gopts.ctx) if err != nil { return err diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index 4d5818593..d2313e5c9 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -110,11 +110,6 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error { } } - err = repo.LoadIndex(ctx) - if err != nil { - return err - } - var id restic.ID if snapshotIDString == "latest" { @@ -129,6 +124,11 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error { } } + err = repo.LoadIndex(ctx) + if err != nil { + return err + } + res, err := restorer.NewRestorer(ctx, repo, id) if err != nil { Exitf(2, "creating restorer failed: %v\n", err) diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index deb649e26..32161bd03 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -86,10 +86,6 @@ func runStats(gopts GlobalOptions, args []string) error { return err } - if err = repo.LoadIndex(ctx); err != nil { - return err - } - if !gopts.NoLock { lock, err := lockRepo(ctx, repo) defer unlockRepo(lock) @@ -98,6 +94,10 @@ func runStats(gopts GlobalOptions, args []string) error { } } + if err = repo.LoadIndex(ctx); err != nil { + return err + } + if !gopts.JSON { Printf("scanning...\n") }