Mercurial > public > mercurial-scm > hg-stable
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 |