# HG changeset patch # User Mads Kiilerich # Date 1477414587 -7200 # Node ID 5ee944b9c750acce1ae6a8bc6011343499a30a5d # Parent 264f00b3e5f045ac5b58d79e2a3976585f4e7739 revset: don't cache abstractsmartset min/max invocations infinitely There was a "leak", apparently introduced in ab66c1dee405. When running: hg = hglib.open('repo') while True: hg.log("max(branch('default'))") all filteredset instances from branch() would be cached indefinitely by the @util.cachefunc annotation on the max() implementation. util.cachefunc seems dangerous as method decorator and is barely used elsewhere in the code base. Instead, just open code caching by having the min/max methods replace themselves with a plain lambda returning the result. diff -r 264f00b3e5f0 -r 5ee944b9c750 mercurial/revset.py --- a/mercurial/revset.py Mon Oct 24 09:14:34 2016 -0500 +++ b/mercurial/revset.py Tue Oct 25 18:56:27 2016 +0200 @@ -2924,23 +2924,29 @@ """True if the set will iterate in topographical order""" raise NotImplementedError() - @util.cachefunc def min(self): """return the minimum element in the set""" - if self.fastasc is not None: - for r in self.fastasc(): - return r - raise ValueError('arg is an empty sequence') - return min(self) - - @util.cachefunc + if self.fastasc is None: + v = min(self) + else: + for v in self.fastasc(): + break + else: + raise ValueError('arg is an empty sequence') + self.min = lambda: v + return v + def max(self): """return the maximum element in the set""" - if self.fastdesc is not None: - for r in self.fastdesc(): - return r - raise ValueError('arg is an empty sequence') - return max(self) + if self.fastdesc is None: + return max(self) + else: + for v in self.fastdesc(): + break + else: + raise ValueError('arg is an empty sequence') + self.max = lambda: v + return v def first(self): """return the first element in the set (user iteration perspective)