peer: add an iterbatcher interface
authorAugie Fackler <augie@google.com>
Tue, 01 Mar 2016 18:39:25 -0500
changeset 28436 8d38eab2777a
parent 28435 176736afa886
child 28437 c3eacee01c7e
peer: add an iterbatcher interface This is very much like ordinary batch(), but it will let me add a mode for batch where we have pathologically large requests which are then handled streamily. This will be a significant improvement for things like remotefilelog, which may want to request thousands of entities at once.
mercurial/peer.py
mercurial/wireproto.py
--- a/mercurial/peer.py	Wed Mar 02 14:18:43 2016 -0500
+++ b/mercurial/peer.py	Tue Mar 01 18:39:25 2016 -0500
@@ -41,6 +41,14 @@
     def submit(self):
         raise NotImplementedError()
 
+class iterbatcher(batcher):
+
+    def submit(self):
+        raise NotImplementedError()
+
+    def results(self):
+        raise NotImplementedError()
+
 class localbatch(batcher):
     '''performs the queued calls directly'''
     def __init__(self, local):
@@ -50,6 +58,19 @@
         for name, args, opts, resref in self.calls:
             resref.set(getattr(self.local, name)(*args, **opts))
 
+class localiterbatcher(iterbatcher):
+    def __init__(self, local):
+        super(iterbatcher, self).__init__()
+        self.local = local
+
+    def submit(self):
+        # submit for a local iter batcher is a noop
+        pass
+
+    def results(self):
+        for name, args, opts, resref in self.calls:
+            yield getattr(self.local, name)(*args, **opts)
+
 def batchable(f):
     '''annotation for batchable methods
 
@@ -91,6 +112,14 @@
     def batch(self):
         return localbatch(self)
 
+    def iterbatch(self):
+        """Batch requests but allow iterating over the results.
+
+        This is to allow interleaving responses with things like
+        progress updates for clients.
+        """
+        return localiterbatcher(self)
+
     def capable(self, name):
         '''tell whether repo supports named capability.
         return False if not supported.
--- a/mercurial/wireproto.py	Wed Mar 02 14:18:43 2016 -0500
+++ b/mercurial/wireproto.py	Tue Mar 01 18:39:25 2016 -0500
@@ -114,6 +114,25 @@
             encresref.set(encres)
             resref.set(batchable.next())
 
+class remoteiterbatcher(peer.iterbatcher):
+    def __init__(self, remote):
+        super(remoteiterbatcher, self).__init__()
+        self._remote = remote
+
+    def submit(self):
+        """Break the batch request into many patch calls and pipeline them.
+
+        This is mostly valuable over http where request sizes can be
+        limited, but can be used in other places as well.
+        """
+        rb = self._remote.batch()
+        rb.calls = self.calls
+        rb.submit()
+
+    def results(self):
+        for name, args, opts, resref in self.calls:
+            yield resref.value
+
 # Forward a couple of names from peer to make wireproto interactions
 # slightly more sensible.
 batchable = peer.batchable
@@ -193,6 +212,9 @@
     def _submitone(self, op, args):
         return self._call(op, **args)
 
+    def iterbatch(self):
+        return remoteiterbatcher(self)
+
     @batchable
     def lookup(self, key):
         self.requirecap('lookup', _('look up remote revision'))