Skip to content

Commit 2639ced

Browse files
committed
use LRU cache for regexp
1 parent 60217b4 commit 2639ced

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

modules/markup/html.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"code.gitea.io/gitea/modules/log"
2121
"code.gitea.io/gitea/modules/markup/common"
2222
"code.gitea.io/gitea/modules/references"
23+
"code.gitea.io/gitea/modules/regexplru"
2324
"code.gitea.io/gitea/modules/setting"
2425
"code.gitea.io/gitea/modules/templates/vars"
2526
"code.gitea.io/gitea/modules/util"
@@ -831,7 +832,7 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
831832
case IssueNameStyleAlphanumeric:
832833
found, ref = references.FindRenderizableReferenceAlphanumeric(node.Data)
833834
case IssueNameStyleRegexp:
834-
pattern, err := regexp.Compile(ctx.Metas["regexp"]) // TODO: Compile only once, at regexp definition time
835+
pattern, err := regexplru.GetCompiled(ctx.Metas["regexp"])
835836
if err != nil {
836837
return
837838
}

modules/regexplru/regexplru.go

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package regexplru
6+
7+
import (
8+
"regexp"
9+
10+
"code.gitea.io/gitea/modules/log"
11+
12+
lru "github.com/hashicorp/golang-lru"
13+
)
14+
15+
var lruCache *lru.Cache
16+
17+
func init() {
18+
var err error
19+
lruCache, err = lru.New(1000)
20+
if err != nil {
21+
log.Fatal("failed to new LRU cache, err: %v", err)
22+
}
23+
}
24+
25+
// GetCompiled works like regexp.Compile, the compiled expr or error is stored in LRU cache
26+
func GetCompiled(expr string) (r *regexp.Regexp, err error) {
27+
v, ok := lruCache.Get(expr)
28+
if !ok {
29+
r, err = regexp.Compile(expr)
30+
if err != nil {
31+
lruCache.Add(expr, err)
32+
return nil, err
33+
}
34+
lruCache.Add(expr, r)
35+
} else {
36+
r, ok = v.(*regexp.Regexp)
37+
if !ok {
38+
if err, ok = v.(error); ok {
39+
return nil, err
40+
}
41+
panic("impossible")
42+
}
43+
}
44+
return r, nil
45+
}

modules/regexplru/regexplru_test.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package regexplru
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestRegexpLru(t *testing.T) {
14+
r, err := GetCompiled("a")
15+
assert.NoError(t, err)
16+
assert.True(t, r.MatchString("a"))
17+
18+
r, err = GetCompiled("a")
19+
assert.NoError(t, err)
20+
assert.True(t, r.MatchString("a"))
21+
22+
assert.EqualValues(t, 1, lruCache.Len())
23+
24+
_, err = GetCompiled("(")
25+
assert.Error(t, err)
26+
assert.EqualValues(t, 2, lruCache.Len())
27+
}

0 commit comments

Comments
 (0)