[PATCH 3 of 3 v2] repoview: cache repoview class instances (issue5043)
Gregory Szorc
gregory.szorc at gmail.com
Sun Jan 17 22:18:42 UTC 2016
# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1453069024 28800
# Sun Jan 17 14:17:04 2016 -0800
# Node ID 3a418d20ca9d0345416d65b82fd3f49101bcc5b2
# Parent 91969eee20a1dcd52470258164bc44528861a4c6
repoview: cache repoview class instances (issue5043)
The Python garbage collector was reporting the proxycls instances
created on every invocation of localrepository.filtered() were
uncollectable. This led to leaking memory.
We fix the leak by introducing a cache of the proxy classes. After
this patch, the garbage collector no longer reports uncollectable
objects after each iteration of `hg convert`. This likely prevents
memory leaks in a number of other operations as well (pretty much
anything relying heavily on repo.filtered() calls).
We stop short of caching the instantiated proxycls instances, which
we /should/ be able to do safely. This feels a bit too risky for
a change just before code freeze, however.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -361,16 +361,18 @@ class localrepository(object):
# - new obsolescence marker,
# - working directory parent change,
# - bookmark changes
self.filteredrevcache = {}
# generic mapping between names and nodes
self.names = namespaces.namespaces()
+ self._repoviewfn = repoview.repoviewcache(weakref.ref(self))
+
def close(self):
self._writecaches()
def _writecaches(self):
if self._revbranchcache:
self._revbranchcache.write()
def _restrictcapabilities(self, caps):
@@ -448,21 +450,17 @@ class localrepository(object):
def unfiltered(self):
"""Return unfiltered version of the repository
Intended to be overwritten by filtered repo."""
return self
def filtered(self, name):
"""Return a filtered version of a repository"""
- # build a new class with the mixin and the current class
- # (possibly subclass of the repo)
- class proxycls(repoview.repoview, self.unfiltered().__class__):
- pass
- return proxycls(self, name)
+ return self._repoviewfn(name)
@repofilecache('bookmarks', 'bookmarks.current')
def _bookmarks(self):
return bookmarks.bmstore(self)
@property
def _activebookmark(self):
return self._bookmarks.active
diff --git a/mercurial/repoview.py b/mercurial/repoview.py
--- a/mercurial/repoview.py
+++ b/mercurial/repoview.py
@@ -339,8 +339,20 @@ class repoview(object):
return delattr(self._unfilteredrepo, attr)
# The `requirements` attribute is initialized during __init__. But
# __getattr__ won't be called as it also exists on the class. We need
# explicit forwarding to main repo here
@property
def requirements(self):
return self._unfilteredrepo.requirements
+
+def repoviewcache(reporef):
+ cache = {}
+
+ def getview(filtername):
+ if filtername not in cache:
+ class proxycls(repoview, reporef().__class__):
+ pass
+ cache[filtername] = proxycls
+ return cache[filtername](reporef(), filtername)
+
+ return getview
diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py
--- a/mercurial/statichttprepo.py
+++ b/mercurial/statichttprepo.py
@@ -8,25 +8,27 @@
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import errno
import os
import urllib
import urllib2
+import weakref
from .i18n import _
from . import (
byterange,
changelog,
error,
localrepo,
manifest,
namespaces,
+ repoview,
scmutil,
store,
url,
util,
)
class httprangereader(object):
def __init__(self, url, opener):
@@ -158,16 +160,17 @@ class statichttprepository(localrepo.loc
self.changelog = changelog.changelog(self.svfs)
self._tags = None
self.nodetagscache = None
self._branchcaches = {}
self._revbranchcache = None
self.encodepats = None
self.decodepats = None
self._transref = None
+ self._repoviewfn = repoview.repoviewcache(weakref.ref(self))
def _restrictcapabilities(self, caps):
caps = super(statichttprepository, self)._restrictcapabilities(caps)
return caps.difference(["pushkey"])
def url(self):
return self._url
More information about the Mercurial-devel
mailing list