paul@423 | 1 | diff -r 5738b78f53b5 MoinMoin/Page.py |
paul@423 | 2 | --- a/MoinMoin/Page.py Sat Nov 30 20:09:43 2013 +0100 |
paul@423 | 3 | +++ b/MoinMoin/Page.py Sat Mar 29 16:23:44 2014 +0100 |
paul@423 | 4 | @@ -41,6 +41,7 @@ |
paul@423 | 5 | |
paul@423 | 6 | from MoinMoin import config, caching, user, util, wikiutil |
paul@423 | 7 | from MoinMoin.logfile import eventlog |
paul@423 | 8 | +from MoinMoin.support.python_compatibility import hash_new |
paul@423 | 9 | |
paul@423 | 10 | def is_cache_exception(e): |
paul@423 | 11 | args = e.args |
paul@423 | 12 | @@ -1254,15 +1255,17 @@ |
paul@423 | 13 | request.formatter = old_formatter |
paul@423 | 14 | |
paul@423 | 15 | |
paul@423 | 16 | - def getFormatterName(self): |
paul@423 | 17 | + def getFormatterName(self, request=None): |
paul@423 | 18 | """ Return a formatter name as used in the caching system |
paul@423 | 19 | |
paul@423 | 20 | + @param request: the active request (optional) |
paul@423 | 21 | @rtype: string |
paul@423 | 22 | @return: formatter name as used in caching |
paul@423 | 23 | """ |
paul@423 | 24 | - if not hasattr(self, 'formatter') or self.formatter is None: |
paul@423 | 25 | + formatter = getattr(self, 'formatter', None) or request and getattr(request, 'formatter', None) |
paul@423 | 26 | + if not formatter: |
paul@423 | 27 | return '' |
paul@423 | 28 | - module = self.formatter.__module__ |
paul@423 | 29 | + module = formatter.__module__ |
paul@423 | 30 | return module[module.rfind('.') + 1:] |
paul@423 | 31 | |
paul@423 | 32 | def canUseCache(self, parser=None): |
paul@423 | 33 | @@ -1351,9 +1354,12 @@ |
paul@423 | 34 | |
paul@423 | 35 | def loadCache(self, request): |
paul@423 | 36 | """ Return page content cache or raises 'CacheNeedsUpdate' """ |
paul@423 | 37 | - cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item') |
paul@423 | 38 | - attachmentsPath = self.getPagePath('attachments', check_create=0) |
paul@423 | 39 | - if cache.needsUpdate(self._text_filename(), attachmentsPath): |
paul@423 | 40 | + for with_params in (True, False): |
paul@423 | 41 | + cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item') |
paul@423 | 42 | + attachmentsPath = self.getPagePath('attachments', check_create=0) |
paul@423 | 43 | + if not cache.needsUpdate(self._text_filename(), attachmentsPath): |
paul@423 | 44 | + break |
paul@423 | 45 | + else: |
paul@423 | 46 | raise Exception('CacheNeedsUpdate') |
paul@423 | 47 | |
paul@423 | 48 | import marshal |
paul@423 | 49 | @@ -1372,7 +1378,7 @@ |
paul@423 | 50 | """ Format content into code, update cache and return code """ |
paul@423 | 51 | import marshal |
paul@423 | 52 | from MoinMoin.formatter.text_python import Formatter |
paul@423 | 53 | - formatter = Formatter(request, ["page"], self.formatter) |
paul@423 | 54 | + formatter = Formatter(request, ["page", "pageparams"], self.formatter) |
paul@423 | 55 | |
paul@423 | 56 | # Save request state while formatting page |
paul@423 | 57 | saved_current_lang = request.current_lang |
paul@423 | 58 | @@ -1384,10 +1390,44 @@ |
paul@423 | 59 | src = formatter.assemble_code(text) |
paul@423 | 60 | code = compile(src.encode(config.charset), |
paul@423 | 61 | self.page_name.encode(config.charset), 'exec') |
paul@423 | 62 | - cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item') |
paul@423 | 63 | + self.enforceCacheLimit(request) |
paul@423 | 64 | + # Determine whether the parameters/args need to be incorporated into the |
paul@423 | 65 | + # cache entry key. |
paul@423 | 66 | + with_params = "pageparams" in formatter.getReportedDependencies() |
paul@423 | 67 | + cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item') |
paul@423 | 68 | cache.update(marshal.dumps(code)) |
paul@423 | 69 | return code |
paul@423 | 70 | |
paul@423 | 71 | + def enforceCacheLimit(self, request): |
paul@423 | 72 | + """ Prevent too many cache entries being stored for a page """ |
paul@423 | 73 | + keys = caching.get_cache_list(request, self, 'item') |
paul@423 | 74 | + try: |
paul@423 | 75 | + cache_limit = int(getattr(request.cfg, 'page_cache_limit', "10")) |
paul@423 | 76 | + except ValueError: |
paul@423 | 77 | + cache_limit = 10 |
paul@423 | 78 | + |
paul@423 | 79 | + if len(keys) >= cache_limit: |
paul@423 | 80 | + items = [caching.CacheEntry(request, self, key, scope='item') for key in keys] |
paul@423 | 81 | + item_ages = [(item.mtime(), item) for item in items] |
paul@423 | 82 | + item_ages.sort() |
paul@423 | 83 | + for item_age, item in item_ages[:-cache_limit]: |
paul@423 | 84 | + item.remove() |
paul@423 | 85 | + |
paul@423 | 86 | + def getCacheKey(self, request, with_params=False, key=None): |
paul@423 | 87 | + """ Generate a cache key for a page using optional request information """ |
paul@423 | 88 | + key = key or self.getFormatterName(request) |
paul@423 | 89 | + if with_params and request.args: |
paul@423 | 90 | + args = request.args.items(True) |
paul@423 | 91 | + args.sort() |
paul@423 | 92 | + key_args = [] |
paul@423 | 93 | + for k, v in args: |
paul@423 | 94 | + if not (k == "action" and v == "refresh"): |
paul@423 | 95 | + key_args.append("%s=%s" % (k, wikiutil.url_quote(v))) |
paul@423 | 96 | + arg_str = "&".join(key_args) |
paul@423 | 97 | + if arg_str: |
paul@423 | 98 | + key = "%s:%s" % (key, hash_new('sha1', arg_str).hexdigest()) |
paul@423 | 99 | + return key |
paul@423 | 100 | + |
paul@423 | 101 | def _specialPageText(self, request, special_type): |
paul@423 | 102 | """ Output the default page content for new pages. |
paul@423 | 103 | |
paul@423 | 104 | diff -r 5738b78f53b5 MoinMoin/action/refresh.py |
paul@423 | 105 | --- a/MoinMoin/action/refresh.py Sat Nov 30 20:09:43 2013 +0100 |
paul@423 | 106 | +++ b/MoinMoin/action/refresh.py Sat Mar 29 16:23:44 2014 +0100 |
paul@423 | 107 | @@ -14,11 +14,14 @@ |
paul@423 | 108 | arena = request.values.get('arena', 'Page.py') |
paul@423 | 109 | if arena == 'Page.py': |
paul@423 | 110 | arena = Page(request, pagename) |
paul@423 | 111 | - key = request.values.get('key', 'text_html') |
paul@423 | 112 | + prefix = request.values.get('key', 'text_html') |
paul@423 | 113 | |
paul@423 | 114 | # Remove cache entry (if exists), and send the page |
paul@423 | 115 | from MoinMoin import caching |
paul@423 | 116 | - caching.CacheEntry(request, arena, key, scope='item').remove() |
paul@423 | 117 | + keys = caching.get_cache_list(request, arena, 'item') |
paul@423 | 118 | + for key in keys: |
paul@423 | 119 | + if key.startswith(prefix): |
paul@423 | 120 | + caching.CacheEntry(request, arena, key, scope='item').remove() |
paul@423 | 121 | caching.CacheEntry(request, arena, "pagelinks", scope='item').remove() |
paul@423 | 122 | request.page.send_page() |
paul@423 | 123 | |
paul@423 | 124 | diff -r 5738b78f53b5 MoinMoin/formatter/text_python.py |
paul@423 | 125 | --- a/MoinMoin/formatter/text_python.py Sat Nov 30 20:09:43 2013 +0100 |
paul@423 | 126 | +++ b/MoinMoin/formatter/text_python.py Sat Mar 29 16:23:44 2014 +0100 |
paul@423 | 127 | @@ -10,6 +10,7 @@ |
paul@423 | 128 | |
paul@423 | 129 | import time |
paul@423 | 130 | from MoinMoin import wikiutil |
paul@423 | 131 | +from MoinMoin.support.python_compatibility import set |
paul@423 | 132 | |
paul@423 | 133 | |
paul@423 | 134 | class Formatter: |
paul@423 | 135 | @@ -40,6 +41,12 @@ |
paul@423 | 136 | self.text_cmd_begin = '\nrequest.write(' |
paul@423 | 137 | self.text_cmd_end = ')\n' |
paul@423 | 138 | |
paul@423 | 139 | + # Record dependency requirements of certain content |
paul@423 | 140 | + self.__dependencies = set() |
paul@423 | 141 | + |
paul@423 | 142 | + def getReportedDependencies(self): |
paul@423 | 143 | + return self.__dependencies |
paul@423 | 144 | + |
paul@423 | 145 | def assemble_code(self, text): |
paul@423 | 146 | """inserts the code into the generated text |
paul@423 | 147 | """ |
paul@423 | 148 | @@ -186,7 +193,10 @@ |
paul@423 | 149 | return self.formatter.div(on, **kw) |
paul@423 | 150 | |
paul@423 | 151 | def macro(self, macro_obj, name, args, markup=None): |
paul@423 | 152 | - if self.__is_static(macro_obj.get_dependencies(name)): |
paul@423 | 153 | + Dependencies = macro_obj.get_dependencies(name) |
paul@423 | 154 | + self.__dependencies.update(Dependencies) |
paul@423 | 155 | + |
paul@423 | 156 | + if self.__is_static(Dependencies): |
paul@423 | 157 | # XXX: why is this necessary?? |
paul@423 | 158 | macro_obj.formatter = self |
paul@423 | 159 | return macro_obj.execute(name, args) |
paul@423 | 160 | @@ -204,6 +214,7 @@ |
paul@423 | 161 | Dependencies = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name, "Dependencies") |
paul@423 | 162 | except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError): |
paul@423 | 163 | Dependencies = self.defaultDependencies |
paul@423 | 164 | + self.__dependencies.update(Dependencies) |
paul@423 | 165 | |
paul@423 | 166 | if self.__is_static(Dependencies): |
paul@423 | 167 | return self.formatter.parser(parser_name, lines) |