Merge lp:~jameinel/bzr/2.1-categorize-requests-819604 into lp:bzr/2.1

Proposed by John A Meinel
Status: Work in progress
Proposed branch: lp:~jameinel/bzr/2.1-categorize-requests-819604
Merge into: lp:bzr/2.1
Prerequisite: lp:~jameinel/bzr/2.1-client-reconnect-819604
Diff against target: 315 lines (+148/-95)
2 files modified
bzrlib/smart/request.py (+138/-95)
bzrlib/tests/test_smart_request.py (+10/-0)
To merge this branch: bzr merge lp:~jameinel/bzr/2.1-categorize-requests-819604
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Martin Pool Approve
Martin Packman (community) Approve
Review via email: mp+78708@code.launchpad.net

Commit message

Bug #819604, categorize all smart Requests as to their safety for retrying them automatically.

Description of the change

1) I analyzed all of the requests that are currently registered as to whether they are safe or not to retry. I ended up with 4 categories:

# safe The request is strictly idempotent, calling it twice results in
# the same result as calling it one time. This includes all read-only
# requests, and write requests like 'put' where the end result is
# identical content.
# unsafe A request which is unsafe means that state is updated in a way that
# replaying that request results in a different state. For example
# 'append' writes more bytes to a given file. If append succeeds, it
# moves the file pointer.
# semi This is a request that isn't strictly idempotent, but doesn't
# result in corruption if it is retried. This is for things like
# 'lock' and 'unlock'. If you call lock, it updates the disk
# structure. If you fail to read the response, you won't be able to
# use the lock, because you don't have the lock token. Calling lock
# again will fail, because the lock is already taken. However, we
# can't tell if the server received our request or not. If it didn't,
# then retrying the request is fine, as it will actually do what we
# want. If it did, we will interrupt the current operation, but we
# are no worse off than interrupting the current operation because of
# a ConnectionReset.
# stream This is a request that takes a stream that cannot be restarted if
# consumed. This request is 'safe' in that if we determine the
# connection is closed before we consume the stream, we can try
# again.

2) The retry code will ultimately only care if something is 'unsafe' or not, so we could simplify this list if we wanted. Or we could extend it to split 'safe' into differentiating between 'read-only' and 'idempotent'.

One interesting potential from this classification, is that we could actually test it. Specifically, for each request, we set up a RemoteRepository in some sort of state. We could then create a test that:
 a) for 'read-only', after the request is sent, there is no change on disk.
 b) for 'idempotent' there is a change, however, sending the request a second time, there is no change.
 c) for 'semi', there is some change on disk, sending the request a second time causes a client-side failure (exception is raised)
 d) for 'stream', I'm not really sure
 e) for 'unsafe' we could confirm that sending the request once results in a change, and sending it again, results in yet-another change.

However, the test suite setup is non-trivial, since you need specific arguments for every function. Which is an awful lot of scenarios to describe.

3) I decided to add this to registry, rather that putting it on the classes themselves. Either would be fine, as we only need to lookup one request at runtime that actually got ConnectionReset. The main reason I went this route is that I want to make sure a human looks at every request and determines its safety. Adding it as a class attribute tends to leave it as the default from inheritance, which makes it a little too easy to mark something safe when it isn't. And if you get it wrong, this is something that only causes corruption when you get a ConnectionReset at exactly the right time. So really hard to debug and diagnose.

4) This is one of those patches that will definitely need to be updated to merge it to newer versions of bzr, since it touches so many lines of code, and we are very likely to have added new RPCs since bzr 2.1.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

I like this, it's good documentation.

Miscellaneous gripe, the word 'safe' is overused in naming things. It requires context to know what it really means, and that tends to be lost when if the terminology spreads to multiple places.

review: Approve
Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 10/8/2011 10:36 PM, Martin Packman wrote:
> Review: Approve
>
> I like this, it's good documentation.
>
> Miscellaneous gripe, the word 'safe' is overused in naming things.
> It requires context to know what it really means, and that tends to
> be lost when if the terminology spreads to multiple places.

