]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/test/librbd/deep_copy/test_mock_ObjectCopyRequest.cc
import ceph 15.2.10
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_ObjectCopyRequest.cc
index c2e03db37b715ac7353ec564efbcdc57017f044d..cb64be8b2d3c02783a785948757a1bd11720b9be 100644 (file)
@@ -11,6 +11,7 @@
 #include "librbd/Operations.h"
 #include "librbd/api/Image.h"
 #include "librbd/deep_copy/ObjectCopyRequest.h"
+#include "librbd/deep_copy/Utils.h"
 #include "librbd/io/ImageRequest.h"
 #include "librbd/io/ImageRequestWQ.h"
 #include "librbd/io/ReadResult.h"
@@ -116,6 +117,7 @@ public:
   ContextWQ *m_work_queue;
 
   SnapMap m_snap_map;
+  SnapSeqs m_snap_seqs;
   std::vector<librados::snap_t> m_src_snap_ids;
   std::vector<librados::snap_t> m_dst_snap_ids;
 
@@ -206,12 +208,18 @@ public:
       librbd::MockTestImageCtx &mock_src_image_ctx,
       librbd::MockTestImageCtx &mock_dst_image_ctx,
       librados::snap_t src_snap_id_start,
+      librados::snap_t src_snap_id_end,
       librados::snap_t dst_snap_id_start,
       Context *on_finish) {
+    SnapMap snap_map;
+    util::compute_snap_map(mock_dst_image_ctx.cct, src_snap_id_start,
+                           src_snap_id_end, m_dst_snap_ids, m_snap_seqs,
+                           &snap_map);
+
     expect_get_object_name(mock_dst_image_ctx);
     return new MockObjectCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
                                      src_snap_id_start, dst_snap_id_start,
-                                     m_snap_map, 0, false, nullptr, on_finish);
+                                     snap_map, 0, false, nullptr, on_finish);
   }
 
   void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
@@ -349,6 +357,7 @@ public:
                             m_snap_map.rbegin()->second.end());
     }
     m_snap_map[src_snap_id] = dst_snap_ids;
+    m_snap_seqs[src_snap_id] = dst_snap_id;
     m_src_snap_ids.push_back(src_snap_id);
     m_dst_snap_ids.push_back(dst_snap_id);
 
@@ -480,8 +489,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, DNE) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -513,8 +522,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Write) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -526,10 +535,10 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Write) {
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
   expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
-  expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[0], OBJECT_EXISTS, 0);
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
 
   request->send();
   ASSERT_EQ(0, ctx.wait());
@@ -560,8 +569,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingStaleSnapSet) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -581,19 +590,20 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingStaleSnapSet) {
 
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, dummy_snap_set1);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
   expect_sparse_read(mock_src_io_ctx, 0, 123, -ENOENT);
+
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, dummy_snap_set2);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
   expect_sparse_read(mock_src_io_ctx, 0, 234, -ENOENT);
+
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[3]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(),
-               {m_dst_snap_ids[1], {m_dst_snap_ids[1],
-                                    m_dst_snap_ids[0]}},
-               0);
+
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[2], OBJECT_EXISTS, 0);
@@ -602,6 +612,12 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingStaleSnapSet) {
                            m_dst_snap_ids[3], is_fast_diff(mock_dst_image_ctx) ?
                            OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
 
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, 0, one.range_end(),
+               {m_dst_snap_ids[1], {m_dst_snap_ids[1],
+                                    m_dst_snap_ids[0]}},
+               0);
+
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_EQ(0, compare_objects());
@@ -626,8 +642,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingUpToDateSnapMap) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -635,6 +651,7 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadMissingUpToDateSnapMap) {
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
+
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), -ENOENT);
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
 
