95
95
def iter_topo_order(self):
96
96
"""Yield the nodes of the graph in a topological order.
98
98
After finishing iteration the sorter is empty and you cannot continue
102
visitable = set(graph)
104
# this is a stack storing the depth first search into the graph.
105
pending_node_stack = []
106
# at each level of 'recursion' we have to check each parent. This
107
# stack stores the parents we have not yet checked for the node at the
108
# matching depth in pending_node_stack
109
pending_parents_stack = []
111
# this is a set of the completed nodes for fast checking whether a
112
# parent in a node we are processing on the stack has already been
113
# emitted and thus can be skipped.
114
completed_node_names = set()
102
117
# now pick a random node in the source graph, and transfer it to the
103
# top of the depth first search stack.
104
node_name, parents = self._graph.popitem()
105
self._push_node(node_name, parents)
106
while self._node_name_stack:
107
# loop until this call completes.
108
parents_to_visit = self._pending_parents_stack[-1]
109
# if all parents are done, the revision is done
118
# top of the depth first search stack of pending nodes.
119
node_name, parents = graph.popitem()
120
pending_node_stack.append(node_name)
121
pending_parents_stack.append(list(parents))
123
# loop until pending_node_stack is empty
124
while pending_node_stack:
125
parents_to_visit = pending_parents_stack[-1]
126
# if there are no parents left, the revision is done
110
127
if not parents_to_visit:
111
128
# append the revision to the topo sorted list
112
# all the nodes parents have been added to the output, now
113
# we can add it to the output.
114
yield self._pop_node()
129
# all the nodes parents have been added to the output,
130
# now we can add it to the output.
131
popped_node = pending_node_stack.pop()
132
pending_parents_stack.pop()
133
completed_node_names.add(popped_node)
116
while self._pending_parents_stack[-1]:
117
# recurse depth first into a single parent
118
next_node_name = self._pending_parents_stack[-1].pop()
119
if next_node_name in self._completed_node_names:
120
# this parent was completed by a child on the
121
# call stack. skip it.
123
# otherwise transfer it from the source graph into the
124
# top of the current depth first search stack.
126
parents = self._graph.pop(next_node_name)
128
# if the next node is not in the source graph it has
129
# already been popped from it and placed into the
130
# current search stack (but not completed or we would
131
# have hit the continue 4 lines up.
132
# this indicates a cycle.
133
raise errors.GraphCycleError(self._node_name_stack)
134
self._push_node(next_node_name, parents)
135
# and do not continue processing parents until this 'call'
139
def _push_node(self, node_name, parents):
140
"""Add node_name to the pending node stack.
142
Names in this stack will get emitted into the output as they are popped
145
self._node_name_stack.append(node_name)
146
self._pending_parents_stack.append(list(parents))
149
"""Pop the top node off the stack
151
The node is appended to the sorted output.
153
# we are returning from the flattened call frame:
154
# pop off the local variables
155
node_name = self._node_name_stack.pop()
156
self._pending_parents_stack.pop()
158
self._completed_node_names.add(node_name)
136
# recurse depth first into a single parent
137
next_node_name = parents_to_visit.pop()
139
if next_node_name in completed_node_names:
140
# parent was already completed by a child, skip it.
142
if next_node_name not in visitable:
143
# parent is not a node in the original graph, skip it.
146
# transfer it along with its parents from the source graph
147
# into the top of the current depth first search stack.
149
parents = graph.pop(next_node_name)
151
# if the next node is not in the source graph it has
152
# already been popped from it and placed into the
153
# current search stack (but not completed or we would
154
# have hit the continue 6 lines up). this indicates a
156
raise errors.GraphCycleError(pending_node_stack)
157
pending_node_stack.append(next_node_name)
158
pending_parents_stack.append(list(parents))
162
161
def merge_sort(graph, branch_tip, mainline_revisions=None, generate_revno=False):
163
162
"""Topological sort a graph which groups merges.
165
164
:param graph: sequence of pairs of node->parents_list.
166
:param branch_tip: the tip of the branch to graph. Revisions not
165
:param branch_tip: the tip of the branch to graph. Revisions not
167
166
reachable from branch_tip are not included in the
169
168
:param mainline_revisions: If not None this forces a mainline to be
379
# the scheduling order is: F, E, D, C, B, A
401
# the scheduling order is: F, E, D, C, B, A
380
402
# that is - 'left subtree, right subtree, node'
381
403
# which would mean that when we schedule A we can emit the entire tree.
382
404
self._scheduled_nodes = []
383
# This records for each node when we have processed its left most
405
# This records for each node when we have processed its left most
384
406
# unmerged subtree. After this subtree is scheduled, all other subtrees
385
407
# have their merge depth increased by one from this nodes merge depth.
386
408
# it contains tuples - name, merge_depth
387
409
self._left_subtree_pushed_stack = []
389
411
# seed the search with the tip of the branch
390
if branch_tip is not None:
412
if (branch_tip is not None and
413
branch_tip != _mod_revision.NULL_REVISION and
414
branch_tip != (_mod_revision.NULL_REVISION,)):
391
415
parents = self._graph.pop(branch_tip)
392
416
self._push_node(branch_tip, 0, parents)
394
418
def sorted(self):
395
419
"""Sort the graph and return as a list.
397
421
After calling this the sorter is empty and you must create a new one.
399
423
return list(self.iter_topo_order())
401
425
def iter_topo_order(self):
402
426
"""Yield the nodes of the graph in a topological order.
404
428
After finishing iteration the sorter is empty and you cannot continue
407
while self._node_name_stack:
431
# These are safe to offload to local variables, because they are used
432
# as a stack and modified in place, never assigned to.
433
node_name_stack = self._node_name_stack
434
node_merge_depth_stack = self._node_merge_depth_stack
435
pending_parents_stack = self._pending_parents_stack
436
left_subtree_pushed_stack = self._left_subtree_pushed_stack
437
completed_node_names = self._completed_node_names
438
scheduled_nodes = self._scheduled_nodes
440
graph_pop = self._graph.pop
442
def push_node(node_name, merge_depth, parents,
443
node_name_stack_append=node_name_stack.append,
444
node_merge_depth_stack_append=node_merge_depth_stack.append,
445
left_subtree_pushed_stack_append=left_subtree_pushed_stack.append,
446
pending_parents_stack_append=pending_parents_stack.append,
447
first_child_stack_append=self._first_child_stack.append,
450
"""Add node_name to the pending node stack.
452
Names in this stack will get emitted into the output as they are popped
455
This inlines a lot of self._variable.append functions as local
458
node_name_stack_append(node_name)
459
node_merge_depth_stack_append(merge_depth)
460
left_subtree_pushed_stack_append(False)
461
pending_parents_stack_append(list(parents))
462
# as we push it, check if it is the first child
465
# node has parents, assign from the left most parent.
467
parent_info = revnos[parents[0]]
469
# Left-hand parent is a ghost, consider it not to exist
471
if parent_info is not None:
472
first_child = parent_info[1]
473
parent_info[1] = False
475
# We don't use the same algorithm here, but we need to keep the
478
first_child_stack_append(first_child)
480
def pop_node(node_name_stack_pop=node_name_stack.pop,
481
node_merge_depth_stack_pop=node_merge_depth_stack.pop,
482
first_child_stack_pop=self._first_child_stack.pop,
483
left_subtree_pushed_stack_pop=left_subtree_pushed_stack.pop,
484
pending_parents_stack_pop=pending_parents_stack.pop,
485
original_graph=self._original_graph,
487
completed_node_names_add=self._completed_node_names.add,
488
scheduled_nodes_append=scheduled_nodes.append,
489
revno_to_branch_count=self._revno_to_branch_count,
491
"""Pop the top node off the stack
493
The node is appended to the sorted output.
495
# we are returning from the flattened call frame:
496
# pop off the local variables
497
node_name = node_name_stack_pop()
498
merge_depth = node_merge_depth_stack_pop()
499
first_child = first_child_stack_pop()
500
# remove this node from the pending lists:
501
left_subtree_pushed_stack_pop()
502
pending_parents_stack_pop()
504
parents = original_graph[node_name]
507
# node has parents, assign from the left most parent.
509
parent_revno = revnos[parents[0]][0]
511
# left-hand parent is a ghost, treat it as not existing
513
if parent_revno is not None:
515
# not the first child, make a new branch
516
base_revno = parent_revno[0]
517
branch_count = revno_to_branch_count.get(base_revno, 0)
519
revno_to_branch_count[base_revno] = branch_count
520
revno = (parent_revno[0], branch_count, 1)
521
# revno = (parent_revno[0], branch_count, parent_revno[-1]+1)
523
# as the first child, we just increase the final revision
525
revno = parent_revno[:-1] + (parent_revno[-1] + 1,)
527
# no parents, use the root sequence
528
root_count = revno_to_branch_count.get(0, -1)
531
revno = (0, root_count, 1)
534
revno_to_branch_count[0] = root_count
536
# store the revno for this node for future reference
537
revnos[node_name][0] = revno
538
completed_node_names_add(node_name)
539
scheduled_nodes_append((node_name, merge_depth, revno))
543
while node_name_stack:
408
544
# loop until this call completes.
409
parents_to_visit = self._pending_parents_stack[-1]
545
parents_to_visit = pending_parents_stack[-1]
410
546
# if all parents are done, the revision is done
411
547
if not parents_to_visit:
412
548
# append the revision to the topo sorted scheduled list:
413
549
# all the nodes parents have been scheduled added, now
414
550
# we can add it to the output.
417
while self._pending_parents_stack[-1]:
418
if not self._left_subtree_pushed_stack[-1]:
553
while pending_parents_stack[-1]:
554
if not left_subtree_pushed_stack[-1]:
419
555
# recurse depth first into the primary parent
420
next_node_name = self._pending_parents_stack[-1].pop(0)
556
next_node_name = pending_parents_stack[-1].pop(0)
557
is_left_subtree = True
558
left_subtree_pushed_stack[-1] = True
422
560
# place any merges in right-to-left order for scheduling
423
561
# which gives us left-to-right order after we reverse
424
# the scheduled queue. XXX: This has the effect of
562
# the scheduled queue. XXX: This has the effect of
425
563
# allocating common-new revisions to the right-most
426
# subtree rather than the left most, which will
564
# subtree rather than the left most, which will
427
565
# display nicely (you get smaller trees at the top
428
566
# of the combined merge).
429
next_node_name = self._pending_parents_stack[-1].pop()
430
if next_node_name in self._completed_node_names:
567
next_node_name = pending_parents_stack[-1].pop()
568
is_left_subtree = False
569
if next_node_name in completed_node_names:
431
570
# this parent was completed by a child on the
432
571
# call stack. skip it.
434
573
# otherwise transfer it from the source graph into the
435
574
# top of the current depth first search stack.
437
parents = self._graph.pop(next_node_name)
576
parents = graph_pop(next_node_name)
439
578
# if the next node is not in the source graph it has
440
579
# already been popped from it and placed into the
441
580
# current search stack (but not completed or we would
442
581
# have hit the continue 4 lines up.
443
582
# this indicates a cycle.
444
raise errors.GraphCycleError(self._node_name_stack)
583
if next_node_name in self._original_graph:
584
raise errors.GraphCycleError(node_name_stack)
586
# This is just a ghost parent, ignore it
445
588
next_merge_depth = 0
446
if self._left_subtree_pushed_stack[-1]:
447
590
# a new child branch from name_stack[-1]
448
593
next_merge_depth = 1
451
self._left_subtree_pushed_stack[-1] = True
452
594
next_merge_depth = (
453
self._node_merge_depth_stack[-1] + next_merge_depth)
595
node_merge_depth_stack[-1] + next_merge_depth)
456
598
next_merge_depth,
458
# and do not continue processing parents until this 'call'
600
# and do not continue processing parents until this 'call'
461
604
# We have scheduled the graph. Now deliver the ordered output:
462
605
sequence_number = 0
463
while self._scheduled_nodes:
464
node_name, merge_depth, revno = self._scheduled_nodes.pop()
465
if node_name == self._stop_revision:
606
stop_revision = self._stop_revision
607
generate_revno = self._generate_revno
608
original_graph = self._original_graph
610
while scheduled_nodes:
611
node_name, merge_depth, revno = scheduled_nodes.pop()
612
if node_name == stop_revision:
467
if not len(self._scheduled_nodes):
614
if not len(scheduled_nodes):
468
615
# last revision is the end of a merge
469
616
end_of_merge = True
470
elif self._scheduled_nodes[-1][1] < merge_depth:
617
elif scheduled_nodes[-1][1] < merge_depth:
471
618
# the next node is to our left
472
619
end_of_merge = True
473
elif (self._scheduled_nodes[-1][1] == merge_depth and
474
(self._scheduled_nodes[-1][0] not in
475
self._original_graph[node_name])):
620
elif (scheduled_nodes[-1][1] == merge_depth and
621
(scheduled_nodes[-1][0] not in
622
original_graph[node_name])):
476
623
# the next node was part of a multiple-merge.
477
624
end_of_merge = True
479
626
end_of_merge = False
480
if self._generate_revno:
481
628
yield (sequence_number, node_name, merge_depth, revno, end_of_merge)
483
630
yield (sequence_number, node_name, merge_depth, end_of_merge)
515
667
# pop off the local variables
516
668
node_name = self._node_name_stack.pop()
517
669
merge_depth = self._node_merge_depth_stack.pop()
518
sequence = self._assigned_sequence_stack.pop()
670
first_child = self._first_child_stack.pop()
519
671
# remove this node from the pending lists:
520
672
self._left_subtree_pushed_stack.pop()
521
673
self._pending_parents_stack.pop()
523
675
parents = self._original_graph[node_name]
525
678
# node has parents, assign from the left most parent.
526
parent_revno = self._revnos[parents[0]]
680
parent_revno = self._revnos[parents[0]][0]
682
# left-hand parent is a ghost, treat it as not existing
684
if parent_revno is not None:
528
686
# not the first child, make a new branch
529
revno = parent_revno[0] + (sequence, 1)
687
base_revno = parent_revno[0]
688
branch_count = self._revno_to_branch_count.get(base_revno, 0)
690
self._revno_to_branch_count[base_revno] = branch_count
691
revno = (parent_revno[0], branch_count, 1)
692
# revno = (parent_revno[0], branch_count, parent_revno[-1]+1)
531
# increment the sequence number within the branch
532
revno = parent_revno[0][:-1] + (parent_revno[0][-1] + 1,)
694
# as the first child, we just increase the final revision
696
revno = parent_revno[:-1] + (parent_revno[-1] + 1,)
534
698
# no parents, use the root sequence
536
# make a parallel import revision number
537
revno = (0, sequence, 1)
699
root_count = self._revno_to_branch_count.get(0, 0)
700
root_count = self._revno_to_branch_count.get(0, -1)
703
revno = (0, root_count, 1)
706
self._revno_to_branch_count[0] = root_count
541
708
# store the revno for this node for future reference
542
709
self._revnos[node_name][0] = revno