#include "tools/rbd_mirror/image_replayer/OpenImageRequest.h"
#include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h"
#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h"
#include "test/journal/mock/MockJournaler.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "test/librbd/mock/MockImageCtx.h"
MOCK_METHOD0(send, void());
};
+template<>
+struct PrepareReplayRequest<librbd::MockTestImageCtx> {
+ static PrepareReplayRequest* s_instance;
+
+ bool* resync_requested = nullptr;
+ bool* syncing = nullptr;
+ Context *on_finish = nullptr;
+
+ static PrepareReplayRequest* create(
+ librbd::MockTestImageCtx* local_image_ctx,
+ ::journal::MockJournaler* remote_journaler,
+ librbd::mirror::PromotionState remote_promotion_state,
+ const std::string& local_mirror_uuid,
+ const std::string& remote_mirror_uuid,
+ librbd::journal::MirrorPeerClientMeta* client_meta,
+ ProgressContext* progress_ctx,
+ bool* resync_requested, bool* syncing, Context* on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->resync_requested = resync_requested;
+ s_instance->syncing = syncing;
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ PrepareReplayRequest() {
+ ceph_assert(s_instance == nullptr);
+ s_instance = this;
+ }
+ ~PrepareReplayRequest() {
+ s_instance = nullptr;
+ }
+
+ MOCK_METHOD0(send, void());
+};
+
CreateLocalImageRequest<librbd::MockTestImageCtx>*
CreateLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+PrepareReplayRequest<librbd::MockTestImageCtx>*
+ PrepareReplayRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
} // namespace journal
} // namespace image_replayer
typedef OpenImageRequest<librbd::MockTestImageCtx> MockOpenImageRequest;
typedef OpenLocalImageRequest<librbd::MockTestImageCtx> MockOpenLocalImageRequest;
typedef journal::CreateLocalImageRequest<librbd::MockTestImageCtx> MockCreateLocalImageRequest;
+ typedef journal::PrepareReplayRequest<librbd::MockTestImageCtx> MockPrepareReplayRequest;
typedef librbd::mirror::GetInfoRequest<librbd::MockTestImageCtx> MockGetMirrorInfoRequest;
typedef std::list<cls::journal::Tag> Tags;
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));
- }
- void create_local_image() {
- 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_journaler_get_client(::journal::MockJournaler &mock_journaler,
- const std::string &client_id,
- cls::journal::Client &client, int r) {
- EXPECT_CALL(mock_journaler, get_client(StrEq(client_id), _, _))
- .WillOnce(DoAll(WithArg<1>(Invoke([client](cls::journal::Client *out_client) {
- *out_client = client;
- })),
- WithArg<2>(Invoke([this, r](Context *on_finish) {
- m_threads->work_queue->queue(on_finish, r);
- }))));
- }
-
- void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
- uint64_t tag_class, const Tags& tags,
- int r) {
- EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
- .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
- *out_tags = tags;
- })),
- WithArg<2>(Invoke([this, r](Context *on_finish) {
- m_threads->work_queue->queue(on_finish, r);
- }))));
- }
-
- void expect_journaler_update_client(::journal::MockJournaler &mock_journaler,
- const librbd::journal::ClientData &client_data,
- int r) {
- bufferlist bl;
- encode(client_data, bl);
-
- EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _))
- .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
- m_threads->work_queue->queue(on_finish, r);
- })));
- }
-
void expect_open_image(MockOpenImageRequest &mock_open_image_request,
librados::IoCtx &io_ctx, const std::string &image_id,
librbd::MockTestImageCtx &mock_image_ctx, int r) {
construct(IsSameIoCtx(&io_ctx), image_id));
EXPECT_CALL(mock_open_local_image_request, send())
.WillOnce(Invoke([this, &mock_open_local_image_request, mock_image_ctx, r]() {
- *mock_open_local_image_request.image_ctx = mock_image_ctx;
+ if (r >= 0) {
+ *mock_open_local_image_request.image_ctx = mock_image_ctx;
+ }
m_threads->work_queue->queue(mock_open_local_image_request.on_finish,
r);
}));
}));
}
- void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
- uint64_t tag_tid) {
- EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
- }
-
- void expect_journal_get_tag_data(librbd::MockJournal &mock_journal,
- const librbd::journal::TagData &tag_data) {
- EXPECT_CALL(mock_journal, get_tag_data()).WillOnce(Return(tag_data));
- }
-
- void expect_is_resync_requested(librbd::MockJournal &mock_journal,
- bool do_resync, int r) {
- EXPECT_CALL(mock_journal, is_resync_requested(_))
- .WillOnce(DoAll(SetArgPointee<0>(do_resync),
- Return(r)));
- }
-
void expect_create_local_image(
MockCreateLocalImageRequest &mock_create_local_image_request,
const std::string& local_image_id, int r) {
}));
}
+ void expect_prepare_replay(
+ MockPrepareReplayRequest& mock_prepare_replay_request,
+ bool resync_requested, bool syncing, int r) {
+ EXPECT_CALL(mock_prepare_replay_request, send())
+ .WillOnce(Invoke([this, &mock_prepare_replay_request, resync_requested,
+ syncing, r]() {
+ if (r >= 0) {
+ *mock_prepare_replay_request.resync_requested = resync_requested;
+ *mock_prepare_replay_request.syncing = syncing;
+ }
+ m_threads->work_queue->queue(mock_prepare_replay_request.on_finish,
+ r);
+ }));
+ }
+
void expect_image_sync(MockImageSync &mock_image_sync, int r) {
EXPECT_CALL(mock_image_sync, get());
EXPECT_CALL(mock_image_sync, send())
EXPECT_CALL(mock_image_sync, put());
}
- bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
- bufferlist bl;
- encode(tag_data, bl);
- return bl;
- }
-
MockBootstrapRequest *create_request(MockThreads* mock_threads,
MockInstanceWatcher *mock_instance_watcher,
::journal::MockJournaler &mock_journaler,
librbd::ImageCtx *m_remote_image_ctx;
librbd::ImageCtx *m_local_image_ctx = nullptr;
librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
- bool m_do_resync;
+ bool m_do_resync = false;
};
-TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemotedRemoteSyncingState) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, Success) {
InSequence seq;
// open the remote image
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
- "remote mirror uuid", true, 4, 1});
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
- // update client state
+ // close remote image
+ MockCloseImageRequest mock_close_image_request;
+ expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
+
+ C_SaferCond ctx;
+ MockThreads mock_threads(m_threads);
+ MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
+ cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
- librbd::journal::ClientData client_data;
- client_data.client_meta = mirror_peer_client_meta;
- ::journal::MockJournaler mock_journaler;
- expect_journaler_update_client(mock_journaler, client_data, 0);
-
- // lookup remote image tag class
- client_data = {librbd::journal::ImageClientMeta{123}};
- cls::journal::Client client;
- encode(client_data, client.data);
- expect_journaler_get_client(mock_journaler,
- librbd::Journal<>::IMAGE_CLIENT_ID,
- client, 0);
-
- // remote demotion / promotion event
- Tags tags = {
- {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 1, 99})},
- {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 2, 1})},
- {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 3, 1})},
- {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 4, 1})},
- {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 5, 1})},
- {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 6, 1})},
- {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 7, 1})}
- };
- expect_journaler_get_tags(mock_journaler, 123, tags, 0);
+ MockBootstrapRequest *request = create_request(
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
+ mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+}
+TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageError) {
+ InSequence seq;
+
+ // open the remote image
+ librbd::MockJournal mock_journal;
+ librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ MockOpenImageRequest mock_open_image_request;
+ expect_open_image(mock_open_image_request, m_remote_io_ctx,
+ mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
+
+ // test if remote image is primary
+ MockGetMirrorInfoRequest mock_get_mirror_info_request;
+ expect_get_remote_mirror_info(mock_get_mirror_info_request,
+ {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
+ cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
+ librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
+
+ // open the local image
+ librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.journal = &mock_journal;
+ MockOpenLocalImageRequest mock_open_local_image_request;
+ expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
+ mock_local_image_ctx.id, &mock_local_image_ctx,
+ -EINVAL);
+
+ // close remote image
MockCloseImageRequest mock_close_image_request;
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
- mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
+ mock_local_image_ctx.id};
+ mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteNotTagOwner) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImageDNE) {
InSequence seq;
// open the remote image
expect_get_remote_mirror_info(mock_get_mirror_info_request,
{cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
- librbd::mirror::PROMOTION_STATE_NON_PRIMARY, 0);
+ librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
// open the local image
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
mock_local_image_ctx.journal = &mock_journal;
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
- mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
+ mock_local_image_ctx.id, &mock_local_image_ctx,
+ -ENOENT);
+
+ // create local image
+ MockCreateLocalImageRequest mock_create_local_image_request;
+ expect_create_local_image(mock_create_local_image_request, "local image id",
+ 0);
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 344, 0});
+ // re-open the local image
+ expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
+ "local image id", &mock_local_image_ctx, 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+
+ // close remote image
MockCloseImageRequest mock_close_image_request;
- expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
- ::journal::MockJournaler mock_journaler;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(-EREMOTEIO, ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, OpenLocalImagePrimary) {
InSequence seq;
// open the remote image
expect_get_remote_mirror_info(mock_get_mirror_info_request,
{cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
- librbd::mirror::PROMOTION_STATE_NON_PRIMARY, 0);
+ librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
// open the local image
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
mock_local_image_ctx.journal = &mock_journal;
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
- mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
-
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
-
- // lookup remote image tag class
- cls::journal::Client client;
- librbd::journal::ClientData client_data{
- librbd::journal::ImageClientMeta{123}};
- encode(client_data, client.data);
- ::journal::MockJournaler mock_journaler;
- expect_journaler_get_client(mock_journaler,
- librbd::Journal<>::IMAGE_CLIENT_ID,
- client, 0);
-
- // remote demotion / promotion event
- Tags tags = {
- {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 1, 99})},
- {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 2, 1})},
- {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 2, 1})},
- {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 4, 369})}
- };
- expect_journaler_get_tags(mock_journaler, 123, tags, 0);
+ mock_local_image_ctx.id, &mock_local_image_ctx,
+ -EREMOTEIO);
+ // close remote image
MockCloseImageRequest mock_close_image_request;
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(-EREMOTEIO, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
- create_local_image();
+TEST_F(TestMockImageReplayerBootstrapRequest, CreateLocalImageError) {
+ InSequence seq;
+
+ // open the remote image
+ librbd::MockJournal mock_journal;
+ librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ MockOpenImageRequest mock_open_image_request;
+ expect_open_image(mock_open_image_request, m_remote_io_ctx,
+ mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
+
+ // test if remote image is primary
+ MockGetMirrorInfoRequest mock_get_mirror_info_request;
+ expect_get_remote_mirror_info(mock_get_mirror_info_request,
+ {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
+ cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
+ librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
+
+ // create local image
+ MockCreateLocalImageRequest mock_create_local_image_request;
+ expect_create_local_image(mock_create_local_image_request, "local image id",
+ -EINVAL);
+
+ // close remote image
+ MockCloseImageRequest mock_close_image_request;
+ expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
+
+ C_SaferCond ctx;
+ MockThreads mock_threads(m_threads);
+ MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
+ cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
+ mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+ MockBootstrapRequest *request = create_request(
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler, "",
+ mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
+ request->send();
+ ASSERT_EQ(-EINVAL, ctx.wait());
+}
+TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayError) {
InSequence seq;
// open the remote image
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
-
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
- "remote mirror uuid", true, 4, 1});
-
- // lookup remote image tag class
- cls::journal::Client client;
- librbd::journal::ClientData client_data{
- librbd::journal::ImageClientMeta{123}};
- encode(client_data, client.data);
- ::journal::MockJournaler mock_journaler;
- expect_journaler_get_client(mock_journaler,
- librbd::Journal<>::IMAGE_CLIENT_ID,
- client, 0);
-
- // remote demotion / promotion event
- Tags tags = {
- {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 1, 99})},
- {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 2, 1})},
- {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 3, 1})},
- {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 4, 1})},
- {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 5, 1})},
- {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 6, 1})},
- {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 7, 1})}
- };
- expect_journaler_get_tags(mock_journaler, 123, tags, 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, -EINVAL);
+
+ // close local image
MockCloseImageRequest mock_close_image_request;
+ expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
+
+ // close remote image
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayResyncRequested) {
InSequence seq;
// open the remote image
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
-
- expect_journal_get_tag_tid(mock_journal, 346);
- expect_journal_get_tag_data(mock_journal,
- {librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 345, 1});
-
- // lookup remote image tag class
- cls::journal::Client client;
- librbd::journal::ClientData client_data{
- librbd::journal::ImageClientMeta{123}};
- encode(client_data, client.data);
- ::journal::MockJournaler mock_journaler;
- expect_journaler_get_client(mock_journaler,
- librbd::Journal<>::IMAGE_CLIENT_ID,
- client, 0);
-
- // remote demotion / promotion event
- Tags tags = {
- {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
- true, 344, 99})},
- {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- "local mirror uuid", true, 345, 1})},
- {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 3, 1})}
- };
- expect_journaler_get_tags(mock_journaler, 123, tags, 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, true, false, 0);
+
+ // close remote image
MockCloseImageRequest mock_close_image_request;
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
ASSERT_EQ(0, ctx.wait());
+ ASSERT_TRUE(m_do_resync);
}
-TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplaySyncing) {
InSequence seq;
// open the remote image
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
-
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::ORPHAN_MIRROR_UUID,
- true, 344, 0});
-
- // lookup remote image tag class
- cls::journal::Client client;
- librbd::journal::ClientData client_data{
- librbd::journal::ImageClientMeta{123}};
- encode(client_data, client.data);
- ::journal::MockJournaler mock_journaler;
- expect_journaler_get_client(mock_journaler,
- librbd::Journal<>::IMAGE_CLIENT_ID,
- client, 0);
-
- // remote demotion / promotion event
- Tags tags = {
- {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 1, 99})},
- {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
- librbd::Journal<>::LOCAL_MIRROR_UUID,
- true, 2, 1})}
- };
- expect_journaler_get_tags(mock_journaler, 123, tags, 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
+
+ // image sync
+ MockImageSync mock_image_sync;
+ expect_image_sync(mock_image_sync, 0);
+
+ // close remote image
MockCloseImageRequest mock_close_image_request;
- expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(-EEXIST, ctx.wait());
- ASSERT_EQ(NULL, m_local_test_image_ctx);
+ ASSERT_EQ(0, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, PrepareReplayDisconnected) {
InSequence seq;
// open the remote image
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- // resync is requested
- expect_is_resync_requested(mock_journal, true, 0);
-
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
+ // close remote image
MockCloseImageRequest mock_close_image_request;
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
- cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
+ ::journal::MockJournaler mock_remote_journaler;
+ cls::journal::ClientState client_state =
+ cls::journal::CLIENT_STATE_DISCONNECTED;
librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
- ::journal::MockJournaler mock_journaler;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler,
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
"local mirror uuid", "remote mirror uuid", &client_state,
&mirror_peer_client_meta, &ctx);
- m_do_resync = false;
request->send();
ASSERT_EQ(0, ctx.wait());
- ASSERT_TRUE(m_do_resync);
}
-TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncError) {
InSequence seq;
// open the remote image
cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
- // create the local image
- MockCreateLocalImageRequest mock_create_local_image_request;
- expect_create_local_image(mock_create_local_image_request, "local image id",
- 0);
-
// open the local image
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
mock_local_image_ctx.journal = &mock_journal;
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
- "local image id", &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
+ mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
- // sync the remote image to the local image
+ // image sync
MockImageSync mock_image_sync;
- expect_image_sync(mock_image_sync, 0);
+ expect_image_sync(mock_image_sync, -EINVAL);
+ // close remote image
MockCloseImageRequest mock_close_image_request;
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
- ::journal::MockJournaler mock_journaler;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
- librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
- mirror_peer_client_meta.image_id = "";
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
+ mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler, "",
- mock_remote_image_ctx.id, "global image id", "local mirror uuid",
- "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
+ mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(-EINVAL, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, ImageSyncCanceled) {
InSequence seq;
// open the remote image
cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
- // open the missing local image
+ // open the local image
+ librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.journal = &mock_journal;
MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
- "missing image id", nullptr, -ENOENT);
+ mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- // create the missing local image
- MockCreateLocalImageRequest mock_create_local_image_request;
- expect_create_local_image(mock_create_local_image_request, "local image id",
- 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, true, 0);
+
+ // close remote image
+ MockCloseImageRequest mock_close_image_request;
+ expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
+
+ C_SaferCond ctx;
+ MockThreads mock_threads(m_threads);
+ MockInstanceWatcher mock_instance_watcher;
+ ::journal::MockJournaler mock_remote_journaler;
+ cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
+ mock_local_image_ctx.id};
+ mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
+ MockBootstrapRequest *request = create_request(
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
+ mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
+ request->cancel();
+ request->send();
+ ASSERT_EQ(-ECANCELED, ctx.wait());
+}
+
+TEST_F(TestMockImageReplayerBootstrapRequest, CloseLocalImageError) {
+ InSequence seq;
+
+ // open the remote image
+ librbd::MockJournal mock_journal;
+ librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
+ MockOpenImageRequest mock_open_image_request;
+ expect_open_image(mock_open_image_request, m_remote_io_ctx,
+ mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
+
+ // test if remote image is primary
+ MockGetMirrorInfoRequest mock_get_mirror_info_request;
+ expect_get_remote_mirror_info(mock_get_mirror_info_request,
+ {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid",
+ cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
+ librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
// open the local image
librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
mock_local_image_ctx.journal = &mock_journal;
+ MockOpenLocalImageRequest mock_open_local_image_request;
expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
- "local image id", &mock_local_image_ctx, 0);
- expect_is_resync_requested(mock_journal, false, 0);
-
- expect_journal_get_tag_tid(mock_journal, 345);
- expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
+ mock_local_image_ctx.id, &mock_local_image_ctx, 0);
- // sync the remote image to the local image
- MockImageSync mock_image_sync;
- expect_image_sync(mock_image_sync, 0);
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, -EREMOTEIO);
+ // close local image
MockCloseImageRequest mock_close_image_request;
+ expect_close_image(mock_close_image_request, mock_local_image_ctx, -EINVAL);
+
+ // close remote image
expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
- ::journal::MockJournaler mock_journaler;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
- librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
- mirror_peer_client_meta.image_id = "missing image id";
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
+ mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler, "missing image id",
- mock_remote_image_ctx.id, "global image id", "local mirror uuid",
- "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
+ mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(0, ctx.wait());
+ ASSERT_EQ(-EREMOTEIO, ctx.wait());
}
-TEST_F(TestMockImageReplayerBootstrapRequest, CreateLocalImageError) {
- create_local_image();
-
+TEST_F(TestMockImageReplayerBootstrapRequest, CloseRemoteImageError) {
InSequence seq;
// open the remote image
cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
librbd::mirror::PROMOTION_STATE_PRIMARY, 0);
- // create the local image
- MockCreateLocalImageRequest mock_create_local_image_request;
- expect_create_local_image(mock_create_local_image_request, "", -EINVAL);
+ // open the local image
+ librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
+ mock_local_image_ctx.journal = &mock_journal;
+ MockOpenLocalImageRequest mock_open_local_image_request;
+ expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
+ mock_local_image_ctx.id, &mock_local_image_ctx, 0);
+
+ // prepare replay
+ MockPrepareReplayRequest mock_prepare_replay_request;
+ expect_prepare_replay(mock_prepare_replay_request, false, false, 0);
MockCloseImageRequest mock_close_image_request;
- expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
+ expect_close_image(mock_close_image_request, mock_remote_image_ctx, -EINVAL);
C_SaferCond ctx;
MockThreads mock_threads(m_threads);
MockInstanceWatcher mock_instance_watcher;
- ::journal::MockJournaler mock_journaler;
+ ::journal::MockJournaler mock_remote_journaler;
cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
- librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
- mirror_peer_client_meta.image_id = "";
+ librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
+ mock_local_image_ctx.id};
mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
MockBootstrapRequest *request = create_request(
- &mock_threads, &mock_instance_watcher, mock_journaler, "",
- mock_remote_image_ctx.id, "global image id", "local mirror uuid",
- "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
+ &mock_threads, &mock_instance_watcher, mock_remote_journaler,
+ mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id",
+ "local mirror uuid", "remote mirror uuid", &client_state,
+ &mirror_peer_client_meta, &ctx);
request->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
+ ASSERT_EQ(0, ctx.wait());
}
} // namespace image_replayer
#include "tools/rbd_mirror/ImageSync.h"
#include "tools/rbd_mirror/Threads.h"
#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h"
+#include "tools/rbd_mirror/image_replayer/journal/PrepareReplayRequest.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rbd_mirror
#undef dout_prefix
-#define dout_prefix *_dout << "rbd::mirror::image_replayer::BootstrapRequest: " \
- << this << " " << __func__ << ": "
+#define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
+ << "BootstrapRequest: " << this << " " \
+ << __func__ << ": "
namespace rbd {
namespace mirror {
return;
}
- I *local_image_ctx = (*m_local_image_ctx);
- {
- local_image_ctx->image_lock.lock_shared();
- if (local_image_ctx->journal == nullptr) {
- local_image_ctx->image_lock.unlock_shared();
-
- derr << "local image does not support journaling" << dendl;
- m_ret_val = -EINVAL;
- close_local_image();
- return;
- }
+ prepare_replay();
+}
- r = (*m_local_image_ctx)->journal->is_resync_requested(m_do_resync);
- if (r < 0) {
- local_image_ctx->image_lock.unlock_shared();
+template <typename I>
+void BootstrapRequest<I>::prepare_replay() {
+ dout(10) << dendl;
+ update_progress("PREPARE_REPLAY");
- derr << "failed to check if a resync was requested" << dendl;
- m_ret_val = r;
- close_local_image();
- return;
- }
+ // TODO support snapshot-based mirroring
+ auto ctx = create_context_callback<
+ BootstrapRequest<I>,
+ &BootstrapRequest<I>::handle_prepare_replay>(this);
+ auto request = journal::PrepareReplayRequest<I>::create(
+ *m_local_image_ctx, m_remote_journaler, m_promotion_state,
+ m_local_mirror_uuid, m_remote_mirror_uuid, m_client_meta,
+ m_progress_ctx, m_do_resync, &m_syncing, ctx);
+ request->send();
+}
- m_local_tag_tid = local_image_ctx->journal->get_tag_tid();
- m_local_tag_data = local_image_ctx->journal->get_tag_data();
- dout(10) << "local tag=" << m_local_tag_tid << ", "
- << "local tag data=" << m_local_tag_data << dendl;
- local_image_ctx->image_lock.unlock_shared();
- }
+template <typename I>
+void BootstrapRequest<I>::handle_prepare_replay(int r) {
+ dout(10) << "r=" << r << dendl;
- if (m_local_tag_data.mirror_uuid != m_remote_mirror_uuid &&
- m_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY) {
- // if the local mirror is not linked to the (now) non-primary image,
- // stop the replay. Otherwise, we ignore that the remote is non-primary
- // so that we can replay the demotion
- dout(5) << "remote image is not primary -- skipping image replay"
- << dendl;
- m_ret_val = -EREMOTEIO;
+ if (r < 0) {
+ if (r != -EREMOTEIO) {
+ derr << "failed to prepare local replay: " << cpp_strerror(r) << dendl;
+ }
+ m_ret_val = r;
close_local_image();
return;
- }
-
- if (*m_do_resync) {
+ } else if (*m_do_resync) {
+ dout(10) << "local image resync requested" << dendl;
close_remote_image();
return;
- }
-
- if (*m_client_state == cls::journal::CLIENT_STATE_DISCONNECTED) {
+ } else if (*m_client_state == cls::journal::CLIENT_STATE_DISCONNECTED) {
dout(10) << "client flagged disconnected -- skipping bootstrap" << dendl;
// The caller is expected to detect disconnect initializing remote journal.
m_ret_val = 0;
close_remote_image();
return;
- }
-
- update_client_state();
-}
-
-template <typename I>
-void BootstrapRequest<I>::update_client_state() {
- if (m_client_meta->state != librbd::journal::MIRROR_PEER_STATE_SYNCING ||
- m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
- get_remote_tag_class();
- return;
- }
-
- // our local image is not primary, is flagged as syncing on the remote side,
- // but is no longer tied to the remote -- this implies we were forced
- // promoted and then demoted at some point
- dout(15) << dendl;
- update_progress("UPDATE_CLIENT_STATE");
-
- librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
- client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
-
- librbd::journal::ClientData client_data(client_meta);
- bufferlist data_bl;
- encode(client_data, data_bl);
-
- Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client_state>(
- this);
- m_remote_journaler->update_client(data_bl, ctx);
-}
-
-template <typename I>
-void BootstrapRequest<I>::handle_update_client_state(int r) {
- dout(15) << "r=" << r << dendl;
- if (r < 0) {
- derr << "failed to update client: " << cpp_strerror(r) << dendl;
- m_ret_val = r;
- close_local_image();
+ } else if (m_syncing) {
+ dout(10) << "local image still syncing to remote image" << dendl;
+ image_sync();
return;
}
- m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
- get_remote_tag_class();
+ close_remote_image();
}
template <typename I>
void BootstrapRequest<I>::create_local_image() {
+ dout(10) << dendl;
update_progress("CREATE_LOCAL_IMAGE");
// TODO support snapshot-based mirroring
}
template <typename I>
-void BootstrapRequest<I>::get_remote_tag_class() {
- if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_SYNCING) {
- // optimization -- no need to compare remote tags if we just created
- // the image locally or sync was interrupted
- image_sync();
- return;
- }
-
- dout(15) << dendl;
-
- update_progress("GET_REMOTE_TAG_CLASS");
-
- Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tag_class>(
- this);
- m_remote_journaler->get_client(librbd::Journal<>::IMAGE_CLIENT_ID, &m_client, ctx);
-}
-
-template <typename I>
-void BootstrapRequest<I>::handle_get_remote_tag_class(int r) {
- dout(15) << "r=" << r << dendl;
-
- if (r < 0) {
- derr << "failed to retrieve remote client: " << cpp_strerror(r) << dendl;
- m_ret_val = r;
- close_local_image();
- return;
- }
-
- librbd::journal::ClientData client_data;
- auto it = m_client.data.cbegin();
- try {
- decode(client_data, it);
- } catch (const buffer::error &err) {
- derr << "failed to decode remote client meta data: " << err.what()
- << dendl;
- m_ret_val = -EBADMSG;
- close_local_image();
- return;
- }
-
- librbd::journal::ImageClientMeta *client_meta =
- boost::get<librbd::journal::ImageClientMeta>(&client_data.client_meta);
- if (client_meta == nullptr) {
- derr << "unknown remote client registration" << dendl;
- m_ret_val = -EINVAL;
- close_local_image();
- return;
- }
-
- m_remote_tag_class = client_meta->tag_class;
- dout(10) << "remote tag class=" << m_remote_tag_class << dendl;
-
- get_remote_tags();
-}
-
-template <typename I>
-void BootstrapRequest<I>::get_remote_tags() {
- dout(15) << dendl;
- update_progress("GET_REMOTE_TAGS");
-
- Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_remote_tags>(this);
- m_remote_journaler->get_tags(m_remote_tag_class, &m_remote_tags, ctx);
-}
-
-template <typename I>
-void BootstrapRequest<I>::handle_get_remote_tags(int r) {
- dout(15) << "r=" << r << dendl;
-
- if (r < 0) {
- derr << "failed to retrieve remote tags: " << cpp_strerror(r) << dendl;
- m_ret_val = r;
- close_local_image();
- return;
- }
-
+void BootstrapRequest<I>::image_sync() {
+ std::unique_lock locker{m_lock};
if (m_canceled) {
- dout(10) << "request canceled" << dendl;
- m_ret_val = -ECANCELED;
- close_local_image();
- return;
- }
-
- // At this point, the local image was existing, non-primary, and replaying;
- // and the remote image is primary. Attempt to link the local image's most
- // recent tag to the remote image's tag chain.
- bool remote_tag_data_valid = false;
- librbd::journal::TagData remote_tag_data;
- boost::optional<uint64_t> remote_orphan_tag_tid =
- boost::make_optional<uint64_t>(false, 0U);
- bool reconnect_orphan = false;
-
- // decode the remote tags
- for (auto &remote_tag : m_remote_tags) {
- if (m_local_tag_data.predecessor.commit_valid &&
- m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
- m_local_tag_data.predecessor.tag_tid > remote_tag.tid) {
- dout(15) << "skipping processed predecessor remote tag "
- << remote_tag.tid << dendl;
- continue;
- }
-
- try {
- auto it = remote_tag.data.cbegin();
- decode(remote_tag_data, it);
- remote_tag_data_valid = true;
- } catch (const buffer::error &err) {
- derr << "failed to decode remote tag " << remote_tag.tid << ": "
- << err.what() << dendl;
- m_ret_val = -EBADMSG;
- close_local_image();
- return;
- }
+ locker.unlock();
- dout(10) << "decoded remote tag " << remote_tag.tid << ": "
- << remote_tag_data << dendl;
-
- if (!m_local_tag_data.predecessor.commit_valid) {
- // newly synced local image (no predecessor) replays from the first tag
- if (remote_tag_data.mirror_uuid != librbd::Journal<>::LOCAL_MIRROR_UUID) {
- dout(15) << "skipping non-primary remote tag" << dendl;
- continue;
- }
-
- dout(10) << "using initial primary remote tag" << dendl;
- break;
- }
-
- if (m_local_tag_data.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID) {
- // demotion last available local epoch
-
- if (remote_tag_data.mirror_uuid == m_local_tag_data.mirror_uuid &&
- remote_tag_data.predecessor.commit_valid &&
- remote_tag_data.predecessor.tag_tid ==
- m_local_tag_data.predecessor.tag_tid) {
- // demotion matches remote epoch
-
- if (remote_tag_data.predecessor.mirror_uuid == m_local_mirror_uuid &&
- m_local_tag_data.predecessor.mirror_uuid ==
- librbd::Journal<>::LOCAL_MIRROR_UUID) {
- // local demoted and remote has matching event
- dout(15) << "found matching local demotion tag" << dendl;
- remote_orphan_tag_tid = remote_tag.tid;
- continue;
- }
-
- if (m_local_tag_data.predecessor.mirror_uuid == m_remote_mirror_uuid &&
- remote_tag_data.predecessor.mirror_uuid ==
- librbd::Journal<>::LOCAL_MIRROR_UUID) {
- // remote demoted and local has matching event
- dout(15) << "found matching remote demotion tag" << dendl;
- remote_orphan_tag_tid = remote_tag.tid;
- continue;
- }
- }
-
- if (remote_tag_data.mirror_uuid == librbd::Journal<>::LOCAL_MIRROR_UUID &&
- remote_tag_data.predecessor.mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID &&
- remote_tag_data.predecessor.commit_valid && remote_orphan_tag_tid &&
- remote_tag_data.predecessor.tag_tid == *remote_orphan_tag_tid) {
- // remote promotion tag chained to remote/local demotion tag
- dout(15) << "found chained remote promotion tag" << dendl;
- reconnect_orphan = true;
- break;
- }
-
- // promotion must follow demotion
- remote_orphan_tag_tid = boost::none;
- }
- }
-
- if (remote_tag_data_valid &&
- m_local_tag_data.mirror_uuid == m_remote_mirror_uuid) {
- dout(10) << "local image is in clean replay state" << dendl;
- } else if (reconnect_orphan) {
- dout(10) << "remote image was demoted/promoted" << dendl;
- } else {
- derr << "split-brain detected -- skipping image replay" << dendl;
- m_ret_val = -EEXIST;
- close_local_image();
- return;
- }
-
- image_sync();
-}
-
-template <typename I>
-void BootstrapRequest<I>::image_sync() {
- if (m_client_meta->state == librbd::journal::MIRROR_PEER_STATE_REPLAYING) {
- // clean replay state -- no image sync required
+ m_ret_val = -ECANCELED;
+ dout(10) << "request canceled" << dendl;
close_remote_image();
return;
}
- {
- std::unique_lock locker{m_lock};
- if (m_canceled) {
- m_ret_val = -ECANCELED;
- } else {
- dout(15) << dendl;
- ceph_assert(m_image_sync == nullptr);
-
- Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(this);
- m_image_sync = ImageSync<I>::create(
- *m_local_image_ctx, m_remote_image_ctx, m_threads->timer,
- &m_threads->timer_lock, m_local_mirror_uuid, m_remote_journaler,
- m_client_meta, m_threads->work_queue, m_instance_watcher, ctx,
- m_progress_ctx);
-
- m_image_sync->get();
-
- locker.unlock();
- update_progress("IMAGE_SYNC");
- locker.lock();
-
- m_image_sync->send();
- return;
- }
- }
+ dout(15) << dendl;
+ ceph_assert(m_image_sync == nullptr);
- dout(10) << "request canceled" << dendl;
- close_remote_image();
+ Context *ctx = create_context_callback<
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(this);
+ m_image_sync = ImageSync<I>::create(
+ *m_local_image_ctx, m_remote_image_ctx, m_threads->timer,
+ &m_threads->timer_lock, m_local_mirror_uuid, m_remote_journaler,
+ m_client_meta, m_threads->work_queue, m_instance_watcher, ctx,
+ m_progress_ctx);
+ m_image_sync->get();
+ locker.unlock();
+
+ update_progress("IMAGE_SYNC");
+ m_image_sync->send();
}
template <typename I>
std::lock_guard locker{m_lock};
m_image_sync->put();
m_image_sync = nullptr;
+ }
- if (m_canceled) {
- dout(10) << "request canceled" << dendl;
- m_ret_val = -ECANCELED;
- }
-
- if (r < 0) {
- derr << "failed to sync remote image: " << cpp_strerror(r) << dendl;
- m_ret_val = r;
- }
+ if (r < 0) {
+ derr << "failed to sync remote image: " << cpp_strerror(r) << dendl;
+ m_ret_val = r;
}
close_remote_image();