[Libguestfs] [PATCH libnbd 1/5] python: Change aio_buffer into nbd.Buffer class.

Richard W.M. Jones rjones at redhat.com
Sat Aug 10 17:02:56 UTC 2019


Create a class for AIO buffers.  This is a mostly neutral code
refactoring, but we add a convenient function for getting the size of
the buffer (same as previous commit for OCaml).
---
 generator/generator                | 111 +++++++++++++++++------------
 python/handle.c                    |  26 +++++--
 python/t/500-aio-pread.py          |   4 +-
 python/t/505-aio-pread-callback.py |  10 +--
 python/t/510-aio-pwrite.py         |   6 +-
 5 files changed, 96 insertions(+), 61 deletions(-)

diff --git a/generator/generator b/generator/generator
index 26ab365..0107724 100755
--- a/generator/generator
+++ b/generator/generator
@@ -3981,8 +3981,10 @@ raise_exception ()
       pr "extern PyObject *nbd_internal_py_%s (PyObject *self, PyObject *args);\n"
          name;
   ) ([ "create"; "close";
-       "alloc_aio_buffer"; "aio_buffer_from_bytearray";
-       "aio_buffer_to_bytearray" ] @ List.map fst handle_calls);
+       "alloc_aio_buffer";
+       "aio_buffer_from_bytearray";
+       "aio_buffer_to_bytearray";
+       "aio_buffer_size" ] @ List.map fst handle_calls);
 
   pr "\n";
   pr "#endif /* LIBNBD_METHODS_H */\n"
@@ -4009,8 +4011,10 @@ let generate_python_libnbdmod_c () =
       pr "  { (char *) \"%s\", nbd_internal_py_%s, METH_VARARGS, NULL },\n"
          name name;
   ) ([ "create"; "close";
-       "alloc_aio_buffer"; "aio_buffer_from_bytearray";
-       "aio_buffer_to_bytearray" ] @ List.map fst handle_calls);
+       "alloc_aio_buffer";
+       "aio_buffer_from_bytearray";
+       "aio_buffer_to_bytearray";
+       "aio_buffer_size" ] @ List.map fst handle_calls);
   pr "  { NULL, NULL, 0, NULL }\n";
   pr "};\n";
   pr "\n";
@@ -4502,17 +4506,28 @@ Error.__str__ = _str
 
   pr "\
 
-# AIO buffer functions.
-def aio_buffer (len):
-    '''allocate an AIO buffer used for nbd.aio_pread and nbd.aio_pwrite'''
-    return libnbdmod.alloc_aio_buffer (len)
-
-def aio_buffer_from_bytearray (ba):
-    '''create an AIO buffer from a bytearray'''
-    return libnbdmod.aio_buffer_from_bytearray (ba)
-def aio_buffer_to_bytearray (buf):
-    '''copy an AIO buffer into a bytearray'''
-    return libnbdmod.aio_buffer_to_bytearray (buf)
+class Buffer (object):
+    '''Asynchronous I/O persistent buffer'''
+
+    def __init__ (self, len):
+        '''allocate an uninitialized AIO buffer used for nbd.aio_pread'''
+        self._o = libnbdmod.alloc_aio_buffer (len)
+
+    @classmethod
+    def from_bytearray (cls, ba):
+        '''create an AIO buffer from a bytearray'''
+        o = libnbdmod.aio_buffer_from_bytearray (ba)
+        self = cls (0)
+        self._o = o
+        return self
+
+    def to_bytearray (self):
+        '''copy an AIO buffer into a bytearray'''
+        return libnbdmod.aio_buffer_to_bytearray (self._o)
+
+    def size (self):
+        '''return the size of an AIO buffer'''
+        return libnbdmod.aio_buffer_size (self._o)
 
 class NBD (object):
     '''NBD handle'''
