2
2
mirror of https://github.com/octoleo/restic.git synced 2024-06-03 01:20:49 +00:00

find: Correct tree pruning optimization

The `find` command will now take care to only mark trees as "not found"
when the pattern couldn't be found within any subtree.

Closes #1825, #1823
This commit is contained in:
Alexander Neumann 2018-06-09 18:31:13 +02:00
parent e2d347a698
commit ce01ca30d6

View File

@ -144,7 +144,7 @@ func (s *statefulOutput) PrintNormal(prefix string, node *restic.Node) {
Verbosef("\n") Verbosef("\n")
} }
s.oldsn = s.newsn s.oldsn = s.newsn
Verbosef("Found matching entries in snapshot %s\n", s.oldsn.ID()) Verbosef("Found matching entries in snapshot %s\n", s.oldsn.ID().Str())
} }
Printf(formatNode(prefix, node, s.ListLong) + "\n") Printf(formatNode(prefix, node, s.ListLong) + "\n")
} }
@ -180,17 +180,20 @@ type Finder struct {
notfound restic.IDSet notfound restic.IDSet
} }
func (f *Finder) findInTree(ctx context.Context, treeID restic.ID, prefix string) error { // findInTree traverses a tree and outputs matches. foundInSubtree is true if
// some match has been found within some subtree. If err is non-nil, the value
// of foundInSubtree is invalid.
func (f *Finder) findInTree(ctx context.Context, treeID restic.ID, prefix string) (foundInSubtree bool, err error) {
if f.notfound.Has(treeID) { if f.notfound.Has(treeID) {
debug.Log("%v skipping tree %v, has already been checked", prefix, treeID) debug.Log("%v skipping tree %v, has already been checked", prefix, treeID)
return nil return false, nil
} }
debug.Log("%v checking tree %v\n", prefix, treeID) debug.Log("%v checking tree %v\n", prefix, treeID)
tree, err := f.repo.LoadTree(ctx, treeID) tree, err := f.repo.LoadTree(ctx, treeID)
if err != nil { if err != nil {
return err return false, err
} }
var found bool var found bool
@ -204,7 +207,7 @@ func (f *Finder) findInTree(ctx context.Context, treeID restic.ID, prefix string
m, err := path.Match(f.pat.pattern, name) m, err := path.Match(f.pat.pattern, name)
if err != nil { if err != nil {
return err return false, err
} }
if m { if m {
@ -224,8 +227,13 @@ func (f *Finder) findInTree(ctx context.Context, treeID restic.ID, prefix string
} }
if node.Type == "dir" { if node.Type == "dir" {
if err := f.findInTree(ctx, *node.Subtree, path.Join(prefix, node.Name)); err != nil { foundSubtree, err := f.findInTree(ctx, *node.Subtree, path.Join(prefix, node.Name))
return err if err != nil {
return false, err
}
if foundSubtree {
found = true
} }
} }
} }
@ -234,14 +242,15 @@ func (f *Finder) findInTree(ctx context.Context, treeID restic.ID, prefix string
f.notfound.Insert(treeID) f.notfound.Insert(treeID)
} }
return nil return found, nil
} }
func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error { func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error {
debug.Log("searching in snapshot %s\n for entries within [%s %s]", sn.ID(), f.pat.oldest, f.pat.newest) debug.Log("searching in snapshot %s\n for entries within [%s %s]", sn.ID(), f.pat.oldest, f.pat.newest)
f.out.newsn = sn f.out.newsn = sn
return f.findInTree(ctx, *sn.Tree, "/") _, err := f.findInTree(ctx, *sn.Tree, "/")
return err
} }
func runFind(opts FindOptions, gopts GlobalOptions, args []string) error { func runFind(opts FindOptions, gopts GlobalOptions, args []string) error {