]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librados: add read xattr functions for c object operations
authorJosh Durgin <josh.durgin@inktank.com>
Fri, 7 Feb 2014 04:03:20 +0000 (20:03 -0800)
committerJosh Durgin <josh.durgin@inktank.com>
Tue, 18 Feb 2014 20:34:33 +0000 (12:34 -0800)
Only implement string xattr comparison by since integer xattr
comparison assumes ceph-encoded integers in little-endian 64 bit
format, which should not be exposed to librados users.

Add an extra callback for getxattr so that we can initialize the
iterator.

Fixes: #7193
Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
src/include/rados/librados.h
src/librados/librados.cc
src/test/librados/c_read_operations.cc

index 29d20858cb37f0b4223d547eda2594e551705682..5143ddc6a9da904e74a41504c58fef946e67ad31 100644 (file)
@@ -239,6 +239,8 @@ typedef void *rados_write_op_t;
  * An object read operation stores a number of operations which can be
  * executed atomically. For usage, see:
  * - Creation and deletion: rados_create_read_op() rados_release_read_op()
+ * - Extended attribute manipulation: rados_read_op_cmpxattr(),
+ *   rados_read_op_getxattr(), rados_read_op_getxattrs()
  * - Object properties: rados_read_op_stat(), rados_read_op_assert_exists()
  * - IO on objects: rados_read_op_read()
  * - Custom operations: rados_read_op_exec(), rados_read_op_exec_user_buf()
@@ -1953,6 +1955,32 @@ void rados_read_op_set_flags(rados_read_op_t read_op, int flags);
  */
 void rados_read_op_assert_exists(rados_read_op_t read_op);
 
