1 # HG changeset patch 2 # User Paul Boddie <paul@boddie.org.uk> 3 # Date 1390585706 -3600 4 # Node ID 70250fe93a4f946e51eaa63accbb0152054ddab2 5 # Parent d57b620213dd68126d2e5800f173d89f0602403a 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 d57b620213dd -r 70250fe93a4f MoinMoin/Page.py 10 --- a/MoinMoin/Page.py Tue Jul 30 17:41:42 2013 +0200 11 +++ b/MoinMoin/Page.py Fri Jan 24 18:48:26 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 @@ -1336,7 +1337,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 @@ -1357,7 +1358,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 @@ -1369,10 +1370,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 02d1fa8951523776357a9a37235ad5c37f42fcc8 83 # Parent 70250fe93a4f946e51eaa63accbb0152054ddab2 84 Acquire the request formatter name when the page formatter has not yet been set. 85 86 diff -r 70250fe93a4f -r 02d1fa895152 MoinMoin/Page.py 87 --- a/MoinMoin/Page.py Fri Jan 24 18:48:26 2014 +0100 88 +++ b/MoinMoin/Page.py Fri Jan 24 22:44:56 2014 +0100 89 @@ -1240,15 +1240,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 @@ -1392,7 +1394,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 561fe9439debfd095753a32d884383c315dde7ec 123 # Parent 02d1fa8951523776357a9a37235ad5c37f42fcc8 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 02d1fa895152 -r 561fe9439deb 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 @@ -1339,9 +1339,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 @@ -1373,7 +1376,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 @@ -1392,10 +1398,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 02d1fa895152 -r 561fe9439deb 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)