cluster.wait_for_latest_osdmap();
}
+#include "common/ceph_crypto.h"
+using ceph::crypto::SHA1;
+#include "rgw/rgw_common.h"
+TEST_F(LibRadosTwoPoolsPP, ManifestDedupRefRead) {
+ // skip test if not yet nautilus
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("nautilus") == std::string::npos) {
+ cout << "cluster is not yet nautilus, skipping test" << std::endl;
+ return;
+ }
+ }
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(pool_name, "fingerprint_algorithm", "sha1"),
+ inbl, NULL, NULL));
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-chunk (dedup)
+ {
+ ObjectWriteOperation op;
+ int len = strlen("hi there");
+ op.set_chunk(0, len, cache_ioctx, "bar-chunk", 0,
+ CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-dedup", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk (dedup)
+ {
+ ObjectWriteOperation op;
+ int len = strlen("hi there");
+ op.set_chunk(0, len, cache_ioctx, "bar", 0,
+ CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // make all chunks dirty --> flush
+ {
+ // make a dirty chunks
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ // do flush
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ // make a dirty chunks
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ // do flush
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ // chunk's refcount
+ {
+ bufferlist in, out;
+ SHA1 sha1_gen;
+ int size = strlen("There hi");
+ unsigned char fingerprint[CEPH_CRYPTO_SHA1_DIGESTSIZE + 1];
+ char p_str[CEPH_CRYPTO_SHA1_DIGESTSIZE*2+1] = {0};
+ sha1_gen.Update((const unsigned char *)"There hi", size);
+ sha1_gen.Final(fingerprint);
+ buf_to_hex(fingerprint, CEPH_CRYPTO_SHA1_DIGESTSIZE, p_str);
+ cache_ioctx.exec(p_str, "refcount", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(2, read_ret.refs.size());
+ }
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
class LibRadosTwoPoolsECPP : public RadosTestECPP
{
public: