Skip to content

Commit

Permalink
Add caching logic for FindStringSubmatch in tyk/regexp
Browse files Browse the repository at this point in the history
  • Loading branch information
dskoval committed Nov 9, 2018
1 parent 69686af commit 990474b
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 2 deletions.
45 changes: 45 additions & 0 deletions regexp/cache_regexp_str_ret_slice_str.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package regexp

import (
"regexp"
"time"
)

type regexpStrRetSliceStrCache struct {
*cache
}

func newRegexpStrRetSliceStrCache(ttl time.Duration, isEnabled bool) *regexpStrRetSliceStrCache {
return &regexpStrRetSliceStrCache{
cache: newCache(
ttl,
isEnabled,
),
}
}

func (c *regexpStrRetSliceStrCache) do(r *regexp.Regexp, s string, noCacheFn func(s string) []string) []string {
// return if cache is not enabled
if !c.enabled() {
return noCacheFn(s)
}

// generate key, check key size
key := r.String() + s
if len(key) > maxKeySize {
return noCacheFn(s)
}

// cache hit
if res, found := c.getStrSlice(key); found {
return res
}

// cache miss, add to cache if value is not too big
res := noCacheFn(s)
if len(res) <= maxValueSize {
c.add(key, res)
}

return res
}
5 changes: 3 additions & 2 deletions regexp/regexp.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var (
replaceAllStringCache = newRegexpStrStrRetStrCache(defaultCacheItemTTL, true)
replaceAllLiteralStringCache = newRegexpStrStrRetStrCache(defaultCacheItemTTL, true)
replaceAllStringFuncCache = newRegexpStrFuncRetStrCache(defaultCacheItemTTL, true)
findStringSubmatchCache = newRegexpStrRetSliceStrCache(defaultCacheItemTTL, true)
findAllStringCache = newRegexpStrIntRetSliceStrCache(defaultCacheItemTTL, true)
findAllStringSubmatchCache = newRegexpStrIntRetSliceSliceStrCache(defaultCacheItemTTL, true)
)
Expand All @@ -41,6 +42,7 @@ func ResetCache(ttl time.Duration, isEnabled bool) {
replaceAllStringCache.reset(ttl, isEnabled)
replaceAllLiteralStringCache.reset(ttl, isEnabled)
replaceAllStringFuncCache.reset(ttl, isEnabled)
findStringSubmatchCache.reset(ttl, isEnabled)
findAllStringCache.reset(ttl, isEnabled)
findAllStringSubmatchCache.reset(ttl, isEnabled)
}
Expand Down Expand Up @@ -320,8 +322,7 @@ func (re *Regexp) FindStringSubmatch(s string) []string {
if re.Regexp == nil {
return []string{}
}
// TODO: add cache for FindStringSubmatch
return re.Regexp.FindStringSubmatch(s)
return findStringSubmatchCache.do(re.Regexp, s, re.Regexp.FindStringSubmatch)
}

// FindStringSubmatchIndex is the same as regexp.Regexp.FindStringSubmatchIndex but returns cached result instead.
Expand Down
44 changes: 44 additions & 0 deletions regexp/regexp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,47 @@ func BenchmarkRegexpFindAllStringSubmatch(b *testing.B) {

b.Log(res)
}

func TestFindStringSubmatch(t *testing.T) {
ResetCache(defaultCacheItemTTL, true)

// 1st miss
rx := MustCompile("abc(\\w)")
res := rx.FindStringSubmatch("qweabcxyzabc123abcz")
expectedRes := []string{"abcx", "x"}

if !reflect.DeepEqual(res, expectedRes) {
t.Error("Expected :", expectedRes, " Got:", res)
}
// 2nd hit
res2 := rx.FindStringSubmatch("qweabcxyzabc123abcz")
if !reflect.DeepEqual(res2, expectedRes) {
t.Error("Expected :", expectedRes, " Got:", res2)
}
}

func TestTestFindStringSubmatchRegexpNotSet(t *testing.T) {
ResetCache(defaultCacheItemTTL, true)

rx := &Regexp{}

res := rx.FindStringSubmatch("qweabcxyzabc123abcz")
if len(res) > 0 {
t.Error("Expected 0 length slice returned. Got:", res)
}
}

func BenchmarkRegexpFindStringSubmatch(b *testing.B) {
b.ReportAllocs()

ResetCache(defaultCacheItemTTL, true)

rx := MustCompile("abc(\\w)")
var res []string

for i := 0; i < b.N; i++ {
res = rx.FindStringSubmatch("qweabcxyzabc123abcz")
}

b.Log(res)
}

0 comments on commit 990474b

Please sign in to comment.