Mercurial > public > mercurial-scm > hg
comparison mercurial/wireproto.py @ 33766:4c706037adef
wireproto: overhaul iterating batcher code (API)
The remote batching code is difficult to read. Let's improve it.
As part of the refactor, the future returned by method calls on
batchiter() instances is now populated. However, you still need to
consume the results() generator for the future to be set. But at
least now we can stuff the future somewhere and not have to worry
about aligning method call order with result order since you can
use a future to hold the result.
Also as part of the change, we now verify that @batchable generators
yield exactly 2 values. In other words, we enforce their API.
The non-iter batcher has been unused since b6e71f8af5b8. And to my
surprise we had no explicit unit test coverage of it! test-batching.py
has been overhauled to use the iterating batcher.
Since the iterating batcher doesn't allow non-batchable method
calls nor local calls, tests have been updated to reflect reality.
The iterating batcher has been used for multiple releases apparently
without major issue. So this shouldn't cause alarm.
.. api::
@peer.batchable functions must now yield exactly 2 values
Differential Revision: https://phab.mercurial-scm.org/D319
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 09 Aug 2017 23:29:30 -0700 |
parents | e2fc2122029c |
children | b47fe9733d76 |
comparison
equal
deleted
inserted
replaced
33765:e2fc2122029c | 33766:4c706037adef |
---|---|
131 """Break the batch request into many patch calls and pipeline them. | 131 """Break the batch request into many patch calls and pipeline them. |
132 | 132 |
133 This is mostly valuable over http where request sizes can be | 133 This is mostly valuable over http where request sizes can be |
134 limited, but can be used in other places as well. | 134 limited, but can be used in other places as well. |
135 """ | 135 """ |
136 req, rsp = [], [] | 136 # 2-tuple of (command, arguments) that represents what will be |
137 for name, args, opts, resref in self.calls: | 137 # sent over the wire. |
138 mtd = getattr(self._remote, name) | 138 requests = [] |
139 | |
140 # 4-tuple of (command, final future, @batchable generator, remote | |
141 # future). | |
142 results = [] | |
143 | |
144 for command, args, opts, finalfuture in self.calls: | |
145 mtd = getattr(self._remote, command) | |
139 batchable = mtd.batchable(mtd.im_self, *args, **opts) | 146 batchable = mtd.batchable(mtd.im_self, *args, **opts) |
140 encargsorres, encresref = next(batchable) | 147 |
141 assert encresref | 148 commandargs, fremote = next(batchable) |
142 req.append((name, encargsorres)) | 149 assert fremote |
143 rsp.append((batchable, encresref)) | 150 requests.append((command, commandargs)) |
144 if req: | 151 results.append((command, finalfuture, batchable, fremote)) |
145 self._resultiter = self._remote._submitbatch(req) | 152 |
146 self._rsp = rsp | 153 if requests: |
154 self._resultiter = self._remote._submitbatch(requests) | |
155 | |
156 self._results = results | |
147 | 157 |
148 def results(self): | 158 def results(self): |
149 for (batchable, encresref), encres in itertools.izip( | 159 for command, finalfuture, batchable, remotefuture in self._results: |
150 self._rsp, self._resultiter): | 160 # Get the raw result, set it in the remote future, feed it |
151 encresref.set(encres) | 161 # back into the @batchable generator so it can be decoded, and |
152 yield next(batchable) | 162 # set the result on the final future to this value. |
163 remoteresult = next(self._resultiter) | |
164 remotefuture.set(remoteresult) | |
165 finalfuture.set(next(batchable)) | |
166 | |
167 # Verify our @batchable generators only emit 2 values. | |
168 try: | |
169 next(batchable) | |
170 except StopIteration: | |
171 pass | |
172 else: | |
173 raise error.ProgrammingError('%s @batchable generator emitted ' | |
174 'unexpected value count' % command) | |
175 | |
176 yield finalfuture.value | |
153 | 177 |
154 # Forward a couple of names from peer to make wireproto interactions | 178 # Forward a couple of names from peer to make wireproto interactions |
155 # slightly more sensible. | 179 # slightly more sensible. |
156 batchable = peer.batchable | 180 batchable = peer.batchable |
157 future = peer.future | 181 future = peer.future |