Merge lp:~spiv/bzr/fetch-spec-everything-not-in-other into lp:bzr

Proposed by Andrew Bennetts
Status: Merged
Merged at revision: 5648
Proposed branch: lp:~spiv/bzr/fetch-spec-everything-not-in-other
Merge into: lp:bzr
Diff against target: 247 lines (+32/-36)
10 files modified
bzrlib/fetch.py (+10/-15)
bzrlib/graph.py (+6/-5)
bzrlib/remote.py (+3/-3)
bzrlib/repofmt/knitrepo.py (+1/-1)
bzrlib/repofmt/weaverepo.py (+1/-1)
bzrlib/repository.py (+2/-2)
bzrlib/tests/per_interrepository/test_interrepository.py (+1/-1)
bzrlib/tests/test_remote.py (+3/-3)
doc/en/release-notes/bzr-2.3.txt (+0/-5)
doc/en/release-notes/bzr-2.4.txt (+5/-0)
To merge this branch: bzr merge lp:~spiv/bzr/fetch-spec-everything-not-in-other
Reviewer Review Type Date Requested Status
Martin Pool Approve
John A Meinel Pending
Review via email: mp+42811@code.launchpad.net

This proposal supersedes a proposal from 2010-11-29.

Commit message

Add EverythingResult, EverythingNotInOther, and NotInOtherForRevs.

Description of the change

Like <https://code.launchpad.net/~spiv/bzr/sprout-does-not-reopen-repo/+merge/41037> this is a step towards bug 309682 (i.e. is a pre-req for <lp:~spiv/bzr/fetch-all-tags-309682>, as well as being a general improvement.

This patch defines some new “fetch specs” to be passed as the fetch_spec argument of fetch: EverythingResult, EmptySearchResult, EverythingNotInOther, and NotInOtherForRevs. I've created two new abstract classes, AbstractSearchResult, and AbstractSearch, to distinguish between the two different sorts of fetch spec. I think the naming is a bit off, the original fetch spec was called “SearchResult”, which made some sense, but there's also “PendingAncestryResult” which isn't really a “result”. So perhaps we should rename some or all of these things. In the current scheme EverythingNotInOther and NotInOtherForRevs are Searches, rather than Search Results. Suggestions for clearer naming would be very welcome!

Separately I'm not 100% sure we need the ability to have fetch specs that aren't resolved into search results immediately (i.e. how AbstractSearch instances are used). This happens to be effectively how the existing code works: e.g. code that does "target.fetch(source, revision_id=some_rev)" has known the value of some_rev without performing a search, delegating that to the fetch call. I don't think it would it simplify the code much in practice to remove this flexibility, but maybe it would simplify the concepts enough to be worth it?

A nice thing about adding these objects is that it shifts logic to handle these different cases out of the innards of fetch.py to somewhere more modular. This in turn means we can support these things better over HPSS, and so this patch does that: the 'everything' search is now added to the network protocol. Happily new verb was needed, we can safely interpret a BadSearch error in this case as meaning we need to fallback.

Another change in this patch is the deprecation of search_missing_revision_ids' revision_id argument for the new revision_ids (plural).

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote : Posted in a previous version of this proposal

+ if not isinstance(search, graph.EverythingResult):
^- can we add an attribute, rather than an isinstance check?

if not search.is_everything():

490 + def _present_source_revisions_for(self, revision_ids):
491 + """Returns set of all revisions in ancestry of revision_ids present in
492 + the source repo.
493 +
494 + :param revision_ids: if None, all revisions in source are returned.
495 + """
496 + if revision_ids is not None:
497 + # First, ensure all specified revisions exist. Callers expect
498 + # NoSuchRevision when they pass absent revision_ids here.
499 + revision_ids = set(revision_ids)
500 + graph = self.source.get_graph()
501 + present_revs = set(graph.get_parent_map(revision_ids))
502 + missing = revision_ids.difference(present_revs)
503 + if missing:
504 + raise errors.NoSuchRevision(self.source, missing.pop())
505 + source_ids = [rev_id for (rev_id, parents) in
506 + self.source.get_graph().iter_ancestry(revision_ids)
507 + if rev_id != _mod_revision.NULL_REVISION
508 + and parents is not None]
^- you have "graph = self.source.get_graph()" and then you inline "self.source.get_graph()" into the source_ids list comprehension. Better to re-use the graph object.

145 + def get_recipe(self):
146 + raise NotImplementedError(self.get_recipe)
147 +
148 + def get_network_struct(self):
149 + return ('everything',)

Why don't EverythingNotInOther and NotInOtherForRevs implement these functions?

Overall, I think these changes seem good, but I don't really see how this gets us closer to computing a search without having one end doing a step-by-step search. (Certainly you're still using the same 'search_missing_revision_ids', and you don't seem to be serializing anything over the wire...)

review: Needs Fixing
Revision history for this message
Andrew Bennetts (spiv) wrote : Posted in a previous version of this proposal
Download full text (3.8 KiB)

John A Meinel wrote:
> Review: Needs Fixing
> + if not isinstance(search, graph.EverythingResult):
> ^- can we add an attribute, rather than an isinstance check?
>
> if not search.is_everything():

Hmm, I can do that, although currently there's no common base class for these
objects, and my gut feeling is that it would be good to keep their interface as
small and simple as possible. So I'm unsure about whether or not to do this. I
think it's probably easier to add this later than it is to remove it later.

> 490 + def _present_source_revisions_for(self, revision_ids):
> 491 + """Returns set of all revisions in ancestry of revision_ids present in
> 492 + the source repo.
> 493 +
> 494 + :param revision_ids: if None, all revisions in source are returned.
> 495 + """
> 496 + if revision_ids is not None:
> 497 + # First, ensure all specified revisions exist. Callers expect
> 498 + # NoSuchRevision when they pass absent revision_ids here.
> 499 + revision_ids = set(revision_ids)
> 500 + graph = self.source.get_graph()
> 501 + present_revs = set(graph.get_parent_map(revision_ids))
> 502 + missing = revision_ids.difference(present_revs)
> 503 + if missing:
> 504 + raise errors.NoSuchRevision(self.source, missing.pop())
> 505 + source_ids = [rev_id for (rev_id, parents) in
> 506 + self.source.get_graph().iter_ancestry(revision_ids)
> 507 + if rev_id != _mod_revision.NULL_REVISION
> 508 + and parents is not None]
> ^- you have "graph = self.source.get_graph()" and then you inline "self.source.get_graph()" into the source_ids list comprehension. Better to re-use the graph object.

Fixed, thanks for spotting that. I think it occurred because I initially
copy-and-pasted the list comprehension from graph.py.

> 145 + def get_recipe(self):
> 146 + raise NotImplementedError(self.get_recipe)
> 147 +
> 148 + def get_network_struct(self):
> 149 + return ('everything',)
>
> Why don't EverythingNotInOther and NotInOtherForRevs implement these functions?

Because they are a different kind of object. Obviously that's not clear enough
in the current code!

