comparison mercurial/context.py @ 27906:c183f7b79541

context: don't use util.cachefunc due to cycle creation (issue5043) util.cachefunc stores all arguments as the cache key. For filectxfn functions, the arguments include the memctx instance. This creates a cycle where memctx._filectxfn references self. This causes a memory leak. We break the cycle by implementing our own memoizing function that only uses the path as the cache key. Since each memctx has its own cache instance, there is no concern about invalid cache hits.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 17 Jan 2016 12:10:30 -0800
parents ff20fe74e5c6
children 75fa75d31495
comparison
equal deleted inserted replaced
27905:27f2f5c1d499 27906:c183f7b79541
1777 changed = set(self._status.modified) 1777 changed = set(self._status.modified)
1778 changed.update(self._status.added) 1778 changed.update(self._status.added)
1779 changed.update(self._status.removed) 1779 changed.update(self._status.removed)
1780 return changed 1780 return changed
1781 1781
1782 def makecachingfilectxfn(func):
1783 """Create a filectxfn that caches based on the path.
1784
1785 We can't use util.cachefunc because it uses all arguments as the cache
1786 key and this creates a cycle since the arguments include the repo and
1787 memctx.
1788 """
1789 cache = {}
1790
1791 def getfilectx(repo, memctx, path):
1792 if path not in cache:
1793 cache[path] = func(repo, memctx, path)
1794 return cache[path]
1795
1796 return getfilectx
1797
1782 class memctx(committablectx): 1798 class memctx(committablectx):
1783 """Use memctx to perform in-memory commits via localrepo.commitctx(). 1799 """Use memctx to perform in-memory commits via localrepo.commitctx().
1784 1800
1785 Revision information is supplied at initialization time while 1801 Revision information is supplied at initialization time while
1786 related files data and is made available through a callback 1802 related files data and is made available through a callback
1836 return memfilectx(repo, path, fctx.data(), 1852 return memfilectx(repo, path, fctx.data(),
1837 islink=fctx.islink(), isexec=fctx.isexec(), 1853 islink=fctx.islink(), isexec=fctx.isexec(),
1838 copied=copied, memctx=memctx) 1854 copied=copied, memctx=memctx)
1839 self._filectxfn = getfilectx 1855 self._filectxfn = getfilectx
1840 else: 1856 else:
1841 # "util.cachefunc" reduces invocation of possibly expensive 1857 # memoizing increases performance for e.g. vcs convert scenarios.
1842 # "filectxfn" for performance (e.g. converting from another VCS) 1858 self._filectxfn = makecachingfilectxfn(filectxfn)
1843 self._filectxfn = util.cachefunc(filectxfn)
1844 1859
1845 if extra: 1860 if extra:
1846 self._extra = extra.copy() 1861 self._extra = extra.copy()
1847 else: 1862 else:
1848 self._extra = {} 1863 self._extra = {}