95
96
def iter_topo_order(self):
96
97
"""Yield the nodes of the graph in a topological order.
98
99
After finishing iteration the sorter is empty and you cannot continue
103
visitable = set(graph)
105
# this is a stack storing the depth first search into the graph.
106
pending_node_stack = []
107
# at each level of 'recursion' we have to check each parent. This
108
# stack stores the parents we have not yet checked for the node at the
109
# matching depth in pending_node_stack
110
pending_parents_stack = []
112
# this is a set of the completed nodes for fast checking whether a
113
# parent in a node we are processing on the stack has already been
114
# emitted and thus can be skipped.
115
completed_node_names = set()
102
118
# 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
119
# top of the depth first search stack of pending nodes.
120
node_name, parents = graph.popitem()
121
pending_node_stack.append(node_name)
122
pending_parents_stack.append(list(parents))
124
# loop until pending_node_stack is empty
125
while pending_node_stack:
126
parents_to_visit = pending_parents_stack[-1]
127
# if there are no parents left, the revision is done
110
128
if not parents_to_visit:
111
129
# 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()
130
# all the nodes parents have been added to the output,
131
# now we can add it to the output.
132
popped_node = pending_node_stack.pop()
133
pending_parents_stack.pop()
134
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)
162
def merge_sort(graph, branch_tip, mainline_revisions=None):
137
# recurse depth first into a single parent
138
next_node_name = parents_to_visit.pop()
140
if next_node_name in completed_node_names:
141
# parent was already completed by a child, skip it.
143
if next_node_name not in visitable:
144
# parent is not a node in the original graph, skip it.
147
# transfer it along with its parents from the source graph
148
# into the top of the current depth first search stack.
150
parents = graph.pop(next_node_name)
152
# if the next node is not in the source graph it has
153
# already been popped from it and placed into the
154
# current search stack (but not completed or we would
155
# have hit the continue 6 lines up). this indicates a
157
raise errors.GraphCycleError(pending_node_stack)
158
pending_node_stack.append(next_node_name)
159
pending_parents_stack.append(list(parents))
162
def merge_sort(graph, branch_tip, mainline_revisions=None, generate_revno=False):
163
163
"""Topological sort a graph which groups merges.
165
165
:param graph: sequence of pairs of node->parents_list.
166
:param branch_tip: the tip of the branch to graph. Revisions not
166
:param branch_tip: the tip of the branch to graph. Revisions not
167
167
reachable from branch_tip are not included in the
169
169
:param mainline_revisions: If not None this forces a mainline to be
339
# the scheduling order is: F, E, D, C, B, A
402
# the scheduling order is: F, E, D, C, B, A
340
403
# that is - 'left subtree, right subtree, node'
341
404
# which would mean that when we schedule A we can emit the entire tree.
342
405
self._scheduled_nodes = []
343
# This records for each node when we have processed its left most
406
# This records for each node when we have processed its left most
344
407
# unmerged subtree. After this subtree is scheduled, all other subtrees
345
408
# have their merge depth increased by one from this nodes merge depth.
346
self._left_subtree_done_stack = []
409
# it contains tuples - name, merge_depth
410
self._left_subtree_pushed_stack = []
348
412
# seed the search with the tip of the branch
349
if branch_tip is not None:
413
if (branch_tip is not None and
414
branch_tip != _mod_revision.NULL_REVISION and
415
branch_tip != (_mod_revision.NULL_REVISION,)):
350
416
parents = self._graph.pop(branch_tip)
351
417
self._push_node(branch_tip, 0, parents)
353
419
def sorted(self):
354
420
"""Sort the graph and return as a list.
356
422
After calling this the sorter is empty and you must create a new one.
358
424
return list(self.iter_topo_order())
360
426
def iter_topo_order(self):
361
427
"""Yield the nodes of the graph in a topological order.
363
429
After finishing iteration the sorter is empty and you cannot continue
366
while self._node_name_stack:
432
# These are safe to offload to local variables, because they are used
433
# as a stack and modified in place, never assigned to.
434
node_name_stack = self._node_name_stack
435
node_merge_depth_stack = self._node_merge_depth_stack
436
pending_parents_stack = self._pending_parents_stack
437
left_subtree_pushed_stack = self._left_subtree_pushed_stack
438
completed_node_names = self._completed_node_names
439
scheduled_nodes = self._scheduled_nodes
441
graph_pop = self._graph.pop
443
def push_node(node_name, merge_depth, parents,
444
node_name_stack_append=node_name_stack.append,
445
node_merge_depth_stack_append=node_merge_depth_stack.append,
446
left_subtree_pushed_stack_append=left_subtree_pushed_stack.append,
447
pending_parents_stack_append=pending_parents_stack.append,
448
first_child_stack_append=self._first_child_stack.append,
451
"""Add node_name to the pending node stack.
453
Names in this stack will get emitted into the output as they are popped
456
This inlines a lot of self._variable.append functions as local
459
node_name_stack_append(node_name)
460
node_merge_depth_stack_append(merge_depth)
461
left_subtree_pushed_stack_append(False)
462
pending_parents_stack_append(list(parents))
463
# as we push it, check if it is the first child
466
# node has parents, assign from the left most parent.
468
parent_info = revnos[parents[0]]
470
# Left-hand parent is a ghost, consider it not to exist
472
if parent_info is not None:
473
first_child = parent_info[1]
474
parent_info[1] = False
476
# We don't use the same algorithm here, but we need to keep the
479
first_child_stack_append(first_child)
481
def pop_node(node_name_stack_pop=node_name_stack.pop,
482
node_merge_depth_stack_pop=node_merge_depth_stack.pop,
483
first_child_stack_pop=self._first_child_stack.pop,
484
left_subtree_pushed_stack_pop=left_subtree_pushed_stack.pop,
485
pending_parents_stack_pop=pending_parents_stack.pop,
486
original_graph=self._original_graph,
488
completed_node_names_add=self._completed_node_names.add,
489
scheduled_nodes_append=scheduled_nodes.append,
490
revno_to_branch_count=self._revno_to_branch_count,
492
"""Pop the top node off the stack
494
The node is appended to the sorted output.
496
# we are returning from the flattened call frame:
497
# pop off the local variables
498
node_name = node_name_stack_pop()
499
merge_depth = node_merge_depth_stack_pop()
500
first_child = first_child_stack_pop()
501
# remove this node from the pending lists:
502
left_subtree_pushed_stack_pop()
503
pending_parents_stack_pop()
505
parents = original_graph[node_name]
508
# node has parents, assign from the left most parent.
510
parent_revno = revnos[parents[0]][0]
512
# left-hand parent is a ghost, treat it as not existing
514
if parent_revno is not None:
516
# not the first child, make a new branch
517
base_revno = parent_revno[0]
518
branch_count = revno_to_branch_count.get(base_revno, 0)
520
revno_to_branch_count[base_revno] = branch_count
521
revno = (parent_revno[0], branch_count, 1)
522
# revno = (parent_revno[0], branch_count, parent_revno[-1]+1)
524
# as the first child, we just increase the final revision
526
revno = parent_revno[:-1] + (parent_revno[-1] + 1,)
528
# no parents, use the root sequence
529
root_count = revno_to_branch_count.get(0, -1)
532
revno = (0, root_count, 1)
535
revno_to_branch_count[0] = root_count
537
# store the revno for this node for future reference
538
revnos[node_name][0] = revno
539
completed_node_names_add(node_name)
540
scheduled_nodes_append((node_name, merge_depth, revno))
544
while node_name_stack:
367
545
# loop until this call completes.
368
parents_to_visit = self._pending_parents_stack[-1]
546
parents_to_visit = pending_parents_stack[-1]
369
547
# if all parents are done, the revision is done
370
548
if not parents_to_visit:
371
549
# append the revision to the topo sorted scheduled list:
372
550
# all the nodes parents have been scheduled added, now
373
551
# we can add it to the output.
376
while self._pending_parents_stack[-1]:
377
if not self._left_subtree_done_stack[-1]:
554
while pending_parents_stack[-1]:
555
if not left_subtree_pushed_stack[-1]:
378
556
# recurse depth first into the primary parent
379
next_node_name = self._pending_parents_stack[-1].pop(0)
557
next_node_name = pending_parents_stack[-1].pop(0)
558
is_left_subtree = True
559
left_subtree_pushed_stack[-1] = True
381
561
# place any merges in right-to-left order for scheduling
382
562
# which gives us left-to-right order after we reverse
383
# the scheduled queue. XXX: This has the effect of
563
# the scheduled queue. XXX: This has the effect of
384
564
# allocating common-new revisions to the right-most
385
# subtree rather than the left most, which will
565
# subtree rather than the left most, which will
386
566
# display nicely (you get smaller trees at the top
387
567
# of the combined merge).
388
next_node_name = self._pending_parents_stack[-1].pop()
389
if next_node_name in self._completed_node_names:
568
next_node_name = pending_parents_stack[-1].pop()
569
is_left_subtree = False
570
if next_node_name in completed_node_names:
390
571
# this parent was completed by a child on the
391
572
# call stack. skip it.
393
574
# otherwise transfer it from the source graph into the
394
575
# top of the current depth first search stack.
396
parents = self._graph.pop(next_node_name)
577
parents = graph_pop(next_node_name)
398
579
# if the next node is not in the source graph it has
399
580
# already been popped from it and placed into the
400
581
# current search stack (but not completed or we would
401
582
# have hit the continue 4 lines up.
402
583
# this indicates a cycle.
403
raise errors.GraphCycleError(self._node_name_stack)
584
if next_node_name in self._original_graph:
585
raise errors.GraphCycleError(node_name_stack)
587
# This is just a ghost parent, ignore it
404
589
next_merge_depth = 0
405
if self._left_subtree_done_stack[-1]:
591
# a new child branch from name_stack[-1]
406
594
next_merge_depth = 1
409
self._left_subtree_done_stack[-1] = True
410
595
next_merge_depth = (
411
self._node_merge_depth_stack[-1] + next_merge_depth)
596
node_merge_depth_stack[-1] + next_merge_depth)
414
599
next_merge_depth,
416
# and do not continue processing parents until this 'call'
601
# and do not continue processing parents until this 'call'
419
605
# We have scheduled the graph. Now deliver the ordered output:
420
606
sequence_number = 0
421
while self._scheduled_nodes:
422
node_name, merge_depth = self._scheduled_nodes.pop()
423
if node_name == self._stop_revision:
607
stop_revision = self._stop_revision
608
generate_revno = self._generate_revno
609
original_graph = self._original_graph
611
while scheduled_nodes:
612
node_name, merge_depth, revno = scheduled_nodes.pop()
613
if node_name == stop_revision:
425
if not len(self._scheduled_nodes):
615
if not len(scheduled_nodes):
616
# last revision is the end of a merge
426
617
end_of_merge = True
427
elif self._scheduled_nodes[-1][1] < merge_depth:
618
elif scheduled_nodes[-1][1] < merge_depth:
428
619
# the next node is to our left
429
620
end_of_merge = True
430
elif (self._scheduled_nodes[-1][1] == merge_depth and
431
(self._scheduled_nodes[-1][0] not in
432
self._original_graph[node_name])):
621
elif (scheduled_nodes[-1][1] == merge_depth and
622
(scheduled_nodes[-1][0] not in
623
original_graph[node_name])):
433
624
# the next node was part of a multiple-merge.
434
625
end_of_merge = True
436
627
end_of_merge = False
437
yield (sequence_number, node_name, merge_depth, end_of_merge)
629
yield (sequence_number, node_name, merge_depth, revno, end_of_merge)
631
yield (sequence_number, node_name, merge_depth, end_of_merge)
438
632
sequence_number += 1
440
634
def _push_node(self, node_name, merge_depth, parents):
441
635
"""Add node_name to the pending node stack.
443
637
Names in this stack will get emitted into the output as they are popped
446
640
self._node_name_stack.append(node_name)
447
641
self._node_merge_depth_stack.append(merge_depth)
448
self._left_subtree_done_stack.append(False)
642
self._left_subtree_pushed_stack.append(False)
449
643
self._pending_parents_stack.append(list(parents))
644
# as we push it, figure out if this is the first child
647
# node has parents, assign from the left most parent.
649
parent_info = self._revnos[parents[0]]
651
# Left-hand parent is a ghost, consider it not to exist
653
if parent_info is not None:
654
first_child = parent_info[1]
655
parent_info[1] = False
657
# We don't use the same algorithm here, but we need to keep the
660
self._first_child_stack.append(first_child)
451
662
def _pop_node(self):
452
"""Pop the top node off the stack
663
"""Pop the top node off the stack
454
665
The node is appended to the sorted output.