worker: implement _blockingreader.readinto() (issue6444)
authorManuel Jacob <me@manueljacob.de>
Sun, 22 May 2022 00:10:58 +0200
changeset 49233 520722523955
parent 49232 4c57ce494a4e
child 49235 72ff7cd05176
worker: implement _blockingreader.readinto() (issue6444) The core logic for readinto() was already implemented in read(), so this is mostly extracting that code into its own method. Another fix for issue6444 was committed to the stable branch: 2fe4efaa59af. That is a minimal fix that implements readinto() only on Python versions that require readinto() (3.8.0 and 3.8.1), which is the right approach for the stable branch. However, I think that this changeset has its value. It improves performance in cases when pickle can use readinto(), it reduces code duplication compared to the other patch, and by defining readinto() on all Python versions, it makes behavior more consistent across all Python versions. This changesets reverts the other change.
mercurial/worker.py
--- a/mercurial/worker.py	Sat May 21 23:31:30 2022 +0200
+++ b/mercurial/worker.py	Sun May 22 00:10:58 2022 +0200
@@ -79,35 +79,12 @@
     def __init__(self, wrapped):
         self._wrapped = wrapped
 
-    # Do NOT implement readinto() by making it delegate to
-    # _wrapped.readinto(), since that is unbuffered. The unpickler is fine
-    # with just read() and readline(), so we don't need to implement it.
-
-    if (3, 8, 0) <= sys.version_info[:3] < (3, 8, 2):
-
-        # This is required for python 3.8, prior to 3.8.2.  See issue6444.
-        def readinto(self, b):
-            pos = 0
-            size = len(b)
-
-            while pos < size:
-                ret = self._wrapped.readinto(b[pos:])
-                if not ret:
-                    break
-                pos += ret
-
-            return pos
-
     def readline(self):
         return self._wrapped.readline()
 
-    # issue multiple reads until size is fulfilled (or EOF is encountered)
-    def read(self, size=-1):
-        if size < 0:
-            return self._wrapped.readall()
-
-        buf = bytearray(size)
+    def readinto(self, buf):
         pos = 0
+        size = len(buf)
 
         with memoryview(buf) as view:
             while pos < size:
@@ -117,7 +94,16 @@
                     break
                 pos += ret
 
-        del buf[pos:]
+        return pos
+
+    # issue multiple reads until size is fulfilled (or EOF is encountered)
+    def read(self, size=-1):
+        if size < 0:
+            return self._wrapped.readall()
+
+        buf = bytearray(size)
+        n_read = self.readinto(buf)
+        del buf[n_read:]
         return bytes(buf)