Mercurial > hg
changeset 20833:47d43e2323c5
revset: fix generatorset race condition
If two things were iterating over a generatorset at the same time, they could
miss out on the things the other was generating, resulting in incomplete
results. This fixes it by making it possible for two things to iterate at once,
by always checking the _genlist at the beginning of each iteration.
I was only able to repro it with pending changes from my other commits, but they
aren't ready yet. So I'm unable to add a test for now.
author | Durham Goode <durham@fb.com> |
---|---|
date | Tue, 25 Mar 2014 16:10:07 -0700 |
parents | 5d57b2101ab1 |
children | 8c210b169c69 |
files | mercurial/revset.py |
diffstat | 1 files changed, 14 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/revset.py Tue Mar 25 23:07:52 2014 +0100 +++ b/mercurial/revset.py Tue Mar 25 16:10:07 2014 -0700 @@ -2624,10 +2624,8 @@ gen: a generator producing the values for the generatorset. """ self._gen = gen - self._iter = iter(gen) self._cache = {} self._genlist = baseset([]) - self._iterated = False self._finished = False def __contains__(self, x): @@ -2639,28 +2637,30 @@ if l == x: return True - self._finished = True self._cache[x] = False return False def __iter__(self): - if self._iterated: - # At least a part of the list should be cached if iteration has - # started over the generatorset. - for l in self._genlist: - yield l - - for item in self._consumegen(): - yield item + if self._finished: + for x in self._genlist: + yield x + return + + i = 0 + genlist = self._genlist + consume = self._consumegen() + while True: + if i < len(genlist): + yield genlist[i] + else: + yield consume.next() + i += 1 def _consumegen(self): - self._iterated = True - for item in self._gen: self._cache[item] = True self._genlist.append(item) yield item - self._finished = True def set(self):