@@ -4532,42 +4547,46 @@ class NBD (object):
       let args =
         List.map (
           function
-          | Bool n -> n
-          | BytesIn (n, _) | BytesPersistIn (n, _) -> n
-          | BytesPersistOut (n, _) -> n
-          | BytesOut (_, count) -> count
-          | Closure { cbname } -> cbname
-          | Int n -> n
-          | Int64 n -> n
-          | Path n -> n
-          | SockAddrAndLen (n, _) -> n
-          | String n -> n
-          | StringList n -> n
-          | UInt n -> n
-          | UInt32 n -> n
-          | UInt64 n -> n
+          | Bool n -> n, None, None
+          | BytesIn (n, _) -> n, None, None
+          | BytesOut (_, count) -> count, None, None
+          | BytesPersistIn (n, _) -> n, None, Some (sprintf "%s._o" n)
+          | BytesPersistOut (n, _) -> n, None, Some (sprintf "%s._o" n)
+          | Closure { cbname } -> cbname, None, None
+          | Int n -> n, None, None
+          | Int64 n -> n, None, None
+          | Path n -> n, None, None
+          | SockAddrAndLen (n, _) -> n, None, None
+          | String n -> n, None, None
+          | StringList n -> n, None, None
+          | UInt n -> n, None, None
+          | UInt32 n -> n, None, None
+          | UInt64 n -> n, None, None
         ) args in
       let optargs =
         List.map (
           function
-          | OFlags n -> n, "0"
+          | OFlags n -> n, Some "0", None
         ) optargs in
-      let () =
-        let params = args @ List.map (fun (n, def) -> n ^ "=" ^ def) optargs in
-        let params = List.map ((^) ", ") params in
-        let params = String.concat "" params in
-        pr "    def %s (self%s):\n" name params in
-      let () =
-        let longdesc = Str.global_replace py_fn_rex "C<nbd." longdesc in
-        let longdesc = Str.global_replace py_const_rex "C<" longdesc in
-        let longdesc = pod2text longdesc in
-        pr "        '''▶ %s\n\n%s'''\n"
-           shortdesc (String.concat "\n" longdesc) in
-      let () =
-        let vars = args @ List.map fst optargs in
-        let vars = List.map ((^) ", ") vars in
-        let vars = String.concat "" vars in
-        pr "        return libnbdmod.%s (self._o%s)\n" name vars in
+      let args = args @ optargs in
+      pr "    def %s (self" name;
+      List.iter (
+        function
+        | n, None, _ -> pr ", %s" n
+        | n, Some default, _ -> pr ", %s=%s" n default
+      ) args;
+      pr "):\n";
+      let longdesc = Str.global_replace py_fn_rex "C<nbd." longdesc in
+      let longdesc = Str.global_replace py_const_rex "C<" longdesc in
+      let longdesc = pod2text longdesc in
+      pr "        '''▶ %s\n\n%s'''\n" shortdesc (String.concat "\n" longdesc);
+      pr "        return libnbdmod.%s (self._o" name;
+      List.iter (
+        function
+        | _, _, Some getter -> pr ", %s" getter
+        | n, _, None -> pr ", %s" n
+      ) args;
+      pr ")\n";
       pr "\n"
   ) handle_calls;
 
diff --git a/python/handle.c b/python/handle.c
index 7cff41a..4b510ad 100644
--- a/python/handle.c
+++ b/python/handle.c
@@ -72,7 +72,7 @@ nbd_internal_py_close (PyObject *self, PyObject *args)
   return Py_None;
 }
 
-static char aio_buffer_name[] = "struct py_aio_buffer";
+static const char aio_buffer_name[] = "nbd.Buffer";
 
 struct py_aio_buffer *
 nbd_internal_py_get_aio_buffer (PyObject *capsule)
@@ -89,9 +89,7 @@ free_aio_buffer (PyObject *capsule)
   free (buf);
 }
 
-/* Allocate a persistent buffer used for nbd_aio_pread and
- * nbd_aio_pwrite.
- */
+/* Allocate a persistent buffer used for nbd_aio_pread. */
 PyObject *
 nbd_internal_py_alloc_aio_buffer (PyObject *self, PyObject *args)
 {
@@ -115,7 +113,7 @@ nbd_internal_py_alloc_aio_buffer (PyObject *self, PyObject *args)
     free (buf);
     return NULL;
   }
-  buf->data = calloc (1, buf->len);
+  buf->data = malloc (buf->len);
   if (buf->data == NULL) {
     PyErr_NoMemory ();
     free (buf);
@@ -193,3 +191,21 @@ nbd_internal_py_aio_buffer_to_bytearray (PyObject *self, PyObject *args)
 
   return PyByteArray_FromStringAndSize (buf->data, buf->len);
 }
