339 name = name[len(prefix) :] |
340 name = name[len(prefix) :] |
340 repos.append((name.lstrip(b'/'), repo)) |
341 repos.append((name.lstrip(b'/'), repo)) |
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( |
347 b'web', b'templates', untrusted=False |
352 b'web', b'templates', untrusted=False |
348 ) |
353 ) |
381 for r in self._runwsgi(req, res): |
386 for r in self._runwsgi(req, res): |
382 yield r |
387 yield r |
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: |
395 self.refresh() |
415 self.refresh() |
396 |
416 |