~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/graph.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-05-29 15:57:16 UTC
  • mfrom: (3427.5.9 dep_warnings)
  • Revision ID: pqm@pqm.ubuntu.com-20080529155716-0w3kic8lioa63231
(jam) Enable Deprecation Warnings when running -Werror and when
        running selftest

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import time
 
18
 
 
19
from bzrlib import (
 
20
    debug,
 
21
    errors,
 
22
    revision,
 
23
    symbol_versioning,
 
24
    trace,
 
25
    tsort,
 
26
    )
 
27
from bzrlib.deprecated_graph import (node_distances, select_farthest)
 
28
 
 
29
STEP_UNIQUE_SEARCHER_EVERY = 5
 
30
 
 
31
# DIAGRAM of terminology
 
32
#       A
 
33
#       /\
 
34
#      B  C
 
35
#      |  |\
 
36
#      D  E F
 
37
#      |\/| |
 
38
#      |/\|/
 
39
#      G  H
 
40
#
 
41
# In this diagram, relative to G and H:
 
42
# A, B, C, D, E are common ancestors.
 
43
# C, D and E are border ancestors, because each has a non-common descendant.
 
44
# D and E are least common ancestors because none of their descendants are
 
45
# common ancestors.
 
46
# C is not a least common ancestor because its descendant, E, is a common
 
47
# ancestor.
 
48
#
 
49
# The find_unique_lca algorithm will pick A in two steps:
 
50
# 1. find_lca('G', 'H') => ['D', 'E']
 
51
# 2. Since len(['D', 'E']) > 1, find_lca('D', 'E') => ['A']
 
52
 
 
53
 
 
54
class DictParentsProvider(object):
 
55
    """A parents provider for Graph objects."""
 
56
 
 
57
    def __init__(self, ancestry):
 
58
        self.ancestry = ancestry
 
59
 
 
60
    def __repr__(self):
 
61
        return 'DictParentsProvider(%r)' % self.ancestry
 
62
 
 
63
    def get_parent_map(self, keys):
 
64
        """See _StackedParentsProvider.get_parent_map"""
 
65
        ancestry = self.ancestry
 
66
        return dict((k, ancestry[k]) for k in keys if k in ancestry)
 
67
 
 
68
 
 
69
class _StackedParentsProvider(object):
 
70
 
 
71
    def __init__(self, parent_providers):
 
72
        self._parent_providers = parent_providers
 
73
 
 
74
    def __repr__(self):
 
75
        return "_StackedParentsProvider(%r)" % self._parent_providers
 
76
 
 
77
    def get_parent_map(self, keys):
 
78
        """Get a mapping of keys => parents
 
79
 
 
80
        A dictionary is returned with an entry for each key present in this
 
81
        source. If this source doesn't have information about a key, it should
 
82
        not include an entry.
 
83
 
 
84
        [NULL_REVISION] is used as the parent of the first user-committed
 
85
        revision.  Its parent list is empty.
 
86
 
 
87
        :param keys: An iterable returning keys to check (eg revision_ids)
 
88
        :return: A dictionary mapping each key to its parents
 
89
        """
 
90
        found = {}
 
91
        remaining = set(keys)
 
92
        for parents_provider in self._parent_providers:
 
93
            new_found = parents_provider.get_parent_map(remaining)
 
94
            found.update(new_found)
 
95
            remaining.difference_update(new_found)
 
96
            if not remaining:
 
97
                break
 
98
        return found
 
99
 
 
100
 
 
101
class CachingParentsProvider(object):
 
102
    """A parents provider which will cache the revision => parents in a dict.
 
103
 
 
104
    This is useful for providers that have an expensive lookup.
 
105
    """
 
106
 
 
107
    def __init__(self, parent_provider):
 
108
        self._real_provider = parent_provider
 
109
        # Theoretically we could use an LRUCache here
 
110
        self._cache = {}
 
111
 
 
112
    def __repr__(self):
 
113
        return "%s(%r)" % (self.__class__.__name__, self._real_provider)
 
114
 
 
115
    def get_parent_map(self, keys):
 
116
        """See _StackedParentsProvider.get_parent_map"""
 
117
        needed = set()
 
118
        # If the _real_provider doesn't have a key, we cache a value of None,
 
119
        # which we then later use to realize we cannot provide a value for that
 
120
        # key.
 
121
        parent_map = {}
 
122
        cache = self._cache
 
123
        for key in keys:
 
124
            if key in cache:
 
125
                value = cache[key]
 
126
                if value is not None:
 
127
                    parent_map[key] = value
 
128
            else:
 
129
                needed.add(key)
 
130
 
 
131
        if needed:
 
132
            new_parents = self._real_provider.get_parent_map(needed)
 
133
            cache.update(new_parents)
 
134
            parent_map.update(new_parents)
 
135
            needed.difference_update(new_parents)
 
136
            cache.update(dict.fromkeys(needed, None))
 
137
        return parent_map
 
138
 
 
139
 
 
140
class Graph(object):
 
141
    """Provide incremental access to revision graphs.
 
142
 
 
143
    This is the generic implementation; it is intended to be subclassed to
 
144
    specialize it for other repository types.
 
145
    """
 
146
 
 
147
    def __init__(self, parents_provider):
 
148
        """Construct a Graph that uses several graphs as its input
 
149
 
 
150
        This should not normally be invoked directly, because there may be
 
151
        specialized implementations for particular repository types.  See
 
152
        Repository.get_graph().
 
153
 
 
154
        :param parents_provider: An object providing a get_parent_map call
 
155
            conforming to the behavior of
 
156
            StackedParentsProvider.get_parent_map.
 
157
        """
 
158
        if getattr(parents_provider, 'get_parents', None) is not None:
 
159
            self.get_parents = parents_provider.get_parents
 
160
        if getattr(parents_provider, 'get_parent_map', None) is not None:
 
161
            self.get_parent_map = parents_provider.get_parent_map
 
162
        self._parents_provider = parents_provider
 
163
 
 
164
    def __repr__(self):
 
165
        return 'Graph(%r)' % self._parents_provider
 
166
 
 
167
    def find_lca(self, *revisions):
 
168
        """Determine the lowest common ancestors of the provided revisions
 
169
 
 
170
        A lowest common ancestor is a common ancestor none of whose
 
171
        descendants are common ancestors.  In graphs, unlike trees, there may
 
172
        be multiple lowest common ancestors.
 
173
 
 
174
        This algorithm has two phases.  Phase 1 identifies border ancestors,
 
175
        and phase 2 filters border ancestors to determine lowest common
 
176
        ancestors.
 
177
 
 
178
        In phase 1, border ancestors are identified, using a breadth-first
 
179
        search starting at the bottom of the graph.  Searches are stopped
 
180
        whenever a node or one of its descendants is determined to be common
 
181
 
 
182
        In phase 2, the border ancestors are filtered to find the least
 
183
        common ancestors.  This is done by searching the ancestries of each
 
184
        border ancestor.
 
185
 
 
186
        Phase 2 is perfomed on the principle that a border ancestor that is
 
187
        not an ancestor of any other border ancestor is a least common
 
188
        ancestor.
 
189
 
 
190
        Searches are stopped when they find a node that is determined to be a
 
191
        common ancestor of all border ancestors, because this shows that it
 
192
        cannot be a descendant of any border ancestor.
 
193
 
 
194
        The scaling of this operation should be proportional to
 
195
        1. The number of uncommon ancestors
 
196
        2. The number of border ancestors
 
197
        3. The length of the shortest path between a border ancestor and an
 
198
           ancestor of all border ancestors.
 
199
        """
 
200
        border_common, common, sides = self._find_border_ancestors(revisions)
 
