1 # HG changeset patch 2 # User Paul Boddie <paul@boddie.org.uk> 3 # Date 1390585938 -3600 4 # Node ID 71d9815d2e6f5487ec87c4f5c04e5a156ffd21d3 5 # Parent 5738b78f53b540ece0b48efa49b63fa4cbc09be9 6 Added caching support for the "pageparams" dependency where the request 7 parameters are combined with the page name to make a cache entry. 8 9 diff -r 5738b78f53b5 -r 71d9815d2e6f MoinMoin/Page.py 10 --- a/MoinMoin/Page.py Sat Nov 30 20:09:43 2013 +0100 11 +++ b/MoinMoin/Page.py Fri Jan 24 18:52:18 2014 +0100 12 @@ -41,6 +41,7 @@ 13 14 from MoinMoin import config, caching, user, util, wikiutil 15 from MoinMoin.logfile import eventlog 16 +from MoinMoin.support.python_compatibility import hash_new 17 18 def is_cache_exception(e): 19 args = e.args 20 @@ -1351,7 +1352,7 @@ 21 22 def loadCache(self, request): 23 """ Return page content cache or raises 'CacheNeedsUpdate' """ 24 - cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item') 25 + cache = caching.CacheEntry(request, self, self.getCacheKey(request), scope='item') 26 attachmentsPath = self.getPagePath('attachments', check_create=0) 27 if cache.needsUpdate(self._text_filename(), attachmentsPath): 28 raise Exception('CacheNeedsUpdate') 29 @@ -1372,7 +1373,7 @@ 30 """ Format content into code, update cache and return code """ 31 import marshal 32 from MoinMoin.formatter.text_python import Formatter 33 - formatter = Formatter(request, ["page"], self.formatter) 34 + formatter = Formatter(request, ["page", "pageparams"], self.formatter) 35 36 # Save request state while formatting page 37 saved_current_lang = request.current_lang 38 @@ -1384,10 +1385,39 @@ 39 src = formatter.assemble_code(text) 40 code = compile(src.encode(config.charset), 41 self.page_name.encode(config.charset), 'exec') 42 - cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item') 43 + self.enforceCacheLimit(request) 44 + cache = caching.CacheEntry(request, self, self.getCacheKey(request), scope='item') 45 cache.update(marshal.dumps(code)) 46 return code 47 48 + def enforceCacheLimit(self, request): 49 + """ Prevent too many cache entries being stored for a page """ 50 + keys = caching.get_cache_list(request, self, 'item') 51 + try: 52 + cache_limit = int(getattr(request.cfg, 'page_cache_limit', "10")) 53 + except ValueError: 54 + cache_limit = 10 55 + 56 + if len(keys) >= cache_limit: 57 + items = [caching.CacheEntry(request, self, key, scope='item') for key in keys] 58 + item_ages = [(item.mtime(), item) for item in items] 59 + item_ages.sort() 60 + for item_age, item in item_ages[:-cache_limit]: 61 + item.remove() 62 + 63 + def getCacheKey(self, request): 64 + """ Generate a cache key for a page using optional request information """ 65 + key = self.getFormatterName() 66 + if request.args: 67 + args = request.args.items() 68 + args.sort() 69 + key_args = [] 70 + for k, v in args: 71 + key_args.append("%s=%s" % (k, wikiutil.url_quote(v))) 72 + arg_str = "&".join(key_args) 73 + key = "%s:%s" % (key, hash_new('sha1', arg_str).hexdigest()) 74 + return key 75 + 76 def _specialPageText(self, request, special_type): 77 """ Output the default page content for new pages. 78 79 # HG changeset patch 80 # User Paul Boddie <paul@boddie.org.uk> 81 # Date 1390599896 -3600 82 # Node ID e3850612c891d5b6468f212acd797413c70fe18f 83 # Parent 71d9815d2e6f5487ec87c4f5c04e5a156ffd21d3 84 Acquire the request formatter name when the page formatter has not yet been set. 85 86 diff -r 71d9815d2e6f -r e3850612c891 MoinMoin/Page.py 87 --- a/MoinMoin/Page.py Fri Jan 24 18:52:18 2014 +0100 88 +++ b/MoinMoin/Page.py Fri Jan 24 22:44:56 2014 +0100 89 @@ -1255,15 +1255,17 @@ 90 request.formatter = old_formatter 91 92 93 - def getFormatterName(self): 94 + def getFormatterName(self, request=None): 95 """ Return a formatter name as used in the caching system 96 97 + @param request: the active request (optional) 98 @rtype: string 99 @return: formatter name as used in caching 100 """ 101 - if not hasattr(self, 'formatter') or self.formatter is None: 102 + formatter = getattr(self, 'formatter', None) or request and getattr(request, 'formatter', None) 103 + if not formatter: 104 return '' 105 - module = self.formatter.__module__ 106 + module = formatter.__module__ 107 return module[module.rfind('.') + 1:] 108 109 def canUseCache(self, parser=None): 110 @@ -1407,7 +1409,7 @@ 111 112 def getCacheKey(self, request): 113 """ Generate a cache key for a page using optional request information """ 114 - key = self.getFormatterName() 115 + key = self.getFormatterName(request) 116 if request.args: 117 args = request.args.items() 118 args.sort() 119 # HG changeset patch 120 # User Paul Boddie <paul@boddie.org.uk> 121 # Date 1390675730 -3600 122 # Node ID 908ceaf41dbe9f664f0c0813abc7b4c0611022fe 123 # Parent e3850612c891d5b6468f212acd797413c70fe18f 124 Added tracking of reported dependencies and prevented generation of specific 125 cache entries for request parameter combinations when no extension requires or 126 supports such specific entries. 127 128 diff -r e3850612c891 -r 908ceaf41dbe MoinMoin/Page.py 129 --- a/MoinMoin/Page.py Fri Jan 24 22:44:56 2014 +0100 130 +++ b/MoinMoin/Page.py Sat Jan 25 19:48:50 2014 +0100 131 @@ -1354,9 +1354,12 @@ 132 133 def loadCache(self, request): 134 """ Return page content cache or raises 'CacheNeedsUpdate' """ 135 - cache = caching.CacheEntry(request, self, self.getCacheKey(request), scope='item') 136 - attachmentsPath = self.getPagePath('attachments', check_create=0) 137 - if cache.needsUpdate(self._text_filename(), attachmentsPath): 138 + for with_params in (True, False): 139 + cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item') 140 + attachmentsPath = self.getPagePath('attachments', check_create=0) 141 + if not cache.needsUpdate(self._text_filename(), attachmentsPath): 142 + break 143 + else: 144 raise Exception('CacheNeedsUpdate') 145 146 import marshal 147 @@ -1388,7 +1391,10 @@ 148 code = compile(src.encode(config.charset), 149 self.page_name.encode(config.charset), 'exec') 150 self.enforceCacheLimit(request) 151 - cache = caching.CacheEntry(request, self, self.getCacheKey(request), scope='item') 152 + # Determine whether the parameters/args need to be incorporated into the 153 + # cache entry key. 154 + with_params = "pageparams" in formatter.getReportedDependencies() 155 + cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item') 156 cache.update(marshal.dumps(code)) 157 return code 158 159 @@ -1407,10 +1413,10 @@ 160 for item_age, item in item_ages[:-cache_limit]: 161 item.remove() 162 163 - def getCacheKey(self, request): 164 + def getCacheKey(self, request, with_params=False): 165 """ Generate a cache key for a page using optional request information """ 166 key = self.getFormatterName(request) 167 - if request.args: 168 + if with_params and request.args: 169 args = request.args.items() 170 args.sort() 171 key_args = [] 172 diff -r e3850612c891 -r 908ceaf41dbe MoinMoin/formatter/text_python.py 173 --- a/MoinMoin/formatter/text_python.py Fri Jan 24 22:44:56 2014 +0100 174 +++ b/MoinMoin/formatter/text_python.py Sat Jan 25 19:48:50 2014 +0100 175 @@ -10,6 +10,7 @@ 176 177 import time 178 from MoinMoin import wikiutil 179 +from MoinMoin.support.python_compatibility import set 180 181 182 class Formatter: 183 @@ -40,6 +41,12 @@ 184 self.text_cmd_begin = '\nrequest.write(' 185 self.text_cmd_end = ')\n' 186 187 + # Record dependency requirements of certain content 188 + self.__dependencies = set() 189 + 190 + def getReportedDependencies(self): 191 + return self.__dependencies 192 + 193 def assemble_code(self, text): 194 """inserts the code into the generated text 195 """ 196 @@ -186,7 +193,10 @@ 197 return self.formatter.div(on, **kw) 198 199 def macro(self, macro_obj, name, args, markup=None): 200 - if self.__is_static(macro_obj.get_dependencies(name)): 201 + Dependencies = macro_obj.get_dependencies(name) 202 + self.__dependencies.update(Dependencies) 203 + 204 + if self.__is_static(Dependencies): 205 # XXX: why is this necessary?? 206 macro_obj.formatter = self 207 return macro_obj.execute(name, args) 208 @@ -204,6 +214,7 @@ 209 Dependencies = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name, "Dependencies") 210 except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError): 211 Dependencies = self.defaultDependencies 212 + self.__dependencies.update(Dependencies) 213 214 if self.__is_static(Dependencies): 215 return self.formatter.parser(parser_name, lines)