tpl: Fix race condition in regexp cache - hugo - [fork] hugo port for 9front
HTML git clone git@git.drkhsh.at/hugo.git
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
DIR commit aedb13b2195fbc0d535d366e5b2fa6369b11677c
DIR parent f6c3ca8b2aba93945490d46e802667e98c68a398
HTML Author: Cameron Moore <moorereason@gmail.com>
Date: Sun, 13 Mar 2016 23:17:42 -0500
tpl: Fix race condition in regexp cache
Protect regular expression cache with a mutex.
Fixes #1973
Diffstat:
M tpl/template_funcs.go | 51 +++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 10 deletions(-)
---
DIR diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
@@ -33,6 +33,7 @@ import (
"sort"
"strconv"
"strings"
+ "sync"
"time"
"unicode/utf8"
@@ -1244,7 +1245,42 @@ func replace(a, b, c interface{}) (string, error) {
return strings.Replace(aStr, bStr, cStr, -1), nil
}
-var regexpCache = make(map[string]*regexp.Regexp)
+// regexpCache represents a cache of regexp objects protected by a mutex.
+type regexpCache struct {
+ mu sync.RWMutex
+ re map[string]*regexp.Regexp
+}
+
+// Get retrieves a regexp object from the cache based upon the pattern.
+// If the pattern is not found in the cache, create one
+func (rc *regexpCache) Get(pattern string) (re *regexp.Regexp, err error) {
+ var ok bool
+
+ if re, ok = rc.get(pattern); !ok {
+ re, err = regexp.Compile(pattern)
+ if err != nil {
+ return nil, err
+ }
+ rc.set(pattern, re)
+ }
+
+ return re, nil
+}
+
+func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
+ rc.mu.RLock()
+ re, ok = rc.re[key]
+ rc.mu.RUnlock()
+ return
+}
+
+func (rc *regexpCache) set(key string, re *regexp.Regexp) {
+ rc.mu.Lock()
+ rc.re[key] = re
+ rc.mu.Unlock()
+}
+
+var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
// replaceRE exposes a regular expression replacement function to the templates.
func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
@@ -1263,16 +1299,11 @@ func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
return
}
- if _, ok := regexpCache[patternStr]; !ok {
- re, err2 := regexp.Compile(patternStr)
- if err2 != nil {
- return "", err2
- }
-
- regexpCache[patternStr] = re
+ re, err := reCache.Get(patternStr)
+ if err != nil {
+ return "", err
}
-
- return regexpCache[patternStr].ReplaceAllString(srcStr, replStr), err
+ return re.ReplaceAllString(srcStr, replStr), nil
}
// dateFormat converts the textual representation of the datetime string into