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.
--- 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)