Last active
December 13, 2015 18:19
-
-
Save zeebo/4954914 to your computer and use it in GitHub Desktop.
complicated locking strategy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"html/template" | |
"path/filepath" | |
"sync" | |
) | |
// i like this inline struct style thing. it's fun. | |
var cachedTemplates = struct { | |
sync.RWMutex | |
t map[string]*template.Template | |
}{t: map[string]*template.Template{}} | |
// this lock is to make sure only one thing is compiling | |
// at a time. helps reduce contention on the map lock. | |
var compileLock sync.Mutex | |
// set of functions to add to our template | |
var funcs = template.FuncMap{ | |
"reverse": reverse, | |
} | |
func T(name string) *template.Template { | |
// fast path: grab a read lock and return the template if it | |
// exists | |
cachedTemplates.RLock() | |
t, ok := cachedTemplates.t[name] | |
cachedTemplates.RUnlock() | |
if ok { | |
return t | |
} | |
// goal: we don't want to compile the same template twice | |
// and we want to hold the write lock on the map as minimally | |
// as possible to avoid blocking requests that already have it | |
// so we have a compiling lock here. | |
compileLock.Lock() | |
defer compileLock.Unlock() | |
// maybe two threads missed on the same name, so check if we lost | |
// the race to grab the compile lock and it has been fufilled by | |
// the other thread. note we don't need a read lock here because | |
// the write lock below is a subset of the compile lock. There can | |
// be no concurrent writers to the template map during this read. | |
if t, ok := cachedTemplates.t[name]; ok { | |
return t | |
} | |
// nope we definitely have to compile the template | |
t = template.New("_base.html").Funcs(funcs) | |
t = template.Must(t.ParseFiles( | |
"templates/_base.html", | |
filepath.Join("templates", name), | |
)) | |
cachedTemplates.Lock() | |
cachedTemplates.t[name] = t | |
cachedTemplates.Unlock() | |
return t | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment