]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind: add wrapper for rados_write_op_omap_cmp 48376/head
authorSandy Kaur <sandy.kaur@ibm.com>
Fri, 1 Oct 2021 17:09:42 +0000 (12:09 -0500)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 5 Oct 2022 15:48:27 +0000 (17:48 +0200)
Signed-off-by: Sandy Kaur <sandy.kaur@ibm.com>
(cherry picked from commit c5a45d38d42de896fc989e51a260ba214b67b5e0)

src/pybind/rados/c_rados.pxd
src/pybind/rados/mock_rados.pxi
src/pybind/rados/rados.pyx
src/test/pybind/test_rados.py

index 97ee5d0b9063c5ce846a36bbd1a91900e689b2f8..51564c03c66273541074c4d3a1a4aa9198cd0480 100644 (file)
@@ -31,6 +31,14 @@ cdef extern from "rados/librados.h" nogil:
         _LIBRADOS_OP_FLAG_FADVISE_NOCACHE "LIBRADOS_OP_FLAG_FADVISE_NOCACHE"
 
 
+    enum:
+        _LIBRADOS_CMPXATTR_OP_EQ "LIBRADOS_CMPXATTR_OP_EQ"
+        _LIBRADOS_CMPXATTR_OP_NE "LIBRADOS_CMPXATTR_OP_NE"
+        _LIBRADOS_CMPXATTR_OP_GT "LIBRADOS_CMPXATTR_OP_GT"
+        _LIBRADOS_CMPXATTR_OP_GTE "LIBRADOS_CMPXATTR_OP_GTE"
+        _LIBRADOS_CMPXATTR_OP_LT "LIBRADOS_CMPXATTR_OP_LT"
+        _LIBRADOS_CMPXATTR_OP_LTE "LIBRADOS_CMPXATTR_OP_LTE"
+
     enum:
         _LIBRADOS_OPERATION_NOFLAG "LIBRADOS_OPERATION_NOFLAG"
         _LIBRADOS_OPERATION_BALANCE_READS "LIBRADOS_OPERATION_BALANCE_READS"
@@ -259,6 +267,7 @@ cdef extern from "rados/librados.h" nogil:
     int rados_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, const char * oid, time_t * mtime, int flags)
     int rados_aio_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, time_t *mtime, int flags)
     void rados_write_op_cmpext(rados_write_op_t write_op, const char *cmp_buf, size_t cmp_len, uint64_t off, int *prval)
+    void rados_write_op_omap_cmp(rados_write_op_t write_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval)
     void rados_write_op_omap_set(rados_write_op_t write_op, const char * const* keys, const char * const* vals, const size_t * lens, size_t num)
     void rados_write_op_omap_rm_keys(rados_write_op_t write_op, const char * const* keys, size_t keys_len)
     void rados_write_op_omap_clear(rados_write_op_t write_op)
index 38053af8020e3efa384d3eaad16b6480d07c760e..4c1fe858b1a5fbc9fe0f97ac7db7bb7bf27a2775 100644 (file)
@@ -34,6 +34,15 @@ cdef nogil:
         _LIBRADOS_OP_FLAG_FADVISE_NOCACHE "LIBRADOS_OP_FLAG_FADVISE_NOCACHE"
 
 
+    enum: 
+        _LIBRADOS_CMPXATTR_OP_EQ "LIBRADOS_CMPXATTR_OP_EQ"
+        _LIBRADOS_CMPXATTR_OP_NE "LIBRADOS_CMPXATTR_OP_NE"
+        _LIBRADOS_CMPXATTR_OP_GT "LIBRADOS_CMPXATTR_OP_GT"
+        _LIBRADOS_CMPXATTR_OP_GTE "LIBRADOS_CMPXATTR_OP_GTE"
+        _LIBRADOS_CMPXATTR_OP_LT "LIBRADOS_CMPXATTR_OP_LT"
+        _LIBRADOS_CMPXATTR_OP_LTE "LIBRADOS_CMPXATTR_OP_LTE"
+
+      
     enum:
         _LIBRADOS_OPERATION_NOFLAG "LIBRADOS_OPERATION_NOFLAG"
         _LIBRADOS_OPERATION_BALANCE_READS "LIBRADOS_OPERATION_BALANCE_READS"
