changeset:   4206:0274b9f1343b
branch:      docbook
parent:      4199:f414aece63e0
user:        matthijs@stdin.nl
date:        Mon Nov 24 22:40:14 2008 +0100
summary:     docbook parser: Use the caching framework for the compiled XSL file.

diff -r f414aece63e0 -r 0274b9f1343b MoinMoin/config/multiconfig.py
--- a/MoinMoin/config/multiconfig.py	Tue Nov 11 22:00:33 2008 +0100
+++ b/MoinMoin/config/multiconfig.py	Mon Nov 24 22:40:14 2008 +0100
@@ -900,8 +900,10 @@
     ('plugin_dir', None, "Plugin directory, by default computed to be `data_dir`/plugin."),
     ('plugin_dirs', [], "Additional plugin directories."),
 
-    ('docbook_html_dir', r"/usr/share/xml/docbook/stylesheet/nwalsh/html/",
-     'Path to the directory with the Docbook to HTML XSLT files (optional, used by the docbook parser). The default value is correct for Debian Etch.'),
+    ('docbook_html_dir', None,
+     'Path to the docbook.xsl file. Deprecated, use docbook_xsl instead.'),
+    ('docbook_xsl', r"/usr/share/xml/docbook/stylesheet/nwalsh/html/docbook.xsl",
+     'Path to the HTML XSLT file (optional, used by the docbook parser). The default value is correct for Debian Etch.'),
     ('shared_intermap', None,
      "Path to a file containing global InterWiki definitions (or a list of such filenames)"),
   )),
diff -r f414aece63e0 -r 0274b9f1343b MoinMoin/parser/text_docbook.py
--- a/MoinMoin/parser/text_docbook.py	Tue Nov 11 22:00:33 2008 +0100
+++ b/MoinMoin/parser/text_docbook.py	Mon Nov 24 22:40:14 2008 +0100
@@ -35,6 +35,9 @@
 import re
 
 from MoinMoin import  Page
+from MoinMoin import caching
+from MoinMoin import log
+logging = log.getLogger(__name__)
 from MoinMoin.parser.text_xslt import Parser as XsltParser
 from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
 
@@ -52,31 +55,97 @@
         XsltParser.__init__(self, raw, request)
 
         # relative path to docbook.xsl and compiled_xsl
-        docbook_html_directory = request.cfg.docbook_html_dir
-        self.db_xsl = os.path.join(docbook_html_directory, 'docbook.xsl')
-        self.db_compiled_xsl = os.path.join(docbook_html_directory, 'db_compiled.dat')
+        if not request.cfg.docbook_html_dir is None:
+            self.db_xsl = os.path.join(request.cfg.docbook_html, 'docbook.xsl')
+        else:
+            self.db_xsl = request.cfg.docbook_xsl
 
         self.wikiParser = WikiParser(raw=self.raw, request=self.request, pretty_url=1)
         self.key = 'docbook'
 
+        # We save the compiled version of the XSL file in the cache, to
+        # speed up rendering. We have a separate entry for the filename,
+        # so we can properly refresh the cache when the docbook_xsl
+        # configuration value changes.
+        self.cached = caching.CacheEntry(self.request, 
+                                    arena='docbook',
+                                    key='compiled_xsl',
+                                    scope='farm',
+                                    use_pickle=True)
+
+        self.cached_name = caching.CacheEntry(self.request, 
+                                    arena='docbook',
+                                    key='docbook_xsl_filename',
+                                    scope='farm',
+                                    use_pickle=True)
+        
+
     def format(self, formatter):
         self.wikiParser.formatter = formatter
         XsltParser.format(self, formatter)
 
+    def get_cached_stylesheet(self, abs_db_xsl, log=True):
+        """ Try to get the compiled xsl file from the cache.
+            
+        @param abs_db_xsl: The input xsl file of which we should find
+        the compiled version.
+        @param errors: Should we do logging?
+        """
+        try:
+            if self.cached_name.content() != abs_db_xsl:
+                if log:
+                    logging.debug(
+                        "Docbook XSL file configuration changed from %s to %s" % 
+                        (cached_name.content(), abs_db_xsl)
+                    )
+            elif self.cached.needsUpdate(abs_db_xsl):
+                if log:
+                    logging.debug("Docbook XSL file changed")
+            else:
+                # Good, we got a cache hit!
+                compiled = self.cached.content()
+                if log:
+                    logging.debug("Got compiled Docbook XSL file from cache")
+                return compiled
+        except caching.CacheError:
+            if log:
+                logging.debug("Got cache error for compiled XSL file")
+        return None
+
     def append_stylesheet(self):
         """"
             virtual function, for docbook parser
         """
         abs_db_xsl = os.path.abspath(self.db_xsl)
-        abs_db_compiled_xsl = os.path.abspath(self.db_compiled_xsl)
 
-        # same as path.exists, but also test if it is a file
-        if not os.path.isfile(abs_db_compiled_xsl):
-            _compile_xsl(abs_db_xsl, abs_db_compiled_xsl)
+        compiled = self.get_cached_stylesheet(abs_db_xsl)
 
-        assert os.path.isfile(abs_db_compiled_xsl)
+        if compiled is None:
+            # Recompile the XSL file
+            logging.debug("(Re)compiling Docbook XSL file: '%s'" % (abs_db_xsl))
+            compiled = _compile_xsl(abs_db_xsl)
+            # Check the cache again (another thread might have filled
+            # the cache by now) and update the cache if that's not the
+            # case. Don't do any logging of the result, since that might
+            # be confusing.
+            if (self.get_cached_stylesheet(abs_db_xsl, log=False) is None):
+                # We first remove the old cached_name, to prevent an
+                # inconsistent situation and invalid cache hits after
+                # changing the xsl filename configuration. This does
+                # allow for possibly indefinite recompiling, if
+                # everytime a new thread triggers recompilation just
+                # between the remove and update of cached_name. However,
+                # the recheck of the cache combined with the long time
+                # needed to compile the xsl should make this case
+                # extremely unlikely.
+                self.cached_name.remove()
+                self.cached.update(compiled)
+                self.cached_name.update(abs_db_xsl)
+                logging.debug("Saved compiled Docbook XSL file to cache")
+            else:
+                logging.debug("Skipping saving of compiled Docbook XSL file to cache")
 
-        self.processor.appendStylesheetInstance(cPickle.load(file(abs_db_compiled_xsl, 'rb')))
+        self.processor.appendStylesheetInstance(compiled)
 
     def parse_result(self, result):
         """
@@ -153,7 +222,7 @@
 
 
 
-def _compile_xsl(XSLT_FILE, XSLT_COMPILED_FILE):
+def _compile_xsl(XSLT_FILE):
     """
         compiling docbook stylesheet
 
@@ -176,9 +245,8 @@
 
     # Pickled stylesheet will be self.abs_db_compiled_xsl file
     db_root = db_processor.stylesheet.root
-    fw = file(XSLT_COMPILED_FILE, 'wb')
-    cPickle.dump(db_root, fw) # , protocol=2)
-    fw.close()
+
+    return db_root
 
 
 def _splitResult(iterator, result):

