Skip to content

Commit d086b3e

Browse files
committed
Further improve locking (RWMutex version)
As a second step improving unrolled#90, only lock when absolutely necessary and reconstruct functions to ensure that the current templates are referenced in the helper func instead of a global reference. Closes unrolled#91 Signed-off-by: Andrew Thornton <[email protected]>
1 parent 8d2b52a commit d086b3e

File tree

1 file changed

+24
-22
lines changed

1 file changed

+24
-22
lines changed

render.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,11 @@ type HTMLOptions struct {
120120
// Render is a service that provides functions for easily writing JSON, XML,
121121
// binary data, and HTML templates out to a HTTP Response.
122122
type Render struct {
123+
lock sync.RWMutex
124+
123125
// Customize Secure with an Options struct.
124126
opt Options
125127
templates *template.Template
126-
templatesLk sync.RWMutex
127128
compiledCharset string
128129
}
129130

@@ -242,9 +243,9 @@ func (r *Render) compileTemplatesFromDir() {
242243
return nil
243244
})
244245

245-
r.templatesLk.Lock()
246+
r.lock.Lock()
247+
defer r.lock.Unlock()
246248
r.templates = tmpTemplates
247-
r.templatesLk.Unlock()
248249
}
249250

250251
func (r *Render) compileTemplatesFromAsset() {
@@ -289,28 +290,29 @@ func (r *Render) compileTemplatesFromAsset() {
289290
}
290291
}
291292
}
292-
293-
r.templatesLk.Lock()
293+
r.lock.Lock()
294+
defer r.lock.Unlock()
294295
r.templates = tmpTemplates
295-
r.templatesLk.Unlock()
296296
}
297297

298298
// TemplateLookup is a wrapper around template.Lookup and returns
299299
// the template with the given name that is associated with t, or nil
300300
// if there is no such template.
301301
func (r *Render) TemplateLookup(t string) *template.Template {
302+
r.lock.RLock()
303+
defer r.lock.RUnlock()
302304
return r.templates.Lookup(t)
303305
}
304306

305-
func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) {
307+
func (r *Render) execute(templates *template.Template, name string, binding interface{}) (*bytes.Buffer, error) {
306308
buf := new(bytes.Buffer)
307-
return buf, r.templates.ExecuteTemplate(buf, name, binding)
309+
return buf, templates.ExecuteTemplate(buf, name, binding)
308310
}
309311

310-
func (r *Render) layoutFuncs(name string, binding interface{}) template.FuncMap {
312+
func (r *Render) layoutFuncs(templates *template.Template, name string, binding interface{}) template.FuncMap {
311313
return template.FuncMap{
312314
"yield": func() (template.HTML, error) {
313-
buf, err := r.execute(name, binding)
315+
buf, err := r.execute(templates, name, binding)
314316
// Return safe HTML here since we are rendering our own template.
315317
return template.HTML(buf.String()), err
316318
},
@@ -320,23 +322,23 @@ func (r *Render) layoutFuncs(name string, binding interface{}) template.FuncMap
320322
"block": func(partialName string) (template.HTML, error) {
321323
log.Print("Render's `block` implementation is now depericated. Use `partial` as a drop in replacement.")
322324
fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
323-
if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
325+
if templates.Lookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
324326
fullPartialName = partialName
325327
}
326-
if r.opt.RequireBlocks || r.TemplateLookup(fullPartialName) != nil {
327-
buf, err := r.execute(fullPartialName, binding)
328+
if r.opt.RequireBlocks || templates.Lookup(fullPartialName) != nil {
329+
buf, err := r.execute(templates, fullPartialName, binding)
328330
// Return safe HTML here since we are rendering our own template.
329331
return template.HTML(buf.String()), err
330332
}
331333
return "", nil
332334
},
333335
"partial": func(partialName string) (template.HTML, error) {
334336
fullPartialName := fmt.Sprintf("%s-%s", partialName, name)
335-
if r.TemplateLookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
337+
if templates.Lookup(fullPartialName) == nil && r.opt.RenderPartialsWithoutPrefix {
336338
fullPartialName = partialName
337339
}
338-
if r.opt.RequirePartials || r.TemplateLookup(fullPartialName) != nil {
339-
buf, err := r.execute(fullPartialName, binding)
340+
if r.opt.RequirePartials || templates.Lookup(fullPartialName) != nil {
341+
buf, err := r.execute(templates, fullPartialName, binding)
340342
// Return safe HTML here since we are rendering our own template.
341343
return template.HTML(buf.String()), err
342344
}
@@ -402,14 +404,14 @@ func (r *Render) HTML(w io.Writer, status int, name string, binding interface{},
402404
if r.opt.IsDevelopment {
403405
r.compileTemplates()
404406
}
405-
406-
r.templatesLk.RLock()
407-
defer r.templatesLk.RUnlock()
407+
r.lock.RLock()
408+
templates := r.templates
409+
r.lock.RUnlock()
408410

409411
opt := r.prepareHTMLOptions(htmlOpt)
410-
if tpl := r.templates.Lookup(name); tpl != nil {
412+
if tpl := templates.Lookup(name); tpl != nil {
411413
if len(opt.Layout) > 0 {
412-
tpl.Funcs(r.layoutFuncs(name, binding))
414+
tpl.Funcs(r.layoutFuncs(templates, name, binding))
413415
name = opt.Layout
414416
}
415417

@@ -426,7 +428,7 @@ func (r *Render) HTML(w io.Writer, status int, name string, binding interface{},
426428
h := HTML{
427429
Head: head,
428430
Name: name,
429-
Templates: r.templates,
431+
Templates: templates,
430432
bp: r.opt.BufferPool,
431433
}
432434

0 commit comments

Comments
 (0)