mirror of https://github.com/restic/restic.git
filter: special case patterns without globbing characters
In case a part of a path is a simple string, we can just check for equality without complex parsing in filepath.Match. name old time/op new time/op delta FilterLines-4 34.8ms ±17% 41.2ms ±23% +18.36% (p=0.000 n=10+10) FilterPatterns/Relative-4 21.7ms ± 6% 12.1ms ±23% -44.46% (p=0.000 n=10+10) FilterPatterns/Absolute-4 10.0ms ± 5% 9.1ms ±11% -9.80% (p=0.006 n=10+9) FilterPatterns/Wildcard-4 47.0ms ± 7% 42.2ms ± 5% -10.19% (p=0.000 n=9+10) FilterPatterns/ManyNoMatch-4 190ms ± 1% 131ms ±20% -31.47% (p=0.000 n=8+10) name old alloc/op new alloc/op delta FilterPatterns/Relative-4 3.57MB ± 0% 3.57MB ± 0% ~ (p=0.870 n=9+9) FilterPatterns/Absolute-4 3.57MB ± 0% 3.57MB ± 0% ~ (p=0.145 n=10+10) FilterPatterns/Wildcard-4 14.3MB ± 0% 19.7MB ± 0% +37.91% (p=0.000 n=10+10) FilterPatterns/ManyNoMatch-4 3.57MB ± 0% 3.57MB ± 0% ~ (p=0.421 n=10+9) name old allocs/op new allocs/op delta FilterPatterns/Relative-4 22.2k ± 0% 22.2k ± 0% ~ (all equal) FilterPatterns/Absolute-4 22.2k ± 0% 22.2k ± 0% ~ (all equal) FilterPatterns/Wildcard-4 88.7k ± 0% 88.7k ± 0% ~ (all equal) FilterPatterns/ManyNoMatch-4 22.2k ± 0% 22.2k ± 0% ~ (all equal)
This commit is contained in:
parent
54a124de3b
commit
0acc3c5923
|
@ -11,8 +11,13 @@ import (
|
|||
// second argument.
|
||||
var ErrBadString = errors.New("filter.Match: string is empty")
|
||||
|
||||
type patternPart struct {
|
||||
pattern string
|
||||
isSimple bool
|
||||
}
|
||||
|
||||
// Pattern represents a preparsed filter pattern
|
||||
type Pattern []string
|
||||
type Pattern []patternPart
|
||||
|
||||
func prepareStr(str string) ([]string, error) {
|
||||
if str == "" {
|
||||
|
@ -35,7 +40,14 @@ func preparePattern(pattern string) Pattern {
|
|||
pattern = strings.Replace(pattern, string(filepath.Separator), "/", -1)
|
||||
}
|
||||
|
||||
return strings.Split(pattern, "/")
|
||||
parts := strings.Split(pattern, "/")
|
||||
patterns := make([]patternPart, len(parts))
|
||||
for i, part := range parts {
|
||||
isSimple := !strings.ContainsAny(part, "\\[]*?")
|
||||
patterns[i] = patternPart{part, isSimple}
|
||||
}
|
||||
|
||||
return patterns
|
||||
}
|
||||
|
||||
// Match returns true if str matches the pattern. When the pattern is
|
||||
|
@ -89,7 +101,7 @@ func ChildMatch(pattern, str string) (matched bool, err error) {
|
|||
}
|
||||
|
||||
func childMatch(patterns Pattern, strs []string) (matched bool, err error) {
|
||||
if patterns[0] != "" {
|
||||
if patterns[0].pattern != "" {
|
||||
// relative pattern can always be nested down
|
||||
return true, nil
|
||||
}
|
||||
|
@ -112,7 +124,7 @@ func childMatch(patterns Pattern, strs []string) (matched bool, err error) {
|
|||
|
||||
func hasDoubleWildcard(list Pattern) (ok bool, pos int) {
|
||||
for i, item := range list {
|
||||
if item == "**" {
|
||||
if item.pattern == "**" {
|
||||
return true, i
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +143,7 @@ func match(patterns Pattern, strs []string) (matched bool, err error) {
|
|||
newPat := newPat[:pos+i]
|
||||
// in the first iteration the wildcard expands to nothing
|
||||
if i > 0 {
|
||||
newPat[pos+i-1] = "*"
|
||||
newPat[pos+i-1] = patternPart{"*", false}
|
||||
}
|
||||
newPat = append(newPat, patterns[pos+1:]...)
|
||||
|
||||
|
@ -155,16 +167,21 @@ func match(patterns Pattern, strs []string) (matched bool, err error) {
|
|||
if len(patterns) <= len(strs) {
|
||||
maxOffset := len(strs) - len(patterns)
|
||||
// special case absolute patterns
|
||||
if patterns[0] == "" {
|
||||
if patterns[0].pattern == "" {
|
||||
maxOffset = 0
|
||||
}
|
||||
outer:
|
||||
for offset := maxOffset; offset >= 0; offset-- {
|
||||
|
||||
for i := len(patterns) - 1; i >= 0; i-- {
|
||||
ok, err := filepath.Match(patterns[i], strs[offset+i])
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "Match")
|
||||
var ok bool
|
||||
if patterns[i].isSimple {
|
||||
ok = patterns[i].pattern == strs[offset+i]
|
||||
} else {
|
||||
ok, err = filepath.Match(patterns[i].pattern, strs[offset+i])
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "Match")
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
|
|
Loading…
Reference in New Issue