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