201
        # We may have common ancestors that can be reached from each other.
 
202
        # - ask for the heads of them to filter it down to only ones that
 
203
        # cannot be reached from each other - phase 2.
 
204
        return self.heads(border_common)
 
205
 
 
206
    def find_difference(self, left_revision, right_revision):
 
207
        """Determine the graph difference between two revisions"""
 
208
        border, common, searchers = self._find_border_ancestors(
 
209
            [left_revision, right_revision])
 
210
        self._search_for_extra_common(common, searchers)
 
211
        left = searchers[0].seen
 
212
        right = searchers[1].seen
 
213
        return (left.difference(right), right.difference(left))
 
214
 
 
215
    def find_unique_ancestors(self, unique_revision, common_revisions):
 
216
        """Find the unique ancestors for a revision versus others.
 
217
 
 
218
        This returns the ancestry of unique_revision, excluding all revisions
 
219
        in the ancestry of common_revisions. If unique_revision is in the
 
220
        ancestry, then the empty set will be returned.
 
221
 
 
222
        :param unique_revision: The revision_id whose ancestry we are
 
223
            interested in.
 
224
            XXX: Would this API be better if we allowed multiple revisions on
 
225
                 to be searched here?
 
226
        :param common_revisions: Revision_ids of ancestries to exclude.
 
227
        :return: A set of revisions in the ancestry of unique_revision
 
228
        """
 
229
        if unique_revision in common_revisions:
 
230
            return set()
 
231
 
 
232
        # Algorithm description
 
233
        # 1) Walk backwards from the unique node and all common nodes.
 
234
        # 2) When a node is seen by both sides, stop searching it in the unique
 
235
        #    walker, include it in the common walker.
 
236
        # 3) Stop searching when there are no nodes left for the unique walker.
 
237
        #    At this point, you have a maximal set of unique nodes. Some of
 
238
        #    them may actually be common, and you haven't reached them yet.
 
239
        # 4) Start new searchers for the unique nodes, seeded with the
 
240
        #    information you have so far.
 
241
        # 5) Continue searching, stopping the common searches when the search
 
242
        #    tip is an ancestor of all unique nodes.
 
243
        # 6) Aggregate together unique searchers when they are searching the
 
244
        #    same tips. When all unique searchers are searching the same node,
 
245
        #    stop move it to a single 'all_unique_searcher'.
 
246
        # 7) The 'all_unique_searcher' represents the very 'tip' of searching.
 
247
        #    Most of the time this produces very little important information.
 
248
        #    So don't step it as quickly as the other searchers.
 
249
        # 8) Search is done when all common searchers have completed.
 
250
 
 
251
        unique_searcher, common_searcher = self._find_initial_unique_nodes(
 
252
            [unique_revision], common_revisions)
 
253
 
 
254
        unique_nodes = unique_searcher.seen.difference(common_searcher.seen)
 
255
        if not unique_nodes:
 
256
            return unique_nodes
 
257
 
 
258
        (all_unique_searcher,
 
259
         unique_tip_searchers) = self._make_unique_searchers(unique_nodes,
 
260
                                    unique_searcher, common_searcher)
 
261
 
 
262
        self._refine_unique_nodes(unique_searcher, all_unique_searcher,
 
263
                                  unique_tip_searchers, common_searcher)
 
264
        true_unique_nodes = unique_nodes.difference(common_searcher.seen)
 
265
        if 'graph' in debug.debug_flags:
 
266
            trace.mutter('Found %d truly unique nodes out of %d',
 
267
                         len(true_unique_nodes), len(unique_nodes))
 
268
        return true_unique_nodes
 
269
 
 
270
    def _find_initial_unique_nodes(self, unique_revisions, common_revisions):
 
271
        """Steps 1-3 of find_unique_ancestors.
 
272
 
 
273
        Find the maximal set of unique nodes. Some of these might actually
 
274
        still be common, but we are sure that there are no other unique nodes.
 
275
 
 
276
        :return: (unique_searcher, common_searcher)
 
277
        """
 
278
 
 
279
        unique_searcher = self._make_breadth_first_searcher(unique_revisions)
 
280
        # we know that unique_revisions aren't in common_revisions, so skip
 
281
        # past them.
 
282
        unique_searcher.next()
 
283
        common_searcher = self._make_breadth_first_searcher(common_revisions)
 
284
 
 
285
        # As long as we are still finding unique nodes, keep searching
 
286
        while unique_searcher._next_query:
 
287
            next_unique_nodes = set(unique_searcher.step())
 
288
            next_common_nodes = set(common_searcher.step())
 
289
 
 
290
            # Check if either searcher encounters new nodes seen by the other
 
291
            # side.
 
292
            unique_are_common_nodes = next_unique_nodes.intersection(
 
293
                common_searcher.seen)
 
294
            unique_are_common_nodes.update(
 
295
                next_common_nodes.intersection(unique_searcher.seen))
 
296
            if unique_are_common_nodes:
 
297
                ancestors = unique_searcher.find_seen_ancestors(
 
298
                                unique_are_common_nodes)
 
299
                # TODO: This is a bit overboard, we only really care about
 
300
                #       the ancestors of the tips because the rest we
 
301
                #       already know. This is *correct* but causes us to
 
302
                #       search too much ancestry.
 
303
                ancestors.update(common_searcher.find_seen_ancestors(ancestors))
 
304
                unique_searcher.stop_searching_any(ancestors)
 
305
                common_searcher.start_searching(ancestors)
 
306
 
 
307
        return unique_searcher, common_searcher
 
308
 
 
309
    def _make_unique_searchers(self, unique_nodes, unique_searcher,
 
310
                               common_searcher):
 
311
        """Create a searcher for all the unique search tips (step 4).
 
312
 
 
313
        As a side effect, the common_searcher will stop searching any nodes
 
314
        that are ancestors of the unique searcher tips.
 
315
 
 
316
        :return: (all_unique_searcher, unique_tip_searchers)
 
317
        """
 
318
        unique_tips = self._remove_simple_descendants(unique_nodes,
 
319
                        self.get_parent_map(unique_nodes))
 
320
 
 
321
        if len(unique_tips) == 1:
 
322
            unique_tip_searchers = []
 
323
            ancestor_all_unique = unique_searcher.find_seen_ancestors(unique_tips)
 
324
        else:
 
325
            unique_tip_searchers = []
 
326
            for tip in unique_tips:
 
327
                revs_to_search = unique_searcher.find_seen_ancestors([tip])
 
328
                revs_to_search.update(
 
329
                    common_searcher.find_seen_ancestors(revs_to_search))
 
330
                searcher = self._make_breadth_first_searcher(revs_to_search)
 
331
                # We don't care about the starting nodes.
 
332
                searcher._label = tip
 
333
                searcher.step()
 
334
                unique_tip_searchers.append(searcher)
 
335
 
 
336
            ancestor_all_unique = None
 
337
            for searcher in unique_tip_searchers:
 
338
                if ancestor_all_unique is None:
 
339
                    ancestor_all_unique = set(searcher.seen)
 
340
                else:
 
341
                    ancestor_all_unique = ancestor_all_unique.intersection(
 
342
                                                searcher.seen)
 
343
        # Collapse all the common nodes into a single searcher
 
344
        all_unique_searcher = self._make_breadth_first_searcher(
 
345
                                ancestor_all_unique)
 
346
        if ancestor_all_unique:
 
347
            # We've seen these nodes in all the searchers, so we'll just go to
 
348
            # the next
 
349
            all_unique_searcher.step()
 
350
 
 
351
            # Stop any search tips that are already known as ancestors of the
 
352
            # unique nodes
 