The names could stand to be improved, but there are basically two kinds of
“fetch spec” in this patch:

 * a network-ready search result: SearchResult, PendingAncestryResult,
   EverythingResult. They implement all the methods SearchResult implements
   (I'm not certain that's the perfect design, but it's not too far off.)
 * a lightweight object that can be resolved into a network-ready search result
   later: EverythingNotInOther, NotInOtherForRevs. They implement a get_search
   method that inspects the repository/ies to generate the search result.

> Overall, I think these changes seem good, but I don't really see how this gets
> us closer to computing a search without having one end doing a step-by-step
> search. (Certainly you're still using the same 'search_missing_revision_ids',
> and you don't seem to be serializing anything over the wire...)

Right, this change isn't meant to solve that problem. The concrete performance
issue they help with is in the next patch, fetch-all-tags-309682, to make it
and easy for the sprout code to request a fetch of all tags at the
same time as the tip.

Separately...

Read more...

Revision history for this message
Martin Pool (mbp) wrote :

I think I like the concept of splitting these out into something more like objects.

I don't want to hold this hostage but it seems like this would be a good moment to add a little developer documentation to the architectural guide describing at a high level how fetch works.

+ def get_network_struct(self):
+ start_keys = ' '.join(self._recipe[1])
+ stop_keys = ' '.join(self._recipe[2])
+ count = str(self._recipe[3])
+ return (self._recipe[0], '\n'.join((start_keys, stop_keys, count)))
+

rather than adhoc encoding, could you send it as bencode?

+ medium._remember_remote_is_before((2, 3))

out of scope for this, but concluding it's older than 2.3 because it doesn't support this particular operation is really not accurate.

+ """See InterRepository.searcH_missing_revision_ids()."""

typo.

+ def test_fetch_everything_backwards_compat(self):
+ """Can fetch with EverythingResult even when the server does not have
+ the Repository.get_stream_2.3 verb.
+ """
+ local = self.make_branch('local')
+ builder = self.make_branch_builder('remote')
+ builder.build_commit(message="Commit.")
+ remote_branch_url = self.smart_server.get_url() + 'remote'
+ remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
+ self.hpss_calls = []
+ local.repository.fetch(remote_branch.repository,
+ fetch_spec=graph.EverythingResult(remote_branch.repository))
+

I don't understand how this tests that the server doesn't have this verb.

=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- doc/en/release-notes/bzr-2.3.txt 2010-12-14 23:32:28 +0000
+++ doc/en/release-notes/bzr-2.3.txt 2010-12-15 05:36:46 +0000
@@ -158,6 +158,11 @@
   crashes when encountering private bugs (they are just displayed as such).
   (Vincent Ladeuil, #354985)

+* The ``revision_id`` parameter of
+ ``Repository.search_missing_revision_ids`` and
+ ``InterRepository.search_missing_revision_ids`` is deprecated. It is
+ replaced by the ``revision_ids`` parameter. (Andrew Bennetts)
+
 Internals
 *********

spiv said on irc that he's testing this; if it turns out to be faster in practice that should be mentioned too. But I guess this patch alone won't change performance.

review: Needs Information
Revision history for this message
Andrew Bennetts (spiv) wrote :

Martin Pool wrote:
> Review: Needs Information
> I think I like the concept of splitting these out into something more like
> objects.
>
> I don't want to hold this hostage but it seems like this would be a good
> moment to add a little developer documentation to the architectural guide
> describing at a high level how fetch works.

Good idea. I'll see what I can write up without spending ages on it.

> + def get_network_struct(self):
> + start_keys = ' '.join(self._recipe[1])
> + stop_keys = ' '.join(self._recipe[2])
> + count = str(self._recipe[3])
> + return (self._recipe[0], '\n'.join((start_keys, stop_keys, count)))
> +
>
> rather than adhoc encoding, could you send it as bencode?

For this struct: no, because this is how existing clients encode SearchResult in
get_stream requests. (And get_parent_map requests, but that's handled
separately in remote.py. See RemoteRepository._serialise_search_recipe.)

> + medium._remember_remote_is_before((2, 3))
>
> out of scope for this, but concluding it's older than 2.3 because it doesn't
> support this particular operation is really not accurate.

Yeah. But that is definitely out of scope :)

> + """See InterRepository.searcH_missing_revision_ids()."""
>
> typo.

Fixed, thanks.

> + def test_fetch_everything_backwards_compat(self):
> + """Can fetch with EverythingResult even when the server does not have
> + the Repository.get_stream_2.3 verb.
> + """
> + local = self.make_branch('local')
> + builder = self.make_branch_builder('remote')
> + builder.build_commit(message="Commit.")
> + remote_branch_url = self.smart_server.get_url() + 'remote'
> + remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
> + self.hpss_calls = []
> + local.repository.fetch(remote_branch.repository,
> + fetch_spec=graph.EverythingResult(remote_branch.repository))
> +
>
> I don't understand how this tests that the server doesn't have this verb.

Oops, out-of-date docstring and test. I didn't need a new verb in the end, I
just added more search types to the existing get_stream_1.19 verb. I'll fix
that: instead I should be testing that a BadSearch reply to the new search
triggers the old requests (i.e. VFS). Probably that's a bit too hard to mock
(because it involves VFS) so I might have to monkeypatch or add a knob to the
get_stream handler class...

[...]
> spiv said on irc that he's testing this; if it turns out to be faster in
> practice that should be mentioned too. But I guess this patch alone won't
> change performance.

I don't expect it to improve performance (unless compared to fetching all the
tags by hand with the existing bzr CLI!) either.

The concern jam had is that querying for all the tags on every update and other
operations might have a noticeable negative impact on branches with many tags
such as emacs. My guess and preliminary results are that this isn't a problem,
but I'll make sure before landing this.

-Andrew.

Revision history for this message
Andrew Bennetts (spiv) wrote :

In the case of lp:emacs there's no significant performance difference. The HPSS call count, memory consumption and wall clock time are unchanged (aside from noise in measurement). The HPSS request for the initial 'bzr branch' is larger, as it requests every rev named in the tags, not just tip, but that's a drop in the bucket vs. fetching the 239M of lp:emacs.

Also, lp:emacs has no tags pointing to missing revs (or even non-ancestry revs), so "bzr pull" works out identically with the new code vs. bzr.dev: all the revisions named in the source's tags are already present, so nothing changes. The wall clock time for the new code is again the same (within the noise of my measurements).

The main case I'd be concerned about is when the source branch has tags that refer to missing revisions. The target will copy those tags, and then on every update/pull re-request those tags from the source repository. Because those lookups in the revisions index will be misses, the server will end up opening every *.rix file. In the HPSS case that will happen server side, so it probably isn't a big concern there, but it might be an issue if using a dumb remote transport. The solution for affected branches is to delete the broken tags, or fill in the missing revisions. That's probably worth the benefit this gives, which is making tags Just Work in more cases. Branches and tags made with this new bzr version will of course fetch all tags by default, so that scenario won't be a concern for them.

In short: I'm confident. If it copes with a branch with as much history and tags as lp:emacs, it probably copes with everything else.

Revision history for this message
Andrew Bennetts (spiv) wrote :

> > I don't want to hold this hostage but it seems like this would be a good
> > moment to add a little developer documentation to the architectural guide
> > describing at a high level how fetch works.
>
> Good idea. I'll see what I can write up without spending ages on it.

Done: <https://code.launchpad.net/~spiv/bzr/fetch-dev-docs/+merge/46053>

I believe all the points/questions raised so far have now been answered.

Revision history for this message
Martin Pool (mbp) wrote :

I think it would be worth adding docstrings on AbstractSearchResult and SearchResult because the names are suggestive but not self-explanatory. The docstrings on the members are good. It is pretty well covered in your document (https://code.launchpad.net/~spiv/bzr/fetch-dev-docs/+merge/46053) so a sentence or two should be enough.

+ if symbol_versioning.deprecated_passed(revision_id):
+ symbol_versioning.warn(
+ 'search_missing_revision_ids(revision_id=...) was '
+ 'deprecated in 2.3. Use revision_ids=[...] instead.',
+ DeprecationWarning, stacklevel=2)

That will now be 2.4. It seems like we ought to have common handling of deprecated parameters. (https://bugs.launchpad.net/bzr/+bug/712922) And there's a couple more.

merge-with-tweaks

Thanks, and sorry for the delay.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/fetch.py'
--- bzrlib/fetch.py 2011-01-14 17:18:23 +0000
+++ bzrlib/fetch.py 2011-02-07 02:57:39 +0000
@@ -55,6 +55,8 @@
5555
56 :param last_revision: If set, try to limit to the data this revision56 :param last_revision: If set, try to limit to the data this revision
57 references.57 references.
58 :param fetch_spec: A SearchResult specifying which revisions to fetch.
59 If set, this overrides last_revision.
58 :param find_ghosts: If True search the entire history for ghosts.60 :param find_ghosts: If True search the entire history for ghosts.
59 """61 """
60 # repository.fetch has the responsibility for short-circuiting62 # repository.fetch has the responsibility for short-circuiting
@@ -93,12 +95,12 @@
93 pb.show_pct = pb.show_count = False95 pb.show_pct = pb.show_count = False
94 try:96 try:
95 pb.update("Finding revisions", 0, 2)97 pb.update("Finding revisions", 0, 2)
96 search = self._revids_to_fetch()98 search_result = self._revids_to_fetch()
97 mutter('fetching: %s', search)99 mutter('fetching: %s', search_result)
98 if search.is_empty():100 if search_result.is_empty():
99 return101 return
100 pb.update("Fetching revisions", 1, 2)102 pb.update("Fetching revisions", 1, 2)
101 self._fetch_everything_for_search(search)103 self._fetch_everything_for_search(search_result)
102 finally:104 finally:
103 pb.finished()105 pb.finished()
104106
@@ -151,18 +153,11 @@
151 install self._last_revision in self.to_repository.153 install self._last_revision in self.to_repository.
152154
153 :returns: A SearchResult of some sort. (Possibly a155 :returns: A SearchResult of some sort. (Possibly a
154 PendingAncestryResult, EmptySearchResult, etc.)156 PendingAncestryResult, EmptySearchResult, etc.)
155 """157 """
156 mutter("self._fetch_spec, self._last_revision: %r, %r",158 mutter("self._fetch_spec, self._last_revision: %r, %r",
157 self._fetch_spec, self._last_revision)159 self._fetch_spec, self._last_revision)
158 get_search_result = getattr(self._fetch_spec, 'get_search_result', None)160 if self._fetch_spec is not None:
159 if get_search_result is not None:
160 mutter(
161 'resolving fetch_spec into search result: %s', self._fetch_spec)
162 # This is EverythingNotInOther or a similar kind of fetch_spec.
163 # Turn it into a search result.
164 return get_search_result()
165 elif self._fetch_spec is not None:
166 # The fetch spec is already a concrete search result.161 # The fetch spec is already a concrete search result.
167 return self._fetch_spec162 return self._fetch_spec
168 elif self._last_revision == NULL_REVISION:163 elif self._last_revision == NULL_REVISION:
@@ -172,11 +167,11 @@
172 elif self._last_revision is not None:167 elif self._last_revision is not None:
173 return graph.NotInOtherForRevs(self.to_repository,168 return graph.NotInOtherForRevs(self.to_repository,
174 self.from_repository, [self._last_revision],169 self.from_repository, [self._last_revision],
175 find_ghosts=self.find_ghosts).get_search_result()170 find_ghosts=self.find_ghosts).execute()
176 else: # self._last_revision is None:171 else: # self._last_revision is None:
177 return graph.EverythingNotInOther(self.to_repository,172 return graph.EverythingNotInOther(self.to_repository,
178 self.from_repository,173 self.from_repository,
179 find_ghosts=self.find_ghosts).get_search_result()174 find_ghosts=self.find_ghosts).execute()
180175
181176
182class Inter1and2Helper(object):177class Inter1and2Helper(object):
183178
=== modified file 'bzrlib/graph.py'
--- bzrlib/graph.py 2011-01-14 17:18:23 +0000
+++ bzrlib/graph.py 2011-02-07 02:57:39 +0000
@@ -1576,14 +1576,15 @@
15761576
1577class AbstractSearch(object):1577class AbstractSearch(object):
15781578
1579 def get_search_result(self):1579 def execute(self):
1580 """Construct a network-ready search result from this search description.1580 """Construct a network-ready search result from this search description.
15811581
1582 This may take some time to search repositories, etc.1582 This may take some time to search repositories, etc.
15831583
1584 :return: A search result.1584 :return: A search result (an object that implements
1585 AbstractSearchResult's API).
1585 """1586 """
1586 raise NotImplementedError(self.get_search_result)1587 raise NotImplementedError(self.execute)
15871588
15881589
1589class SearchResult(AbstractSearchResult):1590class SearchResult(AbstractSearchResult):
@@ -1813,7 +1814,7 @@
1813 self.from_repo = from_repo1814 self.from_repo = from_repo
1814 self.find_ghosts = find_ghosts1815 self.find_ghosts = find_ghosts
18151816
1816 def get_search_result(self):1817 def execute(self):
1817 return self.to_repo.search_missing_revision_ids(1818 return self.to_repo.search_missing_revision_ids(
1818 self.from_repo, find_ghosts=self.find_ghosts)1819 self.from_repo, find_ghosts=self.find_ghosts)
18191820
@@ -1853,7 +1854,7 @@
1853 self.__class__.__name__, self.from_repo, self.to_repo,1854 self.__class__.__name__, self.from_repo, self.to_repo,
1854 self.find_ghosts, reqd_revs_repr, ifp_revs_repr)1855 self.find_ghosts, reqd_revs_repr, ifp_revs_repr)
18551856
1856 def get_search_result(self):1857 def execute(self):
1857 return self.to_repo.search_missing_revision_ids(1858 return self.to_repo.search_missing_revision_ids(
1858 self.from_repo, revision_ids=self.required_ids,1859 self.from_repo, revision_ids=self.required_ids,
1859 if_present_ids=self.if_present_ids, find_ghosts=self.find_ghosts)1860 if_present_ids=self.if_present_ids, find_ghosts=self.find_ghosts)
18601861
=== modified file 'bzrlib/remote.py'
--- bzrlib/remote.py 2011-01-14 17:18:23 +0000
+++ bzrlib/remote.py 2011-02-07 02:57:39 +0000
@@ -1360,7 +1360,7 @@
1360 if symbol_versioning.deprecated_passed(revision_id):1360 if symbol_versioning.deprecated_passed(revision_id):
1361 symbol_versioning.warn(1361 symbol_versioning.warn(
1362 'search_missing_revision_ids(revision_id=...) was '1362 'search_missing_revision_ids(revision_id=...) was '
1363 'deprecated in 2.3. Use revision_ids=[...] instead.',1363 'deprecated in 2.4. Use revision_ids=[...] instead.',
1364 DeprecationWarning, stacklevel=2)1364 DeprecationWarning, stacklevel=2)
1365 if revision_ids is not None:1365 if revision_ids is not None:
1366 raise AssertionError(1366 raise AssertionError(
@@ -1991,11 +1991,11 @@
1991 if isinstance(search, graph.EverythingResult):1991 if isinstance(search, graph.EverythingResult):
1992 error_verb = e.error_from_smart_server.error_verb1992 error_verb = e.error_from_smart_server.error_verb
1993 if error_verb == 'BadSearch':1993 if error_verb == 'BadSearch':
1994 # Pre-2.3 servers don't support this sort of search.1994 # Pre-2.4 servers don't support this sort of search.
1995 # XXX: perhaps falling back to VFS on BadSearch is a1995 # XXX: perhaps falling back to VFS on BadSearch is a
1996 # good idea in general? It might provide a little bit1996 # good idea in general? It might provide a little bit
1997 # of protection against client-side bugs.1997 # of protection against client-side bugs.
1998 medium._remember_remote_is_before((2, 3))1998 medium._remember_remote_is_before((2, 4))
1999 break1999 break
2000 raise2000 raise
2001 else:2001 else:
20022002
=== modified file 'bzrlib/repofmt/knitrepo.py'
--- bzrlib/repofmt/knitrepo.py 2010-12-21 06:10:11 +0000
+++ bzrlib/repofmt/knitrepo.py 2011-02-07 02:57:39 +0000
@@ -542,7 +542,7 @@
542 if symbol_versioning.deprecated_passed(revision_id):542 if symbol_versioning.deprecated_passed(revision_id):
543 symbol_versioning.warn(543 symbol_versioning.warn(
544 'search_missing_revision_ids(revision_id=...) was '544 'search_missing_revision_ids(revision_id=...) was '
545 'deprecated in 2.3. Use revision_ids=[...] instead.',545 'deprecated in 2.4. Use revision_ids=[...] instead.',
546 DeprecationWarning, stacklevel=2)546 DeprecationWarning, stacklevel=2)
547 if revision_ids is not None:547 if revision_ids is not None:
548 raise AssertionError(548 raise AssertionError(
549549
=== modified file 'bzrlib/repofmt/weaverepo.py'
--- bzrlib/repofmt/weaverepo.py 2011-01-14 17:18:23 +0000
+++ bzrlib/repofmt/weaverepo.py 2011-02-07 02:57:39 +0000
@@ -826,7 +826,7 @@
826 if symbol_versioning.deprecated_passed(revision_id):826 if symbol_versioning.deprecated_passed(revision_id):
827 symbol_versioning.warn(827 symbol_versioning.warn(
828 'search_missing_revision_ids(revision_id=...) was '828 'search_missing_revision_ids(revision_id=...) was '
829 'deprecated in 2.3. Use revision_ids=[...] instead.',829 'deprecated in 2.4. Use revision_ids=[...] instead.',
830 DeprecationWarning, stacklevel=2)830 DeprecationWarning, stacklevel=2)
831 if revision_ids is not None:831 if revision_ids is not None:
832 raise AssertionError(832 raise AssertionError(
833833
=== modified file 'bzrlib/repository.py'
--- bzrlib/repository.py 2011-01-19 23:00:12 +0000
+++ bzrlib/repository.py 2011-02-07 02:57:39 +0000
@@ -1608,7 +1608,7 @@
1608 if symbol_versioning.deprecated_passed(revision_id):1608 if symbol_versioning.deprecated_passed(revision_id):
1609 symbol_versioning.warn(1609 symbol_versioning.warn(
1610 'search_missing_revision_ids(revision_id=...) was '1610 'search_missing_revision_ids(revision_id=...) was '
1611 'deprecated in 2.3. Use revision_ids=[...] instead.',1611 'deprecated in 2.4. Use revision_ids=[...] instead.',
1612 DeprecationWarning, stacklevel=3)1612 DeprecationWarning, stacklevel=3)
1613 if revision_ids is not None:1613 if revision_ids is not None:
1614 raise AssertionError(1614 raise AssertionError(
@@ -3526,7 +3526,7 @@
3526 if symbol_versioning.deprecated_passed(revision_id):3526 if symbol_versioning.deprecated_passed(revision_id):
3527 symbol_versioning.warn(3527 symbol_versioning.warn(
3528 'search_missing_revision_ids(revision_id=...) was '3528 'search_missing_revision_ids(revision_id=...) was '
3529 'deprecated in 2.3. Use revision_ids=[...] instead.',3529 'deprecated in 2.4. Use revision_ids=[...] instead.',
3530 DeprecationWarning, stacklevel=2)3530 DeprecationWarning, stacklevel=2)
3531 if revision_ids is not None:3531 if revision_ids is not None:
3532 raise AssertionError(3532 raise AssertionError(
35333533
=== modified file 'bzrlib/tests/per_interrepository/test_interrepository.py'
--- bzrlib/tests/per_interrepository/test_interrepository.py 2011-01-14 17:18:23 +0000
+++ bzrlib/tests/per_interrepository/test_interrepository.py 2011-02-07 02:57:39 +0000
@@ -138,7 +138,7 @@
138 find_ghosts=False)138 find_ghosts=False)
139 self.callDeprecated(139 self.callDeprecated(
140 ['search_missing_revision_ids(revision_id=...) was deprecated in '140 ['search_missing_revision_ids(revision_id=...) was deprecated in '
141 '2.3. Use revision_ids=[...] instead.'],141 '2.4. Use revision_ids=[...] instead.'],
142 self.assertRaises, errors.NoSuchRevision,142 self.assertRaises, errors.NoSuchRevision,
143 repo_b.search_missing_revision_ids, repo_a, revision_id='pizza',143 repo_b.search_missing_revision_ids, repo_a, revision_id='pizza',
144 find_ghosts=False)144 find_ghosts=False)
145145
=== modified file 'bzrlib/tests/test_remote.py'
--- bzrlib/tests/test_remote.py 2011-01-14 17:18:23 +0000
+++ bzrlib/tests/test_remote.py 2011-02-07 02:57:39 +0000
@@ -3211,15 +3211,15 @@
3211 override_existing=True)3211 override_existing=True)
32123212
3213 def test_fetch_everything_backwards_compat(self):3213 def test_fetch_everything_backwards_compat(self):
3214 """Can fetch with EverythingResult even with pre 2.3 servers.3214 """Can fetch with EverythingResult even with pre 2.4 servers.
3215 3215
3216 Pre-2.3 do not support 'everything' searches with the3216 Pre-2.4 do not support 'everything' searches with the
3217 Repository.get_stream_1.19 verb.3217 Repository.get_stream_1.19 verb.
3218 """3218 """
3219 verb_log = []3219 verb_log = []
3220 class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):3220 class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
3221 """A version of the Repository.get_stream_1.19 verb patched to3221 """A version of the Repository.get_stream_1.19 verb patched to
3222 reject 'everything' searches the way 2.2 and earlier do.3222 reject 'everything' searches the way 2.3 and earlier do.
3223 """3223 """
3224 def recreate_search(self, repository, search_bytes, discard_excess=False):3224 def recreate_search(self, repository, search_bytes, discard_excess=False):
3225 verb_log.append(search_bytes.split('\n', 1)[0])3225 verb_log.append(search_bytes.split('\n', 1)[0])
32263226
=== modified file 'doc/en/release-notes/bzr-2.3.txt'
--- doc/en/release-notes/bzr-2.3.txt 2011-02-03 05:13:46 +0000
+++ doc/en/release-notes/bzr-2.3.txt 2011-02-07 02:57:39 +0000
@@ -275,11 +275,6 @@
275 crashes when encountering private bugs (they are just displayed as such).275 crashes when encountering private bugs (they are just displayed as such).
276 (Vincent Ladeuil, #354985)276 (Vincent Ladeuil, #354985)
277277
278* The ``revision_id`` parameter of
279 ``Repository.search_missing_revision_ids`` and
280 ``InterRepository.search_missing_revision_ids`` is deprecated. It is
281 replaced by the ``revision_ids`` parameter. (Andrew Bennetts)
282
283Internals278Internals
284*********279*********
285280
286281
=== modified file 'doc/en/release-notes/bzr-2.4.txt'
--- doc/en/release-notes/bzr-2.4.txt 2011-02-03 05:46:08 +0000
+++ doc/en/release-notes/bzr-2.4.txt 2011-02-07 02:57:39 +0000
@@ -94,6 +94,11 @@
94* Added ``bzrlib.mergetools`` module with helper functions for working with94* Added ``bzrlib.mergetools`` module with helper functions for working with
95 the list of external merge tools. (Gordon Tyler, #489915)95 the list of external merge tools. (Gordon Tyler, #489915)
9696
97* The ``revision_id`` parameter of
98 ``Repository.search_missing_revision_ids`` and
99 ``InterRepository.search_missing_revision_ids`` is deprecated. It is
100 replaced by the ``revision_ids`` parameter. (Andrew Bennetts)
101
97Internals102Internals
98*********103*********
99104