]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cls/journal: new append method
authorMykola Golub <mgolub@suse.com>
Tue, 28 May 2019 12:22:31 +0000 (13:22 +0100)
committerMykola Golub <mgolub@suse.com>
Sun, 23 Jun 2019 09:06:45 +0000 (10:06 +0100)
which supports padding

Signed-off-by: Mykola Golub <mgolub@suse.com>
src/cls/journal/cls_journal.cc
src/cls/journal/cls_journal_client.cc
src/cls/journal/cls_journal_client.h
src/test/cls_journal/test_cls_journal.cc

index 63d4584240b0f90c5bfd2982068b712239f396c8..146a6a0b8927b6eb503cc617d58459c8f1cd13e5 100644 (file)
@@ -1122,6 +1122,75 @@ int journal_object_guard_append(cls_method_context_t hctx, bufferlist *in,
   return 0;
 }
 
+/**
+ * Input:
+ * @param soft_max_size (uint64_t)
+ * @param data (bufferlist) data to append
+ *
+ * Output:
+ * @returns 0 on success, negative error code on failure
+ * @returns -EOVERFLOW if object size is equal or more than soft_max_size
+ */
+int journal_object_append(cls_method_context_t hctx, bufferlist *in,
+                          bufferlist *out) {
+  uint64_t soft_max_size;
+  bufferlist data;
+  try {
+    auto iter = in->cbegin();
+    decode(soft_max_size, iter);
+    decode(data, iter);
+  } catch (const buffer::error &err) {
+    CLS_ERR("failed to decode input parameters: %s", err.what());
+    return -EINVAL;
+  }
+
+  uint64_t size = 0;
+  int r = cls_cxx_stat(hctx, &size, nullptr);
+  if (r < 0 && r != -ENOENT) {
+    CLS_ERR("append: failed to stat object: %s", cpp_strerror(r).c_str());
+    return r;
+  }
+
+  if (size >= soft_max_size) {
+    CLS_LOG(5, "journal object full: %" PRIu64 " >= %" PRIu64,
+            size, soft_max_size);
+    return -EOVERFLOW;
+  }
+
+  auto offset = size;
+  r = cls_cxx_write2(hctx, offset, data.length(), &data,
+                     CEPH_OSD_OP_FLAG_FADVISE_DONTNEED);
+  if (r < 0) {
+    CLS_ERR("append: error when writing: %s", cpp_strerror(r).c_str());
+    return r;
+  }
+
+  if (cls_get_min_compatible_client(hctx) < ceph_release_t::octopus) {
+    return 0;
+  }
+
+  auto min_alloc_size = cls_get_osd_min_alloc_size(hctx);
+  if (min_alloc_size == 0) {
+    min_alloc_size = 8;
+  }
+
+  CLS_LOG(20, "pad to %" PRIu64, min_alloc_size);
+
+  auto end = offset + data.length();
+  auto new_end = round_up_to(end, min_alloc_size);
+  if (new_end == end) {
+    return 0;
+  }
+
+  r = cls_cxx_truncate(hctx, new_end);
+  if (r < 0) {
+    CLS_ERR("append: error when truncating: %s", cpp_strerror(r).c_str());
+    return r;
+  }
+
+  return 0;
+}
+
 CLS_INIT(journal)
 {
   CLS_LOG(20, "Loaded journal class!");
@@ -1147,6 +1216,7 @@ CLS_INIT(journal)
   cls_method_handle_t h_journal_tag_create;
   cls_method_handle_t h_journal_tag_list;
   cls_method_handle_t h_journal_object_guard_append;
+  cls_method_handle_t h_journal_object_append;
 
   cls_register("journal", &h_class);
 
@@ -1224,4 +1294,6 @@ CLS_INIT(journal)
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           journal_object_guard_append,
                           &h_journal_object_guard_append);
+  cls_register_cxx_method(h_class, "append", CLS_METHOD_RD | CLS_METHOD_WR,
+                          journal_object_append, &h_journal_object_append);
 }
index c22a32cf3a32dba37fe0a8ca6e549a9ef8103f7f..d2bb8f9a496a855a262ffc9cf0316f434ae2e764 100644 (file)
@@ -493,6 +493,15 @@ void guard_append(librados::ObjectWriteOperation *op, uint64_t soft_max_size) {
   op->exec("journal", "guard_append", bl);
 }
 