353
            stopped_common = common_searcher.stop_searching_any(
 
354
                common_searcher.find_seen_ancestors(ancestor_all_unique))
 
355
 
 
356
            total_stopped = 0
 
357
            for searcher in unique_tip_searchers:
 
358
                total_stopped += len(searcher.stop_searching_any(
 
359
                    searcher.find_seen_ancestors(ancestor_all_unique)))
 
360
        if 'graph' in debug.debug_flags:
 
361
            trace.mutter('For %d unique nodes, created %d + 1 unique searchers'
 
362
                         ' (%d stopped search tips, %d common ancestors'
 
363
                         ' (%d stopped common)',
 
364
                         len(unique_nodes), len(unique_tip_searchers),
 
365
                         total_stopped, len(ancestor_all_unique),
 
366
                         len(stopped_common))
 
367
        return all_unique_searcher, unique_tip_searchers
 
368
 
 
369
    def _step_unique_and_common_searchers(self, common_searcher,
 
370
                                          unique_tip_searchers,
 
371
                                          unique_searcher):
 
372
        """Step all the searchers"""
 
373
        newly_seen_common = set(common_searcher.step())
 
374
        newly_seen_unique = set()
 
375
        for searcher in unique_tip_searchers:
 
376
            next = set(searcher.step())
 
377
            next.update(unique_searcher.find_seen_ancestors(next))
 
378
            next.update(common_searcher.find_seen_ancestors(next))
 
379
            for alt_searcher in unique_tip_searchers:
 
380
                if alt_searcher is searcher:
 
381
                    continue
 
382
                next.update(alt_searcher.find_seen_ancestors(next))
 
383
            searcher.start_searching(next)
 
384
            newly_seen_unique.update(next)
 
385
        return newly_seen_common, newly_seen_unique
 
386
 
 
387
    def _find_nodes_common_to_all_unique(self, unique_tip_searchers,
 
388
                                         all_unique_searcher,
 
389
                                         newly_seen_unique, step_all_unique):
 
390
        """Find nodes that are common to all unique_tip_searchers.
 
391
 
 
392
        If it is time, step the all_unique_searcher, and add its nodes to the
 
393
        result.
 
394
        """
 
395
        common_to_all_unique_nodes = newly_seen_unique.copy()
 
396
        for searcher in unique_tip_searchers:
 
397
            common_to_all_unique_nodes.intersection_update(searcher.seen)
 
398
        common_to_all_unique_nodes.intersection_update(
 
399
                                    all_unique_searcher.seen)
 
400
        # Step all-unique less frequently than the other searchers.
 
401
        # In the common case, we don't need to spider out far here, so
 
402
        # avoid doing extra work.
 
403
        if step_all_unique:
 
404
            tstart = time.clock()
 
405
            nodes = all_unique_searcher.step()
 
406
            common_to_all_unique_nodes.update(nodes)
 
407
            if 'graph' in debug.debug_flags:
 
408
                tdelta = time.clock() - tstart
 
409
                trace.mutter('all_unique_searcher step() took %.3fs'
 
410
                             'for %d nodes (%d total), iteration: %s',
 
411
                             tdelta, len(nodes), len(all_unique_searcher.seen),
 
412
                             all_unique_searcher._iterations)
 
413
        return common_to_all_unique_nodes
 
414
 
 
415
    def _collapse_unique_searchers(self, unique_tip_searchers,
 
416
                                   common_to_all_unique_nodes):
 
417
        """Combine searchers that are searching the same tips.
 
418
 
 
419
        When two searchers are searching the same tips, we can stop one of the
 
420
        searchers. We also know that the maximal set of common ancestors is the
 
421
        intersection of the two original searchers.
 
422
 
 
423
        :return: A list of searchers that are searching unique nodes.
 
424
        """
 
425
        # Filter out searchers that don't actually search different
 
426
        # nodes. We already have the ancestry intersection for them
 
427
        unique_search_tips = {}
 
428
        for searcher in unique_tip_searchers:
 
429
            stopped = searcher.stop_searching_any(common_to_all_unique_nodes)
 
430
            will_search_set = frozenset(searcher._next_query)
 
431
            if not will_search_set:
 
432
                if 'graph' in debug.debug_flags:
 
433
                    trace.mutter('Unique searcher %s was stopped.'
 
434
                                 ' (%s iterations) %d nodes stopped',
 
435
                                 searcher._label,
 
436
                                 searcher._iterations,
 
437
                                 len(stopped))
 
438
            elif will_search_set not in unique_search_tips:
 
439
                # This searcher is searching a unique set of nodes, let it
 
440
                unique_search_tips[will_search_set] = [searcher]
 
441
            else:
 
442
                unique_search_tips[will_search_set].append(searcher)
 
443
        # TODO: it might be possible to collapse searchers faster when they
 
444
        #       only have *some* search tips in common.
 
445
        next_unique_searchers = []
 
446
        for searchers in unique_search_tips.itervalues():
 
447
            if len(searchers) == 1:
 
448
                # Searching unique tips, go for it
 
449
                next_unique_searchers.append(searchers[0])
 
450
            else:
 
451
                # These searchers have started searching the same tips, we
 
452
                # don't need them to cover the same ground. The
 
453
                # intersection of their ancestry won't change, so create a
 
454
                # new searcher, combining their histories.
 
455
                next_searcher = searchers[0]
 
456
                for searcher in searchers[1:]:
 
457
                    next_searcher.seen.intersection_update(searcher.seen)
 
458
                if 'graph' in debug.debug_flags:
 
459
                    trace.mutter('Combining %d searchers into a single'
 
460
                                 ' searcher searching %d nodes with'
 
461
                                 ' %d ancestry',
 
462
                                 len(searchers),
 
463
                                 len(next_searcher._next_query),
 
464
                                 len(next_searcher.seen))
 
465
                next_unique_searchers.append(next_searcher)
 
466
        return next_unique_searchers
 
467
 
 
468
    def _refine_unique_nodes(self, unique_searcher, all_unique_searcher,
 
469
                             unique_tip_searchers, common_searcher):
 
470
        """Steps 5-8 of find_unique_ancestors.
 
471
        
 
472
        This function returns when common_searcher has stopped searching for
 
473
        more nodes.
 
474
        """
 
475
        # We step the ancestor_all_unique searcher only every
 
476
        # STEP_UNIQUE_SEARCHER_EVERY steps.
 
477
        step_all_unique_counter = 0
 
478
        # While we still have common nodes to search
 
479
        while common_searcher._next_query:
 
480
            (newly_seen_common,
 
481
             newly_seen_unique) = self._step_unique_and_common_searchers(
 
482
                common_searcher, unique_tip_searchers, unique_searcher)
 
483
            # These nodes are common ancestors of all unique nodes
 
484
            common_to_all_unique_nodes = self._find_nodes_common_to_all_unique(
 
485
                unique_tip_searchers, all_unique_searcher, newly_seen_unique,
 
486
                step_all_unique_counter==0)
 
487
            step_all_unique_counter = ((step_all_unique_counter + 1)
 
488
                                       % STEP_UNIQUE_SEARCHER_EVERY)
 
489
 
 
490
            if newly_seen_common:
 
491
                # If a 'common' node is an ancestor of all unique searchers, we
 
492
                # can stop searching it.
 
493
                common_searcher.stop_searching_any(
 
494
                    all_unique_searcher.seen.intersection(newly_seen_common))
 
495
            if common_to_all_unique_nodes:
 
496
                common_to_all_unique_nodes.update(
 
497
                    common_searcher.find_seen_ancestors(
 
498
                        common_to_all_unique_nodes))
 
