570
570
self._current_ghosts.
572
572
self._iterations += 1
573
found, ghosts, next, parents = self._do_query(self._next_query)
574
self._current_present = found
575
self._current_ghosts = ghosts
576
self._next_query = next
577
self._current_parents = parents
579
def _do_query(self, revisions):
580
"""Query for revisions.
582
:param revisions: Revisions to query.
583
:return: A tuple: (set(found_revisions), set(ghost_revisions),
584
set(parents_of_found_revisions), dict(found_revisions:parents)).
573
586
found_parents = set()
574
new_search_revisions = set()
575
parent_map = self._parents_provider.get_parent_map(
587
parents_of_found = set()
588
parent_map = self._parents_provider.get_parent_map(revisions)
577
589
for rev_id, parents in parent_map.iteritems():
578
590
found_parents.add(rev_id)
579
new_search_revisions.update(p for p in parents if
581
ghost_parents = self._next_query - found_parents
582
self._next_query = new_search_revisions
583
self.seen.update(self._next_query)
584
self._current_present = found_parents
585
self._current_ghosts = ghost_parents
591
parents_of_found.update(p for p in parents if p not in self.seen)
592
ghost_parents = revisions - found_parents
593
self.seen.update(parents_of_found)
594
return found_parents, ghost_parents, parents_of_found, parent_map
587
596
def __iter__(self):
606
615
None of the specified revisions are required to be present in the
607
616
search list. In this case, the call is a no-op.
609
stopped = self._next_query.intersection(revisions)
610
self._next_query = self._next_query.difference(revisions)
618
revisions = frozenset(revisions)
619
if self._returning == 'query':
620
stopped = self._next_query.intersection(revisions)
621
self._next_query = self._next_query.difference(revisions)
624
stopped.update(self._current_present.intersection(revisions))
625
stopped.update(self._current_ghosts.intersection(revisions))
626
self._current_present.difference_update(stopped)
627
self._current_ghosts.difference_update(stopped)
628
# stopping 'x' should stop returning parents of 'x', but
629
# not if 'y' always references those same parents
630
stop_rev_references = {}
632
for parent_id in self._current_parents[rev]:
633
if parent_id not in stop_rev_references:
634
stop_rev_references[parent_id] = 0
635
stop_rev_references[parent_id] += 1
636
# if only the stopped revisions reference it, the ref count will be
638
for rev, parents in self._current_parents.iteritems():
639
for parent_id in parents:
641
stop_rev_references[parent_id] -= 1
645
for rev_id, refs in stop_rev_references.iteritems():
647
stop_parents.add(rev_id)
648
self._next_query.difference_update(stop_parents)
613
651
def start_searching(self, revisions):
614
self._next_query.update(revisions.difference(self.seen))
615
self.seen.update(revisions)
652
"""Add revisions to the search.
654
The parents of revisions will be returned from the next call to next()
655
or next_with_ghosts(). If next_with_ghosts was the most recently used
656
next* call then the return value is the result of looking up the
657
ghost/not ghost status of revisions. (A tuple (present, ghosted)).
659
revisions = frozenset(revisions)
660
if self._returning == 'query':
661
self._next_query.update(revisions.difference(self.seen))
662
self.seen.update(revisions)
664
# perform a query on revisions
665
revs, ghosts, query, parents = self._do_query(revisions)
666
self._current_present.update(revs)
667
self._current_ghosts.update(ghosts)
668
self._next_query.update(query)
669
self._current_parents.update(parents)