1 diff -r 5738b78f53b5 MoinMoin/Page.py 2 --- a/MoinMoin/Page.py Sat Nov 30 20:09:43 2013 +0100 3 +++ b/MoinMoin/Page.py Sat Mar 29 16:23:44 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 @@ -1254,15 +1255,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 @@ -1351,9 +1354,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 @@ -1372,7 +1378,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 @@ -1384,10 +1390,44 @@ 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(True) 91 + args.sort() 92 + key_args = [] 93 + for k, v in args: 94 + if not (k == "action" and v == "refresh"): 95 + key_args.append("%s=%s" % (k, wikiutil.url_quote(v))) 96 + arg_str = "&".join(key_args) 97 + if arg_str: 98 + key = "%s:%s" % (key, hash_new('sha1', arg_str).hexdigest()) 99 + return key 100 + 101 def _specialPageText(self, request, special_type): 102 """ Output the default page content for new pages. 103 104 diff -r 5738b78f53b5 MoinMoin/action/refresh.py 105 --- a/MoinMoin/action/refresh.py Sat Nov 30 20:09:43 2013 +0100 106 +++ b/MoinMoin/action/refresh.py Sat Mar 29 16:23:44 2014 +0100 107 @@ -14,11 +14,14 @@ 108 arena = request.values.get('arena', 'Page.py') 109 if arena == 'Page.py': 110 arena = Page(request, pagename) 111 - key = request.values.get('key', 'text_html') 112 + prefix = request.values.get('key', 'text_html') 113 114 # Remove cache entry (if exists), and send the page 115 from MoinMoin import caching 116 - caching.CacheEntry(request, arena, key, scope='item').remove() 117 + keys = caching.get_cache_list(request, arena, 'item') 118 + for key in keys: 119 + if key.startswith(prefix): 120 + caching.CacheEntry(request, arena, key, scope='item').remove() 121 caching.CacheEntry(request, arena, "pagelinks", scope='item').remove() 122 request.page.send_page() 123 124 diff -r 5738b78f53b5 MoinMoin/formatter/text_python.py 125 --- a/MoinMoin/formatter/text_python.py Sat Nov 30 20:09:43 2013 +0100 126 +++ b/MoinMoin/formatter/text_python.py Sat Mar 29 16:23:44 2014 +0100 127 @@ -10,6 +10,7 @@ 128 129 import time 130 from MoinMoin import wikiutil 131 +from MoinMoin.support.python_compatibility import set 132 133 134 class Formatter: 135 @@ -40,6 +41,12 @@ 136 self.text_cmd_begin = '\nrequest.write(' 137 self.text_cmd_end = ')\n' 138 139 + # Record dependency requirements of certain content 140 + self.__dependencies = set() 141 + 142 + def getReportedDependencies(self): 143 + return self.__dependencies 144 + 145 def assemble_code(self, text): 146 """inserts the code into the generated text 147 """ 148 @@ -186,7 +193,10 @@ 149 return self.formatter.div(on, **kw) 150 151 def macro(self, macro_obj, name, args, markup=None): 152 - if self.__is_static(macro_obj.get_dependencies(name)): 153 + Dependencies = macro_obj.get_dependencies(name) 154 + self.__dependencies.update(Dependencies) 155 + 156 + if self.__is_static(Dependencies): 157 # XXX: why is this necessary?? 158 macro_obj.formatter = self 159 return macro_obj.execute(name, args) 160 @@ -204,6 +214,7 @@ 161 Dependencies = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name, "Dependencies") 162 except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError): 163 Dependencies = self.defaultDependencies 164 + self.__dependencies.update(Dependencies) 165 166 if self.__is_static(Dependencies): 167 return self.formatter.parser(parser_name, lines)