comparison mercurial/revset.py @ 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 9a09a625bc93
children bc95143446e8
comparison
equal deleted inserted replaced
20832:5d57b2101ab1 20833:47d43e2323c5
2622 def __init__(self, gen): 2622 def __init__(self, gen):
2623 """ 2623 """
2624 gen: a generator producing the values for the generatorset. 2624 gen: a generator producing the values for the generatorset.
2625 """ 2625 """
2626 self._gen = gen 2626 self._gen = gen
2627 self._iter = iter(gen)
2628 self._cache = {} 2627 self._cache = {}
2629 self._genlist = baseset([]) 2628 self._genlist = baseset([])
2630 self._iterated = False
2631 self._finished = False 2629 self._finished = False
2632 2630
2633 def __contains__(self, x): 2631 def __contains__(self, x):
2634 if x in self._cache: 2632 if x in self._cache:
2635 return self._cache[x] 2633 return self._cache[x]
2637 # Use new values only, as existing values would be cached. 2635 # Use new values only, as existing values would be cached.
2638 for l in self._consumegen(): 2636 for l in self._consumegen():
2639 if l == x: 2637 if l == x:
2640 return True 2638 return True
2641 2639
2642 self._finished = True
2643 self._cache[x] = False 2640 self._cache[x] = False
2644 return False 2641 return False
2645 2642
2646 def __iter__(self): 2643 def __iter__(self):
2647 if self._iterated: 2644 if self._finished:
2648 # At least a part of the list should be cached if iteration has 2645 for x in self._genlist:
2649 # started over the generatorset. 2646 yield x
2650 for l in self._genlist: 2647 return
2651 yield l 2648
2652 2649 i = 0
2653 for item in self._consumegen(): 2650 genlist = self._genlist
2654 yield item 2651 consume = self._consumegen()
2652 while True:
2653 if i < len(genlist):
2654 yield genlist[i]
2655 else:
2656 yield consume.next()
2657 i += 1
2655 2658
2656 def _consumegen(self): 2659 def _consumegen(self):
2657 self._iterated = True
2658
2659 for item in self._gen: 2660 for item in self._gen:
2660 self._cache[item] = True 2661 self._cache[item] = True
2661 self._genlist.append(item) 2662 self._genlist.append(item)
2662 yield item 2663 yield item
2663
2664 self._finished = True 2664 self._finished = True
2665 2665
2666 def set(self): 2666 def set(self):
2667 return self 2667 return self
2668 2668