234
234
for searcher in active_searchers.itervalues():
236
236
while len(active_searchers) > 0:
237
for candidate, searcher in list(active_searchers.iteritems()):
237
for candidate in active_searchers.keys():
239
searcher = active_searchers[candidate]
241
# rare case: we deleted candidate in a previous iteration
242
# through this for loop, because it was determined to be
243
# a descendant of another candidate.
239
246
ancestors = searcher.next()
240
247
except StopIteration:
290
297
sorter = tsort.TopoSorter(zip(revisions, self.get_parents(revisions)))
291
298
return sorter.iter_topo_order()
300
def is_ancestor(self, candidate_ancestor, candidate_descendant):
301
"""Determine whether a revision is an ancestor of another.
303
There are two possible outcomes: True and False, but there are three
304
possible relationships:
306
a) candidate_ancestor is an ancestor of candidate_descendant
307
b) candidate_ancestor is an descendant of candidate_descendant
308
c) candidate_ancestor is an sibling of candidate_descendant
310
To check for a, we walk from candidate_descendant, looking for
313
To check for b, we walk from candidate_ancestor, looking for
314
candidate_descendant.
316
To make a and b more efficient, we can stop any searches that hit
319
If we exhaust our searches, but neither a or b is true, then c is true.
321
In order to find c efficiently, we must avoid searching from
322
candidate_descendant or candidate_ancestor into common ancestors. But
323
if we don't search common ancestors at all, we won't know if we hit
324
common ancestors. So we have a walker for common ancestors. Note that
325
its searches are not required to terminate in order to determine c to
328
ancestor_walker = self._make_breadth_first_searcher(
329
[candidate_ancestor])
330
descendant_walker = self._make_breadth_first_searcher(
331
[candidate_descendant])
332
common_walker = self._make_breadth_first_searcher([])
333
active_ancestor = True
334
active_descendant = True
335
while (active_ancestor or active_descendant):
337
if active_descendant:
339
nodes = descendant_walker.next()
340
except StopIteration:
341
active_descendant = False
343
if candidate_ancestor in nodes:
345
new_common.update(nodes.intersection(ancestor_walker.seen))
348
nodes = ancestor_walker.next()
349
except StopIteration:
350
active_ancestor = False
352
if candidate_descendant in nodes:
354
new_common.update(nodes.intersection(
355
descendant_walker.seen))
357
new_common.update(common_walker.next())
358
except StopIteration:
360
for walker in (ancestor_walker, descendant_walker):
361
for node in new_common:
362
c_ancestors = walker.find_seen_ancestors(node)
363
walker.stop_searching_any(c_ancestors)
364
common_walker.start_searching(new_common)
294
368
class _BreadthFirstSearcher(object):
295
369
"""Parallel search the breadth-first the ancestry of revisions.