Show More
@@ -120,7 +120,6 b' from mercurial import (' | |||||
120 | extensions, |
|
120 | extensions, | |
121 | hg, |
|
121 | hg, | |
122 | localrepo, |
|
122 | localrepo, | |
123 | peer, |
|
|||
124 | phases, |
|
123 | phases, | |
125 | pushkey, |
|
124 | pushkey, | |
126 | pycompat, |
|
125 | pycompat, | |
@@ -354,11 +353,11 b' def localrepolistkeys(orig, self, namesp' | |||||
354 | else: |
|
353 | else: | |
355 | return orig(self, namespace) |
|
354 | return orig(self, namespace) | |
356 |
|
355 | |||
357 | @peer.batchable |
|
356 | @wireprotov1peer.batchable | |
358 | def listkeyspatterns(self, namespace, patterns): |
|
357 | def listkeyspatterns(self, namespace, patterns): | |
359 | if not self.capable('pushkey'): |
|
358 | if not self.capable('pushkey'): | |
360 | yield {}, None |
|
359 | yield {}, None | |
361 | f = peer.future() |
|
360 | f = wireprotov1peer.future() | |
362 | self.ui.debug('preparing listkeys for "%s" with pattern "%s"\n' % |
|
361 | self.ui.debug('preparing listkeys for "%s" with pattern "%s"\n' % | |
363 | (namespace, patterns)) |
|
362 | (namespace, patterns)) | |
364 | yield { |
|
363 | yield { |
@@ -49,7 +49,6 b' from . import (' | |||||
49 | narrowspec, |
|
49 | narrowspec, | |
50 | obsolete, |
|
50 | obsolete, | |
51 | pathutil, |
|
51 | pathutil, | |
52 | peer, |
|
|||
53 | phases, |
|
52 | phases, | |
54 | pushkey, |
|
53 | pushkey, | |
55 | pycompat, |
|
54 | pycompat, | |
@@ -66,6 +65,7 b' from . import (' | |||||
66 | txnutil, |
|
65 | txnutil, | |
67 | util, |
|
66 | util, | |
68 | vfs as vfsmod, |
|
67 | vfs as vfsmod, | |
|
68 | wireprotov1peer, | |||
69 | ) |
|
69 | ) | |
70 | from .utils import ( |
|
70 | from .utils import ( | |
71 | procutil, |
|
71 | procutil, | |
@@ -153,6 +153,20 b" moderncaps = {'lookup', 'branchmap', 'pu" | |||||
153 | 'unbundle'} |
|
153 | 'unbundle'} | |
154 | legacycaps = moderncaps.union({'changegroupsubset'}) |
|
154 | legacycaps = moderncaps.union({'changegroupsubset'}) | |
155 |
|
155 | |||
|
156 | class localiterbatcher(wireprotov1peer.iterbatcher): | |||
|
157 | def __init__(self, local): | |||
|
158 | super(localiterbatcher, self).__init__() | |||
|
159 | self.local = local | |||
|
160 | ||||
|
161 | def submit(self): | |||
|
162 | # submit for a local iter batcher is a noop | |||
|
163 | pass | |||
|
164 | ||||
|
165 | def results(self): | |||
|
166 | for name, args, opts, resref in self.calls: | |||
|
167 | resref.set(getattr(self.local, name)(*args, **opts)) | |||
|
168 | yield resref.value | |||
|
169 | ||||
156 | class localpeer(repository.peer): |
|
170 | class localpeer(repository.peer): | |
157 | '''peer for a local repo; reflects only the most recent API''' |
|
171 | '''peer for a local repo; reflects only the most recent API''' | |
158 |
|
172 | |||
@@ -273,7 +287,7 b' class localpeer(repository.peer):' | |||||
273 | # Begin of peer interface. |
|
287 | # Begin of peer interface. | |
274 |
|
288 | |||
275 | def iterbatch(self): |
|
289 | def iterbatch(self): | |
276 |
return |
|
290 | return localiterbatcher(self) | |
277 |
|
291 | |||
278 | # End of peer interface. |
|
292 | # End of peer interface. | |
279 |
|
293 |
@@ -19,7 +19,6 b' from . import (' | |||||
19 | changegroup as changegroupmod, |
|
19 | changegroup as changegroupmod, | |
20 | encoding, |
|
20 | encoding, | |
21 | error, |
|
21 | error, | |
22 | peer, |
|
|||
23 | pushkey as pushkeymod, |
|
22 | pushkey as pushkeymod, | |
24 | pycompat, |
|
23 | pycompat, | |
25 | repository, |
|
24 | repository, | |
@@ -29,7 +28,76 b' from . import (' | |||||
29 |
|
28 | |||
30 | urlreq = util.urlreq |
|
29 | urlreq = util.urlreq | |
31 |
|
30 | |||
32 | class remoteiterbatcher(peer.iterbatcher): |
|
31 | def batchable(f): | |
|
32 | '''annotation for batchable methods | |||
|
33 | ||||
|
34 | Such methods must implement a coroutine as follows: | |||
|
35 | ||||
|
36 | @batchable | |||
|
37 | def sample(self, one, two=None): | |||
|
38 | # Build list of encoded arguments suitable for your wire protocol: | |||
|
39 | encargs = [('one', encode(one),), ('two', encode(two),)] | |||
|
40 | # Create future for injection of encoded result: | |||
|
41 | encresref = future() | |||
|
42 | # Return encoded arguments and future: | |||
|
43 | yield encargs, encresref | |||
|
44 | # Assuming the future to be filled with the result from the batched | |||
|
45 | # request now. Decode it: | |||
|
46 | yield decode(encresref.value) | |||
|
47 | ||||
|
48 | The decorator returns a function which wraps this coroutine as a plain | |||
|
49 | method, but adds the original method as an attribute called "batchable", | |||
|
50 | which is used by remotebatch to split the call into separate encoding and | |||
|
51 | decoding phases. | |||
|
52 | ''' | |||
|
53 | def plain(*args, **opts): | |||
|
54 | batchable = f(*args, **opts) | |||
|
55 | encargsorres, encresref = next(batchable) | |||
|
56 | if not encresref: | |||
|
57 | return encargsorres # a local result in this case | |||
|
58 | self = args[0] | |||
|
59 | cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr | |||
|
60 | encresref.set(self._submitone(cmd, encargsorres)) | |||
|
61 | return next(batchable) | |||
|
62 | setattr(plain, 'batchable', f) | |||
|
63 | return plain | |||
|
64 | ||||
|
65 | class future(object): | |||
|
66 | '''placeholder for a value to be set later''' | |||
|
67 | def set(self, value): | |||
|
68 | if util.safehasattr(self, 'value'): | |||
|
69 | raise error.RepoError("future is already set") | |||
|
70 | self.value = value | |||
|
71 | ||||
|
72 | class batcher(object): | |||
|
73 | '''base class for batches of commands submittable in a single request | |||
|
74 | ||||
|
75 | All methods invoked on instances of this class are simply queued and | |||
|
76 | return a a future for the result. Once you call submit(), all the queued | |||
|
77 | calls are performed and the results set in their respective futures. | |||
|
78 | ''' | |||
|
79 | def __init__(self): | |||
|
80 | self.calls = [] | |||
|
81 | def __getattr__(self, name): | |||
|
82 | def call(*args, **opts): | |||
|
83 | resref = future() | |||
|
84 | # Please don't invent non-ascii method names, or you will | |||
|
85 | # give core hg a very sad time. | |||
|
86 | self.calls.append((name.encode('ascii'), args, opts, resref,)) | |||
|
87 | return resref | |||
|
88 | return call | |||
|
89 | def submit(self): | |||
|
90 | raise NotImplementedError() | |||
|
91 | ||||
|
92 | class iterbatcher(batcher): | |||
|
93 | ||||
|
94 | def submit(self): | |||
|
95 | raise NotImplementedError() | |||
|
96 | ||||
|
97 | def results(self): | |||
|
98 | raise NotImplementedError() | |||
|
99 | ||||
|
100 | class remoteiterbatcher(iterbatcher): | |||
33 | def __init__(self, remote): |
|
101 | def __init__(self, remote): | |
34 | super(remoteiterbatcher, self).__init__() |
|
102 | super(remoteiterbatcher, self).__init__() | |
35 | self._remote = remote |
|
103 | self._remote = remote | |
@@ -92,11 +160,6 b' class remoteiterbatcher(peer.iterbatcher' | |||||
92 |
|
160 | |||
93 | yield finalfuture.value |
|
161 | yield finalfuture.value | |
94 |
|
162 | |||
95 | # Forward a couple of names from peer to make wireproto interactions |
|
|||
96 | # slightly more sensible. |
|
|||
97 | batchable = peer.batchable |
|
|||
98 | future = peer.future |
|
|||
99 |
|
||||
100 | def encodebatchcmds(req): |
|
163 | def encodebatchcmds(req): | |
101 | """Return a ``cmds`` argument value for the ``batch`` command.""" |
|
164 | """Return a ``cmds`` argument value for the ``batch`` command.""" | |
102 | escapearg = wireprototypes.escapebatcharg |
|
165 | escapearg = wireprototypes.escapebatcharg |
@@ -9,9 +9,10 b' from __future__ import absolute_import, ' | |||||
9 |
|
9 | |||
10 | from mercurial import ( |
|
10 | from mercurial import ( | |
11 | error, |
|
11 | error, | |
12 | peer, |
|
12 | localrepo, | |
13 | util, |
|
13 | util, | |
14 | wireprotov1peer, |
|
14 | wireprotov1peer, | |
|
15 | ||||
15 | ) |
|
16 | ) | |
16 |
|
17 | |||
17 | # equivalent of repo.repository |
|
18 | # equivalent of repo.repository | |
@@ -31,7 +32,7 b' class localthing(thing):' | |||||
31 | return "Hello, %s" % name |
|
32 | return "Hello, %s" % name | |
32 | def batchiter(self): |
|
33 | def batchiter(self): | |
33 | '''Support for local batching.''' |
|
34 | '''Support for local batching.''' | |
34 |
return |
|
35 | return localrepo.localiterbatcher(self) | |
35 |
|
36 | |||
36 | # usage of "thing" interface |
|
37 | # usage of "thing" interface | |
37 | def use(it): |
|
38 | def use(it): | |
@@ -51,7 +52,7 b' def use(it):' | |||||
51 | bar2 = batch.bar(b="Uno", a="Due") |
|
52 | bar2 = batch.bar(b="Uno", a="Due") | |
52 |
|
53 | |||
53 | # Future shouldn't be set until we submit(). |
|
54 | # Future shouldn't be set until we submit(). | |
54 | assert isinstance(foo, peer.future) |
|
55 | assert isinstance(foo, wireprotov1peer.future) | |
55 | assert not util.safehasattr(foo, 'value') |
|
56 | assert not util.safehasattr(foo, 'value') | |
56 | assert not util.safehasattr(bar, 'value') |
|
57 | assert not util.safehasattr(bar, 'value') | |
57 | batch.submit() |
|
58 | batch.submit() | |
@@ -179,16 +180,16 b' class remotething(thing):' | |||||
179 | def batchiter(self): |
|
180 | def batchiter(self): | |
180 | return wireprotov1peer.remoteiterbatcher(self) |
|
181 | return wireprotov1peer.remoteiterbatcher(self) | |
181 |
|
182 | |||
182 | @peer.batchable |
|
183 | @wireprotov1peer.batchable | |
183 | def foo(self, one, two=None): |
|
184 | def foo(self, one, two=None): | |
184 | encargs = [('one', mangle(one),), ('two', mangle(two),)] |
|
185 | encargs = [('one', mangle(one),), ('two', mangle(two),)] | |
185 | encresref = peer.future() |
|
186 | encresref = wireprotov1peer.future() | |
186 | yield encargs, encresref |
|
187 | yield encargs, encresref | |
187 | yield unmangle(encresref.value) |
|
188 | yield unmangle(encresref.value) | |
188 |
|
189 | |||
189 | @peer.batchable |
|
190 | @wireprotov1peer.batchable | |
190 | def bar(self, b, a): |
|
191 | def bar(self, b, a): | |
191 | encresref = peer.future() |
|
192 | encresref = wireprotov1peer.future() | |
192 | yield [('b', mangle(b),), ('a', mangle(a),)], encresref |
|
193 | yield [('b', mangle(b),), ('a', mangle(a),)], encresref | |
193 | yield unmangle(encresref.value) |
|
194 | yield unmangle(encresref.value) | |
194 |
|
195 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now