From f5ed04bd4a2ba1a62482b381470f04aad98375f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Thu, 16 Nov 2017 01:23:37 +0100 Subject: [PATCH] tpl/partials: Fix cache locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make sure a cached partial is ony executed exactly once. Performance same: ```bash name old time/op new time/op delta TemplateParamsKeysToLower-4 17.2µs ± 0% 16.5µs ± 0% ~ (p=1.000 n=1+1) Partial-4 18.6µs ± 0% 19.4µs ± 0% ~ (p=1.000 n=1+1) PartialCached-4 64.2ns ± 0% 63.7ns ± 0% ~ (p=1.000 n=1+1) name old alloc/op new alloc/op delta TemplateParamsKeysToLower-4 2.66kB ± 0% 2.66kB ± 0% ~ (all equal) Partial-4 1.31kB ± 0% 1.31kB ± 0% ~ (all equal) PartialCached-4 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta TemplateParamsKeysToLower-4 92.0 ± 0% 92.0 ± 0% ~ (all equal) Partial-4 41.0 ± 0% 41.0 ± 0% ~ (all equal) ``` --- tpl/partials/partials.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tpl/partials/partials.go b/tpl/partials/partials.go index d3a75edad..d999041be 100644 --- a/tpl/partials/partials.go +++ b/tpl/partials/partials.go @@ -110,27 +110,30 @@ func (ns *Namespace) IncludeCached(name string, context interface{}, variant ... return ns.getOrCreate(key, name, context) } -func (ns *Namespace) getOrCreate(key, name string, context interface{}) (p interface{}, err error) { - var ok bool +func (ns *Namespace) getOrCreate(key, name string, context interface{}) (interface{}, error) { ns.cachedPartials.RLock() - p, ok = ns.cachedPartials.p[key] + p, ok := ns.cachedPartials.p[key] ns.cachedPartials.RUnlock() if ok { - return + return p, nil } ns.cachedPartials.Lock() - if p, ok = ns.cachedPartials.p[key]; !ok { - ns.cachedPartials.Unlock() - p, err = ns.Include(name, context) - - ns.cachedPartials.Lock() - ns.cachedPartials.p[key] = p + defer ns.cachedPartials.Unlock() + // Double-check. + if p, ok = ns.cachedPartials.p[key]; ok { + return p, nil } - ns.cachedPartials.Unlock() - return + p, err := ns.Include(name, context) + if err != nil { + return nil, err + } + + ns.cachedPartials.p[key] = p + + return p, nil }