+/**
+ * Ensure that the an xattr satisfies a comparison
+ * @param read_op operation to add this action to
+ * @param name name of the xattr to look up
+ * @param comparison_operator currently undocumented, look for
+ * LIBRADOS_CMPXATTR_OP_EQ in librados.h
+ * @param value buffer to compare actual xattr value to
+ * @param value_len length of buffer to compare actual xattr value to
+ */
+void rados_read_op_cmpxattr(rados_read_op_t read_op,
+                           const char *name,
+                           uint8_t comparison_operator,
+                           const char *value,
+                           size_t value_len);
+
+/**
+ * Start iterating over xattrs on an object.
+ *
+ * @param read_op operation to add this action to
+ * @param iter where to store the iterator
+ * @param prval where to store the return value of this action
+ */
+void rados_read_op_getxattrs(rados_read_op_t read_op,
+                            rados_xattrs_iter_t *iter,
+                            int *prval);
+
 
 /**
  * Get object size and mtime
index 652994130a844416cd6b31f11d0a343ff081811e..34a2b1d4eec8623f6165f1ce5dd342de296d6d96 100644 (file)
@@ -3200,6 +3200,20 @@ extern "C" void rados_read_op_assert_exists(rados_read_op_t read_op)
   ((::ObjectOperation *)read_op)->stat(NULL, (utime_t *)NULL, NULL);
 }
 
+extern "C" void rados_read_op_cmpxattr(rados_read_op_t read_op,
+                                      const char *name,
+                                      uint8_t comparison_operator,
+                                      const char *value,
+                                      size_t value_len)
+{
+  bufferlist bl;
+  bl.append(value, value_len);
+  ((::ObjectOperation *)read_op)->cmpxattr(name,
+                                          comparison_operator,
+                                          CEPH_OSD_CMPXATTR_MODE_STRING,
+                                          bl);
+}
+
 extern "C" void rados_read_op_stat(rados_read_op_t read_op,
                                   uint64_t *psize,
                                   time_t *pmtime,
@@ -3294,6 +3308,25 @@ extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op,
                                       prval);
 }
 
+class C_XattrsIter : public Context {
+  RadosXattrsIter *iter;
+public:
+  C_XattrsIter(RadosXattrsIter *iter) : iter(iter) {}
+  void finish(int r) {
+    iter->i = iter->attrset.begin();
+  }
+};
+
+extern "C" void rados_read_op_getxattrs(rados_read_op_t read_op,
+                                       rados_xattrs_iter_t *iter,
+                                       int *prval)
+{
+  RadosXattrsIter *xattrs_iter = new RadosXattrsIter;
+  ((::ObjectOperation *)read_op)->getxattrs(&xattrs_iter->attrset, prval);
+  ((::ObjectOperation *)read_op)->add_handler(new C_XattrsIter(xattrs_iter));
+  *iter = xattrs_iter;
+}
+
 extern "C" int rados_read_op_operate(rados_read_op_t read_op,
                                     rados_ioctx_t io,
                                     const char *oid,
index 9d303acfa0f461fd9c33a63f9bfbdcb9bbe849d2..aa058c64ead856237740f500d0b55a179b612094 100644 (file)
@@ -21,6 +21,45 @@ protected:
   void remove_object() {
     ASSERT_EQ(0, rados_remove(ioctx, obj));
   }
+  int cmp_xattr(const char *xattr, const char *value, size_t value_len,
+               uint8_t cmp_op)
+  {
+    rados_read_op_t op = rados_create_read_op();
+    rados_read_op_cmpxattr(op, xattr, cmp_op, value, value_len);
+    int r = rados_read_op_operate(op, ioctx, obj, 0);
+    rados_release_read_op(op);
+    return r;
+  }
+
+
+  void compare_xattrs(char const* const* keys,
+                     char const* const* vals,
+                     const size_t *lens,
+                     size_t len,
+                     rados_xattrs_iter_t iter)
+  {
+    size_t i = 0;
+    char *key = NULL;
+    char *val = NULL;
+    size_t val_len = 0;
+    while (i < len) {
+      ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**) &key,
+                                       (const char**) &val, &val_len));
+      if (len == 0 && key == NULL && val == NULL)
+       break;
+      EXPECT_EQ(std::string(keys[i]), std::string(key));
+      EXPECT_EQ(0, memcmp(vals[i], val, val_len));
+      EXPECT_EQ(lens[i], val_len);
+      ++i;
+    }
+    ASSERT_EQ(i, len);
+    ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**)&key,
+                                     (const char**)&val, &val_len));
+    ASSERT_EQ((char*)NULL, key);
+    ASSERT_EQ((char*)NULL, val);
+    ASSERT_EQ(0u, val_len);
+    rados_getxattrs_end(iter);
+  }
 };
 
 TEST_F(CReadOpsTest, NewDelete) {
@@ -75,6 +114,62 @@ TEST_F(CReadOpsTest, AssertExists) {
   remove_object();
 }
 
+TEST_F(CReadOpsTest, CmpXattr) {
+  write_object();
+
+  char buf[len];
+  memset(buf, 0xcc, sizeof(buf));
+
+  const char *xattr = "test";
+  rados_setxattr(ioctx, obj, xattr, buf, sizeof(buf));
+
+  // equal value
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE));
+
+  // < value
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_EQ));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_NE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GT));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GTE));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LTE));
+
+  // > value
+  memset(buf, 0xcd, sizeof(buf));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE));
+
+  // it compares C strings, so NUL at the beginning is the same
+  // regardless of the following data
+  rados_setxattr(ioctx, obj, xattr, "\0\0", 1);
+  buf[0] = '\0';
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE));
+
+  buf[1] = '\0';
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE));
+  EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT));
+  EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE));
+
+  remove_object();
+}
+
 TEST_F(CReadOpsTest, Read) {
   write_object();
 
@@ -263,3 +358,39 @@ TEST_F(CReadOpsTest, Stat) {
   EXPECT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0));
   rados_release_read_op(op);
 }
+
+TEST_F(CReadOpsTest, GetXattrs) {
+  write_object();
+
+  char *keys[] = {(char*)"bar",
+                 (char*)"foo",
+                 (char*)"test1",
+                 (char*)"test2"};
+  char *vals[] = {(char*)"",
+                 (char*)"\0",
+                 (char*)"abc",
+                 (char*)"va\0lue"};
+  size_t lens[] = {0, 1, 3, 6};
+
+  int rval = 1;
+  rados_read_op_t op = rados_create_read_op();
+  rados_xattrs_iter_t it;
+  rados_read_op_getxattrs(op, &it, &rval);
+  EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  EXPECT_EQ(0, rval);
+  rados_release_read_op(op);
+  compare_xattrs(keys, vals, lens, 0, it);
+
+  for (int i = 0; i < 4; ++i)
+    rados_setxattr(ioctx, obj, keys[i], vals[i], lens[i]);
+
+  rval = 1;
+  op = rados_create_read_op();
+  rados_read_op_getxattrs(op, &it, &rval);
+  EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  EXPECT_EQ(0, rval);
+  rados_release_read_op(op);
+  compare_xattrs(keys, vals, lens, 4, it);
+
+  remove_object();
+}