]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librados: add exec to the c object operations api
authorJosh Durgin <josh.durgin@inktank.com>
Fri, 7 Feb 2014 03:51:59 +0000 (19:51 -0800)
committerJosh Durgin <josh.durgin@inktank.com>
Tue, 18 Feb 2014 20:34:33 +0000 (12:34 -0800)
Add two versions: one that allocates a buffer of the appropriate
length for the user, but relies on the user to free it, and one that
uses a user-supplied buffer but may fail if it is too short.

Reuse the bufferlist -> buffer conversion context added for reads into
the user supplied buffer.

The librados-allocated buffer can be handled just like librados
allocated buffers used by the various command functions, so just reuse
do_out_buffer() for them.

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 bd97bc71be01d64e308b6909a1666f5bebd88b31..29d20858cb37f0b4223d547eda2594e551705682 100644 (file)
@@ -241,6 +241,7 @@ typedef void *rados_write_op_t;
  * - Creation and deletion: rados_create_read_op() rados_release_read_op()
  * - 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()
  * - Request properties: rados_read_op_set_flags()
  * - Performing the operation: rados_read_op_operate(),
  *   rados_aio_read_op_operate()
@@ -1987,6 +1988,59 @@ void rados_read_op_read(rados_read_op_t read_op,
                        int *prval);
 
 /**
+ * Execute an OSD class method on an object
+ * See rados_exec() for general description.
+ *
+ * The output buffer is allocated on the heap; the caller is
+ * expected to release that memory with rados_buffer_free(). The
+ * buffer and length pointers can all be NULL, in which case they are
+ * not filled in.
+ *
+ * @param read_op operation to add this action to
+ * @param cls the name of the class
+ * @param method the name of the method
+ * @param in_buf where to find input
+ * @param in_len length of in_buf in bytes
+ * @param out_buf where to put librados-allocated output buffer
+ * @param out_len length of out_buf in bytes
+ * @param prval where to store the return value from the method
+ */
+void rados_read_op_exec(rados_read_op_t read_op,
+                       const char *cls,
+                       const char *method,
+                       const char *in_buf,
+                       size_t in_len,
+                       char **out_buf,
+                       size_t *out_len,
+                       int *prval);
+
+/**
+ * Execute an OSD class method on an object
+ * See rados_exec() for general description.
+ *
+ * If the output buffer is too small, prval will
+ * be set to -ERANGE and used_len will be 0.
+ *
+ * @param read_op operation to add this action to
+ * @param cls the name of the class
+ * @param method the name of the method
+ * @param in_buf where to find input
+ * @param in_len length of in_buf in bytes
+ * @param out_buf user-provided buffer to read into
+ * @param out_len length of out_buf in bytes
+ * @param used_len where to store the number of bytes read into out_buf
+ * @param prval where to store the return value from the method
+ */
+void rados_read_op_exec_user_buf(rados_read_op_t read_op,
+                                const char *cls,
+                                const char *method,
+                                const char *in_buf,
+                                size_t in_len,
+                                char *out_buf,
+                                size_t out_len,
+                                size_t *used_len,
+                                int *prval);
+
 
 /**
  * Perform a write operation synchronously
index 8dfc91315afaf774ceeb7e64bf3b035109f3e2d6..652994130a844416cd6b31f11d0a343ff081811e 100644 (file)
@@ -3247,6 +3247,53 @@ extern "C" void rados_read_op_read(rados_read_op_t read_op,
   ((::ObjectOperation *)read_op)->read(offset, len, &ctx->out_bl, prval, ctx);
 }
 
+class C_out_buffer : public Context {
+  char **out_buf;
+  size_t *out_len;
+public:
+  bufferlist out_bl;
+  C_out_buffer(char **out_buf, size_t *out_len) : out_buf(out_buf),
+                                                 out_len(out_len) {}
+  void finish(int r) {
+    // ignore r since we don't know the meaning of return values
+    // from custom class methods
+    do_out_buffer(out_bl, out_buf, out_len);
+  }
+};
+
+extern "C" void rados_read_op_exec(rados_read_op_t read_op,
+                                  const char *cls,
+                                  const char *method,
+                                  const char *in_buf,
+                                  size_t in_len,
+                                  char **out_buf,
+                                  size_t *out_len,
+                                  int *prval)
+{
+  bufferlist inbl;
+  inbl.append(in_buf, in_len);
+  C_out_buffer *ctx = new C_out_buffer(out_buf, out_len);
+  ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+                                      prval);
+}
+
+extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op,
+                                           const char *cls,
+                                           const char *method,
+                                           const char *in_buf,
+                                           size_t in_len,
+                                           char *out_buf,
+                                           size_t out_len,
+                                           size_t *used_len,
+                                           int *prval)
+{
+  C_bl_to_buf *ctx = new C_bl_to_buf(out_buf, out_len, used_len, prval);
+  bufferlist inbl;
+  inbl.append(in_buf, in_len);
+  ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+                                      prval);
+}
+
 extern "C" int rados_read_op_operate(rados_read_op_t read_op,
                                     rados_ioctx_t io,
                                     const char *oid,
index bec72f5a7ead79c2935e171b2aba26e5cbc22ce1..9d303acfa0f461fd9c33a63f9bfbdcb9bbe849d2 100644 (file)
@@ -173,6 +173,65 @@ TEST_F(CReadOpsTest, ShortRead) {
   remove_object();
 }
 
+TEST_F(CReadOpsTest, Exec) {
+  // create object so we don't get -ENOENT
+  write_object();
+
+  rados_read_op_t op = rados_create_read_op();
+  ASSERT_TRUE(op);
+  size_t bytes_read = 0;
+  char *out = NULL;
+  int rval = 0;
+  rados_read_op_exec(op, "rbd", "get_all_features", NULL, 0, &out,
+                    &bytes_read, &rval);
+  ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  rados_release_read_op(op);
+  EXPECT_EQ(0, rval);
+  EXPECT_TRUE(out);
+  uint64_t features;
+  EXPECT_EQ(sizeof(features), bytes_read);
+  // make sure buffer is at least as long as it claims
+  ASSERT_TRUE(out[bytes_read-1] == out[bytes_read-1]);
+  rados_buffer_free(out);
+
+  remove_object();
+}
+
+TEST_F(CReadOpsTest, ExecUserBuf) {
+  // create object so we don't get -ENOENT
+  write_object();
+
+  rados_read_op_t op = rados_create_read_op();
+  size_t bytes_read = 0;
+  uint64_t features;
+  char out[sizeof(features)];
+  int rval = 0;
+  rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
+                             sizeof(out), &bytes_read, &rval);
+  ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  rados_release_read_op(op);
+  EXPECT_EQ(0, rval);
+  EXPECT_EQ(sizeof(features), bytes_read);
+
+  // buffer too short
+  bytes_read = 1024;
+  op = rados_create_read_op();
+  rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
+                             sizeof(features) - 1, &bytes_read, &rval);
+  ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  EXPECT_EQ(0u, bytes_read);
+  EXPECT_EQ(-ERANGE, rval);
+
+  // input buffer and no rval or bytes_read
+  op = rados_create_read_op();
+  rados_read_op_exec_user_buf(op, "rbd", "get_all_features", out, sizeof(out),
+                             out, sizeof(out), NULL, NULL);
+  ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
+  rados_release_read_op(op);
+
+  remove_object();
+}
+
 TEST_F(CReadOpsTest, Stat) {
   rados_read_op_t op = rados_create_read_op();
   uint64_t size = 1;