Skip to content

Commit 3f2f52a

Browse files
committed
make InMemLoader safe for concurrent use
1 parent 801afaf commit 3f2f52a

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

loader.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"os"
2323
"path"
2424
"path/filepath"
25+
"sync"
2526
)
2627

2728
// Loader is a minimal interface required for loading templates.
@@ -42,7 +43,6 @@ import (
4243
// `/bar.html.jet` and `/bar.jet.html` (in that order). To avoid unneccessary lookups, use the full file name in your templates (so the first lookup
4344
// is always a hit, or override this list of extensions using Set.SetExtensions().
4445
type Loader interface {
45-
4646
// Exists returns whether or not a template exists under the requested path.
4747
Exists(templatePath string) bool
4848

@@ -84,10 +84,11 @@ func (l *OSFileSystemLoader) Open(templatePath string) (io.ReadCloser, error) {
8484
}
8585

8686
// InMemLoader is a simple in-memory loader storing template contents in a simple map.
87-
// It is not safe for concurrent use.
8887
// InMemLoader normalizes paths passed to its methods by converting any input path to a slash-delimited path,
8988
// turning it into an absolute path by prepending a "/" if neccessary, and cleaning it (see path.Clean()).
89+
// It is safe for concurrent use.
9090
type InMemLoader struct {
91+
lock sync.RWMutex
9192
files map[string][]byte
9293
}
9394

@@ -109,6 +110,8 @@ func (l *InMemLoader) normalize(templatePath string) string {
109110
// Open returns a template's contents, or an error if no template was added under this path using Set().
110111
func (l *InMemLoader) Open(templatePath string) (io.ReadCloser, error) {
111112
templatePath = l.normalize(templatePath)
113+
l.lock.RLock()
114+
defer l.lock.RUnlock()
112115
f, ok := l.files[templatePath]
113116
if !ok {
114117
return nil, fmt.Errorf("%s does not exist", templatePath)
@@ -120,18 +123,24 @@ func (l *InMemLoader) Open(templatePath string) (io.ReadCloser, error) {
120123
// Exists returns whether or not a template is indexed under this path.
121124
func (l *InMemLoader) Exists(templatePath string) bool {
122125
templatePath = l.normalize(templatePath)
126+
l.lock.RLock()
127+
defer l.lock.RUnlock()
123128
_, ok := l.files[templatePath]
124129
return ok
125130
}
126131

127132
// Set adds a template to the loader.
128133
func (l *InMemLoader) Set(templatePath, contents string) {
129134
templatePath = l.normalize(templatePath)
135+
l.lock.Lock()
136+
defer l.lock.Unlock()
130137
l.files[templatePath] = []byte(contents)
131138
}
132139

133140
// Delete removes whatever contents are stored under the given path.
134141
func (l *InMemLoader) Delete(templatePath string) {
135142
templatePath = l.normalize(templatePath)
143+
l.lock.Lock()
144+
defer l.lock.Unlock()
136145
delete(l.files, templatePath)
137146
}

0 commit comments

Comments
 (0)