]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/rbd: add image async open and close methods
authorMykola Golub <mgolub@suse.com>
Fri, 23 Oct 2020 10:38:21 +0000 (11:38 +0100)
committerJason Dillaman <dillaman@redhat.com>
Wed, 10 Feb 2021 18:37:15 +0000 (13:37 -0500)
Signed-off-by: Mykola Golub <mgolub@suse.com>
(cherry picked from commit b27db87c0391231b39ecd4b5aacf8ac24193c1cf)

src/pybind/rbd/rbd.pyx
src/test/pybind/test_rbd.py

index be4b94452fcbefe6559b3da0fdd3de622ea50293..466a2ff292c41ffa3779d629382a0bc42bbe53db 100644 (file)
@@ -466,9 +466,20 @@ cdef extern from "rbd/librbd.h" nogil:
                            rbd_image_t *image, const char *snap_name)
     int rbd_open_by_id_read_only(rados_ioctx_t io, const char *image_id,
                                  rbd_image_t *image, const char *snap_name)
+    int rbd_aio_open(rados_ioctx_t io, const char *name, rbd_image_t *image,
+                     const char *snap_name, rbd_completion_t c)
+    int rbd_aio_open_by_id(rados_ioctx_t io, const char *id, rbd_image_t *image,
+                           const char *snap_name, rbd_completion_t c)
+    int rbd_aio_open_read_only(rados_ioctx_t io, const char *name,
+                               rbd_image_t *image, const char *snap_name,
+                               rbd_completion_t c)
+    int rbd_aio_open_by_id_read_only(rados_ioctx_t io, const char *id,
+                                     rbd_image_t *image, const char *snap_name,
+                                     rbd_completion_t c)
     int rbd_features_to_string(uint64_t features, char *str_features, size_t *size)
     int rbd_features_from_string(const char *str_features, uint64_t *features)
     int rbd_close(rbd_image_t image)
+    int rbd_aio_close(rbd_image_t image, rbd_completion_t c)
     int rbd_resize2(rbd_image_t image, uint64_t size, bint allow_shrink,
                     librbd_progress_fn_t cb, void *cbdata)
     int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize)
@@ -2679,6 +2690,45 @@ class RBD(object):
             raise make_ex(ret, 'error getting features bitmask from str')
         return features
 
+    def aio_open_image(self, oncomplete, ioctx, name=None, snapshot=None,
+                       read_only=False, image_id=None):
+        """
+        Asynchronously open the image at the given snapshot.
+        Specify either name or id, otherwise :class:`InvalidArgument` is raised.
+
+        oncomplete will be called with the created Image object as
+        well as the completion:
+
+        oncomplete(completion, image)
+
+        If a snapshot is specified, the image will be read-only, unless
+        :func:`Image.set_snap` is called later.
+
+        If read-only mode is used, metadata for the :class:`Image`
+        object (such as which snapshots exist) may become obsolete. See
+        the C api for more details.
+
+        To clean up from opening the image, :func:`Image.close` or
+        :func:`Image.aio_close` should be called.
+
+        :param oncomplete: what to do when open is complete
+        :type oncomplete: completion
+        :param ioctx: determines which RADOS pool the image is in
+        :type ioctx: :class:`rados.Ioctx`
+        :param name: the name of the image
+        :type name: str
+        :param snapshot: which snapshot to read from
+        :type snaphshot: str
+        :param read_only: whether to open the image in read-only mode
+        :type read_only: bool
+        :param image_id: the id of the image
+        :type image_id: str
+        :returns: :class:`Completion` - the completion object
+        """
+
+        image = Image(ioctx, name, snapshot, read_only, image_id, oncomplete)
+        comp, image._open_completion = image._open_completion, None
+        return comp
 
 cdef class MirrorPeerIterator(object):
     """
@@ -3321,9 +3371,10 @@ cdef class Image(object):
     cdef object name
     cdef object ioctx
     cdef rados_ioctx_t _ioctx
+    cdef Completion _open_completion
 
     def __init__(self, ioctx, name=None, snapshot=None,
-                 read_only=False, image_id=None):
+                 read_only=False, image_id=None, _oncomplete=None):
         """
         Open the image at the given snapshot.
         Specify either name or id, otherwise :class:`InvalidArgument` is raised.
@@ -3369,6 +3420,51 @@ cdef class Image(object):
             char *_name = opt_str(name)
             char *_image_id = opt_str(image_id)
             char *_snapshot = opt_str(snapshot)
+            cdef Completion completion
+
+        if _oncomplete:
+            def oncomplete(completion_v):
+                cdef Completion _completion_v = completion_v
+                return_value = _completion_v.get_return_value()
+                if return_value == 0:
+                    self.closed = False
+                    if name is None:
+                        self.name = self.get_name()
+                return _oncomplete(_completion_v, self)
+
+            completion = self.__get_completion(oncomplete)
+            try:
+                completion.__persist()
+                if read_only:
+                    with nogil:
+                        if name is not None:
+                            ret = rbd_aio_open_read_only(
+                                _ioctx, _name, &self.image, _snapshot,
+                                completion.rbd_comp)
+                        else:
+                            ret = rbd_aio_open_by_id_read_only(
+                                _ioctx, _image_id, &self.image, _snapshot,
+                                completion.rbd_comp)
+                else:
+                    with nogil:
+                        if name is not None:
+                            ret = rbd_aio_open(
+                                _ioctx, _name, &self.image, _snapshot,
+                                completion.rbd_comp)
+                        else:
+                            ret = rbd_aio_open_by_id(
+                                _ioctx, _image_id, &self.image, _snapshot,
+                                completion.rbd_comp)
+                if ret != 0:
+                    raise make_ex(ret, 'error opening image %s at snapshot %s' %
+                                  (self.name, snapshot))
+            except:
+                completion.__unpersist()
+                raise
+
+            self._open_completion = completion
+            return
+
         if read_only:
             with nogil:
                 if name is not None:
@@ -3445,6 +3541,31 @@ cdef class Image(object):
                 raise make_ex(ret, 'error while closing image %s' % (
                               self.name,))
 
+    @requires_not_closed
+    def aio_close(self, oncomplete):
+        """
+        Asynchronously close the image.
+
+        After this is called, this object should not be used.
+
+        :param oncomplete: what to do when close is complete
+        :type oncomplete: completion
+        :returns: :class:`Completion` - the completion object
+        """
+        cdef Completion completion = self.__get_completion(oncomplete)
+        self.closed = True
+        try:
+            completion.__persist()
+            with nogil:
+                ret = rbd_aio_close(self.image, completion.rbd_comp)
+            if ret < 0:
+                raise make_ex(ret, 'error while closing image %s' %
+                              self.name)
+        except:
+            completion.__unpersist()
+            raise
+        return completion
+
     def __dealloc__(self):
         self.close()
 
index 21910078737801c4fdaf8b12ad1e0d757e9ebee7..7242e6646dd5a4f64c7993adcd4aee4a499d8345 100644 (file)
@@ -322,6 +322,40 @@ def test_open_by_id():
                 eq(image.get_name(), image_name)
             RBD().remove(ioctx, image_name)
 
+def test_aio_open():
+    with Rados(conffile='') as cluster:
+        with cluster.open_ioctx(pool_name) as ioctx:
+            image_name = get_temp_image_name()
+            order = 20
+            RBD().create(ioctx, image_name, IMG_SIZE, order)
+
+            # this is a list so that the open_cb() can modify it
+            image = [None]
+            def open_cb(_, image_):
+                image[0] = image_
+
+            comp = RBD().aio_open_image(open_cb, ioctx, image_name)
+            comp.wait_for_complete_and_cb()
+            eq(comp.get_return_value(), 0)
+            eq(sys.getrefcount(comp), 2)
+            assert_not_equal(image[0], None)
+
+            image = image[0]
+            eq(image.get_name(), image_name)
+            check_stat(image.stat(), IMG_SIZE, order)
+
+            closed = [False]
+            def close_cb(_):
+                closed[0] = True
+
+            comp = image.aio_close(close_cb)
+            comp.wait_for_complete_and_cb()
+            eq(comp.get_return_value(), 0)
+            eq(sys.getrefcount(comp), 2)
+            eq(closed[0], True)
+
+            RBD().remove(ioctx, image_name)
+
 def test_remove_dne():
     assert_raises(ImageNotFound, remove_image)