+
+PyObject *
+nbd_internal_py_aio_buffer_size (PyObject *self, PyObject *args)
+{
+  PyObject *obj;
+  struct py_aio_buffer *buf;
+
+  if (!PyArg_ParseTuple (args,
+                         (char *) "O:nbd_internal_py_aio_buffer_size",
+                         &obj))
+    return NULL;
+
+  buf = nbd_internal_py_get_aio_buffer (obj);
+  if (buf == NULL)
+    return NULL;
+
+  return PyLong_FromSsize_t (buf->len);
+}
diff --git a/python/t/500-aio-pread.py b/python/t/500-aio-pread.py
index 6ff06fd..0c5a07a 100644
--- a/python/t/500-aio-pread.py
+++ b/python/t/500-aio-pread.py
@@ -20,12 +20,12 @@ import nbd
 h = nbd.NBD ()
 h.connect_command (["nbdkit", "-s", "--exit-with-parent", "-v",
                     "pattern", "size=512"])
-buf = nbd.aio_buffer (512)
+buf = nbd.Buffer (512)
 cookie = h.aio_pread (buf, 0)
 while not (h.aio_command_completed (cookie)):
     h.poll (-1)
 
-buf = nbd.aio_buffer_to_bytearray (buf)
+buf = buf.to_bytearray ()
 
 print ("%r" % buf)
 
diff --git a/python/t/505-aio-pread-callback.py b/python/t/505-aio-pread-callback.py
index 9246616..e552db8 100644
--- a/python/t/505-aio-pread-callback.py
+++ b/python/t/505-aio-pread-callback.py
@@ -43,21 +43,21 @@ def callback (user_data, err):
     assert user_data == 42
 
 # First try: succeed in both callbacks
-buf = nbd.aio_buffer (512)
+buf = nbd.Buffer (512)
 cookie = h.aio_pread_structured_callback (buf, 0,
                                           lambda *args: chunk (42, *args),
                                           lambda *args: callback (42, *args))
 while not (h.aio_command_completed (cookie)):
     h.poll (-1)
 
-buf = nbd.aio_buffer_to_bytearray (buf)
+buf = buf.to_bytearray ()
 
 print ("%r" % buf)
 
 assert buf == expected
 
 # Second try: fail only during callback
-buf = nbd.aio_buffer (512)
+buf = nbd.Buffer (512)
 cookie = h.aio_pread_structured_callback (buf, 0,
                                           lambda *args: chunk (42, *args),
                                           lambda *args: callback (43, *args))
@@ -69,7 +69,7 @@ except nbd.Error as ex:
     assert ex.errnum == errno.ENOMEM
 
 # Third try: fail during both
-buf = nbd.aio_buffer (512)
+buf = nbd.Buffer (512)
 cookie = h.aio_pread_structured_callback (buf, 0,
                                           lambda *args: chunk (43, *args),
                                           lambda *args: callback (44, *args))
@@ -81,7 +81,7 @@ except nbd.Error as ex:
     assert ex.errnum == errno.ENOMEM
 
 # Fourth try: fail only during chunk
-buf = nbd.aio_buffer (512)
+buf = nbd.Buffer (512)
 cookie = h.aio_pread_structured_callback (buf, 0,
                                           lambda *args: chunk (43, *args),
                                           lambda *args: callback (42, *args))
diff --git a/python/t/510-aio-pwrite.py b/python/t/510-aio-pwrite.py
index 4bbc494..71aa9ba 100644
--- a/python/t/510-aio-pwrite.py
+++ b/python/t/510-aio-pwrite.py
@@ -33,17 +33,17 @@ h = nbd.NBD ()
 h.connect_command (["nbdkit", "-s", "--exit-with-parent", "-v",
                     "file", datafile])
 
-buf1 = nbd.aio_buffer_from_bytearray (buf)
+buf1 = nbd.Buffer.from_bytearray (buf)
 cookie = h.aio_pwrite (buf1, 0, nbd.CMD_FLAG_FUA)
 while not (h.aio_command_completed (cookie)):
     h.poll (-1)
 
-buf2 = nbd.aio_buffer (512)
+buf2 = nbd.Buffer (512)
 cookie = h.aio_pread (buf2, 0)
 while not (h.aio_command_completed (cookie)):
     h.poll (-1)
 
-assert buf == nbd.aio_buffer_to_bytearray (buf2)
+assert buf == buf2.to_bytearray ()
 
 with open (datafile, "rb") as f:
     content = f.read ()
-- 
2.22.0




More information about the Libguestfs mailing list