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
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<librbd::MockTestImageCtx> *instance_watcher,
Context *on_finish, ProgressContext *progress_ctx) {
+++ /dev/null
-// -*- 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 <boost/scope_exit.hpp>
-
-namespace librbd {
-
-namespace {
-
-struct MockTestImageCtx : public librbd::MockImageCtx {
- MockTestImageCtx(librbd::ImageCtx &image_ctx)
- : librbd::MockImageCtx(image_ctx) {
- }
-};
-
-} // anonymous namespace
-
-namespace journal {
-
-template <>
-struct TypeTraits<librbd::MockTestImageCtx> {
- typedef ::journal::MockJournaler Journaler;
-};
-
-} // namespace journal
-} // namespace librbd
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <>
-struct ObjectCopyRequest<librbd::MockTestImageCtx> {
- static ObjectCopyRequest* s_instance;
- static ObjectCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx,
- librbd::MockTestImageCtx *remote_image_ctx,
- const ImageCopyRequest<librbd::MockTestImageCtx>::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<librbd::MockTestImageCtx>::SnapMap *snap_map = nullptr;
- std::map<uint64_t, Context *> object_contexts;
-
- ObjectCopyRequest() : lock("lock") {
- s_instance = this;
- }
-};
-
-ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::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<librbd::MockTestImageCtx>;
-
-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<librbd::MockTestImageCtx> MockImageCopyRequest;
- typedef ObjectCopyRequest<librbd::MockTestImageCtx> 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<void()> 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<uint64_t> 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<void()> 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<void()> 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
+++ /dev/null
-// -*- 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 <map>
-
-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<librbd::MockTestImageCtx> MockMetadataCopyRequest;
- typedef std::map<std::string, bufferlist> 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
+++ /dev/null
-// -*- 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<librbd::MockTestImageCtx>;
-
-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<uint64_t> *what)
-{
- uint64_t object_size = 1 << image_ctx->order;
- for (int i=0; i<num_ops; i++) {
- uint64_t off = rand() % (object_size - max_size + 1);
- uint64_t len = 1 + rand() % max_size;
-
- bufferlist bl;
- bl.append(std::string(len, '1'));
-
- int r = image_ctx->io_work_queue->write(off, len, std::move(bl), 0);
- ASSERT_EQ(static_cast<int>(len), r);
-
- interval_set<uint64_t> w;
- w.insert(off, len);
- what->union_of(w);
- }
- std::cout << " wrote " << *what << std::endl;
-}
-
-} // anonymous namespace
-
-class TestMockImageSyncObjectCopyRequest : public TestMockFixture {
-public:
- typedef ObjectCopyRequest<librbd::MockTestImageCtx> 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<FunctionContext>([](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<uint64_t> &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<uint64_t> &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<Context>(
- 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<std::pair<cls::rbd::SnapshotNamespace,
- std::string>,
- 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<librados::snap_t> m_remote_snap_ids;
- std::vector<librados::snap_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> one;
- scribble(m_remote_image_ctx, 10, 102400, &one);
- ASSERT_EQ(0, create_snap("one"));
-
- interval_set<uint64_t> two;
- scribble(m_remote_image_ctx, 10, 102400, &two);
- ASSERT_EQ(0, create_snap("two"));
-
- if (one.range_end() < two.range_end()) {
- interval_set<uint64_t> 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<uint64_t> 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<uint64_t> 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
+++ /dev/null
-// -*- 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<librbd::MockTestImageCtx> {
- typedef ::journal::MockJournaler Journaler;
-};
-
-} // namespace journal
-} // namespace librbd
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <>
-struct SnapshotCreateRequest<librbd::MockTestImageCtx> {
- 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<librbd::MockTestImageCtx>* SnapshotCreateRequest<librbd::MockTestImageCtx>::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<librbd::MockTestImageCtx>;
-
-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<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
- typedef SnapshotCreateRequest<librbd::MockTestImageCtx> 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<FunctionContext>([](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
+++ /dev/null
-// -*- 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<librbd::MockTestImageCtx>;
-
-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<librbd::MockTestImageCtx> 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<FunctionContext>([](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
#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"
};
} // namespace journal
-} // namespace librbd
-
-// template definitions
-template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
-#include "tools/rbd_mirror/ImageSync.cc"
-
-namespace rbd {
-namespace mirror {
-
-template<>
-struct InstanceWatcher<librbd::MockTestImageCtx> {
- 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<librbd::MockTestImageCtx> {
+class DeepCopyRequest<librbd::MockTestImageCtx> {
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;
}
MOCK_METHOD0(send, void());
};
-template <>
-class MetadataCopyRequest<librbd::MockTestImageCtx> {
-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<librbd::MockTestImageCtx>* DeepCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
- MOCK_METHOD0(send, void());
-};
-
-template <>
-class SnapshotCopyRequest<librbd::MockTestImageCtx> {
-public:
- static SnapshotCopyRequest* s_instance;
- Context *on_finish;
-
- static SnapshotCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx,
- librbd::MockTestImageCtx *remote_image_ctx,
- SnapshotCopyRequest<librbd::ImageCtx>::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<librbd::MockTestImageCtx>;
+#include "tools/rbd_mirror/ImageSync.cc"
- void get() {
- }
+namespace rbd {
+namespace mirror {
- MOCK_METHOD0(send, void());
- MOCK_METHOD0(cancel, void());
+template<>
+struct InstanceWatcher<librbd::MockTestImageCtx> {
+ 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<librbd::MockTestImageCtx> {
public:
MOCK_METHOD0(send, void());
};
-ImageCopyRequest<librbd::MockTestImageCtx>* ImageCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-MetadataCopyRequest<librbd::MockTestImageCtx>* MetadataCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
-SnapshotCopyRequest<librbd::MockTestImageCtx>* SnapshotCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
SyncPointCreateRequest<librbd::MockTestImageCtx>* SyncPointCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
SyncPointPruneRequest<librbd::MockTestImageCtx>* SyncPointPruneRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::Return;
-using ::testing::ReturnNew;
+using ::testing::StrEq;
using ::testing::WithArg;
using ::testing::InvokeWithoutArgs;
public:
typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
- typedef image_sync::ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
- typedef image_sync::MetadataCopyRequest<librbd::MockTestImageCtx> MockMetadataCopyRequest;
- typedef image_sync::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
typedef image_sync::SyncPointCreateRequest<librbd::MockTestImageCtx> MockSyncPointCreateRequest;
typedef image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest;
+ typedef librbd::DeepCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
void SetUp() override {
TestMockFixture::SetUp();
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<FunctionContext>([](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,
}));
}
- 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]() {
}));
}
- 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,
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;
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;
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())
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,
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();
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
#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"
using librbd::util::create_context_callback;
using librbd::util::unique_lock_name;
+template <typename I>
+class ImageSync<I>::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 <typename I>
ImageSync<I>::ImageSync(I *local_image_ctx, I *remote_image_ctx,
SafeTimer *timer, Mutex *timer_lock,
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<double>(
+ "rbd_mirror_sync_point_update_age")), m_client_meta_copy(*client_meta) {
}
template <typename I>
ImageSync<I>::~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 <typename I>
return;
}
- if (m_snapshot_copy_request != nullptr) {
- m_snapshot_copy_request->cancel();
- }
-
if (m_image_copy_request != nullptr) {
m_image_copy_request->cancel();
}
// 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;
}
return;
}
- send_copy_snapshots();
-}
-
-template <typename I>
-void ImageSync<I>::send_copy_snapshots() {
- m_lock.Lock();
- if (m_canceled) {
- m_lock.Unlock();
- finish(-ECANCELED);
- return;
- }
-
- dout(20) << dendl;
-
- Context *ctx = create_context_callback<
- ImageSync<I>, &ImageSync<I>::handle_copy_snapshots>(this);
- m_snapshot_copy_request = SnapshotCopyRequest<I>::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 <typename I>
-void ImageSync<I>::handle_copy_snapshots(int r) {
- dout(20) << ": r=" << r << dendl;
-
+void ImageSync<I>::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 <typename I>
-void ImageSync<I>::send_copy_image() {
m_lock.Lock();
if (m_canceled) {
m_lock.Unlock();
Context *ctx = create_context_callback<
ImageSync<I>, &ImageSync<I>::handle_copy_image>(this);
- m_image_copy_request = ImageCopyRequest<I>::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<I>::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();
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) {
return;
}
- send_copy_object_map();
+ send_flush_sync_point();
}
template <typename I>
-void ImageSync<I>::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<I>::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 <typename I>
+void ImageSync<I>::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<I>, &ImageSync<I>::handle_update_sync_point>(
+ this);
+ m_journaler->update_client(client_data_bl, ctx);
}
template <typename I>
-void ImageSync<I>::handle_copy_object_map(int r) {
- dout(20) << dendl;
+void ImageSync<I>::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 <typename I>
-void ImageSync<I>::send_refresh_object_map() {
- dout(20) << dendl;
+void ImageSync<I>::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<I>, &ImageSync<I>::handle_refresh_object_map>(this);
- m_object_map = m_local_image_ctx->create_object_map(CEPH_NOSNAP);
- m_object_map->open(ctx);
+ ImageSync<I>, &ImageSync<I>::handle_flush_sync_point>(
+ this);
+ m_journaler->update_client(client_data_bl, ctx);
}
template <typename I>
-void ImageSync<I>::handle_refresh_object_map(int r) {
- dout(20) << dendl;
+void ImageSync<I>::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();
}
return;
}
- send_copy_metadata();
-}
-
-template <typename I>
-void ImageSync<I>::send_copy_metadata() {
- dout(20) << dendl;
- update_progress("COPY_METADATA");
-
- Context *ctx = create_context_callback<
- ImageSync<I>, &ImageSync<I>::handle_copy_metadata>(this);
- auto request = MetadataCopyRequest<I>::create(
- m_local_image_ctx, m_remote_image_ctx, ctx);
- request->send();
-}
-
-template <typename I>
-void ImageSync<I>::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);
}
#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 <map>
class Context;
class ContextWQ;
-class Mutex;
-class SafeTimer;
namespace journal { class Journaler; }
+namespace librbd { class ProgressContext; }
+namespace librbd { template <typename> class DeepCopyRequest; }
namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
namespace rbd {
template <typename> class InstanceWatcher;
-namespace image_sync { template <typename> class ImageCopyRequest; }
-namespace image_sync { template <typename> class SnapshotCopyRequest; }
-
template <typename ImageCtxT = librbd::ImageCtx>
class ImageSync : public BaseRequest {
public:
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,
* 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 .
* <finish> < . . . . . . . . . . . . . .
typedef std::vector<librados::snap_t> SnapIds;
typedef std::map<librados::snap_t, SnapIds> SnapMap;
+ class ImageCopyProgressContext;
ImageCtxT *m_local_image_ctx;
ImageCtxT *m_remote_image_ctx;
Mutex m_lock;
bool m_canceled = false;
- image_sync::SnapshotCopyRequest<ImageCtxT> *m_snapshot_copy_request = nullptr;
- image_sync::ImageCopyRequest<ImageCtxT> *m_image_copy_request = nullptr;
- decltype(ImageCtxT::object_map) m_object_map = nullptr;
+ librbd::DeepCopyRequest<ImageCtxT> *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);
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);
};
+++ /dev/null
-// -*- 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 <typename I>
-ImageCopyRequest<I>::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<double>(
- "rbd_mirror_sync_point_update_age")),
- m_client_meta_copy(*client_meta) {
- assert(!m_client_meta_copy.sync_points.empty());
-}
-
-template <typename I>
-void ImageCopyRequest<I>::send() {
- int r = compute_snap_map();
- if (r < 0) {
- finish(r);
- return;
- }
-
- send_update_max_object_count();
-}
-
-template <typename I>
-void ImageCopyRequest<I>::cancel() {
- Mutex::Locker locker(m_lock);
-
- dout(20) << dendl;
- m_canceled = true;
-}
-
-template <typename I>
-void ImageCopyRequest<I>::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<I>, &ImageCopyRequest<I>::handle_update_max_object_count>(
- this);
- m_journaler->update_client(client_data_bl, ctx);
-}
-
-template <typename I>
-void ImageCopyRequest<I>::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 <typename I>
-void ImageCopyRequest<I>::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<int64_t>("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 <typename I>
-void ImageCopyRequest<I>::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<I>, &ImageCopyRequest<I>::handle_object_copy>(this);
- ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
- m_local_image_ctx, m_remote_image_ctx, &m_snap_map, ono, ctx);
- req->send();
-}
-
-template <typename I>
-void ImageCopyRequest<I>::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 <typename I>
-void ImageCopyRequest<I>::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<I>, &ImageCopyRequest<I>::handle_update_sync_point>(
- this);
- m_journaler->update_client(client_data_bl, ctx);
-}
-
-template <typename I>
-void ImageCopyRequest<I>::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 <typename I>
-void ImageCopyRequest<I>::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<I>, &ImageCopyRequest<I>::handle_flush_sync_point>(
- this);
- m_journaler->update_client(client_data_bl, ctx);
-}
-
-template <typename I>
-void ImageCopyRequest<I>::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 <typename I>
-int ImageCopyRequest<I>::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 <typename I>
-void ImageCopyRequest<I>::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<librbd::ImageCtx>;
+++ /dev/null
-// -*- 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 <map>
-#include <vector>
-
-class Context;
-class SafeTimer;
-namespace journal { class Journaler; }
-namespace librbd { struct ImageCtx; }
-
-namespace rbd {
-namespace mirror {
-
-class ProgressContext;
-
-namespace image_sync {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-class ImageCopyRequest : public BaseRequest {
-public:
- typedef std::vector<librados::snap_t> SnapIds;
- typedef std::map<librados::snap_t, SnapIds> SnapMap;
- typedef librbd::journal::TypeTraits<ImageCtxT> 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
- *
- * <start>
- * |
- * v
- * UPDATE_MAX_OBJECT_COUNT
- * |
- * | . . . . .
- * | . . (parallel execution of
- * v v . multiple objects at once)
- * COPY_OBJECT . .
- * |
- * v
- * FLUSH_SYNC_POINT
- * |
- * v
- * <finish>
- *
- * @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<librbd::ImageCtx>;
-
-#endif // RBD_MIRROR_IMAGE_SYNC_IMAGE_COPY_REQUEST_H
+++ /dev/null
-// -*- 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 <typename I>
-void MetadataCopyRequest<I>::send() {
- list_remote_metadata();
-}
-
-template <typename I>
-void MetadataCopyRequest<I>::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<I>,
- &MetadataCopyRequest<I>::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 <typename I>
-void MetadataCopyRequest<I>::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 <typename I>
-void MetadataCopyRequest<I>::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<I>,
- &MetadataCopyRequest<I>::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 <typename I>
-void MetadataCopyRequest<I>::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 <typename I>
-void MetadataCopyRequest<I>::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<librbd::ImageCtx>;
+++ /dev/null
-// -*- 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 <map>
-#include <string>
-
-class Context;
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-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
- *
- * <start>
- * |
- * v
- * LIST_REMOTE_METADATA <-----\
- * | | (repeat if additional
- * v | metadata)
- * SET_LOCAL_METADATA --------/
- * |
- * v
- * <finish>
- *
- * @endverbatim
- */
- typedef std::map<std::string, bufferlist> 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<librbd::ImageCtx>;
-
-#endif // RBD_MIRROR_IMAGE_SYNC_METADATA_COPY_REQUEST_H
+++ /dev/null
-// -*- 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 <typename I>
-ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::send() {
- send_list_snaps();
-}
-
-template <typename I>
-void ObjectCopyRequest<I>::send_list_snaps() {
- dout(20) << dendl;
-
- librados::AioCompletion *rados_completion = create_rados_callback<
- ObjectCopyRequest<I>, &ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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<I>, &ObjectCopyRequest<I>::handle_read_object>(this);
- int r = m_remote_io_ctx.aio_operate(m_remote_oid, comp, &op, nullptr);
- assert(r == 0);
- comp->release();
-}
-
-template <typename I>
-void ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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<uint32_t>(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 <typename I>
-void ObjectCopyRequest<I>::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 <typename I>
-Context *ObjectCopyRequest<I>::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 <typename I>
-void ObjectCopyRequest<I>::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<uint64_t> 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<uint64_t> 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 <typename I>
-void ObjectCopyRequest<I>::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<librbd::ImageCtx>;
+++ /dev/null
-// -*- 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 <list>
-#include <map>
-#include <string>
-#include <vector>
-
-class Context;
-class RWLock;
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-class ObjectCopyRequest {
-public:
- typedef std::vector<librados::snap_t> SnapIds;
- typedef std::map<librados::snap_t, SnapIds> 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
- *
- * <start>
- * |
- * 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
- * <finish>
- *
- * @endverbatim
- */
-
- enum SyncOpType {
- SYNC_OP_TYPE_WRITE,
- SYNC_OP_TYPE_TRUNC,
- SYNC_OP_TYPE_REMOVE
- };
-
- typedef std::map<uint64_t, uint64_t> 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<SyncOp> SyncOps;
- typedef std::pair<librados::snap_t, librados::snap_t> WriteReadSnapIds;
- typedef std::map<WriteReadSnapIds, SyncOps> SnapSyncOps;
- typedef std::map<librados::snap_t, uint8_t> SnapObjectStates;
- typedef std::map<librados::snap_t, uint64_t> 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<librbd::ImageCtx>;
-
-#endif // RBD_MIRROR_IMAGE_SYNC_OBJECT_COPY_REQUEST_H
+++ /dev/null
-// -*- 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 <typename I>
-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<cls::rbd::SnapshotNamespace,
- std::string>,
- 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 <typename I>
-SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::cancel() {
- Mutex::Locker locker(m_lock);
-
- dout(20) << dendl;
- m_canceled = true;
-}
-
-template <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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<cls::rbd::UserSnapshotNamespace>(&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 <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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<cls::rbd::UserSnapshotNamespace>(&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<I> *req = SnapshotCreateRequest<I>::create(
- m_local_image_ctx, m_snap_name, m_snap_namespace, size, parent_spec,
- parent_overlap, ctx);
- req->send();
-}
-
-template <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-void SnapshotCopyRequest<I>::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<I>, &SnapshotCopyRequest<I>::handle_update_client>(
- this);
- m_journaler->update_client(data_bl, ctx);
-}
-
-template <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-bool SnapshotCopyRequest<I>::handle_cancellation() {
- {
- Mutex::Locker locker(m_lock);
- if (!m_canceled) {
- return false;
- }
- }
- dout(10) << ": snapshot copy canceled" << dendl;
- finish(-ECANCELED);
- return true;
-}
-
-template <typename I>
-void SnapshotCopyRequest<I>::error(int r) {
- dout(20) << ": r=" << r << dendl;
-
- m_work_queue->queue(new FunctionContext([this, r](int r1) { finish(r); }));
-}
-
-template <typename I>
-void SnapshotCopyRequest<I>::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 <typename I>
-int SnapshotCopyRequest<I>::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 <typename I>
-Context *SnapshotCopyRequest<I>::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<librbd::ImageCtx>;
+++ /dev/null
-// -*- 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 <map>
-#include <set>
-#include <string>
-#include <tuple>
-
-class Context;
-class ContextWQ;
-namespace journal { class Journaler; }
-namespace librbd { namespace journal { struct MirrorPeerClientMeta; } }
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-class SnapshotCopyRequest : public BaseRequest {
-public:
- typedef librbd::journal::TypeTraits<ImageCtxT> TypeTraits;
- typedef typename TypeTraits::Journaler Journaler;
-
- typedef std::vector<librados::snap_t> SnapIds;
- typedef std::map<librados::snap_t, SnapIds> 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
- *
- * <start>
- * |
- * | /-----------\
- * | | |
- * 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
- * <finish>
- *
- * @endverbatim
- */
-
- typedef std::set<librados::snap_t> SnapIdSet;
- typedef std::map<librados::snap_t, librados::snap_t> 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<librbd::ImageCtx>;
-
-#endif // RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_COPY_REQUEST_H
+++ /dev/null
-// -*- 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 <typename I>
-SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::send() {
- send_set_size();
-}
-
-template <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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 <typename I>
-Context *SnapshotCreateRequest<I>::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 <typename I>
-void SnapshotCreateRequest<I>::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<librbd::ImageCtx>;
+++ /dev/null
-// -*- 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 <map>
-#include <set>
-#include <string>
-#include <tuple>
-
-class Context;
-
-namespace rbd {
-namespace mirror {
-namespace image_sync {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-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
- *
- * <start>
- * |
- * 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
- * <finish>
- *
- * @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<librbd::ImageCtx>;
-
-#endif // RBD_MIRROR_IMAGE_SYNC_SNAPSHOT_CREATE_REQUEST_H