499
                # The all_unique searcher can start searching the common nodes
 
500
                # but everyone else can stop.
 
501
                # This is the sort of thing where we would like to not have it
 
502
                # start_searching all of the nodes, but only mark all of them
 
503
                # as seen, and have it search only the actual tips. Otherwise
 
504
                # it is another get_parent_map() traversal for it to figure out
 
505
                # what we already should know.
 
506
                all_unique_searcher.start_searching(common_to_all_unique_nodes)
 
507
                common_searcher.stop_searching_any(common_to_all_unique_nodes)
 
508
 
 
509
            next_unique_searchers = self._collapse_unique_searchers(
 
510
                unique_tip_searchers, common_to_all_unique_nodes)
 
511
            if len(unique_tip_searchers) != len(next_unique_searchers):
 
512
                if 'graph' in debug.debug_flags:
 
513
                    trace.mutter('Collapsed %d unique searchers => %d'
 
514
                                 ' at %s iterations',
 
515
                                 len(unique_tip_searchers),
 
516
                                 len(next_unique_searchers),
 
517
                                 all_unique_searcher._iterations)
 
518
            unique_tip_searchers = next_unique_searchers
 
519
 
 
520
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
521
    def get_parents(self, revisions):
 
522
        """Find revision ids of the parents of a list of revisions
 
523
 
 
524
        A list is returned of the same length as the input.  Each entry
 
525
        is a list of parent ids for the corresponding input revision.
 
526
 
 
527
        [NULL_REVISION] is used as the parent of the first user-committed
 
528
        revision.  Its parent list is empty.
 
529
 
 
530
        If the revision is not present (i.e. a ghost), None is used in place
 
531
        of the list of parents.
 
532
 
 
533
        Deprecated in bzr 1.2 - please see get_parent_map.
 
534
        """
 
535
        parents = self.get_parent_map(revisions)
 
536
        return [parents.get(r, None) for r in revisions]
 
537
 
 
538
    def get_parent_map(self, revisions):
 
539
        """Get a map of key:parent_list for revisions.
 
540
 
 
541
        This implementation delegates to get_parents, for old parent_providers
 
542
        that do not supply get_parent_map.
 
543
        """
 
544
        result = {}
 
545
        for rev, parents in self.get_parents(revisions):
 
546
            if parents is not None:
 
547
                result[rev] = parents
 
548
        return result
 
549
 
 
550
    def _make_breadth_first_searcher(self, revisions):
 
551
        return _BreadthFirstSearcher(revisions, self)
 
552
 
 
553
    def _find_border_ancestors(self, revisions):
 
554
        """Find common ancestors with at least one uncommon descendant.
 
555
 
 
556
        Border ancestors are identified using a breadth-first
 
557
        search starting at the bottom of the graph.  Searches are stopped
 
558
        whenever a node or one of its descendants is determined to be common.
 
559
 
 
560
        This will scale with the number of uncommon ancestors.
 
561
 
 
562
        As well as the border ancestors, a set of seen common ancestors and a
 
563
        list of sets of seen ancestors for each input revision is returned.
 
564
        This allows calculation of graph difference from the results of this
 
565
        operation.
 
566
        """
 
567
        if None in revisions:
 
568
            raise errors.InvalidRevisionId(None, self)
 
569
        common_ancestors = set()
 
570
        searchers = [self._make_breadth_first_searcher([r])
 
571
                     for r in revisions]
 
572
        active_searchers = searchers[:]
 
573
        border_ancestors = set()
 
574
 
 
575
        while True:
 
576
            newly_seen = set()
 
577
            for searcher in searchers:
 
578
                new_ancestors = searcher.step()
 
579
                if new_ancestors:
 
580
                    newly_seen.update(new_ancestors)
 
581
            new_common = set()
 
582
            for revision in newly_seen:
 
583
                if revision in common_ancestors:
 
584
                    # Not a border ancestor because it was seen as common
 
585
                    # already
 
586
                    new_common.add(revision)
 
587
                    continue
 
588
                for searcher in searchers:
 
589
                    if revision not in searcher.seen:
 
590
                        break
 
591
                else:
 
592
                    # This is a border because it is a first common that we see
 
593
                    # after walking for a while.
 
594
                    border_ancestors.add(revision)
 
595
                    new_common.add(revision)
 
596
            if new_common:
 
597
                for searcher in searchers:
 
598
                    new_common.update(searcher.find_seen_ancestors(new_common))
 
599
                for searcher in searchers:
 
600
                    searcher.start_searching(new_common)
 
601
                common_ancestors.update(new_common)
 
602
 
 
603
            # Figure out what the searchers will be searching next, and if
 
604
            # there is only 1 set being searched, then we are done searching,
 
605
            # since all searchers would have to be searching the same data,
 
606
            # thus it *must* be in common.
 
607
            unique_search_sets = set()
 
608
            for searcher in searchers:
 
609
                will_search_set = frozenset(searcher._next_query)
 
610
                if will_search_set not in unique_search_sets:
 
611
                    # This searcher is searching a unique set of nodes, let it
 
612
                    unique_search_sets.add(will_search_set)
 
613
 
 
614
            if len(unique_search_sets) == 1:
 
615
                nodes = unique_search_sets.pop()
 
616
                uncommon_nodes = nodes.difference(common_ancestors)
 
617
                if uncommon_nodes:
 
618
                    raise AssertionError("Somehow we ended up converging"
 
619
                                         " without actually marking them as"
 
620
                                         " in common."
 
621
                                         "\nStart_nodes: %s"
 
622
                                         "\nuncommon_nodes: %s"
 
623
                                         % (revisions, uncommon_nodes))
 
624
                break
 
625
        return border_ancestors, common_ancestors, searchers
 
626
 
 
627
    def heads(self, keys):
 
628
        """Return the heads from amongst keys.
 
629
 
 
630
        This is done by searching the ancestries of each key.  Any key that is
 
631
        reachable from another key is not returned; all the others are.
 
632
 
 
633
        This operation scales with the relative depth between any two keys. If
 
634
        any two keys are completely disconnected all ancestry of both sides
 
635
        will be retrieved.
 
636
 
 
637
        :param keys: An iterable of keys.
 
638
        :return: A set of the heads. Note that as a set there is no ordering
 
639
            information. Callers will need to filter their input to create
 
640
            order if they need it.
 
641
        """
 
642
        candidate_heads = set(keys)
 
643
        if revision.NULL_REVISION in candidate_heads:
 
644
            # NULL_REVISION is only a head if it is the only entry
 
645
            candidate_heads.remove(revision.NULL_REVISION)
 
646
            if not candidate_heads:
 
647
                return set([revision.NULL_REVISION])
 
648
        if len(candidate_heads) < 2:
 
649
            return candidate_heads
 
650
        searchers = dict((c, self._make_breadth_first_searcher([c]))
 
651
                          for c in candidate_heads)
 
652
        active_searchers = dict(searchers)
 
653
        # skip over the actual candidate for each searcher
 
654
        for searcher in active_searchers.itervalues():
 
655
            searcher.next()
 
656
        # The common walker finds nodes that are common to two or more of the
 
657
        # input keys, so that we don't access all history when a currently
 
658
        # uncommon search point actually meets up with something behind a
 
659
        # common search point. Common search points do not keep searches
 
660
        # active; they just allow us to make searches inactive without
 
661
        # accessing all history.
 
662
        common_walker = self._make_breadth_first_searcher([])
 
663
        while len(active_searchers) > 0:
 
664
            ancestors = set()
 
665
            # advance searches
 
666
            try:
 
667
                common_walker.next()
 
668
            except StopIteration:
 
669
                # No common points being searched at this time.
 
