##// END OF EJS Templates
hgwebdir: avoid systematic full garbage collection...
Georges Racinet -
r48581:de2e04fe default
parent child Browse files
Show More
@@ -0,0 +1,49 b''
1 from __future__ import absolute_import
2
3 import os
4 from mercurial.hgweb import hgwebdir_mod
5
6 hgwebdir = hgwebdir_mod.hgwebdir
7
8 os.mkdir(b'webdir')
9 os.chdir(b'webdir')
10
11 webdir = os.path.realpath(b'.')
12
13
14 def trivial_response(req, res):
15 return []
16
17
18 def make_hgwebdir(gc_rate=None):
19 config = os.path.join(webdir, b'hgwebdir.conf')
20 with open(config, 'wb') as configfile:
21 configfile.write(b'[experimental]\n')
22 if gc_rate is not None:
23 configfile.write(b'web.full-garbage-collection-rate=%d\n' % gc_rate)
24 hg_wd = hgwebdir(config)
25 hg_wd._runwsgi = trivial_response
26 return hg_wd
27
28
29 def process_requests(webdir_instance, number):
30 # we don't care for now about passing realistic arguments
31 for _ in range(number):
32 for chunk in webdir_instance.run_wsgi(None, None):
33 pass
34
35
36 without_gc = make_hgwebdir(gc_rate=0)
37 process_requests(without_gc, 5)
38 assert without_gc.requests_count == 5
39 assert without_gc.gc_full_collections_done == 0
40
41 with_gc = make_hgwebdir(gc_rate=2)
42 process_requests(with_gc, 5)
43 assert with_gc.requests_count == 5
44 assert with_gc.gc_full_collections_done == 2
45
46 with_systematic_gc = make_hgwebdir() # default value of the setting
47 process_requests(with_systematic_gc, 3)
48 assert with_systematic_gc.requests_count == 3
49 assert with_systematic_gc.gc_full_collections_done == 3
@@ -1266,6 +1266,11 b' coreconfigitem('
1266 )
1266 )
1267 coreconfigitem(
1267 coreconfigitem(
1268 b'experimental',
1268 b'experimental',
1269 b'web.full-garbage-collection-rate',
1270 default=1, # still forcing a full collection on each request
1271 )
1272 coreconfigitem(
1273 b'experimental',
1269 b'worker.wdir-get-thread-safe',
1274 b'worker.wdir-get-thread-safe',
1270 default=False,
1275 default=False,
1271 )
1276 )
@@ -285,6 +285,7 b' class hgwebdir(object):'
285 self.lastrefresh = 0
285 self.lastrefresh = 0
286 self.motd = None
286 self.motd = None
287 self.refresh()
287 self.refresh()
288 self.requests_count = 0
288 if not baseui:
289 if not baseui:
289 # set up environment for new ui
290 # set up environment for new ui
290 extensions.loadall(self.ui)
291 extensions.loadall(self.ui)
@@ -341,6 +342,10 b' class hgwebdir(object):'
341
342
342 self.repos = repos
343 self.repos = repos
343 self.ui = u
344 self.ui = u
345 self.gc_full_collect_rate = self.ui.configint(
346 b'experimental', b'web.full-garbage-collection-rate'
347 )
348 self.gc_full_collections_done = 0
344 encoding.encoding = self.ui.config(b'web', b'encoding')
349 encoding.encoding = self.ui.config(b'web', b'encoding')
345 self.style = self.ui.config(b'web', b'style')
350 self.style = self.ui.config(b'web', b'style')
346 self.templatepath = self.ui.config(
351 self.templatepath = self.ui.config(
@@ -383,12 +388,27 b' class hgwebdir(object):'
383 finally:
388 finally:
384 # There are known cycles in localrepository that prevent
389 # There are known cycles in localrepository that prevent
385 # those objects (and tons of held references) from being
390 # those objects (and tons of held references) from being
386 # collected through normal refcounting. We mitigate those
391 # collected through normal refcounting.
387 # leaks by performing an explicit GC on every request.
392 # In some cases, the resulting memory consumption can
388 # TODO remove this once leaks are fixed.
393 # be tamed by performing explicit garbage collections.
389 # TODO only run this on requests that create localrepository
394 # In presence of actual leaks or big long-lived caches, the
390 # instances instead of every request.
395 # impact on performance of such collections can become a
391 gc.collect()
396 # problem, hence the rate shouldn't be set too low.
397 # See "Collecting the oldest generation" in
398 # https://devguide.python.org/garbage_collector
399 # for more about such trade-offs.
400 rate = self.gc_full_collect_rate
401
402 # this is not thread safe, but the consequence (skipping
403 # a garbage collection) is arguably better than risking
404 # to have several threads perform a collection in parallel
405 # (long useless wait on all threads).
406 self.requests_count += 1
407 if rate > 0 and self.requests_count % rate == 0:
408 gc.collect()
409 self.gc_full_collections_done += 1
410 else:
411 gc.collect(generation=1)
392
412
393 def _runwsgi(self, req, res):
413 def _runwsgi(self, req, res):
394 try:
414 try:
General Comments 0
You need to be logged in to leave comments. Login now