Skip to content

Commit d9a6f2c

Browse files
authored
perf: (issue #377) add caching and use re2 for alias scanning in files (#491)
Attempting to continue the work done in #408. Closes #377. ### Changes - use caching to optimize file globbing and regex compilation - swap stdlib `regexp` out for [go-re2](https://github.com/wasilibs/go-re2) for improved regex compilation and pattern matching - added a test to assert alias-finding logic works properly when given a set of files with flag references in them ### Benchmarks I compiled and executed locally using `local-find-code-refs --debug --dryRun -t=$SOME_TOKEN -d=. -p=default -r=some-repo --ignoreServiceErrors` Ran this on a repo where the command execution never completed (waited >30 minutes until I cancelled) and when using this branch's version, the command was able to complete within 8m14s.
1 parent e0f210d commit d9a6f2c

File tree

342 files changed

+83726
-15
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

342 files changed

+83726
-15
lines changed

aliases/alias.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@ import (
77
"os"
88
"os/exec"
99
"path/filepath"
10-
"regexp"
1110
"strconv"
1211
"strings"
1312
"time"
1413

1514
"github.com/bmatcuk/doublestar/v4"
1615
"github.com/iancoleman/strcase"
16+
regexp "github.com/wasilibs/go-re2"
1717

1818
"github.com/launchdarkly/ld-find-code-refs/v2/internal/helpers"
1919
"github.com/launchdarkly/ld-find-code-refs/v2/internal/log"
2020
"github.com/launchdarkly/ld-find-code-refs/v2/internal/validation"
2121
"github.com/launchdarkly/ld-find-code-refs/v2/options"
2222
)
2323

24+
var globCache = make(map[string][]string)
25+
var regexCache = make(map[string]*regexp.Regexp)
26+
2427
// GenerateAliases returns a map of flag keys to aliases based on config.
2528
func GenerateAliases(flags []string, aliases []options.Alias, dir string) (map[string][]string, error) {
2629
allFileContents, err := processFileContent(aliases, dir)
@@ -88,10 +91,9 @@ func GenerateAliasesFromFilePattern(a options.Alias, flag, dir string, allFileCo
8891
// Concatenate the contents of all files into a single byte array to be matched by specified patterns
8992
fileContents := []byte{}
9093
for _, path := range a.Paths {
91-
absGlob := filepath.Join(dir, path)
92-
matches, err := doublestar.FilepathGlob(absGlob)
94+
matches, err := cacheFilepathGlob(dir, path)
9395
if err != nil {
94-
return nil, fmt.Errorf("filepattern '%s': could not process path glob '%s'", a.Name, absGlob)
96+
return nil, fmt.Errorf("filepattern '%s': could not process path glob '%s'", a.Name, path)
9597
}
9698
for _, match := range matches {
9799
if pathFileContents := allFileContents[match]; len(pathFileContents) > 0 {
@@ -101,7 +103,12 @@ func GenerateAliasesFromFilePattern(a options.Alias, flag, dir string, allFileCo
101103
}
102104

103105
for _, p := range a.Patterns {
104-
pattern := regexp.MustCompile(strings.ReplaceAll(p, "FLAG_KEY", flag))
106+
patternStr := strings.ReplaceAll(p, "FLAG_KEY", flag)
107+
pattern, ok := regexCache[patternStr]
108+
if !ok {
109+
pattern = regexp.MustCompile(patternStr)
110+
regexCache[patternStr] = pattern
111+
}
105112
results := pattern.FindAllStringSubmatch(string(fileContents), -1)
106113
for _, res := range results {
107114
if len(res) > 1 {
@@ -157,13 +164,12 @@ func processFileContent(aliases []options.Alias, dir string) (FileContentsMap, e
157164

158165
paths := []string{}
159166
for _, glob := range a.Paths {
160-
absGlob := filepath.Join(dir, glob)
161-
matches, err := doublestar.FilepathGlob(absGlob)
167+
matches, err := cacheFilepathGlob(dir, glob)
162168
if err != nil {
163-
return nil, fmt.Errorf("filepattern '%s': could not process path glob '%s'", aliasId, absGlob)
169+
return nil, fmt.Errorf("filepattern '%s': could not process path glob '%s'", aliasId, glob)
164170
}
165171
if matches == nil {
166-
log.Info.Printf("filepattern '%s': no matching files found for alias path glob '%s'", aliasId, absGlob)
172+
log.Info.Printf("filepattern '%s': no matching files found for alias path glob '%s'", aliasId, glob)
167173
}
168174
paths = append(paths, matches...)
169175
}
@@ -188,3 +194,15 @@ func processFileContent(aliases []options.Alias, dir string) (FileContentsMap, e
188194
}
189195
return allFileContents, nil
190196
}
197+
198+
func cacheFilepathGlob(dir, glob string) ([]string, error) {
199+
absGlob := filepath.Join(dir, glob)
200+
if cachedMatches, ok := globCache[absGlob]; ok {
201+
return cachedMatches, nil
202+
}
203+
204+
matches, err := doublestar.FilepathGlob(absGlob)
205+
globCache[absGlob] = matches
206+
207+
return matches, err
208+
}

aliases/alias_test.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@ func Test_GenerateAliases(t *testing.T) {
9393
name: "file exact pattern",
9494
flags: slice(testFlagKey),
9595
aliases: []o.Alias{
96-
fileExactPattern(testFlagKey),
96+
fileExactPattern(),
9797
},
9898
want: map[string][]string{testFlagKey: slice("SOME_FLAG")},
9999
},
100100
{
101101
name: "file wildcard pattern",
102102
flags: slice(testFlagKey, testWildFlagKey),
103103
aliases: []o.Alias{
104-
fileWildPattern(testFlagKey),
104+
fileWildPattern(),
105105
},
106-
want: map[string][]string{testWildFlagKey: slice("WILD_FLAG", "WILD_FLAG_SECOND_ALIAS"), testFlagKey: slice("SOME_FLAG")},
106+
want: map[string][]string{testWildFlagKey: slice("WILD_FLAG", "WILD_FLAG_SECOND_ALIAS", "ABSOLUTELY_WILD"), testFlagKey: slice("SOME_FLAG")},
107107
},
108108
{
109109
name: "command",
@@ -198,6 +198,24 @@ func Test_processFileContent(t *testing.T) {
198198
}
199199
}
200200

201+
func Test_GenerateAliasesFromFilePattern(t *testing.T) {
202+
expectedAliases := []string{"WILD_FLAG", "WILD_FLAG_SECOND_ALIAS", "ABSOLUTELY_WILD"}
203+
204+
fileContents := map[string][]byte{
205+
"testdata/alias_test.txt": []byte("SOME_FLAG = 'someFlag'"),
206+
"testdata/wild/alias_test.txt": []byte("WILD_FLAG = 'wildFlag'"),
207+
"testdata/wild/nested-wild/alias_test.txt": []byte("WILD_FLAG_SECOND_ALIAS = 'wildFlag'"),
208+
"testdata/wild/nested-wild/another/another/alias_test.txt": []byte("ABSOLUTELY_WILD = 'wildFlag'"),
209+
}
210+
211+
alias := fileWildPattern()
212+
213+
aliases, err := GenerateAliasesFromFilePattern(alias, testWildFlagKey, "", fileContents)
214+
require.NoError(t, err)
215+
216+
assert.ElementsMatch(t, expectedAliases, aliases)
217+
}
218+
201219
func slice(args ...string) []string {
202220
return args
203221
}
@@ -222,15 +240,15 @@ func literal(flags []string) o.Alias {
222240
return a
223241
}
224242

225-
func fileExactPattern(flag string) o.Alias {
243+
func fileExactPattern() o.Alias {
226244
a := alias(o.FilePattern)
227245
pattern := "(\\w+)\\s= 'FLAG_KEY'"
228246
a.Paths = []string{"testdata/alias_test.txt"}
229247
a.Patterns = []string{pattern}
230248
return a
231249
}
232250

233-
func fileWildPattern(flag string) o.Alias {
251+
func fileWildPattern() o.Alias {
234252
a := alias(o.FilePattern)
235253
pattern := "(\\w+)\\s= 'FLAG_KEY'"
236254
a.Paths = []string{"testdata/**/*.txt"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ABSOLUTELY_WILD = 'wildFlag'

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ require (
2020
golang.org/x/tools v0.32.0
2121
)
2222

23-
require github.com/launchdarkly/api-client-go/v15 v15.1.0
23+
require (
24+
github.com/launchdarkly/api-client-go/v15 v15.1.0
25+
github.com/wasilibs/go-re2 v1.10.0
26+
)
2427

2528
require (
2629
dario.cat/mergo v1.0.0 // indirect
@@ -50,6 +53,8 @@ require (
5053
github.com/spf13/afero v1.12.0 // indirect
5154
github.com/spf13/cast v1.7.1 // indirect
5255
github.com/subosito/gotenv v1.6.0 // indirect
56+
github.com/tetratelabs/wazero v1.9.0 // indirect
57+
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect
5358
github.com/xanzy/ssh-agent v0.3.3 // indirect
5459
go.uber.org/atomic v1.9.0 // indirect
5560
go.uber.org/multierr v1.9.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
226226
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
227227
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
228228
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
229+
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
230+
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
231+
github.com/wasilibs/go-re2 v1.10.0 h1:vQZEBYZOCA9jdBMmrO4+CvqyCj0x4OomXTJ4a5/urQ0=
232+
github.com/wasilibs/go-re2 v1.10.0/go.mod h1:k+5XqO2bCJS+QpGOnqugyfwC04nw0jaglmjrrkG8U6o=
233+
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4=
234+
github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY=
229235
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
230236
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
231237
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

vendor/github.com/tetratelabs/wazero/.editorconfig

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/tetratelabs/wazero/.gitattributes

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/tetratelabs/wazero/.gitignore

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/tetratelabs/wazero/.gitmodules

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/tetratelabs/wazero/CONTRIBUTING.md

Lines changed: 75 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)