@@ -380,6 +389,8 @@ cdef nogil:
         pass
     void rados_write_op_cmpext(rados_write_op_t write_op, const char *cmp_buf, size_t cmp_len, uint64_t off, int *prval):
         pass
+    void rados_write_op_omap_cmp(rados_write_op_t write_op, const char *key, uint8_t comparison_operator, const char *val, size_t val_len, int *prval):
+        pass
     void rados_write_op_omap_set(rados_write_op_t write_op, const char * const* keys, const char * const* vals, const size_t * lens, size_t num):
         pass
     void rados_write_op_omap_rm_keys(rados_write_op_t write_op, const char * const* keys, size_t keys_len):
index 0c300ca4047782b36826b390533f742572145671..67d8a1e2c7e35f38df1817d69515b063cc686576 100644 (file)
@@ -49,6 +49,13 @@ LIBRADOS_OP_FLAG_FADVISE_WILLNEED = _LIBRADOS_OP_FLAG_FADVISE_WILLNEED
 LIBRADOS_OP_FLAG_FADVISE_DONTNEED = _LIBRADOS_OP_FLAG_FADVISE_DONTNEED
 LIBRADOS_OP_FLAG_FADVISE_NOCACHE = _LIBRADOS_OP_FLAG_FADVISE_NOCACHE
 
+LIBRADOS_CMPXATTR_OP_EQ = _LIBRADOS_CMPXATTR_OP_EQ
+LIBRADOS_CMPXATTR_OP_NE = _LIBRADOS_CMPXATTR_OP_NE
+LIBRADOS_CMPXATTR_OP_GT = _LIBRADOS_CMPXATTR_OP_GT
+LIBRADOS_CMPXATTR_OP_GTE = _LIBRADOS_CMPXATTR_OP_GTE
+LIBRADOS_CMPXATTR_OP_LT = _LIBRADOS_CMPXATTR_OP_LT
+LIBRADOS_CMPXATTR_OP_LTE = _LIBRADOS_CMPXATTR_OP_LTE
+
 LIBRADOS_SNAP_HEAD = _LIBRADOS_SNAP_HEAD
 
 LIBRADOS_OPERATION_NOFLAG = _LIBRADOS_OPERATION_NOFLAG
@@ -1910,6 +1917,24 @@ cdef class WriteOp(object):
         with nogil:
             rados_write_op_cmpext(self.write_op, _cmp_buf, _cmp_buf_len, _offset, NULL)
 
+    def omap_cmp(self, key: str, val: str, cmp_op: int = LIBRADOS_CMPXATTR_OP_EQ):
+        """
+        Ensure that an omap key value satisfies comparison
+        :param key: omap key whose associated value is evaluated for comparison
+        :param val: value to compare with
+        :param cmp_op: comparison operator, one of LIBRADOS_CMPXATTR_OP_EQ (1),
+            LIBRADOS_CMPXATTR_OP_GT (3), or LIBRADOS_CMPXATTR_OP_LT (5).
+        """
+        key_raw = cstr(key, 'key')
+        val_raw = cstr(val, 'val')
+        cdef:
+            char *_key = key_raw
+            char *_val = val_raw
+            size_t _val_len = len(val)
+            uint8_t _comparison_operator = cmp_op
+        with nogil:
+            rados_write_op_omap_cmp(self.write_op, _key, _comparison_operator, _val, _val_len, NULL)
+
 class WriteOpCtx(WriteOp, OpCtx):
     """write operation context manager"""
 