670
                pass
 
671
            for candidate in active_searchers.keys():
 
672
                try:
 
673
                    searcher = active_searchers[candidate]
 
674
                except KeyError:
 
675
                    # rare case: we deleted candidate in a previous iteration
 
676
                    # through this for loop, because it was determined to be
 
677
                    # a descendant of another candidate.
 
678
                    continue
 
679
                try:
 
680
                    ancestors.update(searcher.next())
 
681
                except StopIteration:
 
682
                    del active_searchers[candidate]
 
683
                    continue
 
684
            # process found nodes
 
685
            new_common = set()
 
686
            for ancestor in ancestors:
 
687
                if ancestor in candidate_heads:
 
688
                    candidate_heads.remove(ancestor)
 
689
                    del searchers[ancestor]
 
690
                    if ancestor in active_searchers:
 
691
                        del active_searchers[ancestor]
 
692
                # it may meet up with a known common node
 
693
                if ancestor in common_walker.seen:
 
694
                    # some searcher has encountered our known common nodes:
 
695
                    # just stop it
 
696
                    ancestor_set = set([ancestor])
 
697
                    for searcher in searchers.itervalues():
 
698
                        searcher.stop_searching_any(ancestor_set)
 
699
                else:
 
700
                    # or it may have been just reached by all the searchers:
 
701
                    for searcher in searchers.itervalues():
 
702
                        if ancestor not in searcher.seen:
 
703
                            break
 
704
                    else:
 
705
                        # The final active searcher has just reached this node,
 
706
                        # making it be known as a descendant of all candidates,
 
707
                        # so we can stop searching it, and any seen ancestors
 
708
                        new_common.add(ancestor)
 
709
                        for searcher in searchers.itervalues():
 
710
                            seen_ancestors =\
 
711
                                searcher.find_seen_ancestors([ancestor])
 
712
                            searcher.stop_searching_any(seen_ancestors)
 
713
            common_walker.start_searching(new_common)
 
714
        return candidate_heads
 
715
 
 
716
    def find_unique_lca(self, left_revision, right_revision,
 
717
                        count_steps=False):
 
718
        """Find a unique LCA.
 
719
 
 
720
        Find lowest common ancestors.  If there is no unique  common
 
721
        ancestor, find the lowest common ancestors of those ancestors.
 
722
 
 
723
        Iteration stops when a unique lowest common ancestor is found.
 
724
        The graph origin is necessarily a unique lowest common ancestor.
 
725
 
 
726
        Note that None is not an acceptable substitute for NULL_REVISION.
 
727
        in the input for this method.
 
728
 
 
729
        :param count_steps: If True, the return value will be a tuple of
 
730
            (unique_lca, steps) where steps is the number of times that
 
731
            find_lca was run.  If False, only unique_lca is returned.
 
732
        """
 
733
        revisions = [left_revision, right_revision]
 
734
        steps = 0
 
735
        while True:
 
736
            steps += 1
 
737
            lca = self.find_lca(*revisions)
 
738
            if len(lca) == 1:
 
739
                result = lca.pop()
 
740
                if count_steps:
 
741
                    return result, steps
 
742
                else:
 
743
                    return result
 
744
            if len(lca) == 0:
 
745
                raise errors.NoCommonAncestor(left_revision, right_revision)
 
746
            revisions = lca
 
747
 
 
748
    def iter_ancestry(self, revision_ids):
 
749
        """Iterate the ancestry of this revision.
 
750
 
 
751
        :param revision_ids: Nodes to start the search
 
752
        :return: Yield tuples mapping a revision_id to its parents for the
 
753
            ancestry of revision_id.
 
754
            Ghosts will be returned with None as their parents, and nodes
 
755
            with no parents will have NULL_REVISION as their only parent. (As
 
756
            defined by get_parent_map.)
 
757
            There will also be a node for (NULL_REVISION, ())
 
758
        """
 
759
        pending = set(revision_ids)
 
760
        processed = set()
 
761
        while pending:
 
762
            processed.update(pending)
 
763
            next_map = self.get_parent_map(pending)
 
764
            next_pending = set()
 
765
            for item in next_map.iteritems():
 
766
                yield item
 
767
                next_pending.update(p for p in item[1] if p not in processed)
 
768
            ghosts = pending.difference(next_map)
 
769
            for ghost in ghosts:
 
770
                yield (ghost, None)
 
771
            pending = next_pending
 
772
 
 
773
    def iter_topo_order(self, revisions):
 
774
        """Iterate through the input revisions in topological order.
 
775
 
 
776
        This sorting only ensures that parents come before their children.
 
777
        An ancestor may sort after a descendant if the relationship is not
 
778
        visible in the supplied list of revisions.
 
779
        """
 
780
        sorter = tsort.TopoSorter(self.get_parent_map(revisions))
 
781
        return sorter.iter_topo_order()
 
782
 
 
783
    def is_ancestor(self, candidate_ancestor, candidate_descendant):
 
784
        """Determine whether a revision is an ancestor of another.
 
785
 
 
786
        We answer this using heads() as heads() has the logic to perform the
 
787
        smallest number of parent lookups to determine the ancestral
 
788
        relationship between N revisions.
 
789
        """
 
790
        return set([candidate_descendant]) == self.heads(
 
791
            [candidate_ancestor, candidate_descendant])
 
792
 
 
793
    def _search_for_extra_common(self, common, searchers):
 
794
        """Make sure that unique nodes are genuinely unique.
 
795
 
 
796
        After _find_border_ancestors, all nodes marked "common" are indeed
 
797
        common. Some of the nodes considered unique are not, due to history
 
798
        shortcuts stopping the searches early.
 
799
 
 
800
        We know that we have searched enough when all common search tips are
 
801
        descended from all unique (uncommon) nodes because we know that a node
 
802
        cannot be an ancestor of its own ancestor.
 
803
 
 
804
        :param common: A set of common nodes
 
805
        :param searchers: The searchers returned from _find_border_ancestors
 
806
        :return: None
 
807
        """
 
808
        # Basic algorithm...
 
809
        #   A) The passed in searchers should all be on the same tips, thus
 
810
        #      they should be considered the "common" searchers.
 
811
        #   B) We find the difference between the searchers, these are the
 
812
        #      "unique" nodes for each side.
 
813
        #   C) We do a quick culling so that we only start searching from the
 
814
        #      more interesting unique nodes. (A unique ancestor is more
 
815
        #      interesting than any of its children.)
 
816
        #   D) We start searching for ancestors common to all unique nodes.
 
817
        #   E) We have the common searchers stop searching any ancestors of
 
818
        #      nodes found by (D)
 
819
        #   F) When there are no more common search tips, we stop
 
820
 
 
821
        # TODO: We need a way to remove unique_searchers when they overlap with
 
822
        #       other unique searchers.
 
823
        if len(searchers) != 2:
 
824
            raise NotImplementedError(
 
825
                "Algorithm not yet implemented for > 2 searchers")
 
826
        common_searchers = searchers
 
827
        left_searcher = searchers[0]
 
828
        right_searcher = searchers[1]
 
829
        unique = left_searcher.seen.symmetric_difference(right_searcher.seen)
 
830
        if not unique: # No unique nodes, nothing to do
 
831
            return
 
832
        total_unique = len(unique)
 
833
        unique = self._remove_simple_descendants(unique,
 
834
                    self.get_parent_map(unique))
 
835
        simple_unique = len(unique)
 
836
 
 
837
        unique_searchers = []
 
838
        for revision_id in unique:
 
839
            if revision_id in left_searcher.seen:
 
840
                parent_searcher = left_searcher
 
841
            else:
 
842
                parent_searcher = right_searcher
 