+void append(librados::ObjectWriteOperation *op, uint64_t soft_max_size,
+            bufferlist &data) {
+  bufferlist bl;
+  encode(soft_max_size, bl);
+  encode(data, bl);
+
+  op->exec("journal", "append", bl);
+}
+
 } // namespace client
 } // namespace journal
 } // namespace cls
index 50579cfcb52679f3d83dd6a79b4a2335dc8f093f..f8ad9db5113a053101c6ca4bce129632927dc7bd 100644 (file)
@@ -99,6 +99,8 @@ int tag_list_finish(bufferlist::const_iterator *iter,
 
 // journal entry helpers
 void guard_append(librados::ObjectWriteOperation *op, uint64_t soft_max_size);
+void append(librados::ObjectWriteOperation *op, uint64_t soft_max_size,
+            bufferlist &data);
 
 } // namespace client
 } // namespace journal
index 2082bbc2935c3158d66912a1bd09d456d68d5e28..06fb8fc9153f42cf151cd4242702f3406afdb89c 100644 (file)
 
 using namespace cls::journal;
 
+static bool is_sparse_read_supported(librados::IoCtx &ioctx,
+                                     const std::string &oid) {
+  EXPECT_EQ(0, ioctx.create(oid, true));
+  bufferlist inbl;
+  inbl.append(std::string(1, 'X'));
+  EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 1));
+  EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 3));
+
+  std::map<uint64_t, uint64_t> m;
+  bufferlist outbl;
+  int r = ioctx.sparse_read(oid, m, outbl, 4, 0);
+  ioctx.remove(oid);
+
+  int expected_r = 2;
+  std::map<uint64_t, uint64_t> expected_m = {{1, 1}, {3, 1}};
+  bufferlist expected_outbl;
+  expected_outbl.append(std::string(2, 'X'));
+
+  return (r == expected_r && m == expected_m &&
+          outbl.contents_equal(expected_outbl));
+}
+
 class TestClsJournal : public ::testing::Test {
 public:
 
@@ -609,3 +631,65 @@ TEST_F(TestClsJournal, GuardAppendOverflow) {
   client::guard_append(&op2, 1);
   ASSERT_EQ(-EOVERFLOW, ioctx.operate(oid, &op2));
 }
+
+TEST_F(TestClsJournal, Append) {
+  librados::IoCtx ioctx;
+  ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+  std::string oid = get_temp_image_name();
+  ioctx.remove(oid);
+
+  bool sparse_read_supported = is_sparse_read_supported(ioctx, oid);
+
+  bufferlist bl;
+  bl.append("journal entry!");
+
+  librados::ObjectWriteOperation op1;
+  client::append(&op1, 1, bl);
+  ASSERT_EQ(0, ioctx.operate(oid, &op1));
+
+  librados::ObjectWriteOperation op2;
+  client::append(&op2, 1, bl);
+  ASSERT_EQ(-EOVERFLOW, ioctx.operate(oid, &op2));
+
+  bufferlist outbl;
+  ASSERT_LE(bl.length(), ioctx.read(oid, outbl, 0, 0));
+
+  bufferlist tmpbl;
+  tmpbl.substr_of(outbl, 0, bl.length());
+  ASSERT_TRUE(bl.contents_equal(tmpbl));
+
+  if (outbl.length() == bl.length()) {
+    std::cout << "padding is not enabled" << std::endl;
+    return;
+  }
+
+  tmpbl.clear();
+  tmpbl.substr_of(outbl, bl.length(), outbl.length() - bl.length());
+  ASSERT_TRUE(tmpbl.is_zero());
+
+  if (!sparse_read_supported) {
+    std::cout << "sparse_read is not supported" << std::endl;
+    return;
+  }
+
+  librados::ObjectWriteOperation op3;
+  client::append(&op3, 1 << 24, bl);
+  ASSERT_EQ(0, ioctx.operate(oid, &op3));
+
+  std::map<uint64_t, uint64_t> m;
+  uint64_t pad_len = outbl.length();
+  outbl.clear();
+  std::map<uint64_t, uint64_t> expected_m =
+      {{0, bl.length()}, {pad_len, bl.length()}};
+  ASSERT_EQ(expected_m.size(), ioctx.sparse_read(oid, m, outbl, 2 * pad_len, 0));
+  ASSERT_EQ(m, expected_m);
+
+  uint64_t buffer_offset = 0;
+  for (auto &it : m) {
+    tmpbl.clear();
+    tmpbl.substr_of(outbl, buffer_offset, it.second);
+    ASSERT_TRUE(bl.contents_equal(tmpbl));
+    buffer_offset += it.second;
+  }
+}