@@ -661,8 +678,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ReadError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -696,8 +713,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -708,6 +725,11 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteError) {
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           m_dst_snap_ids[0], OBJECT_EXISTS, 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
 
@@ -746,8 +768,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -756,15 +778,13 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) {
 
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[2]);
   expect_sparse_read(mock_src_io_ctx, two, 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, two,
-               {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[0], OBJECT_EXISTS, 0);
@@ -776,6 +796,12 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnaps) {
                            m_dst_snap_ids[2], is_fast_diff(mock_dst_image_ctx) ?
                            OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
 
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, two,
+               {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
+
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_EQ(0, compare_objects());
@@ -812,8 +838,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -822,12 +848,10 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) {
 
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_truncate(mock_dst_io_ctx, trim_offset, 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[0], OBJECT_EXISTS, 0);
@@ -835,6 +859,11 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Trim) {
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[1], OBJECT_EXISTS, 0);
 
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
+  expect_start_op(mock_exclusive_lock);
+  expect_truncate(mock_dst_io_ctx, trim_offset, 0);
+
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_EQ(0, compare_objects());
@@ -866,8 +895,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -877,11 +906,9 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) {
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[1]);
+
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_remove(mock_dst_io_ctx, 0);
+
   expect_start_op(mock_exclusive_lock);
   uint8_t state = OBJECT_EXISTS;
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
@@ -891,6 +918,11 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, Remove) {
                            m_dst_snap_ids[1], is_fast_diff(mock_dst_image_ctx) ?
                            OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
 
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
+  expect_start_op(mock_exclusive_lock);
+  expect_remove(mock_dst_io_ctx, 0);
+
   request->send();
   ASSERT_EQ(0, ctx.wait());
   ASSERT_EQ(0, compare_objects());
@@ -918,8 +950,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
 
   C_SaferCond ctx;
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
-                                                  mock_dst_image_ctx, 0, 0,
-                                                  &ctx);
+                                                  mock_dst_image_ctx, 0,
+                                                  CEPH_NOSNAP, 0, &ctx);
 
   librados::MockTestMemIoCtxImpl &mock_src_io_ctx(get_mock_io_ctx(
     request->get_src_io_ctx()));
@@ -928,10 +960,10 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, ObjectMapUpdateError) {
 
   InSequence seq;
   expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx, 0);
+
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[0]);
   expect_sparse_read(mock_src_io_ctx, 0, one.range_end(), 0);
-  expect_start_op(mock_exclusive_lock);
-  expect_write(mock_dst_io_ctx, 0, one.range_end(), {0, {}}, 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
                            m_dst_snap_ids[0], OBJECT_EXISTS, -EBLACKLISTED);
@@ -977,8 +1009,8 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
 
   // map should begin after src start and src end's dst snap seqs should
   // point to HEAD revision
-  m_snap_map.erase(src_snap_id_start);
-  m_snap_map[m_src_image_ctx->snaps[0]][0] = CEPH_NOSNAP;
+  m_snap_seqs.rbegin()->second = CEPH_NOSNAP;
+  m_dst_snap_ids.pop_back();
 
   librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
   librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
@@ -996,6 +1028,7 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
   MockObjectCopyRequest *request = create_request(mock_src_image_ctx,
                                                   mock_dst_image_ctx,
                                                   src_snap_id_start,
+                                                  CEPH_NOSNAP,
                                                   dst_snap_id_start,
                                                   &ctx);
 
@@ -1013,6 +1046,14 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
   expect_set_snap_read(mock_src_io_ctx, m_src_snap_ids[2]);
   expect_sparse_read(mock_src_io_ctx, three, 0);
 
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           m_dst_snap_ids[1], OBJECT_EXISTS, 0);
+
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           CEPH_NOSNAP, OBJECT_EXISTS, 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_write(mock_dst_io_ctx, two,
                {m_dst_snap_ids[0], {m_dst_snap_ids[0]}}, 0);