What would you prefer? 'readonly' and 'idempotent'?

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk6Qu+cACgkQJdeBCYSNAAOs+ACgi8HFJBojvw0iped3kFIdhmbL
jz8AnilOZIjH01WF61WxA0eWAmQ4/N0N
=BPTN
-----END PGP SIGNATURE-----

Revision history for this message
Martin Packman (gz) wrote :

> What would you prefer? 'readonly' and 'idempotent'?

I think terms like those are clearer if they're going to be used in more than one module. As it stands with the usage being all in one place under a nice clear comment I think the current terms are fine.

Revision history for this message
John A Meinel (jameinel) wrote :

I switched to 'read' and 'idem', because the commentary on the bug was to add the ability to disable 'semivfs' (which I also added). So that not-strictly-safe VFS operations can be disabled.

Since I got rid of 'safe', I got rid of 'unsafe' and made it 'mutate'.

So that leaves us at:

not-safe-to-retry: mutate, semivfs
safe-to-retry: semi, idem, read, stream[1]

[1] until you start consuming the stream.

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

On 8 October 2011 23:01, John A Meinel <email address hidden> wrote:
> John A Meinel has proposed merging lp:~jameinel/bzr/2.1-categorize-requests-819604 into lp:bzr/2.1 with lp:~jameinel/bzr/2.1-client-reconnect-819604 as a prerequisite.
>
> Requested reviews:
>  bzr-core (bzr-core)
>
> For more details, see:
> https://code.launchpad.net/~jameinel/bzr/2.1-categorize-requests-819604/+merge/78708
>
> 1) I analyzed all of the requests that are currently registered as to whether they are safe or not to retry. I ended up with 4 categories:
>
> #   safe    The request is strictly idempotent, calling it twice results in
> #           the same result as calling it one time. This includes all read-only
> #           requests, and write requests like 'put' where the end result is
> #           identical content.
> #   unsafe  A request which is unsafe means that state is updated in a way that
> #           replaying that request results in a different state. For example
> #           'append' writes more bytes to a given file. If append succeeds, it
> #           moves the file pointer.
> #   semi    This is a request that isn't strictly idempotent, but doesn't
> #           result in corruption if it is retried. This is for things like
> #           'lock' and 'unlock'. If you call lock, it updates the disk
> #           structure. If you fail to read the response, you won't be able to
> #           use the lock, because you don't have the lock token. Calling lock
> #           again will fail, because the lock is already taken. However, we
> #           can't tell if the server received our request or not. If it didn't,
> #           then retrying the request is fine, as it will actually do what we
> #           want. If it did, we will interrupt the current operation, but we
> #           are no worse off than interrupting the current operation because of
> #           a ConnectionReset.
> #   stream  This is a request that takes a stream that cannot be restarted if
> #           consumed. This request is 'safe' in that if we determine the
> #           connection is closed before we consume the stream, we can try
> #           again.

[tweak] "consume the stream" or "start sending the stream"?

The classification looks ok to me too.

You might want to ask spiv too but

  vote approve

review: Approve
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

FWIW this looks good to me too and since both Martins have already approved it too I'm going to mark it approved.

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

sent to pqm by email

Revision history for this message
John A Meinel (jameinel) wrote :

I'm pretty sure this had a prerequisite branch that wasn't approved or I
would have sent it. Am I wrong? I'm certainly happy to see stuff get landed
where we can.

John
=:->
On Nov 11, 2011 5:15 AM, "Martin Pool" <email address hidden> wrote:

> sent to pqm by email
>
> --
>
> https://code.launchpad.net/~jameinel/bzr/2.1-categorize-requests-819604/+merge/78708
> You are the owner of lp:~jameinel/bzr/2.1-categorize-requests-819604.
>

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