843
            revs_to_search = parent_searcher.find_seen_ancestors([revision_id])
 
844
            if not revs_to_search: # XXX: This shouldn't be possible
 
845
                revs_to_search = [revision_id]
 
846
            searcher = self._make_breadth_first_searcher(revs_to_search)
 
847
            # We don't care about the starting nodes.
 
848
            searcher.step()
 
849
            unique_searchers.append(searcher)
 
850
 
 
851
        # possible todo: aggregate the common searchers into a single common
 
852
        #   searcher, just make sure that we include the nodes into the .seen
 
853
        #   properties of the original searchers
 
854
 
 
855
        ancestor_all_unique = None
 
856
        for searcher in unique_searchers:
 
857
            if ancestor_all_unique is None:
 
858
                ancestor_all_unique = set(searcher.seen)
 
859
            else:
 
860
                ancestor_all_unique = ancestor_all_unique.intersection(
 
861
                                            searcher.seen)
 
862
 
 
863
        trace.mutter('Started %s unique searchers for %s unique revisions',
 
864
                     simple_unique, total_unique)
 
865
 
 
866
        while True: # If we have no more nodes we have nothing to do
 
867
            newly_seen_common = set()
 
868
            for searcher in common_searchers:
 
869
                newly_seen_common.update(searcher.step())
 
870
            newly_seen_unique = set()
 
871
            for searcher in unique_searchers:
 
872
                newly_seen_unique.update(searcher.step())
 
873
            new_common_unique = set()
 
874
            for revision in newly_seen_unique:
 
875
                for searcher in unique_searchers:
 
876
                    if revision not in searcher.seen:
 
877
                        break
 
878
                else:
 
879
                    # This is a border because it is a first common that we see
 
880
                    # after walking for a while.
 
881
                    new_common_unique.add(revision)
 
882
            if newly_seen_common:
 
883
                # These are nodes descended from one of the 'common' searchers.
 
884
                # Make sure all searchers are on the same page
 
885
                for searcher in common_searchers:
 
886
                    newly_seen_common.update(
 
887
                        searcher.find_seen_ancestors(newly_seen_common))
 
888
                # We start searching the whole ancestry. It is a bit wasteful,
 
889
                # though. We really just want to mark all of these nodes as
 
890
                # 'seen' and then start just the tips. However, it requires a
 
891
                # get_parent_map() call to figure out the tips anyway, and all
 
892
                # redundant requests should be fairly fast.
 
893
                for searcher in common_searchers:
 
894
                    searcher.start_searching(newly_seen_common)
 
895
 
 
896
                # If a 'common' node is an ancestor of all unique searchers, we
 
897
                # can stop searching it.
 
898
                stop_searching_common = ancestor_all_unique.intersection(
 
899
                                            newly_seen_common)
 
900
                if stop_searching_common:
 
901
                    for searcher in common_searchers:
 
902
                        searcher.stop_searching_any(stop_searching_common)
 
903
            if new_common_unique:
 
904
                # We found some ancestors that are common
 
905
                for searcher in unique_searchers:
 
906
                    new_common_unique.update(
 
907
                        searcher.find_seen_ancestors(new_common_unique))
 
908
                # Since these are common, we can grab another set of ancestors
 
909
                # that we have seen
 
910
                for searcher in common_searchers:
 
911
                    new_common_unique.update(
 
912
                        searcher.find_seen_ancestors(new_common_unique))
 
913
 
 
914
                # We can tell all of the unique searchers to start at these
 
915
                # nodes, and tell all of the common searchers to *stop*
 
916
                # searching these nodes
 
917
                for searcher in unique_searchers:
 
918
                    searcher.start_searching(new_common_unique)
 
919
                for searcher in common_searchers:
 
920
                    searcher.stop_searching_any(new_common_unique)
 
921
                ancestor_all_unique.update(new_common_unique)
 
922
 
 
923
                # Filter out searchers that don't actually search different
 
924
                # nodes. We already have the ancestry intersection for them
 
925
                next_unique_searchers = []
 
926
                unique_search_sets = set()
 
927
                for searcher in unique_searchers:
 
928
                    will_search_set = frozenset(searcher._next_query)
 
929
                    if will_search_set not in unique_search_sets:
 
930
                        # This searcher is searching a unique set of nodes, let it
 
931
                        unique_search_sets.add(will_search_set)
 
932
                        next_unique_searchers.append(searcher)
 
933
                unique_searchers = next_unique_searchers
 
934
            for searcher in common_searchers:
 
935
                if searcher._next_query:
 
936
                    break
 
937
            else:
 
938
                # All common searcher have stopped searching
 
939
                return
 
940
 
 
941
    def _remove_simple_descendants(self, revisions, parent_map):
 
942
        """remove revisions which are children of other ones in the set
 
943
 
 
944
        This doesn't do any graph searching, it just checks the immediate
 
945
        parent_map to find if there are any children which can be removed.
 
946
 
 
947
        :param revisions: A set of revision_ids
 
948
        :return: A set of revision_ids with the children removed
 
949
        """
 
950
        simple_ancestors = revisions.copy()
 
951
        # TODO: jam 20071214 we *could* restrict it to searching only the
 
952
        #       parent_map of revisions already present in 'revisions', but
 
953
        #       considering the general use case, I think this is actually
 
954
        #       better.
 
955
 
 
956
        # This is the same as the following loop. I don't know that it is any
 
957
        # faster.
 
958
        ## simple_ancestors.difference_update(r for r, p_ids in parent_map.iteritems()
 
959
        ##     if p_ids is not None and revisions.intersection(p_ids))
 
960
        ## return simple_ancestors
 
961
 
 
962
        # Yet Another Way, invert the parent map (which can be cached)
 
963
        ## descendants = {}
 
964
        ## for revision_id, parent_ids in parent_map.iteritems():
 
965
        ##   for p_id in parent_ids:
 
966
        ##       descendants.setdefault(p_id, []).append(revision_id)
 
967
        ## for revision in revisions.intersection(descendants):
 
968
        ##   simple_ancestors.difference_update(descendants[revision])
 
969
        ## return simple_ancestors
 
970
        for revision, parent_ids in parent_map.iteritems():
 
971
            if parent_ids is None:
 
972
                continue
 
973
            for parent_id in parent_ids:
 
974
                if parent_id in revisions:
 
975
                    # This node has a parent present in the set, so we can
 
976
                    # remove it
 
977
                    simple_ancestors.discard(revision)
 
978
                    break
 
979
        return simple_ancestors
 
980
 
 
981
 
 
982
class HeadsCache(object):
 
983
    """A cache of results for graph heads calls."""
 
984
 
 
985
    def __init__(self, graph):
 
986
        self.graph = graph
 
987
        self._heads = {}
 
988
 
 
989
    def heads(self, keys):
 
990
        """Return the heads of keys.
 
991
 
 
992
        This matches the API of Graph.heads(), specifically the return value is
 
993
        a set which can be mutated, and ordering of the input is not preserved
 
994
        in the output.
 
995
 
 
996
        :see also: Graph.heads.
 
997
        :param keys: The keys to calculate heads for.
 
998
        :return: A set containing the heads, which may be mutated without
 
999
            affecting future lookups.
 
1000
        """
 
1001
        keys = frozenset(keys)
 
1002
        try:
 
1003
            return set(self._heads[keys])
 
1004
        except KeyError:
 
1005
            heads = self.graph.heads(keys)
 
1006
            self._heads[keys] = heads
 
1007
            return set(heads)
 
1008
 
 
1009
 
 
1010
class FrozenHeadsCache(object):
 
1011
    """Cache heads() calls, assuming the caller won't modify them."""
 
