comparison mercurial/hgweb/hgweb_mod.py @ 26219:ae33fff17c1e

hg: establish a cache for localrepository instances hgweb contained code for determining whether a cached localrepository instance was up to date. This code was way too low-level to be in hgweb. This functionality has been moved to a new "cachedlocalrepo" class in hg.py. The code has been changed slightly to facilitate use inside a class. hgweb has been refactored to use the new API. As part of this refactor, hgweb.repo no longer exists! We're very close to using a distinct repo instance per thread. The new cache records state when it is created. This intelligence prevents an extra localrepository from being created on the first hgweb request. This is why some redundant output from test-extension.t has gone away.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 22 Aug 2015 18:54:34 -0700
parents 7d45ec47c0af
children a43328baa2ac
comparison
equal deleted inserted replaced
26218:7d45ec47c0af 26219:ae33fff17c1e
22 'stream_out': 'pull', 22 'stream_out': 'pull',
23 'listkeys': 'pull', 23 'listkeys': 'pull',
24 'unbundle': 'push', 24 'unbundle': 'push',
25 'pushkey': 'push', 25 'pushkey': 'push',
26 } 26 }
27
28 ## Files of interest
29 # Used to check if the repository has changed looking at mtime and size of
30 # theses files. This should probably be relocated a bit higher in core.
31 foi = [('spath', '00changelog.i'),
32 ('spath', 'phaseroots'), # ! phase can change content at the same size
33 ('spath', 'obsstore'),
34 ('path', 'bookmarks'), # ! bookmark can change content at the same size
35 ]
36 27
37 def makebreadcrumb(url, prefix=''): 28 def makebreadcrumb(url, prefix=''):
38 '''Return a 'URL breadcrumb' list 29 '''Return a 'URL breadcrumb' list
39 30
40 A 'URL breadcrumb' is a list of URL-name pairs, 31 A 'URL breadcrumb' is a list of URL-name pairs,
64 55
65 Servers can be multi-threaded. Holding state on the WSGI application 56 Servers can be multi-threaded. Holding state on the WSGI application
66 is prone to race conditions. Instances of this class exist to hold 57 is prone to race conditions. Instances of this class exist to hold
67 mutable and race-free state for requests. 58 mutable and race-free state for requests.
68 """ 59 """
69 def __init__(self, app): 60 def __init__(self, app, repo):
70 self.repo = app.repo 61 self.repo = repo
71 self.reponame = app.reponame 62 self.reponame = app.reponame
72 63
73 self.archives = ('zip', 'gz', 'bz2') 64 self.archives = ('zip', 'gz', 'bz2')
74 65
75 self.maxchanges = self.configint('web', 'maxchanges', 10) 66 self.maxchanges = self.configint('web', 'maxchanges', 10)
215 r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb') 206 r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
216 # displaying bundling progress bar while serving feel wrong and may 207 # displaying bundling progress bar while serving feel wrong and may
217 # break some wsgi implementation. 208 # break some wsgi implementation.
218 r.ui.setconfig('progress', 'disable', 'true', 'hgweb') 209 r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
219 r.baseui.setconfig('progress', 'disable', 'true', 'hgweb') 210 r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
220 self.repo = self._webifyrepo(r) 211 self._repo = hg.cachedlocalrepo(self._webifyrepo(r))
221 hook.redirect(True) 212 hook.redirect(True)
222 self.repostate = None
223 self.mtime = -1
224 self.reponame = name 213 self.reponame = name
225 214
226 def _webifyrepo(self, repo): 215 def _webifyrepo(self, repo):
227 repo = getwebview(repo) 216 repo = getwebview(repo)
228 self.websubtable = webutil.getwebsubs(repo) 217 self.websubtable = webutil.getwebsubs(repo)
229 return repo 218 return repo
230 219
231 def refresh(self): 220 def _getrepo(self):
232 repostate = [] 221 r, created = self._repo.fetch()
233 mtime = 0 222 if created:
234 # file of interrests mtime and size 223 r = self._webifyrepo(r)
235 for meth, fname in foi: 224
236 prefix = getattr(self.repo, meth) 225 self.mtime = self._repo.mtime
237 st = get_stat(prefix, fname) 226 return r
238 repostate.append((st.st_mtime, st.st_size))
239 mtime = max(mtime, st.st_mtime)
240 repostate = tuple(repostate)
241 # we need to compare file size in addition to mtime to catch
242 # changes made less than a second ago
243 if repostate != self.repostate:
244 r = hg.repository(self.repo.baseui, self.repo.url())
245 self.repo = self._webifyrepo(r)
246 # update these last to avoid threads seeing empty settings
247 self.repostate = repostate
248 # mtime is needed for ETag
249 self.mtime = mtime
250 227
251 def run(self): 228 def run(self):
252 """Start a server from CGI environment. 229 """Start a server from CGI environment.
253 230
254 Modern servers should be using WSGI and should avoid this 231 Modern servers should be using WSGI and should avoid this
272 """Internal method to run the WSGI application. 249 """Internal method to run the WSGI application.
273 250
274 This is typically only called by Mercurial. External consumers 251 This is typically only called by Mercurial. External consumers
275 should be using instances of this class as the WSGI application. 252 should be using instances of this class as the WSGI application.
276 """ 253 """
277 self.refresh() 254 repo = self._getrepo()
278 rctx = requestcontext(self) 255 rctx = requestcontext(self, repo)
279 256
280 # This state is global across all threads. 257 # This state is global across all threads.
281 encoding.encoding = rctx.config('web', 'encoding', encoding.encoding) 258 encoding.encoding = rctx.config('web', 'encoding', encoding.encoding)
282 rctx.repo.ui.environ = req.env 259 rctx.repo.ui.environ = req.env
283 260