From 73f50a13109f3f158a2c485c30a008f3e6b31f22 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Wed, 27 Sep 2017 12:10:55 +0200 Subject: [PATCH] rbd-mirror: use generalized deep copy for image sync Signed-off-by: Mykola Golub --- src/test/rbd_mirror/CMakeLists.txt | 5 - .../test_mock_BootstrapRequest.cc | 4 +- .../image_sync/test_mock_ImageCopyRequest.cc | 649 --------------- .../test_mock_MetadataCopyRequest.cc | 176 ---- .../image_sync/test_mock_ObjectCopyRequest.cc | 759 ----------------- .../test_mock_SnapshotCopyRequest.cc | 764 ------------------ .../test_mock_SnapshotCreateRequest.cc | 393 --------- src/test/rbd_mirror/test_mock_ImageSync.cc | 252 ++---- src/tools/rbd_mirror/CMakeLists.txt | 5 - src/tools/rbd_mirror/ImageSync.cc | 312 +++---- src/tools/rbd_mirror/ImageSync.h | 61 +- .../rbd_mirror/image_sync/ImageCopyRequest.cc | 423 ---------- .../rbd_mirror/image_sync/ImageCopyRequest.h | 133 --- .../image_sync/MetadataCopyRequest.cc | 119 --- .../image_sync/MetadataCopyRequest.h | 82 -- .../image_sync/ObjectCopyRequest.cc | 506 ------------ .../rbd_mirror/image_sync/ObjectCopyRequest.h | 153 ---- .../image_sync/SnapshotCopyRequest.cc | 614 -------------- .../image_sync/SnapshotCopyRequest.h | 147 ---- .../image_sync/SnapshotCreateRequest.cc | 334 -------- .../image_sync/SnapshotCreateRequest.h | 108 --- 21 files changed, 248 insertions(+), 5751 deletions(-) delete mode 100644 src/test/rbd_mirror/image_sync/test_mock_ImageCopyRequest.cc delete mode 100644 src/test/rbd_mirror/image_sync/test_mock_MetadataCopyRequest.cc delete mode 100644 src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc delete mode 100644 src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc delete mode 100644 src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/ImageCopyRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/ImageCopyRequest.h delete mode 100644 src/tools/rbd_mirror/image_sync/MetadataCopyRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/MetadataCopyRequest.h delete mode 100644 src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/ObjectCopyRequest.h delete mode 100644 src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h delete mode 100644 src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc delete mode 100644 src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h diff --git a/src/test/rbd_mirror/CMakeLists.txt b/src/test/rbd_mirror/CMakeLists.txt index dc8aafe8ec370..a11db807426d4 100644 --- a/src/test/rbd_mirror/CMakeLists.txt +++ b/src/test/rbd_mirror/CMakeLists.txt @@ -29,11 +29,6 @@ add_executable(unittest_rbd_mirror image_replayer/test_mock_GetMirrorImageIdRequest.cc image_replayer/test_mock_PrepareLocalImageRequest.cc image_replayer/test_mock_PrepareRemoteImageRequest.cc - image_sync/test_mock_ImageCopyRequest.cc - image_sync/test_mock_MetadataCopyRequest.cc - image_sync/test_mock_ObjectCopyRequest.cc - image_sync/test_mock_SnapshotCopyRequest.cc - image_sync/test_mock_SnapshotCreateRequest.cc image_sync/test_mock_SyncPointCreateRequest.cc image_sync/test_mock_SyncPointPruneRequest.cc pool_watcher/test_mock_RefreshImagesRequest.cc diff --git a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc index 3d4c16a820d55..ee5e49811e31e 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc @@ -63,8 +63,8 @@ struct ImageSync { static ImageSync* create( librbd::MockTestImageCtx *local_image_ctx, librbd::MockTestImageCtx *remote_image_ctx, - SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid, - ::journal::MockJournaler *journaler, + SafeTimer *timer, Mutex *timer_lock, + const std::string &mirror_uuid, ::journal::MockJournaler *journaler, librbd::journal::MirrorPeerClientMeta *client_meta, ContextWQ *work_queue, InstanceWatcher *instance_watcher, Context *on_finish, ProgressContext *progress_ctx) { diff --git a/src/test/rbd_mirror/image_sync/test_mock_ImageCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_ImageCopyRequest.cc deleted file mode 100644 index 81c0ea931b15b..0000000000000 --- a/src/test/rbd_mirror/image_sync/test_mock_ImageCopyRequest.cc +++ /dev/null @@ -1,649 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "test/rbd_mirror/test_mock_fixture.h" -#include "include/rbd/librbd.hpp" -#include "librbd/ImageCtx.h" -#include "librbd/ImageState.h" -#include "librbd/Operations.h" -#include "librbd/journal/TypeTraits.h" -#include "test/journal/mock/MockJournaler.h" -#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" -#include "test/librbd/mock/MockImageCtx.h" -#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h" -#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.h" -#include "tools/rbd_mirror/Threads.h" -#include - -namespace librbd { - -namespace { - -struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) - : librbd::MockImageCtx(image_ctx) { - } -}; - -} // anonymous namespace - -namespace journal { - -template <> -struct TypeTraits { - typedef ::journal::MockJournaler Journaler; -}; - -} // namespace journal -} // namespace librbd - -namespace rbd { -namespace mirror { -namespace image_sync { - -template <> -struct ObjectCopyRequest { - static ObjectCopyRequest* s_instance; - static ObjectCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx, - librbd::MockTestImageCtx *remote_image_ctx, - const ImageCopyRequest::SnapMap *snap_map, - uint64_t object_number, Context *on_finish) { - assert(s_instance != nullptr); - Mutex::Locker locker(s_instance->lock); - s_instance->snap_map = snap_map; - s_instance->object_contexts[object_number] = on_finish; - s_instance->cond.Signal(); - return s_instance; - } - - MOCK_METHOD0(send, void()); - - Mutex lock; - Cond cond; - - const ImageCopyRequest::SnapMap *snap_map = nullptr; - std::map object_contexts; - - ObjectCopyRequest() : lock("lock") { - s_instance = this; - } -}; - -ObjectCopyRequest* ObjectCopyRequest::s_instance = nullptr; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -// template definitions -#include "tools/rbd_mirror/image_sync/ImageCopyRequest.cc" -template class rbd::mirror::image_sync::ImageCopyRequest; - -namespace rbd { -namespace mirror { -namespace image_sync { - -using ::testing::_; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::WithArg; -using ::testing::InvokeWithoutArgs; - -class TestMockImageSyncImageCopyRequest : public TestMockFixture { -public: - typedef ImageCopyRequest MockImageCopyRequest; - typedef ObjectCopyRequest MockObjectCopyRequest; - - void SetUp() override { - TestMockFixture::SetUp(); - - librbd::RBD rbd; - ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); - - ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); - } - - void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) { - EXPECT_CALL(mock_image_ctx, get_snap_id(_, _)) - .WillRepeatedly(Invoke([&mock_image_ctx](cls::rbd::SnapshotNamespace snap_namespace, - std::string snap_name) { - assert(mock_image_ctx.image_ctx->snap_lock.is_locked()); - return mock_image_ctx.image_ctx->get_snap_id(snap_namespace, snap_name); - })); - } - - void expect_get_object_count(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t count) { - EXPECT_CALL(mock_image_ctx, get_object_count(_)) - .WillOnce(Return(count)).RetiresOnSaturation(); - } - - void expect_update_client(journal::MockJournaler &mock_journaler, int r) { - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillOnce(WithArg<1>(CompleteContext(r))); - } - - void expect_object_copy_send(MockObjectCopyRequest &mock_object_copy_request) { - EXPECT_CALL(mock_object_copy_request, send()); - } - - bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request, - uint64_t object_num, int r, - std::function fn = []() {}) { - Mutex::Locker locker(mock_object_copy_request.lock); - while (mock_object_copy_request.object_contexts.count(object_num) == 0) { - if (mock_object_copy_request.cond.WaitInterval(mock_object_copy_request.lock, - utime_t(10, 0)) != 0) { - return false; - } - } - - FunctionContext *wrapper_ctx = new FunctionContext( - [&mock_object_copy_request, object_num, fn] (int r) { - fn(); - mock_object_copy_request.object_contexts[object_num]->complete(r); - }); - m_threads->work_queue->queue(wrapper_ctx, r); - return true; - } - - MockImageCopyRequest::SnapMap wait_for_snap_map(MockObjectCopyRequest &mock_object_copy_request) { - Mutex::Locker locker(mock_object_copy_request.lock); - while (mock_object_copy_request.snap_map == nullptr) { - if (mock_object_copy_request.cond.WaitInterval(mock_object_copy_request.lock, - utime_t(10, 0)) != 0) { - return MockImageCopyRequest::SnapMap(); - } - } - return *mock_object_copy_request.snap_map; - } - - MockImageCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx, - librbd::MockTestImageCtx &mock_local_image_ctx, - journal::MockJournaler &mock_journaler, - librbd::journal::MirrorPeerSyncPoint &sync_point, - Context *ctx) { - return new MockImageCopyRequest(&mock_local_image_ctx, - &mock_remote_image_ctx, - m_threads->timer, &m_threads->timer_lock, - &mock_journaler, &m_client_meta, - &sync_point, ctx); - } - - using TestFixture::create_snap; - int create_snap(const char* snap_name) { - librados::snap_t remote_snap_id; - int r = create_snap(m_remote_image_ctx, snap_name, &remote_snap_id); - if (r < 0) { - return r; - } - - librados::snap_t local_snap_id; - r = create_snap(m_local_image_ctx, snap_name, &local_snap_id); - if (r < 0) { - return r; - } - - // collection of all existing snaps in local image - MockImageCopyRequest::SnapIds local_snap_ids({local_snap_id}); - if (!m_snap_map.empty()) { - local_snap_ids.insert(local_snap_ids.end(), - m_snap_map.rbegin()->second.begin(), - m_snap_map.rbegin()->second.end()); - } - m_snap_map[remote_snap_id] = local_snap_ids; - m_client_meta.snap_seqs[remote_snap_id] = local_snap_id; - return 0; - } - - librbd::ImageCtx *m_remote_image_ctx; - librbd::ImageCtx *m_local_image_ctx; - librbd::journal::MirrorPeerClientMeta m_client_meta; - MockImageCopyRequest::SnapMap m_snap_map; -}; - -TEST_F(TestMockImageSyncImageCopyRequest, SimpleImage) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap1", - boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 0); - expect_update_client(mock_journaler, 0); - expect_object_copy_send(mock_object_copy_request); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0)); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, Throttled) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap1", - boost::none}}; - - std::string update_sync_age;; - ASSERT_EQ(0, _rados->conf_get("rbd_mirror_sync_point_update_age", update_sync_age)); - ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", "1")); - BOOST_SCOPE_EXIT( (update_sync_age) ) { - ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", update_sync_age.c_str())); - } BOOST_SCOPE_EXIT_END; - - - std::string max_ops_str; - ASSERT_EQ(0, _rados->conf_get("rbd_concurrent_management_ops", max_ops_str)); - int max_ops = std::stoi(max_ops_str); - - uint64_t object_count = 55; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - expect_get_object_count(mock_remote_image_ctx, object_count); - expect_get_object_count(mock_remote_image_ctx, 0); - - EXPECT_CALL(mock_object_copy_request, send()).Times(object_count); - - boost::optional expected_object_number(boost::none); - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillRepeatedly( - Invoke([&expected_object_number, max_ops, object_count, this] - (bufferlist data, Context *ctx) { - ASSERT_EQ(expected_object_number, - m_client_meta.sync_points.front().object_number); - if (!expected_object_number) { - expected_object_number = (max_ops - 1); - } else { - expected_object_number = expected_object_number.get() + max_ops; - } - - if (expected_object_number.get() > (object_count - 1)) { - expected_object_number = (object_count - 1); - } - - m_threads->work_queue->queue(ctx, 0); - })); - - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - std::function sleep_fn = [request]() { - sleep(2); - }; - - ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); - for (uint64_t i = 0; i < object_count; ++i) { - if (i % 10 == 0) { - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, 0, sleep_fn)); - } else { - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, 0)); - } - } - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, SnapshotSubset) { - ASSERT_EQ(0, create_snap("snap1")); - ASSERT_EQ(0, create_snap("snap2")); - ASSERT_EQ(0, create_snap("snap3")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap3", "snap2", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 0); - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 1); - expect_update_client(mock_journaler, 0); - expect_object_copy_send(mock_object_copy_request); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - MockImageCopyRequest::SnapMap snap_map(m_snap_map); - snap_map.erase(snap_map.begin()); - ASSERT_EQ(snap_map, wait_for_snap_map(mock_object_copy_request)); - - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0)); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, RestartCatchup) { - ASSERT_EQ(0, create_snap("snap1")); - ASSERT_EQ(0, create_snap("snap2")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}, - {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 0); - expect_get_object_count(mock_remote_image_ctx, 0); - expect_update_client(mock_journaler, 0); - expect_object_copy_send(mock_object_copy_request); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.back(), - &ctx); - request->send(); - - ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0)); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, RestartPartialSync) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap1", - librbd::journal::MirrorPeerSyncPoint::ObjectNumber{0U}}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 2); - expect_update_client(mock_journaler, 0); - expect_object_copy_send(mock_object_copy_request); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, 0)); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, Cancel) { - std::string max_ops_str; - ASSERT_EQ(0, _rados->conf_get("rbd_concurrent_management_ops", max_ops_str)); - ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", "1")); - BOOST_SCOPE_EXIT( (max_ops_str) ) { - ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", max_ops_str.c_str())); - } BOOST_SCOPE_EXIT_END; - - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 2); - expect_get_object_count(mock_remote_image_ctx, 2); - expect_update_client(mock_journaler, 0); - expect_object_copy_send(mock_object_copy_request); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); - request->cancel(); - - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0)); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, Cancel_Inflight_Sync) { - std::string update_sync_age;; - ASSERT_EQ(0, _rados->conf_get("rbd_mirror_sync_point_update_age", update_sync_age)); - ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", "1")); - BOOST_SCOPE_EXIT( (update_sync_age) ) { - ASSERT_EQ(0, _rados->conf_set("rbd_mirror_sync_point_update_age", update_sync_age.c_str())); - } BOOST_SCOPE_EXIT_END; - - std::string max_ops_str; - ASSERT_EQ(0, _rados->conf_get("rbd_concurrent_management_ops", max_ops_str)); - ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", "3")); - BOOST_SCOPE_EXIT( (max_ops_str) ) { - ASSERT_EQ(0, _rados->conf_set("rbd_concurrent_management_ops", max_ops_str.c_str())); - } BOOST_SCOPE_EXIT_END; - - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - expect_get_snap_id(mock_remote_image_ctx); - - expect_get_object_count(mock_remote_image_ctx, 10); - expect_get_object_count(mock_remote_image_ctx, 0); - - EXPECT_CALL(mock_object_copy_request, send()).Times(6); - - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillRepeatedly(Invoke([this] (bufferlist data, Context *ctx) { - m_threads->work_queue->queue(ctx, 0); - })); - - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - - ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); - - std::function cancel_fn = [request]() { - sleep(2); - request->cancel(); - }; - - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, 0)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, 0)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, 0)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, 0, cancel_fn)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, 0)); - ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, 0)); - - ASSERT_EQ(-ECANCELED, ctx.wait()); - ASSERT_EQ(5u, m_client_meta.sync_points.front().object_number.get()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, Cancel1) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockObjectCopyRequest mock_object_copy_request; - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - - expect_get_snap_id(mock_remote_image_ctx); - - InSequence seq; - expect_get_object_count(mock_remote_image_ctx, 1); - expect_get_object_count(mock_remote_image_ctx, 0); - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillOnce(DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - WithArg<1>(CompleteContext(0)))); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, MissingSnap) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "missing-snap", boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - expect_get_snap_id(mock_remote_image_ctx); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - ASSERT_EQ(-ENOENT, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, MissingFromSnap) { - ASSERT_EQ(0, create_snap("snap1")); - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap1", - "missing-snap", - boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - expect_get_snap_id(mock_remote_image_ctx); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - ASSERT_EQ(-ENOENT, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, EmptySnapMap) { - ASSERT_EQ(0, create_snap("snap1")); - ASSERT_EQ(0, create_snap("snap2")); - m_client_meta.snap_seqs = {{0, 0}}; - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap2", - "snap1", - boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - expect_get_snap_id(mock_remote_image_ctx); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncImageCopyRequest, EmptySnapSeqs) { - ASSERT_EQ(0, create_snap("snap1")); - ASSERT_EQ(0, create_snap("snap2")); - m_client_meta.snap_seqs = {}; - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), - "snap2", - "snap1", - boost::none}}; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - expect_get_snap_id(mock_remote_image_ctx); - - C_SaferCond ctx; - MockImageCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, - m_client_meta.sync_points.front(), - &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd diff --git a/src/test/rbd_mirror/image_sync/test_mock_MetadataCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_MetadataCopyRequest.cc deleted file mode 100644 index 35e663fac7146..0000000000000 --- a/src/test/rbd_mirror/image_sync/test_mock_MetadataCopyRequest.cc +++ /dev/null @@ -1,176 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "test/rbd_mirror/test_mock_fixture.h" -#include "include/rbd/librbd.hpp" -#include "include/stringify.h" -#include "librbd/ImageCtx.h" -#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" -#include "test/librbd/mock/MockImageCtx.h" -#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h" -#include - -namespace librbd { -namespace { - -struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) - : librbd::MockImageCtx(image_ctx) { - } -}; - -} // anonymous namespace -} // namespace librbd - -// template definitions -#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.cc" - -namespace rbd { -namespace mirror { -namespace image_sync { - -using ::testing::_; -using ::testing::DoAll; -using ::testing::InSequence; -using ::testing::Return; -using ::testing::StrEq; -using ::testing::WithArg; - -class TestMockImageSyncMetadataCopyRequest : public TestMockFixture { -public: - typedef MetadataCopyRequest MockMetadataCopyRequest; - typedef std::map Metadata; - - void SetUp() override { - TestMockFixture::SetUp(); - - librbd::RBD rbd; - ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); - - ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); - } - - void expect_metadata_list(librbd::MockTestImageCtx &mock_image_ctx, - const Metadata& metadata, int r) { - bufferlist out_bl; - ::encode(metadata, out_bl); - - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), - StrEq("metadata_list"), _, _, _)) - .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(out_bl)), - Return(r))); - } - - void expect_metadata_set(librbd::MockTestImageCtx &mock_image_ctx, - const Metadata& metadata, int r) { - bufferlist in_bl; - ::encode(metadata, in_bl); - - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), - StrEq("metadata_set"), ContentsEqual(in_bl), _, _)) - .WillOnce(Return(r)); - } - - librbd::ImageCtx *m_remote_image_ctx; - librbd::ImageCtx *m_local_image_ctx; -}; - -TEST_F(TestMockImageSyncMetadataCopyRequest, Success) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - size_t idx = 1; - Metadata key_values_1; - for (; idx <= 128; ++idx) { - bufferlist bl; - bl.append("value" + stringify(idx)); - key_values_1.emplace("key" + stringify(idx), bl); - } - - Metadata key_values_2; - for (; idx <= 255; ++idx) { - bufferlist bl; - bl.append("value" + stringify(idx)); - key_values_2.emplace("key" + stringify(idx), bl); - } - - InSequence seq; - expect_metadata_list(mock_remote_image_ctx, key_values_1, 0); - expect_metadata_set(mock_local_image_ctx, key_values_1, 0); - expect_metadata_list(mock_remote_image_ctx, key_values_2, 0); - expect_metadata_set(mock_local_image_ctx, key_values_2, 0); - - C_SaferCond ctx; - auto request = MockMetadataCopyRequest::create(&mock_local_image_ctx, - &mock_remote_image_ctx, - &ctx); - request->send(); - - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncMetadataCopyRequest, Empty) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - Metadata key_values; - - InSequence seq; - expect_metadata_list(mock_remote_image_ctx, key_values, 0); - - C_SaferCond ctx; - auto request = MockMetadataCopyRequest::create(&mock_local_image_ctx, - &mock_remote_image_ctx, - &ctx); - request->send(); - - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncMetadataCopyRequest, MetadataListError) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - Metadata key_values; - - InSequence seq; - expect_metadata_list(mock_remote_image_ctx, key_values, -EINVAL); - - C_SaferCond ctx; - auto request = MockMetadataCopyRequest::create(&mock_local_image_ctx, - &mock_remote_image_ctx, - &ctx); - request->send(); - - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncMetadataCopyRequest, MetadataSetError) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - Metadata key_values; - bufferlist bl; - bl.append("value"); - key_values.emplace("key", bl); - - InSequence seq; - expect_metadata_list(mock_remote_image_ctx, key_values, 0); - expect_metadata_set(mock_local_image_ctx, key_values, -EINVAL); - - C_SaferCond ctx; - auto request = MockMetadataCopyRequest::create(&mock_local_image_ctx, - &mock_remote_image_ctx, - &ctx); - request->send(); - - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd diff --git a/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc deleted file mode 100644 index f70df5c0582f5..0000000000000 --- a/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc +++ /dev/null @@ -1,759 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "test/rbd_mirror/test_mock_fixture.h" -#include "include/interval_set.h" -#include "include/rbd/librbd.hpp" -#include "include/rbd/object_map_types.h" -#include "librbd/ImageCtx.h" -#include "librbd/ImageState.h" -#include "librbd/internal.h" -#include "librbd/Operations.h" -#include "librbd/io/ImageRequestWQ.h" -#include "librbd/io/ReadResult.h" -#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" -#include "test/librbd/mock/MockImageCtx.h" -#include "tools/rbd_mirror/Threads.h" -#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.h" - -namespace librbd { -namespace { - -struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) - : librbd::MockImageCtx(image_ctx) { - } -}; - -} // anonymous namespace -} // namespace librbd - -// template definitions -#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.cc" -template class rbd::mirror::image_sync::ObjectCopyRequest; - -bool operator==(const SnapContext& rhs, const SnapContext& lhs) { - return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps); -} - -namespace rbd { -namespace mirror { -namespace image_sync { - -using ::testing::_; -using ::testing::DoAll; -using ::testing::DoDefault; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::ReturnNew; -using ::testing::WithArg; - -namespace { - -void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size, - interval_set *what) -{ - uint64_t object_size = 1 << image_ctx->order; - for (int i=0; iio_work_queue->write(off, len, std::move(bl), 0); - ASSERT_EQ(static_cast(len), r); - - interval_set w; - w.insert(off, len); - what->union_of(w); - } - std::cout << " wrote " << *what << std::endl; -} - -} // anonymous namespace - -class TestMockImageSyncObjectCopyRequest : public TestMockFixture { -public: - typedef ObjectCopyRequest MockObjectCopyRequest; - - void SetUp() override { - TestMockFixture::SetUp(); - - librbd::RBD rbd; - ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); - - ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); - } - - void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { - EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce( - ReturnNew([](int) {})); - } - - void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx, - librados::MockTestMemIoCtxImpl &mock_io_ctx, - const librados::snap_set_t &snap_set) { - expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR); - EXPECT_CALL(mock_io_ctx, - list_snaps(mock_image_ctx.image_ctx->get_object_name(0), _)) - .WillOnce(DoAll(WithArg<1>(Invoke([&snap_set](librados::snap_set_t *out_snap_set) { - *out_snap_set = snap_set; - })), - Return(0))); - } - - void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx, - librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) { - expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR); - auto &expect = EXPECT_CALL(mock_io_ctx, - list_snaps(mock_image_ctx.image_ctx->get_object_name(0), - _)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_get_object_name(librbd::MockTestImageCtx &mock_image_ctx) { - EXPECT_CALL(mock_image_ctx, get_object_name(0)) - .WillOnce(Return(mock_image_ctx.image_ctx->get_object_name(0))); - } - - MockObjectCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx, - librbd::MockTestImageCtx &mock_local_image_ctx, - Context *on_finish) { - expect_get_object_name(mock_local_image_ctx); - expect_get_object_name(mock_remote_image_ctx); - return new MockObjectCopyRequest(&mock_local_image_ctx, - &mock_remote_image_ctx, &m_snap_map, - 0, on_finish); - } - - void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, - uint64_t snap_id) { - EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id)); - } - - void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset, - uint64_t length, int r) { - - auto &expect = EXPECT_CALL(mock_io_ctx, sparse_read(_, offset, length, _, _)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, - const interval_set &extents, int r) { - for (auto extent : extents) { - expect_sparse_read(mock_io_ctx, extent.first, extent.second, r); - if (r < 0) { - break; - } - } - } - - void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx, - uint64_t offset, uint64_t length, - const SnapContext &snapc, int r) { - auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx, - const interval_set &extents, - const SnapContext &snapc, int r) { - for (auto extent : extents) { - expect_write(mock_io_ctx, extent.first, extent.second, snapc, r); - if (r < 0) { - break; - } - } - } - - void expect_truncate(librados::MockTestMemIoCtxImpl &mock_io_ctx, - uint64_t offset, int r) { - auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) { - auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _)); - if (r < 0) { - expect.WillOnce(Return(r)); - } else { - expect.WillOnce(DoDefault()); - } - } - - void expect_update_object_map(librbd::MockTestImageCtx &mock_image_ctx, - librbd::MockObjectMap &mock_object_map, - librados::snap_t snap_id, uint8_t state, - int r) { - if (mock_image_ctx.image_ctx->object_map != nullptr) { - auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, _)); - if (r < 0) { - expect.WillOnce(DoAll(WithArg<6>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - })), - Return(true))); - } else { - expect.WillOnce(DoAll(WithArg<6>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) { - assert(mock_image_ctx.image_ctx->snap_lock.is_locked()); - assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked()); - mock_image_ctx.image_ctx->object_map->aio_update( - snap_id, 0, 1, state, boost::none, {}, ctx); - })), - Return(true))); - } - } - } - - using TestFixture::create_snap; - int create_snap(const char* snap_name) { - librados::snap_t remote_snap_id; - int r = create_snap(m_remote_image_ctx, snap_name, &remote_snap_id); - if (r < 0) { - return r; - } - - librados::snap_t local_snap_id; - r = create_snap(m_local_image_ctx, snap_name, &local_snap_id); - if (r < 0) { - return r; - } - - // collection of all existing snaps in local image - MockObjectCopyRequest::SnapIds local_snap_ids({local_snap_id}); - if (!m_snap_map.empty()) { - local_snap_ids.insert(local_snap_ids.end(), - m_snap_map.rbegin()->second.begin(), - m_snap_map.rbegin()->second.end()); - } - m_snap_map[remote_snap_id] = local_snap_ids; - m_remote_snap_ids.push_back(remote_snap_id); - m_local_snap_ids.push_back(local_snap_id); - - return 0; - } - - std::string get_snap_name(librbd::ImageCtx *image_ctx, - librados::snap_t snap_id) { - auto it = std::find_if(image_ctx->snap_ids.begin(), - image_ctx->snap_ids.end(), - [snap_id](const std::pair, - librados::snap_t> &pair) { - return (pair.second == snap_id); - }); - if (it == image_ctx->snap_ids.end()) { - return ""; - } - return it->first.second; - } - - int compare_objects() { - MockObjectCopyRequest::SnapMap snap_map(m_snap_map); - if (snap_map.empty()) { - return -ENOENT; - } - - int r; - uint64_t object_size = 1 << m_remote_image_ctx->order; - while (!snap_map.empty()) { - librados::snap_t remote_snap_id = snap_map.begin()->first; - librados::snap_t local_snap_id = *snap_map.begin()->second.begin(); - snap_map.erase(snap_map.begin()); - - std::string snap_name = get_snap_name(m_remote_image_ctx, remote_snap_id); - if (snap_name.empty()) { - return -ENOENT; - } - - std::cout << "comparing '" << snap_name << " (" << remote_snap_id - << " to " << local_snap_id << ")" << std::endl; - - r = librbd::snap_set(m_remote_image_ctx, - cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); - if (r < 0) { - return r; - } - - r = librbd::snap_set(m_local_image_ctx, - cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); - if (r < 0) { - return r; - } - - bufferlist remote_bl; - remote_bl.append(std::string(object_size, '1')); - r = m_remote_image_ctx->io_work_queue->read( - 0, object_size, librbd::io::ReadResult{&remote_bl}, 0); - if (r < 0) { - return r; - } - - bufferlist local_bl; - local_bl.append(std::string(object_size, '1')); - r = m_local_image_ctx->io_work_queue->read( - 0, object_size, librbd::io::ReadResult{&local_bl}, 0); - if (r < 0) { - return r; - } - - if (!remote_bl.contents_equal(local_bl)) { - return -EBADMSG; - } - } - - r = librbd::snap_set(m_remote_image_ctx, - cls::rbd::UserSnapshotNamespace(), - nullptr); - if (r < 0) { - return r; - } - r = librbd::snap_set(m_local_image_ctx, - cls::rbd::UserSnapshotNamespace(), - nullptr); - if (r < 0) { - return r; - } - - return 0; - } - - librbd::ImageCtx *m_remote_image_ctx; - librbd::ImageCtx *m_local_image_ctx; - - MockObjectCopyRequest::SnapMap m_snap_map; - std::vector m_remote_snap_ids; - std::vector m_local_snap_ids; -}; - -TEST_F(TestMockImageSyncObjectCopyRequest, DNE) { - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, -ENOENT); - - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, Write) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[0], OBJECT_EXISTS, 0); - - request->send(); - ASSERT_EQ(0, ctx.wait()); - ASSERT_EQ(0, compare_objects()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingStaleSnapSet) { - ASSERT_EQ(0, create_snap("one")); - ASSERT_EQ(0, create_snap("two")); - - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - ASSERT_EQ(0, create_snap("three")); - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - librados::clone_info_t dummy_clone_info; - dummy_clone_info.cloneid = librados::SNAP_HEAD; - dummy_clone_info.size = 123; - - librados::snap_set_t dummy_snap_set1; - dummy_snap_set1.clones.push_back(dummy_clone_info); - - dummy_clone_info.size = 234; - librados::snap_set_t dummy_snap_set2; - dummy_snap_set2.clones.push_back(dummy_clone_info); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set1); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]); - expect_sparse_read(mock_remote_io_ctx, 0, 123, -ENOENT); - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set2); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]); - expect_sparse_read(mock_remote_io_ctx, 0, 234, -ENOENT); - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), - {m_local_snap_ids[1], {m_local_snap_ids[1], - m_local_snap_ids[0]}}, - 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[2], OBJECT_EXISTS, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0); - - request->send(); - ASSERT_EQ(0, ctx.wait()); - ASSERT_EQ(0, compare_objects()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingUpToDateSnapMap) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -ENOENT); - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - - request->send(); - ASSERT_EQ(-ENOENT, ctx.wait()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, ReadError) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -EINVAL); - - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, WriteError) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL); - - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, WriteSnaps) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - ASSERT_EQ(0, create_snap("one")); - - interval_set two; - scribble(m_remote_image_ctx, 10, 102400, &two); - ASSERT_EQ(0, create_snap("two")); - - if (one.range_end() < two.range_end()) { - interval_set resize_diff; - resize_diff.insert(one.range_end(), two.range_end() - one.range_end()); - two.union_of(resize_diff); - } - - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[2]); - expect_sparse_read(mock_remote_io_ctx, two, 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, two, - {m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[0], OBJECT_EXISTS, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[1], OBJECT_EXISTS, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[2], OBJECT_EXISTS_CLEAN, 0); - - request->send(); - ASSERT_EQ(0, ctx.wait()); - ASSERT_EQ(0, compare_objects()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, Trim) { - ASSERT_EQ(0, m_remote_image_ctx->operations->metadata_set( - "conf_rbd_skip_partial_discard", "false")); - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - ASSERT_EQ(0, create_snap("one")); - - // trim the object - uint64_t trim_offset = rand() % one.range_end(); - ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard( - trim_offset, one.range_end() - trim_offset, m_remote_image_ctx->skip_partial_discard)); - ASSERT_EQ(0, create_snap("sync")); - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0); - expect_start_op(mock_exclusive_lock); - expect_truncate(mock_local_io_ctx, trim_offset, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[0], OBJECT_EXISTS, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[1], OBJECT_EXISTS, 0); - - request->send(); - ASSERT_EQ(0, ctx.wait()); - ASSERT_EQ(0, compare_objects()); -} - -TEST_F(TestMockImageSyncObjectCopyRequest, Remove) { - // scribble some data - interval_set one; - scribble(m_remote_image_ctx, 10, 102400, &one); - ASSERT_EQ(0, create_snap("one")); - ASSERT_EQ(0, create_snap("two")); - - // remove the object - uint64_t object_size = 1 << m_remote_image_ctx->order; - ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard(0, object_size, m_remote_image_ctx->skip_partial_discard)); - ASSERT_EQ(0, create_snap("sync")); - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap mock_object_map; - mock_local_image_ctx.object_map = &mock_object_map; - - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockObjectCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, &ctx); - - librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx( - request->get_remote_io_ctx())); - librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx( - request->get_local_io_ctx())); - - InSequence seq; - expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0); - expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[1]); - expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0); - expect_start_op(mock_exclusive_lock); - expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0); - expect_start_op(mock_exclusive_lock); - expect_remove(mock_local_io_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[0], OBJECT_EXISTS, 0); - expect_start_op(mock_exclusive_lock); - expect_update_object_map(mock_local_image_ctx, mock_object_map, - m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0); - - request->send(); - ASSERT_EQ(0, ctx.wait()); - ASSERT_EQ(0, compare_objects()); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd diff --git a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc deleted file mode 100644 index 7801b66bd9ced..0000000000000 --- a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCopyRequest.cc +++ /dev/null @@ -1,764 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "test/rbd_mirror/test_mock_fixture.h" -#include "include/rbd/librbd.hpp" -#include "librbd/ImageCtx.h" -#include "librbd/ImageState.h" -#include "librbd/Operations.h" -#include "librbd/journal/TypeTraits.h" -#include "test/journal/mock/MockJournaler.h" -#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" -#include "test/librbd/mock/MockImageCtx.h" -#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h" -#include "tools/rbd_mirror/image_sync/SnapshotCreateRequest.h" -#include "tools/rbd_mirror/Threads.h" - -namespace librbd { - -namespace { - -struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) - : librbd::MockImageCtx(image_ctx) { - } -}; - -} // anonymous namespace - -namespace journal { - -template <> -struct TypeTraits { - typedef ::journal::MockJournaler Journaler; -}; - -} // namespace journal -} // namespace librbd - -namespace rbd { -namespace mirror { -namespace image_sync { - -template <> -struct SnapshotCreateRequest { - static SnapshotCreateRequest* s_instance; - static SnapshotCreateRequest* create(librbd::MockTestImageCtx* image_ctx, - const std::string &snap_name, - const cls::rbd::SnapshotNamespace &snap_namespace, - uint64_t size, - const librbd::ParentSpec &parent_spec, - uint64_t parent_overlap, - Context *on_finish) { - assert(s_instance != nullptr); - s_instance->on_finish = on_finish; - return s_instance; - } - - Context *on_finish = nullptr; - - SnapshotCreateRequest() { - s_instance = this; - } - - MOCK_METHOD0(send, void()); -}; - -SnapshotCreateRequest* SnapshotCreateRequest::s_instance = nullptr; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -// template definitions -#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc" -template class rbd::mirror::image_sync::SnapshotCopyRequest; - -namespace rbd { -namespace mirror { -namespace image_sync { - -using ::testing::_; -using ::testing::DoAll; -using ::testing::DoDefault; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::InvokeWithoutArgs; -using ::testing::Return; -using ::testing::ReturnNew; -using ::testing::SetArgPointee; -using ::testing::StrEq; -using ::testing::WithArg; - -class TestMockImageSyncSnapshotCopyRequest : public TestMockFixture { -public: - typedef SnapshotCopyRequest MockSnapshotCopyRequest; - typedef SnapshotCreateRequest MockSnapshotCreateRequest; - - void SetUp() override { - TestMockFixture::SetUp(); - - librbd::RBD rbd; - ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); - - ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); - } - - void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { - EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce( - ReturnNew([](int) {})); - } - - void expect_get_snap_namespace(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t snap_id) { - EXPECT_CALL(mock_image_ctx, get_snap_namespace(snap_id, _)) - .WillOnce(DoAll(SetArgPointee<1>(cls::rbd::UserSnapshotNamespace()), - Return(0))); - } - - void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx, - MockSnapshotCreateRequest &mock_snapshot_create_request, - const std::string &snap_name, uint64_t snap_id, int r) { - EXPECT_CALL(mock_snapshot_create_request, send()) - .WillOnce(DoAll(Invoke([&mock_image_ctx, snap_id, snap_name]() { - inject_snap(mock_image_ctx, snap_id, snap_name); - }), - Invoke([this, &mock_snapshot_create_request, r]() { - m_threads->work_queue->queue(mock_snapshot_create_request.on_finish, r); - }))); - } - - void expect_snap_remove(librbd::MockTestImageCtx &mock_image_ctx, - const std::string &snap_name, int r) { - EXPECT_CALL(*mock_image_ctx.operations, execute_snap_remove(_, StrEq(snap_name), _)) - .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - }))); - } - - void expect_snap_protect(librbd::MockTestImageCtx &mock_image_ctx, - const std::string &snap_name, int r) { - EXPECT_CALL(*mock_image_ctx.operations, execute_snap_protect(_, StrEq(snap_name), _)) - .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - }))); - } - - void expect_snap_unprotect(librbd::MockTestImageCtx &mock_image_ctx, - const std::string &snap_name, int r) { - EXPECT_CALL(*mock_image_ctx.operations, execute_snap_unprotect(_, StrEq(snap_name), _)) - .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - }))); - } - - void expect_snap_is_protected(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t snap_id, bool is_protected, int r) { - EXPECT_CALL(mock_image_ctx, is_snap_protected(snap_id, _)) - .WillOnce(DoAll(SetArgPointee<1>(is_protected), - Return(r))); - } - - void expect_snap_is_unprotected(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t snap_id, bool is_unprotected, int r) { - EXPECT_CALL(mock_image_ctx, is_snap_unprotected(snap_id, _)) - .WillOnce(DoAll(SetArgPointee<1>(is_unprotected), - Return(r))); - } - - void expect_update_client(journal::MockJournaler &mock_journaler, int r) { - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillOnce(WithArg<1>(CompleteContext(r))); - } - - static void inject_snap(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t snap_id, const std::string &snap_name) { - mock_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), - snap_name}] = snap_id; - } - - MockSnapshotCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx, - librbd::MockTestImageCtx &mock_local_image_ctx, - journal::MockJournaler &mock_journaler, - Context *on_finish) { - return new MockSnapshotCopyRequest(&mock_local_image_ctx, - &mock_remote_image_ctx, &m_snap_map, - &mock_journaler, &m_client_meta, - m_threads->work_queue, on_finish); - } - - int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name, - bool protect = false) { - int r = image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); - if (r < 0) { - return r; - } - - if (protect) { - r = image_ctx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), - snap_name.c_str()); - if (r < 0) { - return r; - } - } - - r = image_ctx->state->refresh(); - if (r < 0) { - return r; - } - return 0; - } - - void validate_snap_seqs(const librbd::journal::MirrorPeerClientMeta::SnapSeqs &snap_seqs) { - ASSERT_EQ(snap_seqs, m_client_meta.snap_seqs); - } - - void validate_snap_map(const MockSnapshotCopyRequest::SnapMap &snap_map) { - ASSERT_EQ(snap_map, m_snap_map); - } - - librbd::ImageCtx *m_remote_image_ctx; - librbd::ImageCtx *m_local_image_ctx; - - MockSnapshotCopyRequest::SnapMap m_snap_map; - librbd::journal::MirrorPeerClientMeta m_client_meta; -}; - -TEST_F(TestMockImageSyncSnapshotCopyRequest, Empty) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({}); - validate_snap_seqs({}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, UpdateClientError) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_update_client(mock_journaler, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, UpdateClientCancel) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - InSequence seq; - EXPECT_CALL(mock_journaler, update_client(_, _)) - .WillOnce(DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - WithArg<1>(CompleteContext(0)))); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreate) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap2")); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t remote_snap_id2 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap2"}]; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id2); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap2", 14, 0); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id2, false, 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {12}}, {remote_snap_id2, {14, 12}}}); - validate_snap_seqs({{remote_snap_id1, 12}, {remote_snap_id2, 14}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateError) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - uint64_t remote_snap_id1 = mock_remote_image_ctx.snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - InSequence seq; - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateCancel) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - InSequence seq; - expect_start_op(mock_exclusive_lock); - EXPECT_CALL(mock_snapshot_create_request, send()) - .WillOnce(DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - Invoke([this, &mock_snapshot_create_request]() { - m_threads->work_queue->queue(mock_snapshot_create_request.on_finish, 0); - }))); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapRemoveAndCreate) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1")); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, - m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}], - true, 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_remove(mock_local_image_ctx, "snap1", 0); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {12}}}); - validate_snap_seqs({{remote_snap_id1, 12}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapRemoveError) { - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1")); - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, - m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}], - true, 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_remove(mock_local_image_ctx, "snap1", -EINVAL); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotect) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_unprotect(mock_local_image_ctx, "snap1", 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {local_snap_id1}}}); - validate_snap_seqs({{remote_snap_id1, local_snap_id1}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectError) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_unprotect(mock_local_image_ctx, "snap1", -EBUSY); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(-EBUSY, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectCancel) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_start_op(mock_exclusive_lock); - EXPECT_CALL(*mock_local_image_ctx.operations, - execute_snap_unprotect(_, StrEq("snap1"), _)) - .WillOnce(DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - WithArg<2>(Invoke([this](Context *ctx) { - m_threads->work_queue->queue(ctx, 0); - })))); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectRemove) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, - m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}], - false, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_unprotect(mock_local_image_ctx, "snap1", 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_remove(mock_local_image_ctx, "snap1", 0); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {12}}}); - validate_snap_seqs({{remote_snap_id1, 12}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateProtect) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - MockSnapshotCreateRequest mock_snapshot_create_request; - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_snap_is_protected(mock_local_image_ctx, 12, false, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_protect(mock_local_image_ctx, "snap1", 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {12}}}); - validate_snap_seqs({{remote_snap_id1, 12}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtect) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_protect(mock_local_image_ctx, "snap1", 0); - expect_update_client(mock_journaler, 0); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); - - validate_snap_map({{remote_snap_id1, {local_snap_id1}}}); - validate_snap_seqs({{remote_snap_id1, local_snap_id1}}); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtectError) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_protect(mock_local_image_ctx, "snap1", -EINVAL); - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtectCancel) { - ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); - ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); - - uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ - {cls::rbd::UserSnapshotNamespace(), "snap1"}]; - m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; - - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - C_SaferCond ctx; - MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, - mock_journaler, &ctx); - InSequence seq; - expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); - expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); - expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); - expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); - expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); - expect_start_op(mock_exclusive_lock); - EXPECT_CALL(*mock_local_image_ctx.operations, - execute_snap_protect(_, StrEq("snap1"), _)) - .WillOnce(DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - WithArg<2>(Invoke([this](Context *ctx) { - m_threads->work_queue->queue(ctx, 0); - })))); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd diff --git a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc b/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc deleted file mode 100644 index 4a8ab1fc73cf3..0000000000000 --- a/src/test/rbd_mirror/image_sync/test_mock_SnapshotCreateRequest.cc +++ /dev/null @@ -1,393 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "test/rbd_mirror/test_mock_fixture.h" -#include "test/librados_test_stub/LibradosTestStub.h" -#include "include/rbd/librbd.hpp" -#include "librbd/ImageCtx.h" -#include "librbd/ImageState.h" -#include "librbd/Operations.h" -#include "osdc/Striper.h" -#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" -#include "test/librbd/mock/MockImageCtx.h" -#include "tools/rbd_mirror/image_sync/SnapshotCreateRequest.h" -#include "tools/rbd_mirror/Threads.h" - -namespace librbd { -namespace { - -struct MockTestImageCtx : public librbd::MockImageCtx { - MockTestImageCtx(librbd::ImageCtx &image_ctx) - : librbd::MockImageCtx(image_ctx) { - } -}; - -} // anonymous namespace -} // namespace librbd - -// template definitions -#include "tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc" -template class rbd::mirror::image_sync::SnapshotCreateRequest; - -namespace rbd { -namespace mirror { -namespace image_sync { - -using ::testing::_; -using ::testing::DoAll; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::InvokeWithoutArgs; -using ::testing::Return; -using ::testing::ReturnNew; -using ::testing::StrEq; -using ::testing::WithArg; - -class TestMockImageSyncSnapshotCreateRequest : public TestMockFixture { -public: - typedef SnapshotCreateRequest MockSnapshotCreateRequest; - - void SetUp() override { - TestMockFixture::SetUp(); - - librbd::RBD rbd; - ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); - ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); - } - - void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { - EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce( - ReturnNew([](int) {})); - } - - void expect_test_features(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t features, bool enabled) { - EXPECT_CALL(mock_image_ctx, test_features(features)) - .WillOnce(Return(enabled)); - } - - void expect_set_size(librbd::MockTestImageCtx &mock_image_ctx, int r) { - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_size"), _, _, _)) - .WillOnce(Return(r)); - } - - void expect_remove_parent(librbd::MockTestImageCtx &mock_image_ctx, int r) { - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("remove_parent"), _, _, _)) - .WillOnce(Return(r)); - } - - void expect_set_parent(librbd::MockTestImageCtx &mock_image_ctx, int r) { - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_parent"), _, _, _)) - .WillOnce(Return(r)); - } - - void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx, - const std::string &snap_name, uint64_t snap_id, int r) { - EXPECT_CALL(*mock_image_ctx.operations, execute_snap_create(_, StrEq(snap_name), _, 0, true)) - .WillOnce(DoAll(InvokeWithoutArgs([&mock_image_ctx, snap_id, snap_name]() { - inject_snap(mock_image_ctx, snap_id, snap_name); - }), - WithArg<2>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - })))); - } - - void expect_object_map_resize(librbd::MockTestImageCtx &mock_image_ctx, - librados::snap_t snap_id, int r) { - std::string oid(librbd::ObjectMap<>::object_map_name(mock_image_ctx.id, - snap_id)); - EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), - exec(oid, _, StrEq("rbd"), StrEq("object_map_resize"), _, _, _)) - .WillOnce(Return(r)); - } - - static void inject_snap(librbd::MockTestImageCtx &mock_image_ctx, - uint64_t snap_id, const std::string &snap_name) { - mock_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), - snap_name}] = snap_id; - } - - MockSnapshotCreateRequest *create_request(librbd::MockTestImageCtx &mock_local_image_ctx, - const std::string &snap_name, - const cls::rbd::SnapshotNamespace &snap_namespace, - uint64_t size, - const librbd::ParentSpec &spec, - uint64_t parent_overlap, - Context *on_finish) { - return new MockSnapshotCreateRequest(&mock_local_image_ctx, snap_name, snap_namespace, size, - spec, parent_overlap, on_finish); - } - - librbd::ImageCtx *m_local_image_ctx; -}; - -TEST_F(TestMockImageSyncSnapshotCreateRequest, Resize) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_set_size(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - 123, {}, 0, - &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeError) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_set_size(mock_local_image_ctx, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - 123, {}, 0, - &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParent) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - mock_local_image_ctx.parent_md.spec.pool_id = 213; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_remove_parent(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveParentError) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - mock_local_image_ctx.parent_md.spec.pool_id = 213; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_remove_parent(mock_local_image_ctx, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, RemoveSetParent) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - mock_local_image_ctx.parent_md.spec.pool_id = 213; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_remove_parent(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_set_parent(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {123, "test", 0}, 0, - &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentSpec) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_set_parent(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {123, "test", 0}, 0, - &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentOverlap) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - mock_local_image_ctx.parent_md.spec = {123, "test", 0}; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_set_parent(mock_local_image_ctx, 0); - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - mock_local_image_ctx.parent_md.spec, - 123, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, SetParentError) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_set_parent(mock_local_image_ctx, -ESTALE); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {123, "test", 0}, 0, - &ctx); - request->send(); - ASSERT_EQ(-ESTALE, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreate) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, false); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, SnapCreateError) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMap) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, true); - expect_start_op(mock_exclusive_lock); - expect_object_map_resize(mock_local_image_ctx, 10, 0); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(0, ctx.wait()); -} - -TEST_F(TestMockImageSyncSnapshotCreateRequest, ResizeObjectMapError) { - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - InSequence seq; - expect_start_op(mock_exclusive_lock); - expect_snap_create(mock_local_image_ctx, "snap1", 10, 0); - expect_test_features(mock_local_image_ctx, RBD_FEATURE_OBJECT_MAP, true); - expect_start_op(mock_exclusive_lock); - expect_object_map_resize(mock_local_image_ctx, 10, -EINVAL); - - C_SaferCond ctx; - MockSnapshotCreateRequest *request = create_request(mock_local_image_ctx, - "snap1", - cls::rbd::UserSnapshotNamespace(), - m_local_image_ctx->size, - {}, 0, &ctx); - request->send(); - ASSERT_EQ(-EINVAL, ctx.wait()); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd diff --git a/src/test/rbd_mirror/test_mock_ImageSync.cc b/src/test/rbd_mirror/test_mock_ImageSync.cc index 4b9e95acc4376..aed32bbfb48b7 100644 --- a/src/test/rbd_mirror/test_mock_ImageSync.cc +++ b/src/test/rbd_mirror/test_mock_ImageSync.cc @@ -3,17 +3,14 @@ #include "test/rbd_mirror/test_mock_fixture.h" #include "include/rbd/librbd.hpp" +#include "librbd/DeepCopyRequest.h" #include "librbd/journal/Types.h" #include "librbd/journal/TypeTraits.h" #include "test/journal/mock/MockJournaler.h" #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" #include "test/librbd/mock/MockImageCtx.h" -#include "test/librbd/mock/MockObjectMap.h" #include "tools/rbd_mirror/ImageSync.h" #include "tools/rbd_mirror/Threads.h" -#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h" -#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h" -#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h" #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h" #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h" @@ -37,44 +34,26 @@ struct TypeTraits { }; } // namespace journal -} // namespace librbd - -// template definitions -template class rbd::mirror::ImageSync; -#include "tools/rbd_mirror/ImageSync.cc" - -namespace rbd { -namespace mirror { - -template<> -struct InstanceWatcher { - MOCK_METHOD2(notify_sync_request, void(const std::string, Context *)); - MOCK_METHOD1(cancel_sync_request, bool(const std::string &)); - MOCK_METHOD1(notify_sync_complete, void(const std::string &)); -}; - -namespace image_sync { template <> -class ImageCopyRequest { +class DeepCopyRequest { public: - static ImageCopyRequest* s_instance; + static DeepCopyRequest* s_instance; Context *on_finish; - static ImageCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx, - librbd::MockTestImageCtx *remote_image_ctx, - SafeTimer *timer, Mutex *timer_lock, - journal::MockJournaler *journaler, - librbd::journal::MirrorPeerClientMeta *client_meta, - librbd::journal::MirrorPeerSyncPoint *sync_point, - Context *on_finish, - rbd::mirror::ProgressContext *progress_ctx = nullptr) { + static DeepCopyRequest* create( + librbd::MockTestImageCtx *src_image_ctx, + librbd::MockTestImageCtx *dst_image_ctx, + librados::snap_t snap_id_start, librados::snap_t snap_id_end, + const librbd::deep_copy::ObjectNumber &object_number, + ContextWQ *work_queue, SnapSeqs *snap_seqs, ProgressContext *prog_ctx, + Context *on_finish) { assert(s_instance != nullptr); s_instance->on_finish = on_finish; return s_instance; } - ImageCopyRequest() { + DeepCopyRequest() { s_instance = this; } @@ -88,59 +67,26 @@ class ImageCopyRequest { MOCK_METHOD0(send, void()); }; -template <> -class MetadataCopyRequest { -public: - static MetadataCopyRequest* s_instance; - Context *on_finish{nullptr}; - - static MetadataCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx, - librbd::MockTestImageCtx *remote_image_ctx, - Context *on_finish) { - assert(s_instance != nullptr); - s_instance->on_finish = on_finish; - return s_instance; - } - - MetadataCopyRequest() { - s_instance = this; - } +DeepCopyRequest* DeepCopyRequest::s_instance = nullptr; - MOCK_METHOD0(send, void()); -}; - -template <> -class SnapshotCopyRequest { -public: - static SnapshotCopyRequest* s_instance; - Context *on_finish; - - static SnapshotCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx, - librbd::MockTestImageCtx *remote_image_ctx, - SnapshotCopyRequest::SnapMap *snap_map, - journal::MockJournaler *journaler, - librbd::journal::MirrorPeerClientMeta *client_meta, - ContextWQ *work_queue, - Context *on_finish) { - assert(s_instance != nullptr); - s_instance->on_finish = on_finish; - return s_instance; - } - - SnapshotCopyRequest() { - s_instance = this; - } +} // namespace librbd - void put() { - } +// template definitions +template class rbd::mirror::ImageSync; +#include "tools/rbd_mirror/ImageSync.cc" - void get() { - } +namespace rbd { +namespace mirror { - MOCK_METHOD0(send, void()); - MOCK_METHOD0(cancel, void()); +template<> +struct InstanceWatcher { + MOCK_METHOD2(notify_sync_request, void(const std::string, Context *)); + MOCK_METHOD1(cancel_sync_request, bool(const std::string &)); + MOCK_METHOD1(notify_sync_complete, void(const std::string &)); }; +namespace image_sync { + template <> class SyncPointCreateRequest { public: @@ -187,9 +133,6 @@ class SyncPointPruneRequest { MOCK_METHOD0(send, void()); }; -ImageCopyRequest* ImageCopyRequest::s_instance = nullptr; -MetadataCopyRequest* MetadataCopyRequest::s_instance = nullptr; -SnapshotCopyRequest* SnapshotCopyRequest::s_instance = nullptr; SyncPointCreateRequest* SyncPointCreateRequest::s_instance = nullptr; SyncPointPruneRequest* SyncPointPruneRequest::s_instance = nullptr; @@ -199,7 +142,7 @@ using ::testing::_; using ::testing::InSequence; using ::testing::Invoke; using ::testing::Return; -using ::testing::ReturnNew; +using ::testing::StrEq; using ::testing::WithArg; using ::testing::InvokeWithoutArgs; @@ -207,11 +150,9 @@ class TestMockImageSync : public TestMockFixture { public: typedef ImageSync MockImageSync; typedef InstanceWatcher MockInstanceWatcher; - typedef image_sync::ImageCopyRequest MockImageCopyRequest; - typedef image_sync::MetadataCopyRequest MockMetadataCopyRequest; - typedef image_sync::SnapshotCopyRequest MockSnapshotCopyRequest; typedef image_sync::SyncPointCreateRequest MockSyncPointCreateRequest; typedef image_sync::SyncPointPruneRequest MockSyncPointPruneRequest; + typedef librbd::DeepCopyRequest MockImageCopyRequest; void SetUp() override { TestMockFixture::SetUp(); @@ -224,9 +165,17 @@ class TestMockImageSync : public TestMockFixture { ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); } - void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { - EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce( - ReturnNew([](int) {})); + void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) { + EXPECT_CALL(mock_image_ctx, get_snap_id(_, _)) + .WillOnce(Return(123)); + } + + void expect_snap_set(librbd::MockTestImageCtx &mock_image_ctx, + const std::string &snap_name, int r) { + EXPECT_CALL(*mock_image_ctx.state, snap_set(_, StrEq(snap_name), _)) + .WillOnce(WithArg<2>(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + }))); } void expect_notify_sync_request(MockInstanceWatcher &mock_instance_watcher, @@ -264,13 +213,6 @@ class TestMockImageSync : public TestMockFixture { })); } - void expect_copy_snapshots(MockSnapshotCopyRequest &mock_snapshot_copy_request, int r) { - EXPECT_CALL(mock_snapshot_copy_request, send()) - .WillOnce(Invoke([this, &mock_snapshot_copy_request, r]() { - m_threads->work_queue->queue(mock_snapshot_copy_request.on_finish, r); - })); - } - void expect_copy_image(MockImageCopyRequest &mock_image_copy_request, int r) { EXPECT_CALL(mock_image_copy_request, send()) .WillOnce(Invoke([this, &mock_image_copy_request, r]() { @@ -278,35 +220,9 @@ class TestMockImageSync : public TestMockFixture { })); } - void expect_copy_metadata(MockMetadataCopyRequest &mock_metadata_copy_request, - int r) { - EXPECT_CALL(mock_metadata_copy_request, send()) - .WillOnce(Invoke([this, &mock_metadata_copy_request, r]() { - m_threads->work_queue->queue(mock_metadata_copy_request.on_finish, r); - })); - } - - void expect_rollback_object_map(librbd::MockObjectMap &mock_object_map, int r) { - if ((m_local_image_ctx->features & RBD_FEATURE_OBJECT_MAP) != 0) { - EXPECT_CALL(mock_object_map, rollback(_, _)) - .WillOnce(WithArg<1>(Invoke([this, r](Context *ctx) { - m_threads->work_queue->queue(ctx, r); - }))); - } - } - - void expect_create_object_map(librbd::MockTestImageCtx &mock_image_ctx, - librbd::MockObjectMap *mock_object_map) { - EXPECT_CALL(mock_image_ctx, create_object_map(CEPH_NOSNAP)) - .WillOnce(Return(mock_object_map)); - } - - void expect_open_object_map(librbd::MockTestImageCtx &mock_image_ctx, - librbd::MockObjectMap &mock_object_map) { - EXPECT_CALL(mock_object_map, open(_)) - .WillOnce(Invoke([this](Context *ctx) { - m_threads->work_queue->queue(ctx, 0); - })); + void expect_flush_sync_point(journal::MockJournaler &mock_journaler, int r) { + EXPECT_CALL(mock_journaler, update_client(_, _)) + .WillOnce(WithArg<1>(CompleteContext(r))); } void expect_prune_sync_point(MockSyncPointPruneRequest &mock_sync_point_prune_request, @@ -350,29 +266,16 @@ TEST_F(TestMockImageSync, SimpleSync) { journal::MockJournaler mock_journaler; MockInstanceWatcher mock_instance_watcher; MockImageCopyRequest mock_image_copy_request; - MockSnapshotCopyRequest mock_snapshot_copy_request; MockSyncPointCreateRequest mock_sync_point_create_request; MockSyncPointPruneRequest mock_sync_point_prune_request; - MockMetadataCopyRequest mock_metadata_copy_request; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap(); - mock_local_image_ctx.object_map = mock_object_map; - expect_test_features(mock_local_image_ctx); InSequence seq; expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0); - expect_copy_snapshots(mock_snapshot_copy_request, 0); + expect_get_snap_id(mock_remote_image_ctx); expect_copy_image(mock_image_copy_request, 0); - expect_start_op(mock_exclusive_lock); - expect_rollback_object_map(*mock_object_map, 0); - expect_create_object_map(mock_local_image_ctx, mock_object_map); - expect_open_object_map(mock_local_image_ctx, *mock_object_map); + expect_flush_sync_point(mock_journaler, 0); expect_prune_sync_point(mock_sync_point_prune_request, true, 0); - expect_copy_metadata(mock_metadata_copy_request, 0); expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); C_SaferCond ctx; @@ -389,34 +292,23 @@ TEST_F(TestMockImageSync, RestartSync) { journal::MockJournaler mock_journaler; MockInstanceWatcher mock_instance_watcher; MockImageCopyRequest mock_image_copy_request; - MockSnapshotCopyRequest mock_snapshot_copy_request; MockSyncPointCreateRequest mock_sync_point_create_request; MockSyncPointPruneRequest mock_sync_point_prune_request; - MockMetadataCopyRequest mock_metadata_copy_request; m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}, {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}}; mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap1"}] = 123; mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap2"}] = 234; - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap(); - mock_local_image_ctx.object_map = mock_object_map; expect_test_features(mock_local_image_ctx); InSequence seq; expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); expect_prune_sync_point(mock_sync_point_prune_request, false, 0); - expect_copy_snapshots(mock_snapshot_copy_request, 0); + expect_get_snap_id(mock_remote_image_ctx); expect_copy_image(mock_image_copy_request, 0); - expect_start_op(mock_exclusive_lock); - expect_rollback_object_map(*mock_object_map, 0); - expect_create_object_map(mock_local_image_ctx, mock_object_map); - expect_open_object_map(mock_local_image_ctx, *mock_object_map); + expect_flush_sync_point(mock_journaler, 0); expect_prune_sync_point(mock_sync_point_prune_request, true, 0); - expect_copy_metadata(mock_metadata_copy_request, 0); expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); C_SaferCond ctx; @@ -472,19 +364,15 @@ TEST_F(TestMockImageSync, CancelImageCopy) { journal::MockJournaler mock_journaler; MockInstanceWatcher mock_instance_watcher; MockImageCopyRequest mock_image_copy_request; - MockSnapshotCopyRequest mock_snapshot_copy_request; MockSyncPointCreateRequest mock_sync_point_create_request; MockSyncPointPruneRequest mock_sync_point_prune_request; - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}}; InSequence seq; expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); expect_prune_sync_point(mock_sync_point_prune_request, false, 0); - expect_copy_snapshots(mock_snapshot_copy_request, 0); + expect_get_snap_id(mock_remote_image_ctx); C_SaferCond image_copy_ctx; EXPECT_CALL(mock_image_copy_request, send()) @@ -512,61 +400,15 @@ TEST_F(TestMockImageSync, CancelImageCopy) { ASSERT_EQ(-ECANCELED, ctx.wait()); } -TEST_F(TestMockImageSync, CancelAfterCopySnapshots) { - librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); - librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); - journal::MockJournaler mock_journaler; - MockInstanceWatcher mock_instance_watcher; - MockSnapshotCopyRequest mock_snapshot_copy_request; - MockSyncPointCreateRequest mock_sync_point_create_request; - - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap(); - mock_local_image_ctx.object_map = mock_object_map; - expect_test_features(mock_local_image_ctx); - - C_SaferCond ctx; - MockImageSync *request = create_request(mock_remote_image_ctx, - mock_local_image_ctx, mock_journaler, - mock_instance_watcher, &ctx); - InSequence seq; - expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); - expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0); - EXPECT_CALL(mock_snapshot_copy_request, send()) - .WillOnce((DoAll(InvokeWithoutArgs([request]() { - request->cancel(); - }), - Invoke([this, &mock_snapshot_copy_request]() { - m_threads->work_queue->queue(mock_snapshot_copy_request.on_finish, 0); - })))); - expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id, - false); - EXPECT_CALL(mock_snapshot_copy_request, cancel()); - expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); - - request->send(); - ASSERT_EQ(-ECANCELED, ctx.wait()); -} - TEST_F(TestMockImageSync, CancelAfterCopyImage) { librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); journal::MockJournaler mock_journaler; MockInstanceWatcher mock_instance_watcher; MockImageCopyRequest mock_image_copy_request; - MockSnapshotCopyRequest mock_snapshot_copy_request; MockSyncPointCreateRequest mock_sync_point_create_request; MockSyncPointPruneRequest mock_sync_point_prune_request; - librbd::MockExclusiveLock mock_exclusive_lock; - mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; - - librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap(); - mock_local_image_ctx.object_map = mock_object_map; - expect_test_features(mock_local_image_ctx); - C_SaferCond ctx; MockImageSync *request = create_request(mock_remote_image_ctx, mock_local_image_ctx, mock_journaler, @@ -574,7 +416,7 @@ TEST_F(TestMockImageSync, CancelAfterCopyImage) { InSequence seq; expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0); - expect_copy_snapshots(mock_snapshot_copy_request, 0); + expect_get_snap_id(mock_remote_image_ctx); EXPECT_CALL(mock_image_copy_request, send()) .WillOnce((DoAll(InvokeWithoutArgs([request]() { request->cancel(); diff --git a/src/tools/rbd_mirror/CMakeLists.txt b/src/tools/rbd_mirror/CMakeLists.txt index 78a6e330d94a1..103969d892531 100644 --- a/src/tools/rbd_mirror/CMakeLists.txt +++ b/src/tools/rbd_mirror/CMakeLists.txt @@ -32,11 +32,6 @@ set(rbd_mirror_internal image_replayer/PrepareLocalImageRequest.cc image_replayer/PrepareRemoteImageRequest.cc image_replayer/ReplayStatusFormatter.cc - image_sync/ImageCopyRequest.cc - image_sync/MetadataCopyRequest.cc - image_sync/ObjectCopyRequest.cc - image_sync/SnapshotCopyRequest.cc - image_sync/SnapshotCreateRequest.cc image_sync/SyncPointCreateRequest.cc image_sync/SyncPointPruneRequest.cc pool_watcher/RefreshImagesRequest.cc diff --git a/src/tools/rbd_mirror/ImageSync.cc b/src/tools/rbd_mirror/ImageSync.cc index 94df5a8aac622..5c50b5fc79e5e 100644 --- a/src/tools/rbd_mirror/ImageSync.cc +++ b/src/tools/rbd_mirror/ImageSync.cc @@ -4,16 +4,15 @@ #include "ImageSync.h" #include "InstanceWatcher.h" #include "ProgressContext.h" +#include "common/Timer.h" #include "common/errno.h" #include "journal/Journaler.h" -#include "librbd/ExclusiveLock.h" +#include "librbd/DeepCopyRequest.h" #include "librbd/ImageCtx.h" -#include "librbd/ObjectMap.h" +#include "librbd/ImageState.h" #include "librbd/Utils.h" +#include "librbd/internal.h" #include "librbd/journal/Types.h" -#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h" -#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h" -#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h" #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h" #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h" @@ -30,6 +29,20 @@ using namespace image_sync; using librbd::util::create_context_callback; using librbd::util::unique_lock_name; +template +class ImageSync::ImageCopyProgressContext : public librbd::ProgressContext { +public: + ImageCopyProgressContext(ImageSync *image_sync) : image_sync(image_sync) { + } + + int update_progress(uint64_t object_no, uint64_t object_count) override { + image_sync->handle_copy_image_update_progress(object_no, object_count); + return 0; + } + + ImageSync *image_sync; +}; + template ImageSync::ImageSync(I *local_image_ctx, I *remote_image_ctx, SafeTimer *timer, Mutex *timer_lock, @@ -44,13 +57,16 @@ ImageSync::ImageSync(I *local_image_ctx, I *remote_image_ctx, m_journaler(journaler), m_client_meta(client_meta), m_work_queue(work_queue), m_instance_watcher(instance_watcher), m_progress_ctx(progress_ctx), - m_lock(unique_lock_name("ImageSync::m_lock", this)) { + m_lock(unique_lock_name("ImageSync::m_lock", this)), + m_update_sync_point_interval(m_local_image_ctx->cct->_conf->template get_val( + "rbd_mirror_sync_point_update_age")), m_client_meta_copy(*client_meta) { } template ImageSync::~ImageSync() { - assert(m_snapshot_copy_request == nullptr); assert(m_image_copy_request == nullptr); + assert(m_image_copy_prog_ctx == nullptr); + assert(m_update_sync_ctx == nullptr); } template @@ -70,10 +86,6 @@ void ImageSync::cancel() { return; } - if (m_snapshot_copy_request != nullptr) { - m_snapshot_copy_request->cancel(); - } - if (m_image_copy_request != nullptr) { m_image_copy_request->cancel(); } @@ -144,7 +156,7 @@ void ImageSync::send_create_sync_point() { // TODO: when support for disconnecting laggy clients is added, // re-connect and create catch-up sync point if (m_client_meta->sync_points.size() > 0) { - send_copy_snapshots(); + send_copy_image(); return; } @@ -168,61 +180,40 @@ void ImageSync::handle_create_sync_point(int r) { return; } - send_copy_snapshots(); -} - -template -void ImageSync::send_copy_snapshots() { - m_lock.Lock(); - if (m_canceled) { - m_lock.Unlock(); - finish(-ECANCELED); - return; - } - - dout(20) << dendl; - - Context *ctx = create_context_callback< - ImageSync, &ImageSync::handle_copy_snapshots>(this); - m_snapshot_copy_request = SnapshotCopyRequest::create( - m_local_image_ctx, m_remote_image_ctx, &m_snap_map, m_journaler, - m_client_meta, m_work_queue, ctx); - m_snapshot_copy_request->get(); - m_lock.Unlock(); - - update_progress("COPY_SNAPSHOTS"); - - m_snapshot_copy_request->send(); + send_copy_image(); } template -void ImageSync::handle_copy_snapshots(int r) { - dout(20) << ": r=" << r << dendl; - +void ImageSync::send_copy_image() { + librados::snap_t snap_id_start = 0; + librados::snap_t snap_id_end; + librbd::deep_copy::ObjectNumber object_number; + int r = 0; { - Mutex::Locker locker(m_lock); - m_snapshot_copy_request->put(); - m_snapshot_copy_request = nullptr; - if (r == 0 && m_canceled) { - r = -ECANCELED; + RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock); + assert(!m_client_meta->sync_points.empty()); + auto &sync_point = m_client_meta->sync_points.front(); + snap_id_end = m_remote_image_ctx->get_snap_id( + cls::rbd::UserSnapshotNamespace(), sync_point.snap_name); + if (snap_id_end == CEPH_NOSNAP) { + derr << ": failed to locate snapshot: " << sync_point.snap_name << dendl; + r = -ENOENT; + } else if (!sync_point.from_snap_name.empty()) { + snap_id_start = m_remote_image_ctx->get_snap_id( + cls::rbd::UserSnapshotNamespace(), sync_point.from_snap_name); + if (snap_id_start == CEPH_NOSNAP) { + derr << ": failed to locate from snapshot: " + << sync_point.from_snap_name << dendl; + r = -ENOENT; + } } + object_number = sync_point.object_number; } - - if (r == -ECANCELED) { - dout(10) << ": snapshot copy canceled" << dendl; - finish(r); - return; - } else if (r < 0) { - derr << ": failed to copy snapshot metadata: " << cpp_strerror(r) << dendl; + if (r < 0) { finish(r); return; } - send_copy_image(); -} - -template -void ImageSync::send_copy_image() { m_lock.Lock(); if (m_canceled) { m_lock.Unlock(); @@ -234,10 +225,11 @@ void ImageSync::send_copy_image() { Context *ctx = create_context_callback< ImageSync, &ImageSync::handle_copy_image>(this); - m_image_copy_request = ImageCopyRequest::create( - m_local_image_ctx, m_remote_image_ctx, m_timer, m_timer_lock, - m_journaler, m_client_meta, &m_client_meta->sync_points.front(), - ctx, m_progress_ctx); + m_image_copy_prog_ctx = new ImageCopyProgressContext(this); + m_image_copy_request = librbd::DeepCopyRequest::create( + m_remote_image_ctx, m_local_image_ctx, snap_id_start, snap_id_end, + object_number, m_work_queue, &m_client_meta->snap_seqs, + m_image_copy_prog_ctx, ctx); m_image_copy_request->get(); m_lock.Unlock(); @@ -251,12 +243,25 @@ void ImageSync::handle_copy_image(int r) { dout(20) << ": r=" << r << dendl; { + Mutex::Locker timer_locker(*m_timer_lock); Mutex::Locker locker(m_lock); m_image_copy_request->put(); m_image_copy_request = nullptr; + delete m_image_copy_prog_ctx; + m_image_copy_prog_ctx = nullptr; if (r == 0 && m_canceled) { r = -ECANCELED; } + + if (m_update_sync_ctx != nullptr) { + m_timer->cancel_event(m_update_sync_ctx); + m_update_sync_ctx = nullptr; + } + + if (m_updating_sync_point) { + m_ret_val = r; + return; + } } if (r == -ECANCELED) { @@ -269,89 +274,136 @@ void ImageSync::handle_copy_image(int r) { return; } - send_copy_object_map(); + send_flush_sync_point(); } template -void ImageSync::send_copy_object_map() { - update_progress("COPY_OBJECT_MAP"); - - m_local_image_ctx->owner_lock.get_read(); - m_local_image_ctx->snap_lock.get_read(); - if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP, - m_local_image_ctx->snap_lock)) { - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); - send_prune_sync_points(); - return; - } +void ImageSync::handle_copy_image_update_progress(uint64_t object_no, + uint64_t object_count) { + int percent = 100 * object_no / object_count; + update_progress("COPY_IMAGE " + stringify(percent) + "%"); - assert(m_local_image_ctx->object_map != nullptr); + Mutex::Locker locker(m_lock); + m_image_copy_object_no = object_no; + m_image_copy_object_count = object_count; + + if (m_update_sync_ctx == nullptr && !m_updating_sync_point) { + send_update_sync_point(); + } +} - assert(!m_client_meta->sync_points.empty()); - librbd::journal::MirrorPeerSyncPoint &sync_point = - m_client_meta->sync_points.front(); - auto snap_id_it = m_local_image_ctx->snap_ids.find( - {cls::rbd::UserSnapshotNamespace(), sync_point.snap_name}); - assert(snap_id_it != m_local_image_ctx->snap_ids.end()); - librados::snap_t snap_id = snap_id_it->second; +template +void ImageSync::send_update_sync_point() { + assert(m_lock.is_locked()); - dout(20) << ": snap_id=" << snap_id << ", " - << "snap_name=" << sync_point.snap_name << dendl; + m_update_sync_ctx = nullptr; - Context *finish_op_ctx = nullptr; - if (m_local_image_ctx->exclusive_lock != nullptr) { - finish_op_ctx = m_local_image_ctx->exclusive_lock->start_op(); + if (m_canceled) { + return; } - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); - finish(-EROFS); + + auto sync_point = &m_client_meta->sync_points.front(); + + if (m_client_meta->sync_object_count == m_image_copy_object_count && + sync_point->object_number && + (m_image_copy_object_no - 1) == sync_point->object_number.get()) { + // update sync point did not progress since last sync return; } - // rollback the object map (copy snapshot object map to HEAD) - RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock); - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_copy_object_map(r); - finish_op_ctx->complete(0); - }); - m_local_image_ctx->object_map->rollback(snap_id, ctx); - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); + m_updating_sync_point = true; + + m_client_meta_copy = *m_client_meta; + m_client_meta->sync_object_count = m_image_copy_object_count; + if (m_image_copy_object_no > 0) { + sync_point->object_number = m_image_copy_object_no - 1; + } + + CephContext *cct = m_local_image_ctx->cct; + ldout(cct, 20) << ": sync_point=" << *sync_point << dendl; + + bufferlist client_data_bl; + librbd::journal::ClientData client_data(*m_client_meta); + ::encode(client_data, client_data_bl); + + Context *ctx = create_context_callback< + ImageSync, &ImageSync::handle_update_sync_point>( + this); + m_journaler->update_client(client_data_bl, ctx); } template -void ImageSync::handle_copy_object_map(int r) { - dout(20) << dendl; +void ImageSync::handle_update_sync_point(int r) { + CephContext *cct = m_local_image_ctx->cct; + ldout(cct, 20) << ": r=" << r << dendl; - assert(r == 0); - send_refresh_object_map(); + if (r < 0) { + *m_client_meta = m_client_meta_copy; + lderr(cct) << ": failed to update client data: " << cpp_strerror(r) + << dendl; + } + + { + Mutex::Locker timer_locker(*m_timer_lock); + Mutex::Locker locker(m_lock); + m_updating_sync_point = false; + + if (m_image_copy_request != nullptr) { + m_update_sync_ctx = new FunctionContext( + [this](int r) { + this->send_update_sync_point(); + }); + m_timer->add_event_after(m_update_sync_point_interval, + m_update_sync_ctx); + return; + } + } + + send_flush_sync_point(); } template -void ImageSync::send_refresh_object_map() { - dout(20) << dendl; +void ImageSync::send_flush_sync_point() { + if (m_ret_val < 0) { + finish(m_ret_val); + return; + } + + update_progress("FLUSH_SYNC_POINT"); + + m_client_meta_copy = *m_client_meta; + m_client_meta->sync_object_count = m_image_copy_object_count; + auto sync_point = &m_client_meta->sync_points.front(); + if (m_image_copy_object_no > 0) { + sync_point->object_number = m_image_copy_object_no - 1; + } else { + sync_point->object_number = boost::none; + } + + dout(20) << ": sync_point=" << *sync_point << dendl; - update_progress("REFRESH_OBJECT_MAP"); + bufferlist client_data_bl; + librbd::journal::ClientData client_data(*m_client_meta); + ::encode(client_data, client_data_bl); Context *ctx = create_context_callback< - ImageSync, &ImageSync::handle_refresh_object_map>(this); - m_object_map = m_local_image_ctx->create_object_map(CEPH_NOSNAP); - m_object_map->open(ctx); + ImageSync, &ImageSync::handle_flush_sync_point>( + this); + m_journaler->update_client(client_data_bl, ctx); } template -void ImageSync::handle_refresh_object_map(int r) { - dout(20) << dendl; +void ImageSync::handle_flush_sync_point(int r) { + dout(20) << ": r=" << r << dendl; - assert(r == 0); - { - RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock); - std::swap(m_local_image_ctx->object_map, m_object_map); + if (r < 0) { + *m_client_meta = m_client_meta_copy; + + derr << ": failed to update client data: " << cpp_strerror(r) + << dendl; + finish(r); + return; } - delete m_object_map; send_prune_sync_points(); } @@ -385,30 +437,6 @@ void ImageSync::handle_prune_sync_points(int r) { return; } - send_copy_metadata(); -} - -template -void ImageSync::send_copy_metadata() { - dout(20) << dendl; - update_progress("COPY_METADATA"); - - Context *ctx = create_context_callback< - ImageSync, &ImageSync::handle_copy_metadata>(this); - auto request = MetadataCopyRequest::create( - m_local_image_ctx, m_remote_image_ctx, ctx); - request->send(); -} - -template -void ImageSync::handle_copy_metadata(int r) { - dout(20) << ": r=" << r << dendl; - if (r < 0) { - derr << ": failed to copy metadata: " << cpp_strerror(r) << dendl; - finish(r); - return; - } - finish(0); } diff --git a/src/tools/rbd_mirror/ImageSync.h b/src/tools/rbd_mirror/ImageSync.h index 7e836b716f716..9e00c1290cf58 100644 --- a/src/tools/rbd_mirror/ImageSync.h +++ b/src/tools/rbd_mirror/ImageSync.h @@ -7,6 +7,7 @@ #include "include/int_types.h" #include "librbd/ImageCtx.h" #include "librbd/journal/TypeTraits.h" +#include "librbd/journal/Types.h" #include "common/Mutex.h" #include "tools/rbd_mirror/BaseRequest.h" #include @@ -14,9 +15,9 @@ class Context; class ContextWQ; -class Mutex; -class SafeTimer; namespace journal { class Journaler; } +namespace librbd { class ProgressContext; } +namespace librbd { template class DeepCopyRequest; } namespace librbd { namespace journal { struct MirrorPeerClientMeta; } } namespace rbd { @@ -26,9 +27,6 @@ class ProgressContext; template class InstanceWatcher; -namespace image_sync { template class ImageCopyRequest; } -namespace image_sync { template class SnapshotCopyRequest; } - template class ImageSync : public BaseRequest { public: @@ -37,8 +35,9 @@ class ImageSync : public BaseRequest { typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta; static ImageSync* create(ImageCtxT *local_image_ctx, - ImageCtxT *remote_image_ctx, SafeTimer *timer, - Mutex *timer_lock, const std::string &mirror_uuid, + ImageCtxT *remote_image_ctx, + SafeTimer *timer, Mutex *timer_lock, + const std::string &mirror_uuid, Journaler *journaler, MirrorPeerClientMeta *client_meta, ContextWQ *work_queue, @@ -79,22 +78,13 @@ class ImageSync : public BaseRequest { * CREATE_SYNC_POINT (skip if already exists and * | not disconnected) * v - * COPY_SNAPSHOTS - * | - * v * COPY_IMAGE . . . . . . . . . . . . . . * | . * v . - * COPY_OBJECT_MAP (skip if object . - * | map disabled) . - * v . - * REFRESH_OBJECT_MAP (skip if object . - * | map disabled) . - * v . - * PRUNE_SYNC_POINTS . (image sync canceled) - * | . + * FLUSH_SYNC_POINT . + * | . (image sync canceled) * v . - * COPY_METADATA . + * PRUNE_SYNC_POINTS . * | . * v . * < . . . . . . . . . . . . . . @@ -104,6 +94,7 @@ class ImageSync : public BaseRequest { typedef std::vector SnapIds; typedef std::map SnapMap; + class ImageCopyProgressContext; ImageCtxT *m_local_image_ctx; ImageCtxT *m_remote_image_ctx; @@ -121,9 +112,17 @@ class ImageSync : public BaseRequest { Mutex m_lock; bool m_canceled = false; - image_sync::SnapshotCopyRequest *m_snapshot_copy_request = nullptr; - image_sync::ImageCopyRequest *m_image_copy_request = nullptr; - decltype(ImageCtxT::object_map) m_object_map = nullptr; + librbd::DeepCopyRequest *m_image_copy_request = nullptr; + librbd::ProgressContext *m_image_copy_prog_ctx = nullptr; + + bool m_updating_sync_point = false; + Context *m_update_sync_ctx = nullptr; + double m_update_sync_point_interval; + uint64_t m_image_copy_object_no = 0; + uint64_t m_image_copy_object_count = 0; + MirrorPeerClientMeta m_client_meta_copy; + + int m_ret_val = 0; void send_notify_sync_request(); void handle_notify_sync_request(int r); @@ -134,24 +133,22 @@ class ImageSync : public BaseRequest { void send_create_sync_point(); void handle_create_sync_point(int r); - void send_copy_snapshots(); - void handle_copy_snapshots(int r); + void send_update_max_object_count(); + void handle_update_max_object_count(int r); void send_copy_image(); void handle_copy_image(int r); + void handle_copy_image_update_progress(uint64_t object_no, + uint64_t object_count); + void send_update_sync_point(); + void handle_update_sync_point(int r); - void send_copy_object_map(); - void handle_copy_object_map(int r); - - void send_refresh_object_map(); - void handle_refresh_object_map(int r); + void send_flush_sync_point(); + void handle_flush_sync_point(int r); void send_prune_sync_points(); void handle_prune_sync_points(int r); - void send_copy_metadata(); - void handle_copy_metadata(int r); - void update_progress(const std::string &description); }; diff --git a/src/tools/rbd_mirror/image_sync/ImageCopyRequest.cc b/src/tools/rbd_mirror/image_sync/ImageCopyRequest.cc deleted file mode 100644 index 6768caa005bd4..0000000000000 --- a/src/tools/rbd_mirror/image_sync/ImageCopyRequest.cc +++ /dev/null @@ -1,423 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "ImageCopyRequest.h" -#include "ObjectCopyRequest.h" -#include "include/stringify.h" -#include "common/errno.h" -#include "common/Timer.h" -#include "journal/Journaler.h" -#include "librbd/Utils.h" -#include "tools/rbd_mirror/ProgressContext.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_sync::ImageCopyRequest: " \ - << this << " " << __func__ - -namespace rbd { -namespace mirror { -namespace image_sync { - -using librbd::util::create_context_callback; -using librbd::util::unique_lock_name; - -template -ImageCopyRequest::ImageCopyRequest(I *local_image_ctx, I *remote_image_ctx, - SafeTimer *timer, Mutex *timer_lock, - Journaler *journaler, - MirrorPeerClientMeta *client_meta, - MirrorPeerSyncPoint *sync_point, - Context *on_finish, - ProgressContext *progress_ctx) - : BaseRequest("rbd::mirror::image_sync::ImageCopyRequest", - local_image_ctx->cct, on_finish), - m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx), - m_timer(timer), m_timer_lock(timer_lock), m_journaler(journaler), - m_client_meta(client_meta), m_sync_point(sync_point), - m_progress_ctx(progress_ctx), - m_lock(unique_lock_name("ImageCopyRequest::m_lock", this)), - m_updating_sync_point(false), m_update_sync_ctx(nullptr), - m_update_sync_point_interval(m_local_image_ctx->cct->_conf->template get_val( - "rbd_mirror_sync_point_update_age")), - m_client_meta_copy(*client_meta) { - assert(!m_client_meta_copy.sync_points.empty()); -} - -template -void ImageCopyRequest::send() { - int r = compute_snap_map(); - if (r < 0) { - finish(r); - return; - } - - send_update_max_object_count(); -} - -template -void ImageCopyRequest::cancel() { - Mutex::Locker locker(m_lock); - - dout(20) << dendl; - m_canceled = true; -} - -template -void ImageCopyRequest::send_update_max_object_count() { - uint64_t max_objects = m_client_meta->sync_object_count; - { - RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock); - max_objects = std::max(max_objects, - m_remote_image_ctx->get_object_count(CEPH_NOSNAP)); - for (auto snap_id : m_remote_image_ctx->snaps) { - max_objects = std::max(max_objects, - m_remote_image_ctx->get_object_count(snap_id)); - } - } - - if (max_objects <= m_client_meta->sync_object_count) { - send_object_copies(); - return; - } - - update_progress("UPDATE_MAX_OBJECT_COUNT"); - - dout(20) << ": sync_object_count=" << max_objects << dendl; - - m_client_meta_copy = *m_client_meta; - m_client_meta_copy.sync_object_count = max_objects; - - bufferlist client_data_bl; - librbd::journal::ClientData client_data(m_client_meta_copy); - ::encode(client_data, client_data_bl); - - Context *ctx = create_context_callback< - ImageCopyRequest, &ImageCopyRequest::handle_update_max_object_count>( - this); - m_journaler->update_client(client_data_bl, ctx); -} - -template -void ImageCopyRequest::handle_update_max_object_count(int r) { - dout(20) << ": r=" << r << dendl; - - if (r == 0) { - Mutex::Locker locker(m_lock); - if (m_canceled) { - dout(10) << ": image copy canceled" << dendl; - r = -ECANCELED; - } - } - - if (r < 0) { - if (r != -ECANCELED) { - derr << ": failed to update client data: " << cpp_strerror(r) << dendl; - } - finish(r); - return; - } - - // update provided meta structure to reflect reality - m_client_meta->sync_object_count = m_client_meta_copy.sync_object_count; - - send_object_copies(); -} - -template -void ImageCopyRequest::send_object_copies() { - CephContext *cct = m_local_image_ctx->cct; - - m_object_no = 0; - if (m_sync_point->object_number) { - m_object_no = *m_sync_point->object_number + 1; - } - m_end_object_no = m_client_meta->sync_object_count; - - dout(20) << ": start_object=" << m_object_no << ", " - << "end_object=" << m_end_object_no << dendl; - - update_progress("COPY_OBJECT"); - - bool complete; - { - Mutex::Locker locker(m_lock); - for (int i = 0; i < cct->_conf->get_val("rbd_concurrent_management_ops"); ++i) { - send_next_object_copy(); - if (m_ret_val < 0 && m_current_ops == 0) { - break; - } - } - complete = (m_current_ops == 0); - - if (!complete) { - m_update_sync_ctx = new FunctionContext([this](int r) { - this->send_update_sync_point(); - }); - } - } - - { - Mutex::Locker timer_locker(*m_timer_lock); - if (m_update_sync_ctx) { - m_update_sync_ctx = m_timer->add_event_after( - m_update_sync_point_interval, - m_update_sync_ctx); - } - } - - if (complete) { - send_flush_sync_point(); - } -} - -template -void ImageCopyRequest::send_next_object_copy() { - assert(m_lock.is_locked()); - - if (m_canceled && m_ret_val == 0) { - dout(10) << ": image copy canceled" << dendl; - m_ret_val = -ECANCELED; - } - - if (m_ret_val < 0 || m_object_no >= m_end_object_no) { - return; - } - - uint64_t ono = m_object_no++; - - dout(20) << ": object_num=" << ono << dendl; - - ++m_current_ops; - - Context *ctx = create_context_callback< - ImageCopyRequest, &ImageCopyRequest::handle_object_copy>(this); - ObjectCopyRequest *req = ObjectCopyRequest::create( - m_local_image_ctx, m_remote_image_ctx, &m_snap_map, ono, ctx); - req->send(); -} - -template -void ImageCopyRequest::handle_object_copy(int r) { - dout(20) << ": r=" << r << dendl; - - int percent; - bool complete; - { - Mutex::Locker locker(m_lock); - assert(m_current_ops > 0); - --m_current_ops; - - percent = 100 * m_object_no / m_end_object_no; - - if (r < 0) { - derr << ": object copy failed: " << cpp_strerror(r) << dendl; - if (m_ret_val == 0) { - m_ret_val = r; - } - } - - send_next_object_copy(); - complete = (m_current_ops == 0); - } - - update_progress("COPY_OBJECT " + stringify(percent) + "%", false); - - if (complete) { - bool do_flush = true; - { - Mutex::Locker timer_locker(*m_timer_lock); - Mutex::Locker locker(m_lock); - if (!m_updating_sync_point) { - if (m_update_sync_ctx != nullptr) { - m_timer->cancel_event(m_update_sync_ctx); - m_update_sync_ctx = nullptr; - } - } else { - do_flush = false; - } - } - - if (do_flush) { - send_flush_sync_point(); - } - } -} - -template -void ImageCopyRequest::send_update_sync_point() { - Mutex::Locker l(m_lock); - - m_update_sync_ctx = nullptr; - - if (m_canceled || m_ret_val < 0 || m_current_ops == 0) { - return; - } - - if (m_sync_point->object_number && - (m_object_no-1) == m_sync_point->object_number.get()) { - // update sync point did not progress since last sync - return; - } - - m_updating_sync_point = true; - - m_client_meta_copy = *m_client_meta; - m_sync_point->object_number = m_object_no - 1; - - CephContext *cct = m_local_image_ctx->cct; - ldout(cct, 20) << ": sync_point=" << *m_sync_point << dendl; - - bufferlist client_data_bl; - librbd::journal::ClientData client_data(*m_client_meta); - ::encode(client_data, client_data_bl); - - Context *ctx = create_context_callback< - ImageCopyRequest, &ImageCopyRequest::handle_update_sync_point>( - this); - m_journaler->update_client(client_data_bl, ctx); -} - -template -void ImageCopyRequest::handle_update_sync_point(int r) { - CephContext *cct = m_local_image_ctx->cct; - ldout(cct, 20) << ": r=" << r << dendl; - - if (r < 0) { - *m_client_meta = m_client_meta_copy; - lderr(cct) << ": failed to update client data: " << cpp_strerror(r) - << dendl; - } - - bool complete; - { - Mutex::Locker l(m_lock); - m_updating_sync_point = false; - - complete = m_current_ops == 0 || m_canceled || m_ret_val < 0; - - if (!complete) { - m_update_sync_ctx = new FunctionContext([this](int r) { - this->send_update_sync_point(); - }); - } - } - - if (!complete) { - Mutex::Locker timer_lock(*m_timer_lock); - if (m_update_sync_ctx) { - m_timer->add_event_after(m_update_sync_point_interval, - m_update_sync_ctx); - } - } else { - send_flush_sync_point(); - } -} - -template -void ImageCopyRequest::send_flush_sync_point() { - if (m_ret_val < 0) { - finish(m_ret_val); - return; - } - - update_progress("FLUSH_SYNC_POINT"); - - m_client_meta_copy = *m_client_meta; - if (m_object_no > 0) { - m_sync_point->object_number = m_object_no - 1; - } else { - m_sync_point->object_number = boost::none; - } - - dout(20) << ": sync_point=" << *m_sync_point << dendl; - - bufferlist client_data_bl; - librbd::journal::ClientData client_data(m_client_meta_copy); - ::encode(client_data, client_data_bl); - - Context *ctx = create_context_callback< - ImageCopyRequest, &ImageCopyRequest::handle_flush_sync_point>( - this); - m_journaler->update_client(client_data_bl, ctx); -} - -template -void ImageCopyRequest::handle_flush_sync_point(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - *m_client_meta = m_client_meta_copy; - - derr << ": failed to update client data: " << cpp_strerror(r) - << dendl; - finish(r); - return; - } - - finish(0); -} - -template -int ImageCopyRequest::compute_snap_map() { - - librados::snap_t snap_id_start = 0; - librados::snap_t snap_id_end; - { - RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock); - snap_id_end = m_remote_image_ctx->get_snap_id( - cls::rbd::UserSnapshotNamespace(), m_sync_point->snap_name); - if (snap_id_end == CEPH_NOSNAP) { - derr << ": failed to locate snapshot: " - << m_sync_point->snap_name << dendl; - return -ENOENT; - } - - if (!m_sync_point->from_snap_name.empty()) { - snap_id_start = m_remote_image_ctx->get_snap_id( - cls::rbd::UserSnapshotNamespace(), m_sync_point->from_snap_name); - if (snap_id_start == CEPH_NOSNAP) { - derr << ": failed to locate from snapshot: " - << m_sync_point->from_snap_name << dendl; - return -ENOENT; - } - } - } - - SnapIds snap_ids; - for (auto it = m_client_meta->snap_seqs.begin(); - it != m_client_meta->snap_seqs.end(); ++it) { - snap_ids.insert(snap_ids.begin(), it->second); - if (it->first < snap_id_start) { - continue; - } else if (it->first > snap_id_end) { - break; - } - - m_snap_map[it->first] = snap_ids; - } - - if (m_snap_map.empty()) { - derr << ": failed to map snapshots within boundary" << dendl; - return -EINVAL; - } - - return 0; -} - -template -void ImageCopyRequest::update_progress(const std::string &description, - bool flush) { - dout(20) << ": " << description << dendl; - - if (m_progress_ctx) { - m_progress_ctx->update_progress("IMAGE_COPY/" + description, flush); - } -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_sync::ImageCopyRequest; diff --git a/src/tools/rbd_mirror/image_sync/ImageCopyRequest.h b/src/tools/rbd_mirror/image_sync/ImageCopyRequest.h deleted file mode 100644 index 4be826aa127ae..0000000000000 --- a/src/tools/rbd_mirror/image_sync/ImageCopyRequest.h +++ /dev/null @@ -1,133 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_SYNC_IMAGE_COPY_REQUEST_H -#define RBD_MIRROR_IMAGE_SYNC_IMAGE_COPY_REQUEST_H - -#include "include/int_types.h" -#include "include/rados/librados.hpp" -#include "common/Mutex.h" -#include "librbd/journal/Types.h" -#include "librbd/journal/TypeTraits.h" -#include "tools/rbd_mirror/BaseRequest.h" -#include -#include - -class Context; -class SafeTimer; -namespace journal { class Journaler; } -namespace librbd { struct ImageCtx; } - -namespace rbd { -namespace mirror { - -class ProgressContext; - -namespace image_sync { - -template -class ImageCopyRequest : public BaseRequest { -public: - typedef std::vector SnapIds; - typedef std::map SnapMap; - typedef librbd::journal::TypeTraits TypeTraits; - typedef typename TypeTraits::Journaler Journaler; - typedef librbd::journal::MirrorPeerSyncPoint MirrorPeerSyncPoint; - typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta; - typedef rbd::mirror::ProgressContext ProgressContext; - - static ImageCopyRequest* create(ImageCtxT *local_image_ctx, - ImageCtxT *remote_image_ctx, - SafeTimer *timer, Mutex *timer_lock, - Journaler *journaler, - MirrorPeerClientMeta *client_meta, - MirrorPeerSyncPoint *sync_point, - Context *on_finish, - ProgressContext *progress_ctx = nullptr) { - return new ImageCopyRequest(local_image_ctx, remote_image_ctx, timer, - timer_lock, journaler, client_meta, sync_point, - on_finish, progress_ctx); - } - - ImageCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx, - SafeTimer *timer, Mutex *timer_lock, Journaler *journaler, - MirrorPeerClientMeta *client_meta, - MirrorPeerSyncPoint *sync_point, Context *on_finish, - ProgressContext *progress_ctx = nullptr); - - void send() override; - void cancel() override; - -private: - /** - * @verbatim - * - * - * | - * v - * UPDATE_MAX_OBJECT_COUNT - * | - * | . . . . . - * | . . (parallel execution of - * v v . multiple objects at once) - * COPY_OBJECT . . - * | - * v - * FLUSH_SYNC_POINT - * | - * v - * - * - * @endverbatim - */ - - ImageCtxT *m_local_image_ctx; - ImageCtxT *m_remote_image_ctx; - SafeTimer *m_timer; - Mutex *m_timer_lock; - Journaler *m_journaler; - MirrorPeerClientMeta *m_client_meta; - MirrorPeerSyncPoint *m_sync_point; - ProgressContext *m_progress_ctx; - - SnapMap m_snap_map; - - Mutex m_lock; - bool m_canceled = false; - - uint64_t m_object_no = 0; - uint64_t m_end_object_no; - uint64_t m_current_ops = 0; - int m_ret_val = 0; - - bool m_updating_sync_point; - Context *m_update_sync_ctx; - double m_update_sync_point_interval; - - MirrorPeerClientMeta m_client_meta_copy; - - void send_update_max_object_count(); - void handle_update_max_object_count(int r); - - void send_object_copies(); - void send_next_object_copy(); - void handle_object_copy(int r); - - void send_update_sync_point(); - void handle_update_sync_point(int r); - - void send_flush_sync_point(); - void handle_flush_sync_point(int r); - - int compute_snap_map(); - - void update_progress(const std::string &description, bool flush = true); -}; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_sync::ImageCopyRequest; - -#endif // RBD_MIRROR_IMAGE_SYNC_IMAGE_COPY_REQUEST_H diff --git a/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.cc b/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.cc deleted file mode 100644 index b9311dc64a640..0000000000000 --- a/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.cc +++ /dev/null @@ -1,119 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "tools/rbd_mirror/image_sync/MetadataCopyRequest.h" -#include "common/dout.h" -#include "common/errno.h" -#include "cls/rbd/cls_rbd_client.h" -#include "librbd/Utils.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_sync::MetadataCopyRequest: " \ - << this << " " << __func__ << ": " - -namespace rbd { -namespace mirror { -namespace image_sync { - -namespace { - -const uint64_t MAX_METADATA_ITEMS = 128; - -} // anonymous namespace - -using librbd::util::create_rados_callback; - -template -void MetadataCopyRequest::send() { - list_remote_metadata(); -} - -template -void MetadataCopyRequest::list_remote_metadata() { - dout(20) << "start_key=" << m_last_metadata_key << dendl; - - librados::ObjectReadOperation op; - librbd::cls_client::metadata_list_start(&op, m_last_metadata_key, MAX_METADATA_ITEMS); - - librados::AioCompletion *aio_comp = create_rados_callback< - MetadataCopyRequest, - &MetadataCopyRequest::handle_list_remote_data>(this); - m_out_bl.clear(); - m_remote_image_ctx->md_ctx.aio_operate(m_remote_image_ctx->header_oid, - aio_comp, &op, &m_out_bl); - aio_comp->release(); -} - -template -void MetadataCopyRequest::handle_list_remote_data(int r) { - dout(20) << "r=" << r << dendl; - - Metadata metadata; - if (r == 0) { - bufferlist::iterator it = m_out_bl.begin(); - r = librbd::cls_client::metadata_list_finish(&it, &metadata); - } - - if (r < 0) { - derr << "failed to retrieve metadata: " << cpp_strerror(r) << dendl; - finish(r); - return; - } - - if (metadata.empty()) { - finish(0); - return; - } - - m_last_metadata_key = metadata.rbegin()->first; - m_more_metadata = (metadata.size() >= MAX_METADATA_ITEMS); - set_local_metadata(metadata); -} - -template -void MetadataCopyRequest::set_local_metadata(const Metadata& metadata) { - dout(20) << "count=" << metadata.size() << dendl; - - librados::ObjectWriteOperation op; - librbd::cls_client::metadata_set(&op, metadata); - - librados::AioCompletion *aio_comp = create_rados_callback< - MetadataCopyRequest, - &MetadataCopyRequest::handle_set_local_metadata>(this); - m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, aio_comp, - &op); - aio_comp->release(); -} - -template -void MetadataCopyRequest::handle_set_local_metadata(int r) { - dout(20) << "r=" << r << dendl; - - if (r < 0) { - derr << "failed to set metadata: " << cpp_strerror(r) << dendl; - finish(r); - return; - } - - if (m_more_metadata) { - list_remote_metadata(); - return; - } - - finish(0); -} - -template -void MetadataCopyRequest::finish(int r) { - dout(20) << "r=" << r << dendl; - m_on_finish->complete(r); - delete this; -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_sync::MetadataCopyRequest; diff --git a/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.h b/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.h deleted file mode 100644 index 967b64020aeb8..0000000000000 --- a/src/tools/rbd_mirror/image_sync/MetadataCopyRequest.h +++ /dev/null @@ -1,82 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_SYNC_METADATA_COPY_REQUEST_H -#define RBD_MIRROR_IMAGE_SYNC_METADATA_COPY_REQUEST_H - -#include "include/int_types.h" -#include "include/buffer.h" -#include "include/rados/librados.hpp" -#include "librbd/ImageCtx.h" -#include -#include - -class Context; - -namespace rbd { -namespace mirror { -namespace image_sync { - -template -class MetadataCopyRequest { -public: - static MetadataCopyRequest* create(ImageCtxT *local_image_ctx, - ImageCtxT *remote_image_ctx, - Context *on_finish) { - return new MetadataCopyRequest(local_image_ctx, remote_image_ctx, - on_finish); - } - - MetadataCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx, - Context *on_finish) - : m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx), - m_on_finish(on_finish) { - } - - void send(); - -private: - /** - * @verbatim - * - * - * | - * v - * LIST_REMOTE_METADATA <-----\ - * | | (repeat if additional - * v | metadata) - * SET_LOCAL_METADATA --------/ - * | - * v - * - * - * @endverbatim - */ - typedef std::map Metadata; - - ImageCtxT *m_local_image_ctx; - ImageCtxT *m_remote_image_ctx; - Context *m_on_finish; - - bufferlist m_out_bl; - - std::string m_last_metadata_key; - bool m_more_metadata = false; - - void list_remote_metadata(); - void handle_list_remote_data(int r); - - void set_local_metadata(const Metadata& metadata); - void handle_set_local_metadata(int r); - - void finish(int r); - -}; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_sync::MetadataCopyRequest; - -#endif // RBD_MIRROR_IMAGE_SYNC_METADATA_COPY_REQUEST_H diff --git a/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc b/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc deleted file mode 100644 index ab9dd8da76c3c..0000000000000 --- a/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.cc +++ /dev/null @@ -1,506 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "ObjectCopyRequest.h" -#include "librados/snap_set_diff.h" -#include "librbd/ExclusiveLock.h" -#include "librbd/ObjectMap.h" -#include "librbd/Utils.h" -#include "common/errno.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_sync::ObjectCopyRequest: " \ - << this << " " << __func__ - -namespace librados { - -bool operator==(const clone_info_t& rhs, const clone_info_t& lhs) { - return (rhs.cloneid == lhs.cloneid && - rhs.snaps == lhs.snaps && - rhs.overlap == lhs.overlap && - rhs.size == lhs.size); -} - -bool operator==(const snap_set_t& rhs, const snap_set_t& lhs) { - return (rhs.clones == lhs.clones && - rhs.seq == lhs.seq); -} - -} // namespace librados - -namespace rbd { -namespace mirror { -namespace image_sync { - -using librbd::util::create_context_callback; -using librbd::util::create_rados_callback; - -template -ObjectCopyRequest::ObjectCopyRequest(I *local_image_ctx, I *remote_image_ctx, - const SnapMap *snap_map, - uint64_t object_number, - Context *on_finish) - : m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx), - m_snap_map(snap_map), m_object_number(object_number), - m_on_finish(on_finish) { - assert(!snap_map->empty()); - - m_local_io_ctx.dup(m_local_image_ctx->data_ctx); - m_local_oid = m_local_image_ctx->get_object_name(object_number); - - m_remote_io_ctx.dup(m_remote_image_ctx->data_ctx); - m_remote_oid = m_remote_image_ctx->get_object_name(object_number); - - dout(20) << ": " - << "remote_oid=" << m_remote_oid << ", " - << "local_oid=" << m_local_oid << dendl; -} - -template -void ObjectCopyRequest::send() { - send_list_snaps(); -} - -template -void ObjectCopyRequest::send_list_snaps() { - dout(20) << dendl; - - librados::AioCompletion *rados_completion = create_rados_callback< - ObjectCopyRequest, &ObjectCopyRequest::handle_list_snaps>(this); - - librados::ObjectReadOperation op; - m_snap_set = {}; - m_snap_ret = 0; - op.list_snaps(&m_snap_set, &m_snap_ret); - - m_remote_io_ctx.snap_set_read(CEPH_SNAPDIR); - int r = m_remote_io_ctx.aio_operate(m_remote_oid, rados_completion, &op, - nullptr); - assert(r == 0); - rados_completion->release(); -} - -template -void ObjectCopyRequest::handle_list_snaps(int r) { - if (r == 0 && m_snap_ret < 0) { - r = m_snap_ret; - } - - dout(20) << ": r=" << r << dendl; - - if (r == -ENOENT) { - finish(0); - return; - } - - if (r < 0) { - derr << ": failed to list snaps: " << cpp_strerror(r) << dendl; - finish(r); - return; - } - - if (m_retry_missing_read) { - if (m_snap_set == m_retry_snap_set) { - derr << ": read encountered missing object using up-to-date snap set" - << dendl; - finish(-ENOENT); - return; - } - - dout(20) << ": retrying using updated snap set" << dendl; - m_retry_missing_read = false; - m_retry_snap_set = {}; - } - - compute_diffs(); - send_read_object(); -} - -template -void ObjectCopyRequest::send_read_object() { - if (m_snap_sync_ops.empty()) { - // no more snapshot diffs to read from remote - finish(0); - return; - } - - // build the read request - auto &sync_ops = m_snap_sync_ops.begin()->second; - assert(!sync_ops.empty()); - - bool read_required = false; - librados::ObjectReadOperation op; - for (auto &sync_op : sync_ops) { - switch (sync_op.type) { - case SYNC_OP_TYPE_WRITE: - if (!read_required) { - // map the sync op start snap id back to the necessary read snap id - librados::snap_t remote_snap_seq = - m_snap_sync_ops.begin()->first.second; - m_remote_io_ctx.snap_set_read(remote_snap_seq); - - dout(20) << ": remote_snap_seq=" << remote_snap_seq << dendl; - read_required = true; - } - dout(20) << ": read op: " << sync_op.offset << "~" << sync_op.length - << dendl; - op.sparse_read(sync_op.offset, sync_op.length, &sync_op.extent_map, - &sync_op.out_bl, nullptr); - op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | - LIBRADOS_OP_FLAG_FADVISE_NOCACHE); - break; - default: - break; - } - } - - if (!read_required) { - // nothing written to this object for this snapshot (must be trunc/remove) - send_write_object(); - return; - } - - librados::AioCompletion *comp = create_rados_callback< - ObjectCopyRequest, &ObjectCopyRequest::handle_read_object>(this); - int r = m_remote_io_ctx.aio_operate(m_remote_oid, comp, &op, nullptr); - assert(r == 0); - comp->release(); -} - -template -void ObjectCopyRequest::handle_read_object(int r) { - dout(20) << ": r=" << r << dendl; - - if (r == -ENOENT) { - m_retry_snap_set = m_snap_set; - m_retry_missing_read = true; - - dout(5) << ": object missing potentially due to removed snapshot" << dendl; - send_list_snaps(); - return; - } - - if (r < 0) { - derr << ": failed to read from remote object: " << cpp_strerror(r) - << dendl; - finish(r); - return; - } - - send_write_object(); -} - -template -void ObjectCopyRequest::send_write_object() { - // retrieve the local snap context for the op - SnapIds local_snap_ids; - librados::snap_t local_snap_seq = 0; - librados::snap_t remote_snap_seq = m_snap_sync_ops.begin()->first.first; - if (remote_snap_seq != 0) { - auto snap_map_it = m_snap_map->find(remote_snap_seq); - assert(snap_map_it != m_snap_map->end()); - - // write snapshot context should be before actual snapshot - if (snap_map_it != m_snap_map->begin()) { - --snap_map_it; - assert(!snap_map_it->second.empty()); - local_snap_seq = snap_map_it->second.front(); - local_snap_ids = snap_map_it->second; - } - } - - Context *finish_op_ctx; - { - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - finish_op_ctx = start_local_op(m_local_image_ctx->owner_lock); - } - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - dout(20) << ": " - << "local_snap_seq=" << local_snap_seq << ", " - << "local_snaps=" << local_snap_ids << dendl; - - auto &sync_ops = m_snap_sync_ops.begin()->second; - assert(!sync_ops.empty()); - uint64_t object_offset; - uint64_t buffer_offset; - librados::ObjectWriteOperation op; - for (auto &sync_op : sync_ops) { - switch (sync_op.type) { - case SYNC_OP_TYPE_WRITE: - object_offset = sync_op.offset; - buffer_offset = 0; - for (auto it : sync_op.extent_map) { - if (object_offset < it.first) { - dout(20) << ": zero op: " << object_offset << "~" - << it.first - object_offset << dendl; - op.zero(object_offset, it.first - object_offset); - } - dout(20) << ": write op: " << it.first << "~" << it.second << dendl; - bufferlist tmpbl; - tmpbl.substr_of(sync_op.out_bl, buffer_offset, it.second); - op.write(it.first, tmpbl); - op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | - LIBRADOS_OP_FLAG_FADVISE_NOCACHE); - buffer_offset += it.second; - object_offset = it.first + it.second; - } - if (object_offset < sync_op.offset + sync_op.length) { - uint64_t sync_op_end = sync_op.offset + sync_op.length; - assert(sync_op_end <= m_snap_object_sizes[remote_snap_seq]); - if (sync_op_end == m_snap_object_sizes[remote_snap_seq]) { - dout(20) << ": trunc op: " << object_offset << dendl; - op.truncate(object_offset); - m_snap_object_sizes[remote_snap_seq] = object_offset; - } else { - dout(20) << ": zero op: " << object_offset << "~" - << sync_op_end - object_offset << dendl; - op.zero(object_offset, sync_op_end - object_offset); - } - } - break; - case SYNC_OP_TYPE_TRUNC: - if (sync_op.offset > m_snap_object_sizes[remote_snap_seq]) { - // skip (must have been updated in WRITE op case issuing trunc op) - break; - } - dout(20) << ": trunc op: " << sync_op.offset << dendl; - op.truncate(sync_op.offset); - break; - case SYNC_OP_TYPE_REMOVE: - dout(20) << ": remove op" << dendl; - op.remove(); - break; - default: - ceph_abort(); - } - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_write_object(r); - finish_op_ctx->complete(0); - }); - librados::AioCompletion *comp = create_rados_callback(ctx); - int r = m_local_io_ctx.aio_operate(m_local_oid, comp, &op, local_snap_seq, - local_snap_ids); - assert(r == 0); - comp->release(); -} - -template -void ObjectCopyRequest::handle_write_object(int r) { - dout(20) << ": r=" << r << dendl; - - if (r == -ENOENT) { - r = 0; - } - if (r < 0) { - derr << ": failed to write to local object: " << cpp_strerror(r) - << dendl; - finish(r); - return; - } - - m_snap_sync_ops.erase(m_snap_sync_ops.begin()); - if (!m_snap_sync_ops.empty()) { - send_read_object(); - return; - } - - send_update_object_map(); -} - -template -void ObjectCopyRequest::send_update_object_map() { - m_local_image_ctx->owner_lock.get_read(); - m_local_image_ctx->snap_lock.get_read(); - if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP, - m_local_image_ctx->snap_lock) || - m_snap_object_states.empty()) { - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); - finish(0); - return; - } else if (m_local_image_ctx->object_map == nullptr) { - // possible that exclusive lock was lost in background - derr << ": object map is not initialized" << dendl; - - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); - finish(-EINVAL); - return; - } - - assert(m_local_image_ctx->object_map != nullptr); - - auto snap_object_state = *m_snap_object_states.begin(); - m_snap_object_states.erase(m_snap_object_states.begin()); - - dout(20) << ": " - << "local_snap_id=" << snap_object_state.first << ", " - << "object_state=" << static_cast(snap_object_state.second) - << dendl; - - auto finish_op_ctx = start_local_op(m_local_image_ctx->owner_lock); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_update_object_map(r); - finish_op_ctx->complete(0); - }); - - RWLock::WLocker object_map_locker(m_local_image_ctx->object_map_lock); - bool sent = m_local_image_ctx->object_map->template aio_update< - Context, &Context::complete>( - snap_object_state.first, m_object_number, snap_object_state.second, {}, - {}, ctx); - assert(sent); - m_local_image_ctx->snap_lock.put_read(); - m_local_image_ctx->owner_lock.put_read(); -} - -template -void ObjectCopyRequest::handle_update_object_map(int r) { - dout(20) << ": r=" << r << dendl; - - assert(r == 0); - if (!m_snap_object_states.empty()) { - send_update_object_map(); - return; - } - finish(0); -} - -template -Context *ObjectCopyRequest::start_local_op(RWLock &owner_lock) { - assert(m_local_image_ctx->owner_lock.is_locked()); - if (m_local_image_ctx->exclusive_lock == nullptr) { - return nullptr; - } - return m_local_image_ctx->exclusive_lock->start_op(); -} - -template -void ObjectCopyRequest::compute_diffs() { - CephContext *cct = m_local_image_ctx->cct; - - m_snap_sync_ops = {}; - m_snap_object_states = {}; - m_snap_object_sizes = {}; - - librados::snap_t remote_sync_pont_snap_id = m_snap_map->rbegin()->first; - uint64_t prev_end_size = 0; - bool prev_exists = false; - librados::snap_t start_remote_snap_id = 0; - for (auto &pair : *m_snap_map) { - assert(!pair.second.empty()); - librados::snap_t end_remote_snap_id = pair.first; - librados::snap_t end_local_snap_id = pair.second.front(); - - interval_set diff; - uint64_t end_size; - bool exists; - librados::snap_t clone_end_snap_id; - calc_snap_set_diff(cct, m_snap_set, start_remote_snap_id, - end_remote_snap_id, &diff, &end_size, &exists, - &clone_end_snap_id); - - dout(20) << ": " - << "start_remote_snap=" << start_remote_snap_id << ", " - << "end_remote_snap_id=" << end_remote_snap_id << ", " - << "clone_end_snap_id=" << clone_end_snap_id << ", " - << "end_local_snap_id=" << end_local_snap_id << ", " - << "diff=" << diff << ", " - << "end_size=" << end_size << ", " - << "exists=" << exists << dendl; - if (exists) { - // clip diff to size of object (in case it was truncated) - if (end_size < prev_end_size) { - interval_set trunc; - trunc.insert(end_size, prev_end_size); - trunc.intersection_of(diff); - diff.subtract(trunc); - dout(20) << ": clearing truncate diff: " << trunc << dendl; - } - - // prepare the object map state - { - RWLock::RLocker snap_locker(m_local_image_ctx->snap_lock); - uint8_t object_state = OBJECT_EXISTS; - if (m_local_image_ctx->test_features(RBD_FEATURE_FAST_DIFF, - m_local_image_ctx->snap_lock) && - prev_exists && diff.empty() && end_size == prev_end_size) { - object_state = OBJECT_EXISTS_CLEAN; - } - m_snap_object_states[end_local_snap_id] = object_state; - } - - // reads should be issued against the newest (existing) snapshot within - // the associated snapshot object clone. writes should be issued - // against the oldest snapshot in the snap_map. - assert(clone_end_snap_id >= end_remote_snap_id); - if (clone_end_snap_id > remote_sync_pont_snap_id) { - // do not read past the sync point snapshot - clone_end_snap_id = remote_sync_pont_snap_id; - } - - // object write/zero, or truncate - // NOTE: a single snapshot clone might represent multiple snapshots, but - // the write/zero and truncate ops will only be associated with the first - // snapshot encountered within the clone since the diff will be empty for - // subsequent snapshots and the size will remain constant for a clone. - for (auto it = diff.begin(); it != diff.end(); ++it) { - dout(20) << ": read/write op: " << it.get_start() << "~" - << it.get_len() << dendl; - m_snap_sync_ops[{end_remote_snap_id, clone_end_snap_id}].emplace_back( - SYNC_OP_TYPE_WRITE, it.get_start(), it.get_len()); - } - if (end_size < prev_end_size) { - dout(20) << ": trunc op: " << end_size << dendl; - m_snap_sync_ops[{end_remote_snap_id, clone_end_snap_id}].emplace_back( - SYNC_OP_TYPE_TRUNC, end_size, 0U); - } - m_snap_object_sizes[end_remote_snap_id] = end_size; - } else { - if (prev_exists) { - // object remove - dout(20) << ": remove op" << dendl; - m_snap_sync_ops[{end_remote_snap_id, end_remote_snap_id}].emplace_back( - SYNC_OP_TYPE_REMOVE, 0U, 0U); - } - } - - prev_end_size = end_size; - prev_exists = exists; - start_remote_snap_id = end_remote_snap_id; - } -} - -template -void ObjectCopyRequest::finish(int r) { - dout(20) << ": r=" << r << dendl; - - // ensure IoCtxs are closed prior to proceeding - auto on_finish = m_on_finish; - delete this; - - on_finish->complete(r); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_sync::ObjectCopyRequest; diff --git a/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.h b/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.h deleted file mode 100644 index 57963c22ca330..0000000000000 --- a/src/tools/rbd_mirror/image_sync/ObjectCopyRequest.h +++ /dev/null @@ -1,153 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_SYNC_OBJECT_COPY_REQUEST_H -#define RBD_MIRROR_IMAGE_SYNC_OBJECT_COPY_REQUEST_H - -#include "include/int_types.h" -#include "include/rados/librados.hpp" -#include "common/snap_types.h" -#include "librbd/ImageCtx.h" -#include -#include -#include -#include - -class Context; -class RWLock; - -namespace rbd { -namespace mirror { -namespace image_sync { - -template -class ObjectCopyRequest { -public: - typedef std::vector SnapIds; - typedef std::map SnapMap; - - static ObjectCopyRequest* create(ImageCtxT *local_image_ctx, - ImageCtxT *remote_image_ctx, - const SnapMap *snap_map, - uint64_t object_number, Context *on_finish) { - return new ObjectCopyRequest(local_image_ctx, remote_image_ctx, snap_map, - object_number, on_finish); - } - - ObjectCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx, - const SnapMap *snap_map, uint64_t object_number, - Context *on_finish); - - void send(); - - // testing support - inline librados::IoCtx &get_local_io_ctx() { - return m_local_io_ctx; - } - inline librados::IoCtx &get_remote_io_ctx() { - return m_remote_io_ctx; - } - -private: - /** - * @verbatim - * - * - * | - * v - * LIST_SNAPS < * * * - * | * (-ENOENT and snap set stale) - * | * * * * * * - * | * - * v * - * READ_OBJECT <--------\ - * | | (repeat for each snapshot) - * v | - * WRITE_OBJECT --------/ - * | - * | /-----------\ - * | | | (repeat for each snapshot) - * v v | - * UPDATE_OBJECT_MAP ---/ (skip if object - * | map disabled) - * | - * v - * - * - * @endverbatim - */ - - enum SyncOpType { - SYNC_OP_TYPE_WRITE, - SYNC_OP_TYPE_TRUNC, - SYNC_OP_TYPE_REMOVE - }; - - typedef std::map ExtentMap; - - struct SyncOp { - SyncOp(SyncOpType type, uint64_t offset, uint64_t length) - : type(type), offset(offset), length(length) { - } - - SyncOpType type; - uint64_t offset; - uint64_t length; - - ExtentMap extent_map; - bufferlist out_bl; - }; - - typedef std::list SyncOps; - typedef std::pair WriteReadSnapIds; - typedef std::map SnapSyncOps; - typedef std::map SnapObjectStates; - typedef std::map SnapObjectSizes; - - ImageCtxT *m_local_image_ctx; - ImageCtxT *m_remote_image_ctx; - const SnapMap *m_snap_map; - uint64_t m_object_number; - Context *m_on_finish; - - decltype(m_local_image_ctx->data_ctx) m_local_io_ctx; - decltype(m_remote_image_ctx->data_ctx) m_remote_io_ctx; - std::string m_local_oid; - std::string m_remote_oid; - - librados::snap_set_t m_snap_set; - int m_snap_ret = 0; - - bool m_retry_missing_read = false; - librados::snap_set_t m_retry_snap_set; - - SnapSyncOps m_snap_sync_ops; - SnapObjectStates m_snap_object_states; - SnapObjectSizes m_snap_object_sizes; - - void send_list_snaps(); - void handle_list_snaps(int r); - - void send_read_object(); - void handle_read_object(int r); - - void send_write_object(); - void handle_write_object(int r); - - void send_update_object_map(); - void handle_update_object_map(int r); - - Context *start_local_op(RWLock &owner_lock); - - void compute_diffs(); - void finish(int r); - -}; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_sync::ObjectCopyRequest; - -#endif // RBD_MIRROR_IMAGE_SYNC_OBJECT_COPY_REQUEST_H diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc deleted file mode 100644 index f5f0701d1134c..0000000000000 --- a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc +++ /dev/null @@ -1,614 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "SnapshotCopyRequest.h" -#include "SnapshotCreateRequest.h" -#include "common/errno.h" -#include "common/WorkQueue.h" -#include "journal/Journaler.h" -#include "librbd/ExclusiveLock.h" -#include "librbd/Operations.h" -#include "librbd/Utils.h" -#include "librbd/journal/Types.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCopyRequest: " \ - << this << " " << __func__ - -namespace rbd { -namespace mirror { -namespace image_sync { - -namespace { - -template -const std::string &get_snapshot_name(I *image_ctx, librados::snap_t snap_id) { - auto snap_it = std::find_if(image_ctx->snap_ids.begin(), - image_ctx->snap_ids.end(), - [snap_id]( - const std::pair< - std::pair, - librados::snap_t> &pair) { - return pair.second == snap_id; - }); - assert(snap_it != image_ctx->snap_ids.end()); - return snap_it->first.second; -} - -} // anonymous namespace - -using librbd::util::create_context_callback; -using librbd::util::unique_lock_name; - -template -SnapshotCopyRequest::SnapshotCopyRequest(I *local_image_ctx, - I *remote_image_ctx, - SnapMap *snap_map, - Journaler *journaler, - librbd::journal::MirrorPeerClientMeta *meta, - ContextWQ *work_queue, - Context *on_finish) - : BaseRequest("rbd::mirror::image_sync::SnapshotCopyRequest", - local_image_ctx->cct, on_finish), - m_local_image_ctx(local_image_ctx), m_remote_image_ctx(remote_image_ctx), - m_snap_map(snap_map), m_journaler(journaler), m_client_meta(meta), - m_work_queue(work_queue), m_snap_seqs(meta->snap_seqs), - m_lock(unique_lock_name("SnapshotCopyRequest::m_lock", this)) { - m_snap_map->clear(); - - // snap ids ordered from oldest to newest - m_remote_snap_ids.insert(remote_image_ctx->snaps.begin(), - remote_image_ctx->snaps.end()); - m_local_snap_ids.insert(local_image_ctx->snaps.begin(), - local_image_ctx->snaps.end()); -} - -template -void SnapshotCopyRequest::send() { - librbd::ParentSpec remote_parent_spec; - int r = validate_parent(m_remote_image_ctx, &remote_parent_spec); - if (r < 0) { - derr << ": remote image parent spec mismatch" << dendl; - error(r); - return; - } - - r = validate_parent(m_local_image_ctx, &m_local_parent_spec); - if (r < 0) { - derr << ": local image parent spec mismatch" << dendl; - error(r); - return; - } - - send_snap_unprotect(); -} - -template -void SnapshotCopyRequest::cancel() { - Mutex::Locker locker(m_lock); - - dout(20) << dendl; - m_canceled = true; -} - -template -void SnapshotCopyRequest::send_snap_unprotect() { - - SnapIdSet::iterator snap_id_it = m_local_snap_ids.begin(); - if (m_prev_snap_id != CEPH_NOSNAP) { - snap_id_it = m_local_snap_ids.upper_bound(m_prev_snap_id); - } - - for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) { - librados::snap_t local_snap_id = *snap_id_it; - - m_local_image_ctx->snap_lock.get_read(); - - bool local_unprotected; - int r = m_local_image_ctx->is_snap_unprotected(local_snap_id, - &local_unprotected); - if (r < 0) { - derr << ": failed to retrieve local snap unprotect status: " - << cpp_strerror(r) << dendl; - m_local_image_ctx->snap_lock.put_read(); - finish(r); - return; - } - m_local_image_ctx->snap_lock.put_read(); - - if (local_unprotected) { - // snap is already unprotected -- check next snap - continue; - } - - // if local snapshot is protected and (1) it isn't in our mapping - // table, or (2) the remote snapshot isn't protected, unprotect it - auto snap_seq_it = std::find_if( - m_snap_seqs.begin(), m_snap_seqs.end(), - [local_snap_id](const SnapSeqs::value_type& pair) { - return pair.second == local_snap_id; - }); - - if (snap_seq_it != m_snap_seqs.end()) { - m_remote_image_ctx->snap_lock.get_read(); - bool remote_unprotected; - r = m_remote_image_ctx->is_snap_unprotected(snap_seq_it->first, - &remote_unprotected); - if (r < 0) { - derr << ": failed to retrieve remote snap unprotect status: " - << cpp_strerror(r) << dendl; - m_remote_image_ctx->snap_lock.put_read(); - finish(r); - return; - } - m_remote_image_ctx->snap_lock.put_read(); - - if (remote_unprotected) { - // remote is unprotected -- unprotect local snap - break; - } - } else { - // remote snapshot doesn't exist -- unprotect local snap - break; - } - } - - if (snap_id_it == m_local_snap_ids.end()) { - // no local snapshots to unprotect - m_prev_snap_id = CEPH_NOSNAP; - send_snap_remove(); - return; - } - - m_prev_snap_id = *snap_id_it; - m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id); - - dout(20) << ": " - << "snap_name=" << m_snap_name << ", " - << "snap_id=" << m_prev_snap_id << dendl; - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_snap_unprotect(r); - finish_op_ctx->complete(0); - }); - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - m_local_image_ctx->operations->execute_snap_unprotect( - cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx); -} - -template -void SnapshotCopyRequest::handle_snap_unprotect(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to unprotect snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - if (handle_cancellation()) - { - return; - } - - send_snap_unprotect(); -} - -template -void SnapshotCopyRequest::send_snap_remove() { - SnapIdSet::iterator snap_id_it = m_local_snap_ids.begin(); - if (m_prev_snap_id != CEPH_NOSNAP) { - snap_id_it = m_local_snap_ids.upper_bound(m_prev_snap_id); - } - - for (; snap_id_it != m_local_snap_ids.end(); ++snap_id_it) { - librados::snap_t local_snap_id = *snap_id_it; - - cls::rbd::SnapshotNamespace snap_namespace; - m_local_image_ctx->snap_lock.get_read(); - int r = m_local_image_ctx->get_snap_namespace(local_snap_id, - &snap_namespace); - m_local_image_ctx->snap_lock.put_read(); - if (r < 0) { - derr << ": failed to retrieve local snap namespace: " << m_snap_name - << dendl; - finish(r); - return; - } - - if (boost::get(&snap_namespace) == - nullptr) { - continue; - } - - // if the local snapshot isn't in our mapping table, remove it - auto snap_seq_it = std::find_if( - m_snap_seqs.begin(), m_snap_seqs.end(), - [local_snap_id](const SnapSeqs::value_type& pair) { - return pair.second == local_snap_id; - }); - - if (snap_seq_it == m_snap_seqs.end()) { - break; - } - } - - if (snap_id_it == m_local_snap_ids.end()) { - // no local snapshots to delete - m_prev_snap_id = CEPH_NOSNAP; - send_snap_create(); - return; - } - - m_prev_snap_id = *snap_id_it; - m_snap_name = get_snapshot_name(m_local_image_ctx, m_prev_snap_id); - - dout(20) << ": " - << "snap_name=" << m_snap_name << ", " - << "snap_id=" << m_prev_snap_id << dendl; - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_snap_remove(r); - finish_op_ctx->complete(0); - }); - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - m_local_image_ctx->operations->execute_snap_remove( - cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx); -} - -template -void SnapshotCopyRequest::handle_snap_remove(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to remove snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - if (handle_cancellation()) - { - return; - } - - send_snap_remove(); -} - -template -void SnapshotCopyRequest::send_snap_create() { - SnapIdSet::iterator snap_id_it = m_remote_snap_ids.begin(); - if (m_prev_snap_id != CEPH_NOSNAP) { - snap_id_it = m_remote_snap_ids.upper_bound(m_prev_snap_id); - } - - for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) { - librados::snap_t remote_snap_id = *snap_id_it; - - cls::rbd::SnapshotNamespace snap_namespace; - m_remote_image_ctx->snap_lock.get_read(); - int r = m_remote_image_ctx->get_snap_namespace(remote_snap_id, &snap_namespace); - m_remote_image_ctx->snap_lock.put_read(); - if (r < 0) { - derr << ": failed to retrieve remote snap namespace: " << m_snap_name - << dendl; - finish(r); - return; - } - - // if the remote snapshot isn't in our mapping table, create it - if (m_snap_seqs.find(remote_snap_id) == m_snap_seqs.end() && - boost::get(&snap_namespace) != nullptr) { - break; - } - } - - if (snap_id_it == m_remote_snap_ids.end()) { - // no remote snapshots to create - m_prev_snap_id = CEPH_NOSNAP; - send_snap_protect(); - return; - } - - m_prev_snap_id = *snap_id_it; - m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id); - - m_remote_image_ctx->snap_lock.get_read(); - auto snap_info_it = m_remote_image_ctx->snap_info.find(m_prev_snap_id); - if (snap_info_it == m_remote_image_ctx->snap_info.end()) { - m_remote_image_ctx->snap_lock.put_read(); - derr << ": failed to retrieve remote snap info: " << m_snap_name - << dendl; - finish(-ENOENT); - return; - } - - uint64_t size = snap_info_it->second.size; - m_snap_namespace = snap_info_it->second.snap_namespace; - librbd::ParentSpec parent_spec; - uint64_t parent_overlap = 0; - if (snap_info_it->second.parent.spec.pool_id != -1) { - parent_spec = m_local_parent_spec; - parent_overlap = snap_info_it->second.parent.overlap; - } - m_remote_image_ctx->snap_lock.put_read(); - - - dout(20) << ": " - << "snap_name=" << m_snap_name << ", " - << "snap_id=" << m_prev_snap_id << ", " - << "size=" << size << ", " - << "parent_info=[" - << "pool_id=" << parent_spec.pool_id << ", " - << "image_id=" << parent_spec.image_id << ", " - << "snap_id=" << parent_spec.snap_id << ", " - << "overlap=" << parent_overlap << "]" << dendl; - - Context *finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_snap_create(r); - finish_op_ctx->complete(0); - }); - SnapshotCreateRequest *req = SnapshotCreateRequest::create( - m_local_image_ctx, m_snap_name, m_snap_namespace, size, parent_spec, - parent_overlap, ctx); - req->send(); -} - -template -void SnapshotCopyRequest::handle_snap_create(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to create snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - if (handle_cancellation()) - { - return; - } - - assert(m_prev_snap_id != CEPH_NOSNAP); - - auto snap_it = m_local_image_ctx->snap_ids.find({cls::rbd::UserSnapshotNamespace(), - m_snap_name}); - assert(snap_it != m_local_image_ctx->snap_ids.end()); - librados::snap_t local_snap_id = snap_it->second; - - dout(20) << ": mapping remote snap id " << m_prev_snap_id << " to " - << local_snap_id << dendl; - m_snap_seqs[m_prev_snap_id] = local_snap_id; - - send_snap_create(); -} - -template -void SnapshotCopyRequest::send_snap_protect() { - SnapIdSet::iterator snap_id_it = m_remote_snap_ids.begin(); - if (m_prev_snap_id != CEPH_NOSNAP) { - snap_id_it = m_remote_snap_ids.upper_bound(m_prev_snap_id); - } - - for (; snap_id_it != m_remote_snap_ids.end(); ++snap_id_it) { - librados::snap_t remote_snap_id = *snap_id_it; - - m_remote_image_ctx->snap_lock.get_read(); - - bool remote_protected; - int r = m_remote_image_ctx->is_snap_protected(remote_snap_id, - &remote_protected); - if (r < 0) { - derr << ": failed to retrieve remote snap protect status: " - << cpp_strerror(r) << dendl; - m_remote_image_ctx->snap_lock.put_read(); - finish(r); - return; - } - m_remote_image_ctx->snap_lock.put_read(); - - if (!remote_protected) { - // snap is not protected -- check next snap - continue; - } - - // if local snapshot is not protected, protect it - auto snap_seq_it = m_snap_seqs.find(remote_snap_id); - assert(snap_seq_it != m_snap_seqs.end()); - - m_local_image_ctx->snap_lock.get_read(); - bool local_protected; - r = m_local_image_ctx->is_snap_protected(snap_seq_it->second, - &local_protected); - if (r < 0) { - derr << ": failed to retrieve local snap protect status: " - << cpp_strerror(r) << dendl; - m_local_image_ctx->snap_lock.put_read(); - finish(r); - return; - } - m_local_image_ctx->snap_lock.put_read(); - - if (!local_protected) { - break; - } - } - - if (snap_id_it == m_remote_snap_ids.end()) { - // no local snapshots to protect - m_prev_snap_id = CEPH_NOSNAP; - send_update_client(); - return; - } - - m_prev_snap_id = *snap_id_it; - m_snap_name = get_snapshot_name(m_remote_image_ctx, m_prev_snap_id); - - dout(20) << ": " - << "snap_name=" << m_snap_name << ", " - << "snap_id=" << m_prev_snap_id << dendl; - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_snap_protect(r); - finish_op_ctx->complete(0); - }); - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - m_local_image_ctx->operations->execute_snap_protect( - cls::rbd::UserSnapshotNamespace(), m_snap_name.c_str(), ctx); -} - -template -void SnapshotCopyRequest::handle_snap_protect(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to protect snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - if (handle_cancellation()) - { - return; - } - - send_snap_protect(); -} - -template -void SnapshotCopyRequest::send_update_client() { - dout(20) << dendl; - - compute_snap_map(); - - librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta); - client_meta.snap_seqs = m_snap_seqs; - - librbd::journal::ClientData client_data(client_meta); - bufferlist data_bl; - ::encode(client_data, data_bl); - - Context *ctx = create_context_callback< - SnapshotCopyRequest, &SnapshotCopyRequest::handle_update_client>( - this); - m_journaler->update_client(data_bl, ctx); -} - -template -void SnapshotCopyRequest::handle_update_client(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to update client data: " << cpp_strerror(r) - << dendl; - finish(r); - return; - } - if (handle_cancellation()) - { - return; - } - - m_client_meta->snap_seqs = m_snap_seqs; - - finish(0); -} - -template -bool SnapshotCopyRequest::handle_cancellation() { - { - Mutex::Locker locker(m_lock); - if (!m_canceled) { - return false; - } - } - dout(10) << ": snapshot copy canceled" << dendl; - finish(-ECANCELED); - return true; -} - -template -void SnapshotCopyRequest::error(int r) { - dout(20) << ": r=" << r << dendl; - - m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); })); -} - -template -void SnapshotCopyRequest::compute_snap_map() { - SnapIds local_snap_ids; - for (auto &pair : m_snap_seqs) { - local_snap_ids.reserve(1 + local_snap_ids.size()); - local_snap_ids.insert(local_snap_ids.begin(), pair.second); - m_snap_map->insert(std::make_pair(pair.first, local_snap_ids)); - } -} - -template -int SnapshotCopyRequest::validate_parent(I *image_ctx, - librbd::ParentSpec *spec) { - RWLock::RLocker owner_locker(image_ctx->owner_lock); - RWLock::RLocker snap_locker(image_ctx->snap_lock); - - // ensure remote image's parent specs are still consistent - *spec = image_ctx->parent_md.spec; - for (auto &snap_info_pair : image_ctx->snap_info) { - auto &parent_spec = snap_info_pair.second.parent.spec; - if (parent_spec.pool_id == -1) { - continue; - } else if (spec->pool_id == -1) { - *spec = parent_spec; - continue; - } - - if (*spec != parent_spec) { - return -EINVAL; - } - } - return 0; -} - -template -Context *SnapshotCopyRequest::start_local_op() { - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - if (m_local_image_ctx->exclusive_lock == nullptr) { - return nullptr; - } - return m_local_image_ctx->exclusive_lock->start_op(); -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_sync::SnapshotCopyRequest; diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h b/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h deleted file mode 100644 index 85ae4d41305a0..0000000000000 --- a/src/tools/rbd_mirror/image_sync/SnapshotCopyRequest.h +++ /dev/null @@ -1,147 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H -#define RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H - -#include "include/int_types.h" -#include "include/rados/librados.hpp" -#include "common/snap_types.h" -#include "librbd/ImageCtx.h" -#include "librbd/Types.h" -#include "librbd/journal/TypeTraits.h" -#include "tools/rbd_mirror/BaseRequest.h" -#include -#include -#include -#include - -class Context; -class ContextWQ; -namespace journal { class Journaler; } -namespace librbd { namespace journal { struct MirrorPeerClientMeta; } } - -namespace rbd { -namespace mirror { -namespace image_sync { - -template -class SnapshotCopyRequest : public BaseRequest { -public: - typedef librbd::journal::TypeTraits TypeTraits; - typedef typename TypeTraits::Journaler Journaler; - - typedef std::vector SnapIds; - typedef std::map SnapMap; - - static SnapshotCopyRequest* create(ImageCtxT *local_image_ctx, - ImageCtxT *remote_image_ctx, - SnapMap *snap_map, Journaler *journaler, - librbd::journal::MirrorPeerClientMeta *client_meta, - ContextWQ *work_queue, - Context *on_finish) { - return new SnapshotCopyRequest(local_image_ctx, remote_image_ctx, - snap_map, journaler, client_meta, work_queue, - on_finish); - } - - SnapshotCopyRequest(ImageCtxT *local_image_ctx, ImageCtxT *remote_image_ctx, - SnapMap *snap_map, Journaler *journaler, - librbd::journal::MirrorPeerClientMeta *client_meta, - ContextWQ *work_queue, Context *on_finish); - - void send() override; - void cancel() override; - -private: - /** - * @verbatim - * - * - * | - * | /-----------\ - * | | | - * v v | (repeat as needed) - * UNPROTECT_SNAP ----/ - * | - * | /-----------\ - * | | | - * v v | (repeat as needed) - * REMOVE_SNAP -------/ - * | - * | /-----------\ - * | | | - * v v | (repeat as needed) - * CREATE_SNAP -------/ - * | - * | /-----------\ - * | | | - * v v | (repeat as needed) - * PROTECT_SNAP ------/ - * | - * v - * UPDATE_CLIENT - * | - * v - * - * - * @endverbatim - */ - - typedef std::set SnapIdSet; - typedef std::map SnapSeqs; - - ImageCtxT *m_local_image_ctx; - ImageCtxT *m_remote_image_ctx; - SnapMap *m_snap_map; - Journaler *m_journaler; - librbd::journal::MirrorPeerClientMeta *m_client_meta; - ContextWQ *m_work_queue; - - SnapIdSet m_local_snap_ids; - SnapIdSet m_remote_snap_ids; - SnapSeqs m_snap_seqs; - librados::snap_t m_prev_snap_id = CEPH_NOSNAP; - - std::string m_snap_name; - cls::rbd::SnapshotNamespace m_snap_namespace; - - librbd::ParentSpec m_local_parent_spec; - - Mutex m_lock; - bool m_canceled = false; - - void send_snap_unprotect(); - void handle_snap_unprotect(int r); - - void send_snap_remove(); - void handle_snap_remove(int r); - - void send_snap_create(); - void handle_snap_create(int r); - - void send_snap_protect(); - void handle_snap_protect(int r); - - void send_update_client(); - void handle_update_client(int r); - - bool handle_cancellation(); - - void error(int r); - - void compute_snap_map(); - - int validate_parent(ImageCtxT *image_ctx, librbd::ParentSpec *spec); - - Context *start_local_op(); - -}; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_sync::SnapshotCopyRequest; - -#endif // RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc deleted file mode 100644 index 2384179343549..0000000000000 --- a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.cc +++ /dev/null @@ -1,334 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "SnapshotCreateRequest.h" -#include "common/errno.h" -#include "cls/rbd/cls_rbd_client.h" -#include "cls/rbd/cls_rbd_types.h" -#include "librbd/ExclusiveLock.h" -#include "librbd/ObjectMap.h" -#include "librbd/Operations.h" -#include "librbd/Utils.h" -#include "osdc/Striper.h" - -#define dout_context g_ceph_context -#define dout_subsys ceph_subsys_rbd_mirror -#undef dout_prefix -#define dout_prefix *_dout << "rbd::mirror::image_sync::SnapshotCreateRequest: " \ - << this << " " << __func__ - -namespace rbd { -namespace mirror { -namespace image_sync { - -using librbd::util::create_context_callback; -using librbd::util::create_rados_callback; - -template -SnapshotCreateRequest::SnapshotCreateRequest(I *local_image_ctx, - const std::string &snap_name, - const cls::rbd::SnapshotNamespace &snap_namespace, - uint64_t size, - const librbd::ParentSpec &spec, - uint64_t parent_overlap, - Context *on_finish) - : m_local_image_ctx(local_image_ctx), m_snap_name(snap_name), - m_snap_namespace(snap_namespace), m_size(size), - m_parent_spec(spec), m_parent_overlap(parent_overlap), - m_on_finish(on_finish) { -} - -template -void SnapshotCreateRequest::send() { - send_set_size(); -} - -template -void SnapshotCreateRequest::send_set_size() { - m_local_image_ctx->snap_lock.get_read(); - if (m_local_image_ctx->size == m_size) { - m_local_image_ctx->snap_lock.put_read(); - send_remove_parent(); - return; - } - m_local_image_ctx->snap_lock.put_read(); - - dout(20) << dendl; - - // Change the image size on disk so that the snapshot picks up - // the expected size. We can do this because the last snapshot - // we process is the sync snapshot which was created to match the - // image size. We also don't need to worry about trimming because - // we track the highest possible object number within the sync record - librados::ObjectWriteOperation op; - librbd::cls_client::set_size(&op, m_size); - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_set_size(r); - finish_op_ctx->complete(0); - }); - librados::AioCompletion *comp = create_rados_callback(ctx); - int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, - comp, &op); - assert(r == 0); - comp->release(); -} - -template -void SnapshotCreateRequest::handle_set_size(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to update image size '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - - { - // adjust in-memory image size now that it's updated on disk - RWLock::WLocker snap_locker(m_local_image_ctx->snap_lock); - m_local_image_ctx->size = m_size; - } - - send_remove_parent(); -} - -template -void SnapshotCreateRequest::send_remove_parent() { - m_local_image_ctx->parent_lock.get_read(); - if (m_local_image_ctx->parent_md.spec.pool_id == -1 || - m_local_image_ctx->parent_md.spec == m_parent_spec) { - m_local_image_ctx->parent_lock.put_read(); - send_set_parent(); - return; - } - m_local_image_ctx->parent_lock.put_read(); - - dout(20) << dendl; - - librados::ObjectWriteOperation op; - librbd::cls_client::remove_parent(&op); - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_remove_parent(r); - finish_op_ctx->complete(0); - }); - librados::AioCompletion *comp = create_rados_callback(ctx); - int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, - comp, &op); - assert(r == 0); - comp->release(); -} - -template -void SnapshotCreateRequest::handle_remove_parent(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to remove parent '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - - { - // adjust in-memory parent now that it's updated on disk - RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock); - m_local_image_ctx->parent_md.spec = {}; - m_local_image_ctx->parent_md.overlap = 0; - } - - send_set_parent(); -} - -template -void SnapshotCreateRequest::send_set_parent() { - m_local_image_ctx->parent_lock.get_read(); - if (m_local_image_ctx->parent_md.spec == m_parent_spec && - m_local_image_ctx->parent_md.overlap == m_parent_overlap) { - m_local_image_ctx->parent_lock.put_read(); - send_snap_create(); - return; - } - m_local_image_ctx->parent_lock.put_read(); - - dout(20) << dendl; - - librados::ObjectWriteOperation op; - librbd::cls_client::set_parent(&op, m_parent_spec, m_parent_overlap); - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_set_parent(r); - finish_op_ctx->complete(0); - }); - librados::AioCompletion *comp = create_rados_callback(ctx); - int r = m_local_image_ctx->md_ctx.aio_operate(m_local_image_ctx->header_oid, - comp, &op); - assert(r == 0); - comp->release(); -} - -template -void SnapshotCreateRequest::handle_set_parent(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to set parent '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - - { - // adjust in-memory parent now that it's updated on disk - RWLock::WLocker parent_locker(m_local_image_ctx->parent_lock); - m_local_image_ctx->parent_md.spec = m_parent_spec; - m_local_image_ctx->parent_md.overlap = m_parent_overlap; - } - - send_snap_create(); -} - -template -void SnapshotCreateRequest::send_snap_create() { - dout(20) << ": snap_name=" << m_snap_name << dendl; - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_snap_create(r); - finish_op_ctx->complete(0); - }); - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - m_local_image_ctx->operations->execute_snap_create(m_snap_namespace, - m_snap_name.c_str(), - ctx, - 0U, true); -} - -template -void SnapshotCreateRequest::handle_snap_create(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to create snapshot '" << m_snap_name << "': " - << cpp_strerror(r) << dendl; - finish(r); - return; - } - - send_create_object_map(); -} -template -void SnapshotCreateRequest::send_create_object_map() { - - if (!m_local_image_ctx->test_features(RBD_FEATURE_OBJECT_MAP)) { - finish(0); - return; - } - - m_local_image_ctx->snap_lock.get_read(); - auto snap_it = m_local_image_ctx->snap_ids.find( - {cls::rbd::UserSnapshotNamespace(), m_snap_name}); - if (snap_it == m_local_image_ctx->snap_ids.end()) { - derr << ": failed to locate snap: " << m_snap_name << dendl; - m_local_image_ctx->snap_lock.put_read(); - finish(-ENOENT); - return; - } - librados::snap_t local_snap_id = snap_it->second; - m_local_image_ctx->snap_lock.put_read(); - - std::string object_map_oid(librbd::ObjectMap<>::object_map_name( - m_local_image_ctx->id, local_snap_id)); - uint64_t object_count = Striper::get_num_objects(m_local_image_ctx->layout, - m_size); - dout(20) << ": " - << "object_map_oid=" << object_map_oid << ", " - << "object_count=" << object_count << dendl; - - // initialize an empty object map of the correct size (object sync - // will populate the object map) - librados::ObjectWriteOperation op; - librbd::cls_client::object_map_resize(&op, object_count, OBJECT_NONEXISTENT); - - auto finish_op_ctx = start_local_op(); - if (finish_op_ctx == nullptr) { - derr << ": lost exclusive lock" << dendl; - finish(-EROFS); - return; - } - - auto ctx = new FunctionContext([this, finish_op_ctx](int r) { - handle_create_object_map(r); - finish_op_ctx->complete(0); - }); - librados::AioCompletion *comp = create_rados_callback(ctx); - int r = m_local_image_ctx->md_ctx.aio_operate(object_map_oid, comp, &op); - assert(r == 0); - comp->release(); -} - -template -void SnapshotCreateRequest::handle_create_object_map(int r) { - dout(20) << ": r=" << r << dendl; - - if (r < 0) { - derr << ": failed to create object map: " << cpp_strerror(r) - << dendl; - finish(r); - return; - } - - finish(0); -} - -template -Context *SnapshotCreateRequest::start_local_op() { - RWLock::RLocker owner_locker(m_local_image_ctx->owner_lock); - if (m_local_image_ctx->exclusive_lock == nullptr) { - return nullptr; - } - return m_local_image_ctx->exclusive_lock->start_op(); -} - -template -void SnapshotCreateRequest::finish(int r) { - dout(20) << ": r=" << r << dendl; - - m_on_finish->complete(r); - delete this; -} - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -template class rbd::mirror::image_sync::SnapshotCreateRequest; diff --git a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h b/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h deleted file mode 100644 index 503a164a0d596..0000000000000 --- a/src/tools/rbd_mirror/image_sync/SnapshotCreateRequest.h +++ /dev/null @@ -1,108 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_CREATE_REQUEST_H -#define RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_CREATE_REQUEST_H - -#include "include/int_types.h" -#include "include/rados/librados.hpp" -#include "common/snap_types.h" -#include "librbd/ImageCtx.h" -#include "librbd/Types.h" -#include "librbd/journal/TypeTraits.h" -#include -#include -#include -#include - -class Context; - -namespace rbd { -namespace mirror { -namespace image_sync { - -template -class SnapshotCreateRequest { -public: - static SnapshotCreateRequest* create(ImageCtxT *local_image_ctx, - const std::string &snap_name, - const cls::rbd::SnapshotNamespace &snap_namespace, - uint64_t size, - const librbd::ParentSpec &parent_spec, - uint64_t parent_overlap, - Context *on_finish) { - return new SnapshotCreateRequest(local_image_ctx, snap_name, snap_namespace, size, - parent_spec, parent_overlap, on_finish); - } - - SnapshotCreateRequest(ImageCtxT *local_image_ctx, - const std::string &snap_name, - const cls::rbd::SnapshotNamespace &snap_namespace, - uint64_t size, - const librbd::ParentSpec &parent_spec, - uint64_t parent_overlap, Context *on_finish); - - void send(); - -private: - /** - * @verbatim - * - * - * | - * v (skip if not needed) - * SET_SIZE - * | - * v (skip if not needed) - * REMOVE_PARENT - * | - * v (skip if not needed) - * SET_PARENT - * | - * v - * CREATE_SNAP - * | - * v (skip if not needed) - * CREATE_OBJECT_MAP - * | - * v - * - * - * @endverbatim - */ - - ImageCtxT *m_local_image_ctx; - std::string m_snap_name; - cls::rbd::SnapshotNamespace m_snap_namespace; - uint64_t m_size; - librbd::ParentSpec m_parent_spec; - uint64_t m_parent_overlap; - Context *m_on_finish; - - void send_set_size(); - void handle_set_size(int r); - - void send_remove_parent(); - void handle_remove_parent(int r); - - void send_set_parent(); - void handle_set_parent(int r); - - void send_snap_create(); - void handle_snap_create(int r); - - void send_create_object_map(); - void handle_create_object_map(int r); - - Context *start_local_op(); - - void finish(int r); -}; - -} // namespace image_sync -} // namespace mirror -} // namespace rbd - -extern template class rbd::mirror::image_sync::SnapshotCreateRequest; - -#endif // RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_CREATE_REQUEST_H