index 0996914905656d43a1991e81b42e8671289b40c8..508cbe5ae9e469056a2ed3dd6a59778d746b6cb8 100644 (file)
@@ -5,6 +5,7 @@ from nose.tools import eq_ as eq, ok_ as ok, assert_raises
 from rados import (Rados, Error, RadosStateError, Object, ObjectExists,
                    ObjectNotFound, ObjectBusy, NotConnected,
                    LIBRADOS_ALL_NSPACES, WriteOpCtx, ReadOpCtx, LIBRADOS_CREATE_EXCLUSIVE,
+                   LIBRADOS_CMPXATTR_OP_EQ, LIBRADOS_CMPXATTR_OP_GT, LIBRADOS_CMPXATTR_OP_LT, OSError,
                    LIBRADOS_SNAP_HEAD, LIBRADOS_OPERATION_BALANCE_READS, LIBRADOS_OPERATION_SKIPRWLOCKS, MonitorLog, MAX_ERRNO, NoData, ExtendMismatch)
 from datetime import timedelta
 import time
@@ -598,6 +599,50 @@ class TestIoctx(object):
             self.ioctx.operate_read_op(read_op, "test_obj")
             eq(list(iter), [("4", b"dddd")])
 
+    def test_omap_cmp(self):
+        object_id = 'test'
+        self.ioctx.write(object_id, b'omap_cmp')
+        with WriteOpCtx() as write_op:
+            self.ioctx.set_omap(write_op, ('key1',), ('1',))
+            self.ioctx.operate_write_op(write_op, object_id)
+        with WriteOpCtx() as write_op:
+            write_op.omap_cmp('key1', '1', LIBRADOS_CMPXATTR_OP_EQ)
+            self.ioctx.set_omap(write_op, ('key1',), ('2',))
+            self.ioctx.operate_write_op(write_op, object_id)
+        with ReadOpCtx() as read_op:
+            iter, ret = self.ioctx.get_omap_vals_by_keys(read_op, ('key1',))
+            eq(ret, 0)
+            self.ioctx.operate_read_op(read_op, object_id)
+            eq(list(iter), [('key1', b'2')])
+        with WriteOpCtx() as write_op:
+            write_op.omap_cmp('key1', '1', LIBRADOS_CMPXATTR_OP_GT)
+            self.ioctx.set_omap(write_op, ('key1',), ('3',))
+            self.ioctx.operate_write_op(write_op, object_id)
+        with ReadOpCtx() as read_op:
+            iter, ret = self.ioctx.get_omap_vals_by_keys(read_op, ('key1',))
+            eq(ret, 0)
+            self.ioctx.operate_read_op(read_op, object_id)
+            eq(list(iter), [('key1', b'3')])
+        with WriteOpCtx() as write_op:
+            write_op.omap_cmp('key1', '4', LIBRADOS_CMPXATTR_OP_LT)
+            self.ioctx.set_omap(write_op, ('key1',), ('4',))
+            self.ioctx.operate_write_op(write_op, object_id)
+        with ReadOpCtx() as read_op:
+            iter, ret = self.ioctx.get_omap_vals_by_keys(read_op, ('key1',))
+            eq(ret, 0)
+            self.ioctx.operate_read_op(read_op, object_id)
+            eq(list(iter), [('key1', b'4')])
+        with WriteOpCtx() as write_op:
+            write_op.omap_cmp('key1', '1', LIBRADOS_CMPXATTR_OP_EQ)
+            self.ioctx.set_omap(write_op, ('key1',), ('5',))
+            try:
+                self.ioctx.operate_write_op(write_op, object_id)
+            except (OSError, ExtendMismatch) as e:
+                eq(e.errno, 125)
+            else:
+                message = "omap_cmp did not raise Exception when omap content does not match"
+                raise AssertionError(message)
+
     def test_cmpext_op(self):
         object_id = 'test'
         with WriteOpCtx() as write_op: