From 96030cf261af2a88a4c7787e42e23d48d2f6f6e4 Mon Sep 17 00:00:00 2001 From: stefan Date: Fri, 9 Oct 2009 14:00:50 +0000 Subject: [PATCH] Fix race condition. git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4372 57a73879-2fb5-44c3-a270-3262357dd7e2 --- roundup/cgi/templating.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index 797cd13..b46f9d6 100644 --- a/roundup/cgi/templating.py +++ b/roundup/cgi/templating.py @@ -183,12 +183,28 @@ class Templates: return self.templates[src] # compile the template - self.templates[src] = pt = RoundupPageTemplate() + pt = RoundupPageTemplate() # use pt_edit so we can pass the content_type guess too content_type = mimetypes.guess_type(filename)[0] or 'text/html' pt.pt_edit(open(src).read(), content_type) pt.id = filename pt.mtime = stime + # Add it to the cache. We cannot do this until the template + # is fully initialized, as we could otherwise have a race + # condition when running with multiple threads: + # + # 1. Thread A notices the template is not in the cache, + # adds it, but has not yet set "mtime". + # + # 2. Thread B notices the template is in the cache, checks + # "mtime" (above) and crashes. + # + # Since Python dictionary access is atomic, as long as we + # insert "pt" only after it is fully initialized, we avoid + # this race condition. It's possible that two separate + # threads will both do the work of initializing the template, + # but the risk of wasted work is offset by avoiding a lock. + self.templates[src] = pt return pt def __getitem__(self, name): -- 2.30.2