@@ -1021,16 +1062,83 @@ TEST_F(TestMockDeepCopyObjectCopyRequest, WriteSnapsStart) {
   expect_write(mock_dst_io_ctx, three,
                {m_dst_snap_ids[1], {m_dst_snap_ids[1], m_dst_snap_ids[0]}}, 0);
 
+  request->send();
+  ASSERT_EQ(0, ctx.wait());
+  ASSERT_EQ(0, compare_objects());
+}
+
+TEST_F(TestMockDeepCopyObjectCopyRequest, Incremental) {
+  librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
+  librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
+
+  librbd::MockExclusiveLock mock_exclusive_lock;
+  prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
+
+  librbd::MockObjectMap mock_object_map;
+  mock_dst_image_ctx.object_map = &mock_object_map;
+
+  expect_op_work_queue(mock_src_image_ctx);
+  expect_test_features(mock_dst_image_ctx);
+  expect_get_object_count(mock_dst_image_ctx);
+
+  // scribble some data
+  interval_set<uint64_t> one;
+  scribble(m_src_image_ctx, 10, 102400, &one);
+  ASSERT_EQ(0, create_snap("snap1"));
+  mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps;
+
+  InSequence seq;
+
+  C_SaferCond ctx1;
+  auto request1 = create_request(mock_src_image_ctx, mock_dst_image_ctx,
+                                 0, m_src_snap_ids[0], 0, &ctx1);
+
+  librados::MockTestMemIoCtxImpl &mock_src_io_ctx1(get_mock_io_ctx(
+    request1->get_src_io_ctx()));
+  expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx1, 0);
+
+  expect_set_snap_read(mock_src_io_ctx1, m_src_snap_ids[0]);
+  expect_sparse_read(mock_src_io_ctx1, 0, one.range_end(), 0);
+
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
-                           m_dst_snap_ids[1], OBJECT_EXISTS, 0);
+                           m_dst_snap_ids[0], OBJECT_EXISTS, 0);
+
+  librados::MockTestMemIoCtxImpl &mock_dst_io_ctx1(get_mock_io_ctx(
+    request1->get_dst_io_ctx()));
+  expect_start_op(mock_exclusive_lock);
+  expect_write(mock_dst_io_ctx1, 0, one.range_end(), {0, {}}, 0);
+
+  request1->send();
+  ASSERT_EQ(0, ctx1.wait());
+
+  // clean (no-updates) snapshots
+  ASSERT_EQ(0, create_snap("snap2"));
+  ASSERT_EQ(0, create_snap("snap3"));
+  mock_dst_image_ctx.snaps = m_dst_image_ctx->snaps;
+
+  C_SaferCond ctx2;
+  auto request2 = create_request(mock_src_image_ctx, mock_dst_image_ctx,
+                                 m_src_snap_ids[0], m_src_snap_ids[2],
+                                 m_dst_snap_ids[0], &ctx2);
+
+  librados::MockTestMemIoCtxImpl &mock_src_io_ctx2(get_mock_io_ctx(
+    request2->get_src_io_ctx()));
+  expect_list_snaps(mock_src_image_ctx, mock_src_io_ctx2, 0);
 
   expect_start_op(mock_exclusive_lock);
   expect_update_object_map(mock_dst_image_ctx, mock_object_map,
-                           CEPH_NOSNAP, OBJECT_EXISTS, 0);
+                           m_dst_snap_ids[1],
+                           is_fast_diff(mock_dst_image_ctx) ?
+                             OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
+  expect_start_op(mock_exclusive_lock);
+  expect_update_object_map(mock_dst_image_ctx, mock_object_map,
+                           m_dst_snap_ids[2],
+                           is_fast_diff(mock_dst_image_ctx) ?
+                             OBJECT_EXISTS_CLEAN : OBJECT_EXISTS, 0);
 
-  request->send();
-  ASSERT_EQ(0, ctx.wait());
+  request2->send();
+  ASSERT_EQ(0, ctx2.wait());
   ASSERT_EQ(0, compare_objects());
 }