1012
 
 
1013
    def __init__(self, graph):
 
1014
        self.graph = graph
 
1015
        self._heads = {}
 
1016
 
 
1017
    def heads(self, keys):
 
1018
        """Return the heads of keys.
 
1019
 
 
1020
        Similar to Graph.heads(). The main difference is that the return value
 
1021
        is a frozen set which cannot be mutated.
 
1022
 
 
1023
        :see also: Graph.heads.
 
1024
        :param keys: The keys to calculate heads for.
 
1025
        :return: A frozenset containing the heads.
 
1026
        """
 
1027
        keys = frozenset(keys)
 
1028
        try:
 
1029
            return self._heads[keys]
 
1030
        except KeyError:
 
1031
            heads = frozenset(self.graph.heads(keys))
 
1032
            self._heads[keys] = heads
 
1033
            return heads
 
1034
 
 
1035
    def cache(self, keys, heads):
 
1036
        """Store a known value."""
 
1037
        self._heads[frozenset(keys)] = frozenset(heads)
 
1038
 
 
1039
 
 
1040
class _BreadthFirstSearcher(object):
 
1041
    """Parallel search breadth-first the ancestry of revisions.
 
1042
 
 
1043
    This class implements the iterator protocol, but additionally
 
1044
    1. provides a set of seen ancestors, and
 
1045
    2. allows some ancestries to be unsearched, via stop_searching_any
 
1046
    """
 
1047
 
 
1048
    def __init__(self, revisions, parents_provider):
 
1049
        self._iterations = 0
 
1050
        self._next_query = set(revisions)
 
1051
        self.seen = set()
 
1052
        self._started_keys = set(self._next_query)
 
1053
        self._stopped_keys = set()
 
1054
        self._parents_provider = parents_provider
 
1055
        self._returning = 'next_with_ghosts'
 
1056
        self._current_present = set()
 
1057
        self._current_ghosts = set()
 
1058
        self._current_parents = {}
 
1059
 
 
1060
    def __repr__(self):
 
1061
        if self._iterations:
 
1062
            prefix = "searching"
 
1063
        else:
 
1064
            prefix = "starting"
 
1065
        search = '%s=%r' % (prefix, list(self._next_query))
 
1066
        return ('_BreadthFirstSearcher(iterations=%d, %s,'
 
1067
                ' seen=%r)' % (self._iterations, search, list(self.seen)))
 
1068
 
 
1069
    def get_result(self):
 
1070
        """Get a SearchResult for the current state of this searcher.
 
1071
        
 
1072
        :return: A SearchResult for this search so far. The SearchResult is
 
1073
            static - the search can be advanced and the search result will not
 
1074
            be invalidated or altered.
 
1075
        """
 
1076
        if self._returning == 'next':
 
1077
            # We have to know the current nodes children to be able to list the
 
1078
            # exclude keys for them. However, while we could have a second
 
1079
            # look-ahead result buffer and shuffle things around, this method
 
1080
            # is typically only called once per search - when memoising the
 
1081
            # results of the search. 
 
1082
            found, ghosts, next, parents = self._do_query(self._next_query)
 
1083
            # pretend we didn't query: perhaps we should tweak _do_query to be
 
1084
            # entirely stateless?
 
1085
            self.seen.difference_update(next)
 
1086
            next_query = next.union(ghosts)
 
1087
        else:
 
1088
            next_query = self._next_query
 
1089
        excludes = self._stopped_keys.union(next_query)
 
1090
        included_keys = self.seen.difference(excludes)
 
1091
        return SearchResult(self._started_keys, excludes, len(included_keys),
 
1092
            included_keys)
 
1093
 
 
1094
    def step(self):
 
1095
        try:
 
1096
            return self.next()
 
1097
        except StopIteration:
 
1098
            return ()
 
1099
 
 
1100
    def next(self):
 
1101
        """Return the next ancestors of this revision.
 
1102
 
 
1103
        Ancestors are returned in the order they are seen in a breadth-first
 
1104
        traversal.  No ancestor will be returned more than once. Ancestors are
 
1105
        returned before their parentage is queried, so ghosts and missing
 
1106
        revisions (including the start revisions) are included in the result.
 
1107
        This can save a round trip in LCA style calculation by allowing
 
1108
        convergence to be detected without reading the data for the revision
 
1109
        the convergence occurs on.
 
1110
 
 
1111
        :return: A set of revision_ids.
 
1112
        """
 
1113
        if self._returning != 'next':
 
1114
            # switch to returning the query, not the results.
 
1115
            self._returning = 'next'
 
1116
            self._iterations += 1
 
1117
        else:
 
1118
            self._advance()
 
1119
        if len(self._next_query) == 0:
 
1120
            raise StopIteration()
 
1121
        # We have seen what we're querying at this point as we are returning
 
1122
        # the query, not the results.
 
1123
        self.seen.update(self._next_query)
 
1124
        return self._next_query
 
1125
 
 
1126
    def next_with_ghosts(self):
 
1127
        """Return the next found ancestors, with ghosts split out.
 
1128
        
 
1129
        Ancestors are returned in the order they are seen in a breadth-first
 
1130
        traversal.  No ancestor will be returned more than once. Ancestors are
 
1131
        returned only after asking for their parents, which allows us to detect
 
1132
        which revisions are ghosts and which are not.
 
1133
 
 
1134
        :return: A tuple with (present ancestors, ghost ancestors) sets.
 
1135
        """
 
1136
        if self._returning != 'next_with_ghosts':
 
1137
            # switch to returning the results, not the current query.
 
1138
            self._returning = 'next_with_ghosts'
 
1139
            self._advance()
 
1140
        if len(self._next_query) == 0:
 
1141
            raise StopIteration()
 
1142
        self._advance()
 
1143
        return self._current_present, self._current_ghosts
 
1144
 
 
1145
    def _advance(self):
 
1146
        """Advance the search.
 
1147
 
 
1148
        Updates self.seen, self._next_query, self._current_present,
 
1149
        self._current_ghosts, self._current_parents and self._iterations.
 
1150
        """
 
1151
        self._iterations += 1
 
1152
        found, ghosts, next, parents = self._do_query(self._next_query)
 
1153
        self._current_present = found
 
1154
        self._current_ghosts = ghosts
 
1155
        self._next_query = next
 
1156
        self._current_parents = parents
 
1157
        # ghosts are implicit stop points, otherwise the search cannot be
 
1158
        # repeated when ghosts are filled.
 
1159
        self._stopped_keys.update(ghosts)
 
1160
 
 
1161
    def _do_query(self, revisions):
 
1162
        """Query for revisions.
 
1163
 
 
1164
        Adds revisions to the seen set.
 
1165
 
 
1166
        :param revisions: Revisions to query.
 
1167
        :return: A tuple: (set(found_revisions), set(ghost_revisions),
 
1168
           set(parents_of_found_revisions), dict(found_revisions:parents)).
 
1169
        """
 
1170
        found_revisions = set()
 
1171
        parents_of_found = set()
 
1172
        # revisions may contain nodes that point to other nodes in revisions:
 
1173
        # we want to filter them out.
 
1174
        self.seen.update(revisions)
 
1175
        parent_map = self._parents_provider.get_parent_map(revisions)
 
1176
        found_revisions.update(parent_map)
 
1177
        for rev_id, parents in parent_map.iteritems():
 
1178
            new_found_parents = [p for p in parents if p not in self.seen]
 
1179
            if new_found_parents:
 
1180
                # Calling set.update() with an empty generator is actually
 
1181
                # rather expensive.
 
1182
                parents_of_found.update(new_found_parents)
 
1183
        ghost_revisions = revisions - found_revisions
 
1184
        return found_revisions, ghost_revisions, parents_of_found, parent_map
 
1185
 
 
1186
    def __iter__(self):
 
1187
        return self
 
1188
 
 
1189
    def find_seen_ancestors(self, revisions):
 
1190
        """Find ancestors of these revisions that have already been seen.
 
1191
        
 
1192
        This function generally makes the assumption that querying for the
 
1193
        parents of a node that has already been queried is reasonably cheap.
 
1194
        (eg, not a round trip to a remote host).
 
1195
        """
 
1196
        # TODO: Often we might ask one searcher for its seen ancestors, and
 
1197
        #       then ask another searcher the same question. This can result in
 
1198
        #       searching the same revisions repeatedly if the two searchers
 
1199
        #       have a lot of overlap.
 
1200
        all_seen = self.seen
 
1201
        pending = set(revisions).intersection(all_seen)
 
1202
        seen_ancestors = set(pending)
 
1203
 
 
1204
        if self._returning == 'next':
 
1205
            # self.seen contains what nodes have been returned, not what nodes
 
1206
            # have been queried. We don't want to probe for nodes that haven't
 
1207
            # been searched yet.
 
1208
            not_searched_yet = self._next_query
 
1209
        else:
 
1210
            not_searched_yet = ()
 
1211
        pending.difference_update(not_searched_yet)
 
1212
        get_parent_map = self._parents_provider.get_parent_map
 
1213
        while pending:
 
1214
            parent_map = get_parent_map(pending)
 
1215
            all_parents = []
 
1216
            # We don't care if it is a ghost, since it can't be seen if it is
 
1217
            # a ghost
 
1218
            for parent_ids in parent_map.itervalues():
 
1219
                all_parents.extend(parent_ids)
 
1220
            next_pending = all_seen.intersection(all_parents).difference(seen_ancestors)
 
1221
            seen_ancestors.update(next_pending)
 
1222
            next_pending.difference_update(not_searched_yet)
 
1223
            pending = next_pending
 
1224
 
 
1225
        return seen_ancestors
 
1226
 
 
1227
    def stop_searching_any(self, revisions):
 
1228
        """
 
1229
        Remove any of the specified revisions from the search list.
 
1230
 
 
1231
        None of the specified revisions are required to be present in the
 
1232
        search list.  In this case, the call is a no-op.
 
1233
        """
 
1234
        # TODO: does this help performance?
 
1235
        # if not revisions:
 
1236
        #     return set()
 
1237
        revisions = frozenset(revisions)
 
1238
        if self._returning == 'next':
 
1239
            stopped = self._next_query.intersection(revisions)
 
1240
            self._next_query = self._next_query.difference(revisions)
 
1241
        else:
 
1242
            stopped_present = self._current_present.intersection(revisions)
 
1243
            stopped = stopped_present.union(
 
1244
                self._current_ghosts.intersection(revisions))
 
1245
            self._current_present.difference_update(stopped)
 
1246
            self._current_ghosts.difference_update(stopped)
 
1247
            # stopping 'x' should stop returning parents of 'x', but 
 
1248
            # not if 'y' always references those same parents
 
1249
            stop_rev_references = {}
 
1250
            for rev in stopped_present:
 
1251
                for parent_id in self._current_parents[rev]:
 
1252
                    if parent_id not in stop_rev_references:
 
1253
                        stop_rev_references[parent_id] = 0
 
1254
                    stop_rev_references[parent_id] += 1
 
1255
            # if only the stopped revisions reference it, the ref count will be
 
1256
            # 0 after this loop
 
1257
            for parents in self._current_parents.itervalues():
 
1258
                for parent_id in parents:
 
1259
                    try:
 
1260
                        stop_rev_references[parent_id] -= 1
 
1261
                    except KeyError:
 
1262
                        pass
 
1263
            stop_parents = set()
 
1264
            for rev_id, refs in stop_rev_references.iteritems():
 
1265
                if refs == 0:
 
1266
                    stop_parents.add(rev_id)
 
1267
            self._next_query.difference_update(stop_parents)
 
1268
        self._stopped_keys.update(stopped)
 
1269
        return stopped
 
1270
 
 
1271
    def start_searching(self, revisions):
 
1272
        """Add revisions to the search.
 
1273
 
 
1274
        The parents of revisions will be returned from the next call to next()
 
1275
        or next_with_ghosts(). If next_with_ghosts was the most recently used
 
1276
        next* call then the return value is the result of looking up the
 
1277
        ghost/not ghost status of revisions. (A tuple (present, ghosted)).
 
1278
        """
 
1279
        revisions = frozenset(revisions)
 
1280
        self._started_keys.update(revisions)
 
1281
        new_revisions = revisions.difference(self.seen)
 
1282
        if self._returning == 'next':
 
1283
            self._next_query.update(new_revisions)
 
1284
            self.seen.update(new_revisions)
 
1285
        else:
 
1286
            # perform a query on revisions
 
1287
            revs, ghosts, query, parents = self._do_query(revisions)
 
1288
            self._stopped_keys.update(ghosts)
 
1289
            self._current_present.update(revs)
 
1290
            self._current_ghosts.update(ghosts)
 
1291
            self._next_query.update(query)
 
1292
            self._current_parents.update(parents)
 
1293
            return revs, ghosts
 
1294
 
 
1295
 
 
1296
class SearchResult(object):
 
1297
    """The result of a breadth first search.
 
1298
 
 
1299
    A SearchResult provides the ability to reconstruct the search or access a
 
1300
    set of the keys the search found.
 
1301
    """
 
1302
 
 
1303
    def __init__(self, start_keys, exclude_keys, key_count, keys):
 
1304
        """Create a SearchResult.
 
1305
 
 
1306
        :param start_keys: The keys the search started at.
 
1307
        :param exclude_keys: The keys the search excludes.
 
1308
        :param key_count: The total number of keys (from start to but not
 
1309
            including exclude).
 
1310
        :param keys: The keys the search found. Note that in future we may get
 
1311
            a SearchResult from a smart server, in which case the keys list is
 
1312
            not necessarily immediately available.
 
1313
        """
 
1314
        self._recipe = (start_keys, exclude_keys, key_count)
 
1315
        self._keys = frozenset(keys)
 
1316
 
 
1317
    def get_recipe(self):
 
1318
        """Return a recipe that can be used to replay this search.
 
1319
        
 
1320
        The recipe allows reconstruction of the same results at a later date
 
1321
        without knowing all the found keys. The essential elements are a list
 
1322
        of keys to start and and to stop at. In order to give reproducible
 
1323
        results when ghosts are encountered by a search they are automatically
 
1324
        added to the exclude list (or else ghost filling may alter the
 
1325
        results).
 
1326
 
 
1327
        :return: A tuple (start_keys_set, exclude_keys_set, revision_count). To
 
1328
            recreate the results of this search, create a breadth first
 
1329
            searcher on the same graph starting at start_keys. Then call next()
 
1330
            (or next_with_ghosts()) repeatedly, and on every result, call
 
1331
            stop_searching_any on any keys from the exclude_keys set. The
 
1332
            revision_count value acts as a trivial cross-check - the found
 
1333
            revisions of the new search should have as many elements as
 
1334
            revision_count. If it does not, then additional revisions have been
 
1335
            ghosted since the search was executed the first time and the second
 
1336
            time.
 
1337
        """
 
1338
        return self._recipe
 
1339
 
 
1340
    def get_keys(self):
 
1341
        """Return the keys found in this search.
 
1342
 
 
1343
        :return: A set of keys.
 
1344
        """
 
1345
        return self._keys
 
1346