I'm bumping this to WIP until it's well tested in 2.5.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/smart/request.py'
2--- bzrlib/smart/request.py 2010-02-17 17:11:16 +0000
3+++ bzrlib/smart/request.py 2011-10-10 13:07:30 +0000
4@@ -486,152 +486,195 @@
5 return SuccessfulSmartServerResponse((answer,))
6
7
8+# In the 'info' attribute, we store whether this request is 'safe' to retry if
9+# we get a disconnect while reading the response. It can have the values:
10+# read This is purely a read request, so retrying it is perfectly ok.
11+# idem An idempotent write request. Something like 'put' where if you put
12+# the same bytes twice you end up with the same final bytes.
13+# semi This is a request that isn't strictly idempotent, but doesn't
14+# result in corruption if it is retried. This is for things like
15+# 'lock' and 'unlock'. If you call lock, it updates the disk
16+# structure. If you fail to read the response, you won't be able to
17+# use the lock, because you don't have the lock token. Calling lock
18+# again will fail, because the lock is already taken. However, we
19+# can't tell if the server received our request or not. If it didn't,
20+# then retrying the request is fine, as it will actually do what we
21+# want. If it did, we will interrupt the current operation, but we
22+# are no worse off than interrupting the current operation because of
23+# a ConnectionReset.
24+# semivfs Similar to semi, but specific to a Virtual FileSystem request.
25+# stream This is a request that takes a stream that cannot be restarted if
26+# consumed. This request is 'safe' in that if we determine the
27+# connection is closed before we consume the stream, we can try
28+# again.
29+# mutate State is updated in a way that replaying that request results in a
30+# different state. For example 'append' writes more bytes to a given
31+# file. If append succeeds, it moves the file pointer.
32 request_handlers = registry.Registry()
33 request_handlers.register_lazy(
34- 'append', 'bzrlib.smart.vfs', 'AppendRequest')
35+ 'append', 'bzrlib.smart.vfs', 'AppendRequest', info='mutate')
36 request_handlers.register_lazy(
37 'Branch.get_config_file', 'bzrlib.smart.branch',
38- 'SmartServerBranchGetConfigFile')
39+ 'SmartServerBranchGetConfigFile', info='read')
40 request_handlers.register_lazy(
41- 'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
42+ 'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent',
43+ info='read')
44 request_handlers.register_lazy(
45 'Branch.get_tags_bytes', 'bzrlib.smart.branch',
46- 'SmartServerBranchGetTagsBytes')
47+ 'SmartServerBranchGetTagsBytes', info='read')
48 request_handlers.register_lazy(
49 'Branch.set_tags_bytes', 'bzrlib.smart.branch',
50- 'SmartServerBranchSetTagsBytes')
51-request_handlers.register_lazy(
52- 'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
53-request_handlers.register_lazy(
54- 'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
55-request_handlers.register_lazy(
56- 'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
57+ 'SmartServerBranchSetTagsBytes', info='idem')
58+request_handlers.register_lazy(
59+ 'Branch.get_stacked_on_url', 'bzrlib.smart.branch',
60+ 'SmartServerBranchRequestGetStackedOnURL', info='read')
61+request_handlers.register_lazy(
62+ 'Branch.last_revision_info', 'bzrlib.smart.branch',
63+ 'SmartServerBranchRequestLastRevisionInfo', info='read')
64+request_handlers.register_lazy(
65+ 'Branch.lock_write', 'bzrlib.smart.branch',
66+ 'SmartServerBranchRequestLockWrite', info='semi')
67 request_handlers.register_lazy( 'Branch.revision_history',
68- 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
69-request_handlers.register_lazy( 'Branch.set_config_option',
70- 'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOption')
71-request_handlers.register_lazy( 'Branch.set_last_revision',
72- 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
73+ 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory', info='read')
74+request_handlers.register_lazy(
75+ 'Branch.set_config_option', 'bzrlib.smart.branch',
76+ 'SmartServerBranchRequestSetConfigOption', info='idem')
77+request_handlers.register_lazy(
78+ 'Branch.set_last_revision', 'bzrlib.smart.branch',
79+ 'SmartServerBranchRequestSetLastRevision', info='idem')
80 request_handlers.register_lazy(
81 'Branch.set_last_revision_info', 'bzrlib.smart.branch',
82- 'SmartServerBranchRequestSetLastRevisionInfo')
83+ 'SmartServerBranchRequestSetLastRevisionInfo', info='idem')
84 request_handlers.register_lazy(
85 'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
86- 'SmartServerBranchRequestSetLastRevisionEx')
87+ 'SmartServerBranchRequestSetLastRevisionEx', info='idem')
88 request_handlers.register_lazy(
89 'Branch.set_parent_location', 'bzrlib.smart.branch',
90- 'SmartServerBranchRequestSetParentLocation')
91+ 'SmartServerBranchRequestSetParentLocation', info='idem')
92 request_handlers.register_lazy(
93- 'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
94+ 'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock',
95+ info='semi')
96 request_handlers.register_lazy(
97 'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
98- 'SmartServerBzrDirRequestCloningMetaDir')
99+ 'SmartServerBzrDirRequestCloningMetaDir', info='read')
100 request_handlers.register_lazy(
101 'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
102- 'SmartServerRequestCreateBranch')
103+ 'SmartServerRequestCreateBranch', info='semi')
104 request_handlers.register_lazy(
105 'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
106- 'SmartServerRequestCreateRepository')
107+ 'SmartServerRequestCreateRepository', info='semi')
108 request_handlers.register_lazy(
109 'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
110- 'SmartServerRequestFindRepositoryV1')
111+ 'SmartServerRequestFindRepositoryV1', info='read')
112 request_handlers.register_lazy(
113 'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
114- 'SmartServerRequestFindRepositoryV2')
115+ 'SmartServerRequestFindRepositoryV2', info='read')
116 request_handlers.register_lazy(
117 'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
118- 'SmartServerRequestFindRepositoryV3')
119+ 'SmartServerRequestFindRepositoryV3', info='read')
120 request_handlers.register_lazy(
121 'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
122- 'SmartServerBzrDirRequestConfigFile')
123+ 'SmartServerBzrDirRequestConfigFile', info='read')
124 request_handlers.register_lazy(
125 'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
126- 'SmartServerRequestInitializeBzrDir')
127+ 'SmartServerRequestInitializeBzrDir', info='semi')
128 request_handlers.register_lazy(
129 'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
130- 'SmartServerRequestBzrDirInitializeEx')
131-request_handlers.register_lazy(
132- 'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
133-request_handlers.register_lazy(
134- 'BzrDir.open_2.1', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir_2_1')
135+ 'SmartServerRequestBzrDirInitializeEx', info='semi')
136+request_handlers.register_lazy(
137+ 'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir',
138+ info='read')
139+request_handlers.register_lazy(
140+ 'BzrDir.open_2.1', 'bzrlib.smart.bzrdir',
141+ 'SmartServerRequestOpenBzrDir_2_1', info='read')
142 request_handlers.register_lazy(
143 'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
144- 'SmartServerRequestOpenBranch')
145+ 'SmartServerRequestOpenBranch', info='read')
146 request_handlers.register_lazy(
147 'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
148- 'SmartServerRequestOpenBranchV2')
149+ 'SmartServerRequestOpenBranchV2', info='read')
150 request_handlers.register_lazy(
151 'BzrDir.open_branchV3', 'bzrlib.smart.bzrdir',
152- 'SmartServerRequestOpenBranchV3')
153-request_handlers.register_lazy(
154- 'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
155-request_handlers.register_lazy(
156- 'get', 'bzrlib.smart.vfs', 'GetRequest')
157-request_handlers.register_lazy(
158- 'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
159-request_handlers.register_lazy(
160- 'has', 'bzrlib.smart.vfs', 'HasRequest')
161-request_handlers.register_lazy(
162- 'hello', 'bzrlib.smart.request', 'HelloRequest')
163-request_handlers.register_lazy(
164- 'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
165-request_handlers.register_lazy(
166- 'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
167-request_handlers.register_lazy(
168- 'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
169-request_handlers.register_lazy(
170- 'move', 'bzrlib.smart.vfs', 'MoveRequest')
171-request_handlers.register_lazy(
172- 'put', 'bzrlib.smart.vfs', 'PutRequest')
173-request_handlers.register_lazy(
174- 'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
175-request_handlers.register_lazy(
176- 'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
177-request_handlers.register_lazy(
178- 'rename', 'bzrlib.smart.vfs', 'RenameRequest')
179+ 'SmartServerRequestOpenBranchV3', info='read')
180+request_handlers.register_lazy(
181+ 'delete', 'bzrlib.smart.vfs', 'DeleteRequest', info='semivfs')
182+request_handlers.register_lazy(
183+ 'get', 'bzrlib.smart.vfs', 'GetRequest', info='read')
184+request_handlers.register_lazy(
185+ 'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest', info='read')
186+request_handlers.register_lazy(
187+ 'has', 'bzrlib.smart.vfs', 'HasRequest', info='read')
188+request_handlers.register_lazy(
189+ 'hello', 'bzrlib.smart.request', 'HelloRequest', info='read')
190+request_handlers.register_lazy(
191+ 'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest',
192+ info='read')
193+request_handlers.register_lazy(
194+ 'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest', info='read')
195+request_handlers.register_lazy(
196+ 'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest', info='semivfs')
197+request_handlers.register_lazy(
198+ 'move', 'bzrlib.smart.vfs', 'MoveRequest', info='semivfs')
199+request_handlers.register_lazy(
200+ 'put', 'bzrlib.smart.vfs', 'PutRequest', info='idem')
201+request_handlers.register_lazy(
202+ 'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest', info='idem')
203+request_handlers.register_lazy(
204+ 'readv', 'bzrlib.smart.vfs', 'ReadvRequest', info='read')
205+request_handlers.register_lazy(
206+ 'rename', 'bzrlib.smart.vfs', 'RenameRequest', info='semivfs')
207 request_handlers.register_lazy(
208 'PackRepository.autopack', 'bzrlib.smart.packrepository',
209- 'SmartServerPackRepositoryAutopack')
210-request_handlers.register_lazy('Repository.gather_stats',
211- 'bzrlib.smart.repository',
212- 'SmartServerRepositoryGatherStats')
213-request_handlers.register_lazy('Repository.get_parent_map',
214- 'bzrlib.smart.repository',
215- 'SmartServerRepositoryGetParentMap')
216-request_handlers.register_lazy(
217- 'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
218-request_handlers.register_lazy(
219- 'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
220-request_handlers.register_lazy(
221- 'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
222-request_handlers.register_lazy(
223- 'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
224-request_handlers.register_lazy(
225- 'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
226-request_handlers.register_lazy(
227- 'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
228-request_handlers.register_lazy(
229- 'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
230+ 'SmartServerPackRepositoryAutopack', info='idem')
231+request_handlers.register_lazy(
232+ 'Repository.gather_stats', 'bzrlib.smart.repository',
233+ 'SmartServerRepositoryGatherStats', info='read')
234+request_handlers.register_lazy(
235+ 'Repository.get_parent_map', 'bzrlib.smart.repository',
236+ 'SmartServerRepositoryGetParentMap', info='read')
237+request_handlers.register_lazy(
238+ 'Repository.get_revision_graph', 'bzrlib.smart.repository',
239+ 'SmartServerRepositoryGetRevisionGraph', info='read')
240+request_handlers.register_lazy(
241+ 'Repository.has_revision', 'bzrlib.smart.repository',
242+ 'SmartServerRequestHasRevision', info='read')
243+request_handlers.register_lazy(
244+ 'Repository.insert_stream', 'bzrlib.smart.repository',
245+ 'SmartServerRepositoryInsertStream', info='stream')
246+request_handlers.register_lazy(
247+ 'Repository.insert_stream_1.19', 'bzrlib.smart.repository',
248+ 'SmartServerRepositoryInsertStream_1_19', info='stream')
249+request_handlers.register_lazy(
250+ 'Repository.insert_stream_locked', 'bzrlib.smart.repository',
251+ 'SmartServerRepositoryInsertStreamLocked', info='stream')
252+request_handlers.register_lazy(
253+ 'Repository.is_shared', 'bzrlib.smart.repository',
254+ 'SmartServerRepositoryIsShared', info='read')
255+request_handlers.register_lazy(
256+ 'Repository.lock_write', 'bzrlib.smart.repository',
257+ 'SmartServerRepositoryLockWrite', info='semi')
258 request_handlers.register_lazy(
259 'Repository.set_make_working_trees', 'bzrlib.smart.repository',
260- 'SmartServerRepositorySetMakeWorkingTrees')
261+ 'SmartServerRepositorySetMakeWorkingTrees', info='idem')
262 request_handlers.register_lazy(
263- 'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
264+ 'Repository.unlock', 'bzrlib.smart.repository',
265+ 'SmartServerRepositoryUnlock', info='semi')
266 request_handlers.register_lazy(
267 'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
268- 'SmartServerRepositoryGetRevIdForRevno')
269+ 'SmartServerRepositoryGetRevIdForRevno', info='read')
270 request_handlers.register_lazy(
271 'Repository.get_stream', 'bzrlib.smart.repository',
272- 'SmartServerRepositoryGetStream')
273+ 'SmartServerRepositoryGetStream', info='read')
274 request_handlers.register_lazy(
275 'Repository.get_stream_1.19', 'bzrlib.smart.repository',
276- 'SmartServerRepositoryGetStream_1_19')
277+ 'SmartServerRepositoryGetStream_1_19', info='read')
278 request_handlers.register_lazy(
279 'Repository.tarball', 'bzrlib.smart.repository',
280- 'SmartServerRepositoryTarball')
281-request_handlers.register_lazy(
282- 'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
283-request_handlers.register_lazy(
284- 'stat', 'bzrlib.smart.vfs', 'StatRequest')
285-request_handlers.register_lazy(
286- 'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
287+ 'SmartServerRepositoryTarball', info='read')
288+request_handlers.register_lazy(
289+ 'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest', info='semivfs')
290+request_handlers.register_lazy(
291+ 'stat', 'bzrlib.smart.vfs', 'StatRequest', info='read')
292+request_handlers.register_lazy(
293+ 'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly',
294+ info='read')
295
296=== modified file 'bzrlib/tests/test_smart_request.py'
297--- bzrlib/tests/test_smart_request.py 2009-07-27 02:11:25 +0000
298+++ bzrlib/tests/test_smart_request.py 2011-10-10 13:07:30 +0000
299@@ -109,6 +109,16 @@
300 self.assertEqual(
301 [[transport]] * 3, handler._command.jail_transports_log)
302
303+ def test_all_registered_requests_are_safety_qualified(self):
304+ unclassified_requests = []
305+ allowed_info = ('read', 'idem', 'mutate', 'semivfs', 'semi', 'stream')
306+ for key in request.request_handlers.keys():
307+ info = request.request_handlers.get_info(key)
308+ if info is None or info not in allowed_info:
309+ unclassified_requests.append(key)
310+ if unclassified_requests:
311+ self.fail('These requests were not categorized as safe/unsafe'
312+ ' to retry: %s' % (unclassified_requests,))
313
314
315 class TestSmartRequestHandlerErrorTranslation(TestCase):

Subscribers

People subscribed via source and target branches