changeset 113:de257cc40ce1

Re-enable proper caching of rendered segments in server. The server keeps records on files that are processed while the server is running. Disk caching is simply disabled for files that are known to use other pages -- because unlike the baker, there's no cheap way to know which files are up to date or not, and rendering is faster enough anyway.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 19 Oct 2014 00:30:44 -0700
parents d31cbbdb4ecc
children 371a6c879ab9
files piecrust/serving.py
diffstat 1 files changed, 48 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/serving.py	Sun Oct 19 00:25:02 2014 -0700
+++ b/piecrust/serving.py	Sun Oct 19 00:30:44 2014 -0700
@@ -26,9 +26,30 @@
 
 
 class ServingEnvironment(StandardEnvironment):
+    pass
+
+
+class ServeRecord(object):
     def __init__(self):
-        super(ServingEnvironment, self).__init__()
-        del self.fs_caches['renders']
+        self.entries = {}
+
+    def addEntry(self, entry):
+        key = self._makeKey(entry.uri, entry.sub_num)
+        self.entries[key] = entry
+
+    def getEntry(self, uri, sub_num):
+        key = self._makeKey(uri, sub_num)
+        return self.entries.get(key)
+
+    def _makeKey(self, uri, sub_num):
+        return "%s:%s" % (uri, sub_num)
+
+
+class ServeRecordPageEntry(object):
+    def __init__(self, uri, sub_num):
+        self.uri = uri
+        self.sub_num = sub_num
+        self.used_source_names = set()
 
 
 class Server(object):
@@ -44,7 +65,8 @@
         self._out_dir = None
         self._skip_patterns = None
         self._force_patterns = None
-        self._record = None
+        self._asset_record = None
+        self._page_record = None
         self._mimetype_map = load_mimetype_map()
 
     def run(self):
@@ -59,7 +81,8 @@
                 app, mounts, self._out_dir,
                 skip_patterns=self._skip_patterns,
                 force_patterns=self._force_patterns)
-        self._record = pipeline.run()
+        self._asset_record = pipeline.run()
+        self._page_record = ServeRecord()
 
         # Run the WSGI app.
         wsgi_wrapper = WsgiServer(self)
@@ -84,8 +107,7 @@
             raise MethodNotAllowed()
 
         # Create the app for this request.
-        env = ServingEnvironment()
-        app = PieCrust(root_dir=self.root_dir, debug=self.debug, env=env)
+        app = PieCrust(root_dir=self.root_dir, debug=self.debug)
         app.config.set('site/root', '/')
         app.config.set('site/pretty_urls', True)
         app.config.set('server/is_serving', True)
@@ -119,7 +141,7 @@
     def _try_serve_asset(self, app, environ, request):
         logger.debug("Searching for asset with path: %s" % request.path)
         rel_req_path = request.path.lstrip('/').replace('/', os.sep)
-        entry = self._record.findEntry(rel_req_path)
+        entry = self._asset_record.findEntry(rel_req_path)
         if entry is None:
             return None
 
@@ -197,7 +219,7 @@
                     "(looked in: %s)" %
                     (req_path, [r.source_name for r, _ in routes]))
 
-        # Build the page and render it.
+        # Build the page.
         fac = PageFactory(source, rel_path, fac_metadata)
         page = fac.buildPage()
         render_ctx = PageRenderingContext(page, req_path, page_num)
@@ -208,12 +230,28 @@
             else:
                 flt.addClause(IsFilterClause(taxonomy.name, term_value))
             render_ctx.pagination_filter = flt
-
             render_ctx.custom_data = {
                     taxonomy.term_name: term_value}
+
+        # See if this page is known to use sources. If that's the case,
+        # just don't use cached rendered segments for that page (but still
+        # use them for pages that are included in it).
+        entry = self._page_record.getEntry(req_path, page_num)
+        if (taxonomy is not None or entry is None or
+                entry.used_source_names):
+            cache_key = '%s:%s' % (req_path, page_num)
+            app.env.rendered_segments_repository.invalidate(cache_key)
+
+        # Render the page.
         rendered_page = render_page(render_ctx)
         rp_content = rendered_page.content
 
+        if entry is None:
+            entry = ServeRecordPageEntry(req_path, page_num)
+            self._page_record.addEntry(entry)
+        entry.used_source_names = set(render_ctx.used_source_names)
+
+        # Profiling.
         if app.debug:
             now_time = time.clock()
             timing_info = ('%8.1f ms' %
@@ -221,7 +259,7 @@
             rp_content = rp_content.replace('__PIECRUST_TIMING_INFORMATION__',
                     timing_info)
 
-        # Start response.
+        # Build the response.
         response = Response()
 
         etag = hashlib.md5(rp_content.encode('utf8')).hexdigest()