1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/rbd_mirror/test_mock_fixture.h"
5 #include "librbd/journal/TypeTraits.h"
6 #include "tools/rbd_mirror/InstanceWatcher.h"
7 #include "tools/rbd_mirror/Threads.h"
8 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
9 #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
10 #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h"
11 #include "tools/rbd_mirror/image_replayer/IsPrimaryRequest.h"
12 #include "tools/rbd_mirror/image_replayer/OpenImageRequest.h"
13 #include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h"
14 #include "test/journal/mock/MockJournaler.h"
15 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
16 #include "test/librbd/mock/MockImageCtx.h"
17 #include "test/librbd/mock/MockJournal.h"
23 struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
29 } // anonymous namespace
34 struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
38 } // namespace journal
42 static std::string s_image_id;
45 std::string generate_image_id<MockTestImageCtx>(librados::IoCtx&) {
46 assert(!s_image_id.empty());
56 class ProgressContext;
59 struct ImageSync<librbd::MockTestImageCtx> {
60 static ImageSync* s_instance;
61 Context *on_finish = nullptr;
63 static ImageSync* create(
64 librbd::MockTestImageCtx *local_image_ctx,
65 librbd::MockTestImageCtx *remote_image_ctx,
66 SafeTimer *timer, Mutex *timer_lock, const std::string &mirror_uuid,
67 ::journal::MockJournaler *journaler,
68 librbd::journal::MirrorPeerClientMeta *client_meta, ContextWQ *work_queue,
69 InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
70 Context *on_finish, ProgressContext *progress_ctx) {
71 assert(s_instance != nullptr);
72 s_instance->on_finish = on_finish;
77 assert(s_instance == nullptr);
84 MOCK_METHOD0(get, void());
85 MOCK_METHOD0(put, void());
86 MOCK_METHOD0(send, void());
87 MOCK_METHOD0(cancel, void());
90 ImageSync<librbd::MockTestImageCtx>*
91 ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr;
94 struct InstanceWatcher<librbd::MockTestImageCtx> {
97 namespace image_replayer {
100 struct CloseImageRequest<librbd::MockTestImageCtx> {
101 static CloseImageRequest* s_instance;
102 librbd::MockTestImageCtx **image_ctx = nullptr;
103 Context *on_finish = nullptr;
105 static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
106 Context *on_finish) {
107 assert(s_instance != nullptr);
108 s_instance->image_ctx = image_ctx;
109 s_instance->on_finish = on_finish;
110 s_instance->construct(*image_ctx);
114 CloseImageRequest() {
115 assert(s_instance == nullptr);
118 ~CloseImageRequest() {
119 s_instance = nullptr;
122 MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx));
123 MOCK_METHOD0(send, void());
127 struct CreateImageRequest<librbd::MockTestImageCtx> {
128 static CreateImageRequest* s_instance;
129 Context *on_finish = nullptr;
131 static CreateImageRequest* create(librados::IoCtx &local_io_ctx,
132 ContextWQ *work_queue,
133 const std::string &global_image_id,
134 const std::string &remote_mirror_uuid,
135 const std::string &local_image_name,
136 const std::string &local_image_id,
137 librbd::MockTestImageCtx *remote_image_ctx,
138 Context *on_finish) {
139 assert(s_instance != nullptr);
140 s_instance->on_finish = on_finish;
141 s_instance->construct(local_image_id);
145 CreateImageRequest() {
146 assert(s_instance == nullptr);
149 ~CreateImageRequest() {
150 s_instance = nullptr;
153 MOCK_METHOD1(construct, void(const std::string&));
154 MOCK_METHOD0(send, void());
158 struct IsPrimaryRequest<librbd::MockTestImageCtx> {
159 static IsPrimaryRequest* s_instance;
160 bool *primary = nullptr;
161 Context *on_finish = nullptr;
163 static IsPrimaryRequest* create(librbd::MockTestImageCtx *image_ctx,
164 bool *primary, Context *on_finish) {
165 assert(s_instance != nullptr);
166 s_instance->primary = primary;
167 s_instance->on_finish = on_finish;
172 assert(s_instance == nullptr);
175 ~IsPrimaryRequest() {
176 s_instance = nullptr;
179 MOCK_METHOD0(send, void());
183 struct OpenImageRequest<librbd::MockTestImageCtx> {
184 static OpenImageRequest* s_instance;
185 librbd::MockTestImageCtx **image_ctx = nullptr;
186 Context *on_finish = nullptr;
188 static OpenImageRequest* create(librados::IoCtx &io_ctx,
189 librbd::MockTestImageCtx **image_ctx,
190 const std::string &image_id,
191 bool read_only, Context *on_finish) {
192 assert(s_instance != nullptr);
193 s_instance->image_ctx = image_ctx;
194 s_instance->on_finish = on_finish;
195 s_instance->construct(io_ctx, image_id);
200 assert(s_instance == nullptr);
203 ~OpenImageRequest() {
204 s_instance = nullptr;
207 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
208 const std::string &image_id));
209 MOCK_METHOD0(send, void());
213 struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
214 static OpenLocalImageRequest* s_instance;
215 librbd::MockTestImageCtx **image_ctx = nullptr;
216 Context *on_finish = nullptr;
218 static OpenLocalImageRequest* create(librados::IoCtx &local_io_ctx,
219 librbd::MockTestImageCtx **local_image_ctx,
220 const std::string &local_image_id,
221 ContextWQ *work_queue,
222 Context *on_finish) {
223 assert(s_instance != nullptr);
224 s_instance->image_ctx = local_image_ctx;
225 s_instance->on_finish = on_finish;
226 s_instance->construct(local_io_ctx, local_image_id);
230 OpenLocalImageRequest() {
231 assert(s_instance == nullptr);
234 ~OpenLocalImageRequest() {
235 s_instance = nullptr;
238 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
239 const std::string &image_id));
240 MOCK_METHOD0(send, void());
243 CloseImageRequest<librbd::MockTestImageCtx>*
244 CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
245 CreateImageRequest<librbd::MockTestImageCtx>*
246 CreateImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
247 IsPrimaryRequest<librbd::MockTestImageCtx>*
248 IsPrimaryRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
249 OpenImageRequest<librbd::MockTestImageCtx>*
250 OpenImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
251 OpenLocalImageRequest<librbd::MockTestImageCtx>*
252 OpenLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
254 } // namespace image_replayer
255 } // namespace mirror
258 // template definitions
259 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
263 namespace image_replayer {
266 using ::testing::DoAll;
267 using ::testing::InSequence;
268 using ::testing::Invoke;
269 using ::testing::Return;
270 using ::testing::SetArgPointee;
271 using ::testing::StrEq;
272 using ::testing::WithArg;
274 MATCHER_P(IsSameIoCtx, io_ctx, "") {
275 return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
278 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
280 typedef BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
281 typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
282 typedef CreateImageRequest<librbd::MockTestImageCtx> MockCreateImageRequest;
283 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
284 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
285 typedef IsPrimaryRequest<librbd::MockTestImageCtx> MockIsPrimaryRequest;
286 typedef OpenImageRequest<librbd::MockTestImageCtx> MockOpenImageRequest;
287 typedef OpenLocalImageRequest<librbd::MockTestImageCtx> MockOpenLocalImageRequest;
288 typedef std::list<cls::journal::Tag> Tags;
290 void SetUp() override {
291 TestMockFixture::SetUp();
294 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
295 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
298 void create_local_image() {
300 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
301 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
304 void expect_journaler_get_client(::journal::MockJournaler &mock_journaler,
305 const std::string &client_id,
306 cls::journal::Client &client, int r) {
307 EXPECT_CALL(mock_journaler, get_client(StrEq(client_id), _, _))
308 .WillOnce(DoAll(WithArg<1>(Invoke([client](cls::journal::Client *out_client) {
309 *out_client = client;
311 WithArg<2>(Invoke([this, r](Context *on_finish) {
312 m_threads->work_queue->queue(on_finish, r);
316 void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
317 uint64_t tag_class, const Tags& tags,
319 EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
320 .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
323 WithArg<2>(Invoke([this, r](Context *on_finish) {
324 m_threads->work_queue->queue(on_finish, r);
328 void expect_journaler_register_client(::journal::MockJournaler &mock_journaler,
329 const librbd::journal::ClientData &client_data,
332 ::encode(client_data, bl);
334 EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _))
335 .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
336 m_threads->work_queue->queue(on_finish, r);
340 void expect_journaler_unregister_client(::journal::MockJournaler &mock_journaler,
342 EXPECT_CALL(mock_journaler, unregister_client(_))
343 .WillOnce(Invoke([this, r](Context *on_finish) {
344 m_threads->work_queue->queue(on_finish, r);
348 void expect_journaler_update_client(::journal::MockJournaler &mock_journaler,
349 const librbd::journal::ClientData &client_data,
352 ::encode(client_data, bl);
354 EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _))
355 .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) {
356 m_threads->work_queue->queue(on_finish, r);
360 void expect_open_image(MockOpenImageRequest &mock_open_image_request,
361 librados::IoCtx &io_ctx, const std::string &image_id,
362 librbd::MockTestImageCtx &mock_image_ctx, int r) {
363 EXPECT_CALL(mock_open_image_request, construct(IsSameIoCtx(&io_ctx), image_id));
364 EXPECT_CALL(mock_open_image_request, send())
365 .WillOnce(Invoke([this, &mock_open_image_request, &mock_image_ctx, r]() {
366 *mock_open_image_request.image_ctx = &mock_image_ctx;
367 m_threads->work_queue->queue(mock_open_image_request.on_finish, r);
371 void expect_open_local_image(MockOpenLocalImageRequest &mock_open_local_image_request,
372 librados::IoCtx &io_ctx, const std::string &image_id,
373 librbd::MockTestImageCtx *mock_image_ctx, int r) {
374 EXPECT_CALL(mock_open_local_image_request,
375 construct(IsSameIoCtx(&io_ctx), image_id));
376 EXPECT_CALL(mock_open_local_image_request, send())
377 .WillOnce(Invoke([this, &mock_open_local_image_request, mock_image_ctx, r]() {
378 *mock_open_local_image_request.image_ctx = mock_image_ctx;
379 m_threads->work_queue->queue(mock_open_local_image_request.on_finish,
384 void expect_close_image(MockCloseImageRequest &mock_close_image_request,
385 librbd::MockTestImageCtx &mock_image_ctx, int r) {
386 EXPECT_CALL(mock_close_image_request, construct(&mock_image_ctx));
387 EXPECT_CALL(mock_close_image_request, send())
388 .WillOnce(Invoke([this, &mock_close_image_request, r]() {
389 *mock_close_image_request.image_ctx = nullptr;
390 m_threads->work_queue->queue(mock_close_image_request.on_finish, r);
394 void expect_is_primary(MockIsPrimaryRequest &mock_is_primary_request,
395 bool primary, int r) {
396 EXPECT_CALL(mock_is_primary_request, send())
397 .WillOnce(Invoke([this, &mock_is_primary_request, primary, r]() {
398 *mock_is_primary_request.primary = primary;
399 m_threads->work_queue->queue(mock_is_primary_request.on_finish, r);
403 void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
405 EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
408 void expect_journal_get_tag_data(librbd::MockJournal &mock_journal,
409 const librbd::journal::TagData &tag_data) {
410 EXPECT_CALL(mock_journal, get_tag_data()).WillOnce(Return(tag_data));
413 void expect_is_resync_requested(librbd::MockJournal &mock_journal,
414 bool do_resync, int r) {
415 EXPECT_CALL(mock_journal, is_resync_requested(_))
416 .WillOnce(DoAll(SetArgPointee<0>(do_resync),
420 void expect_create_image(MockCreateImageRequest &mock_create_image_request,
421 const std::string &image_id, int r) {
422 EXPECT_CALL(mock_create_image_request, construct(image_id));
423 EXPECT_CALL(mock_create_image_request, send())
424 .WillOnce(Invoke([this, &mock_create_image_request, r]() {
425 m_threads->work_queue->queue(mock_create_image_request.on_finish, r);
429 void expect_image_sync(MockImageSync &mock_image_sync, int r) {
430 EXPECT_CALL(mock_image_sync, get());
431 EXPECT_CALL(mock_image_sync, send())
432 .WillOnce(Invoke([this, &mock_image_sync, r]() {
433 m_threads->work_queue->queue(mock_image_sync.on_finish, r);
435 EXPECT_CALL(mock_image_sync, put());
438 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
440 ::encode(tag_data, bl);
444 MockBootstrapRequest *create_request(MockInstanceWatcher *mock_instance_watcher,
445 ::journal::MockJournaler &mock_journaler,
446 const std::string &local_image_id,
447 const std::string &remote_image_id,
448 const std::string &global_image_id,
449 const std::string &local_mirror_uuid,
450 const std::string &remote_mirror_uuid,
451 Context *on_finish) {
452 return new MockBootstrapRequest(m_local_io_ctx,
454 mock_instance_watcher,
455 &m_local_test_image_ctx,
459 m_threads->work_queue,
461 &m_threads->timer_lock,
465 &m_mirror_peer_client_meta,
466 on_finish, &m_do_resync);
469 librbd::ImageCtx *m_remote_image_ctx;
470 librbd::ImageCtx *m_local_image_ctx = nullptr;
471 librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
472 librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta;
476 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
477 create_local_image();
481 // lookup remote image tag class
482 cls::journal::Client client;
483 librbd::journal::ClientData client_data{
484 librbd::journal::ImageClientMeta{123}};
485 ::encode(client_data, client.data);
486 ::journal::MockJournaler mock_journaler;
487 expect_journaler_get_client(mock_journaler,
488 librbd::Journal<>::IMAGE_CLIENT_ID,
491 // open the remote image
492 librbd::MockJournal mock_journal;
493 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
494 MockOpenImageRequest mock_open_image_request;
495 expect_open_image(mock_open_image_request, m_remote_io_ctx,
496 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
498 // lookup local peer in remote journal
499 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
500 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
501 mock_local_image_ctx.id};
502 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
503 client_data.client_meta = mirror_peer_client_meta;
505 ::encode(client_data, client.data);
506 expect_journaler_get_client(mock_journaler, "local mirror uuid",
509 // test if remote image is primary
510 MockIsPrimaryRequest mock_is_primary_request;
511 expect_is_primary(mock_is_primary_request, false, 0);
513 // switch the state to replaying
514 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
515 client_data.client_meta = mirror_peer_client_meta;
516 expect_journaler_update_client(mock_journaler, client_data, 0);
518 MockCloseImageRequest mock_close_image_request;
519 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
522 MockInstanceWatcher mock_instance_watcher;
523 MockBootstrapRequest *request = create_request(
524 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
525 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
526 "remote mirror uuid", &ctx);
528 ASSERT_EQ(-EREMOTEIO, ctx.wait());
531 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
532 create_local_image();
536 // lookup remote image tag class
537 cls::journal::Client client;
538 librbd::journal::ClientData client_data{
539 librbd::journal::ImageClientMeta{123}};
540 ::encode(client_data, client.data);
541 ::journal::MockJournaler mock_journaler;
542 expect_journaler_get_client(mock_journaler,
543 librbd::Journal<>::IMAGE_CLIENT_ID,
546 // open the remote image
547 librbd::MockJournal mock_journal;
548 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
549 MockOpenImageRequest mock_open_image_request;
550 expect_open_image(mock_open_image_request, m_remote_io_ctx,
551 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
553 // lookup local peer in remote journal
554 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
555 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
556 mock_local_image_ctx.id};
557 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
558 client_data.client_meta = mirror_peer_client_meta;
560 ::encode(client_data, client.data);
561 expect_journaler_get_client(mock_journaler, "local mirror uuid",
564 // test if remote image is primary
565 MockIsPrimaryRequest mock_is_primary_request;
566 expect_is_primary(mock_is_primary_request, true, 0);
568 // open the local image
569 mock_local_image_ctx.journal = &mock_journal;
570 MockOpenLocalImageRequest mock_open_local_image_request;
571 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
572 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
573 expect_is_resync_requested(mock_journal, false, 0);
575 // remote demotion / promotion event
577 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
578 librbd::Journal<>::LOCAL_MIRROR_UUID,
580 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
581 librbd::Journal<>::LOCAL_MIRROR_UUID,
583 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
584 librbd::Journal<>::ORPHAN_MIRROR_UUID,
586 {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
587 librbd::Journal<>::ORPHAN_MIRROR_UUID,
590 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
591 expect_journal_get_tag_tid(mock_journal, 345);
592 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
594 MockCloseImageRequest mock_close_image_request;
595 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
598 MockInstanceWatcher mock_instance_watcher;
599 MockBootstrapRequest *request = create_request(
600 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
601 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
602 "remote mirror uuid", &ctx);
604 ASSERT_EQ(0, ctx.wait());
607 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
608 create_local_image();
612 // lookup remote image tag class
613 cls::journal::Client client;
614 librbd::journal::ClientData client_data{
615 librbd::journal::ImageClientMeta{123}};
616 ::encode(client_data, client.data);
617 ::journal::MockJournaler mock_journaler;
618 expect_journaler_get_client(mock_journaler,
619 librbd::Journal<>::IMAGE_CLIENT_ID,
622 // open the remote image
623 librbd::MockJournal mock_journal;
624 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
625 MockOpenImageRequest mock_open_image_request;
626 expect_open_image(mock_open_image_request, m_remote_io_ctx,
627 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
629 // lookup local peer in remote journal
630 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
631 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
632 mock_local_image_ctx.id};
633 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
634 client_data.client_meta = mirror_peer_client_meta;
636 ::encode(client_data, client.data);
637 expect_journaler_get_client(mock_journaler, "local mirror uuid",
640 // test if remote image is primary
641 MockIsPrimaryRequest mock_is_primary_request;
642 expect_is_primary(mock_is_primary_request, true, 0);
644 // open the local image
645 mock_local_image_ctx.journal = &mock_journal;
646 MockOpenLocalImageRequest mock_open_local_image_request;
647 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
648 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
649 expect_is_resync_requested(mock_journal, false, 0);
651 // remote demotion / promotion event
653 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
654 librbd::Journal<>::LOCAL_MIRROR_UUID,
656 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
657 librbd::Journal<>::LOCAL_MIRROR_UUID,
659 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
660 librbd::Journal<>::ORPHAN_MIRROR_UUID,
662 {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
663 librbd::Journal<>::LOCAL_MIRROR_UUID,
665 {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
666 librbd::Journal<>::ORPHAN_MIRROR_UUID,
668 {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
669 librbd::Journal<>::LOCAL_MIRROR_UUID,
671 {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
672 librbd::Journal<>::ORPHAN_MIRROR_UUID,
675 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
676 expect_journal_get_tag_tid(mock_journal, 345);
677 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
678 "remote mirror uuid", true, 4, 1});
680 MockCloseImageRequest mock_close_image_request;
681 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
684 MockInstanceWatcher mock_instance_watcher;
685 MockBootstrapRequest *request = create_request(
686 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
687 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
688 "remote mirror uuid", &ctx);
690 ASSERT_EQ(0, ctx.wait());
693 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
694 create_local_image();
698 // lookup remote image tag class
699 cls::journal::Client client;
700 librbd::journal::ClientData client_data{
701 librbd::journal::ImageClientMeta{123}};
702 ::encode(client_data, client.data);
703 ::journal::MockJournaler mock_journaler;
704 expect_journaler_get_client(mock_journaler,
705 librbd::Journal<>::IMAGE_CLIENT_ID,
708 // open the remote image
709 librbd::MockJournal mock_journal;
710 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
711 MockOpenImageRequest mock_open_image_request;
712 expect_open_image(mock_open_image_request, m_remote_io_ctx,
713 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
715 // lookup local peer in remote journal
716 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
717 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
718 mock_local_image_ctx.id};
719 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
720 client_data.client_meta = mirror_peer_client_meta;
722 ::encode(client_data, client.data);
723 expect_journaler_get_client(mock_journaler, "local mirror uuid",
726 // test if remote image is primary
727 MockIsPrimaryRequest mock_is_primary_request;
728 expect_is_primary(mock_is_primary_request, true, 0);
730 // open the local image
731 mock_local_image_ctx.journal = &mock_journal;
732 MockOpenLocalImageRequest mock_open_local_image_request;
733 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
734 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
735 expect_is_resync_requested(mock_journal, false, 0);
737 // remote demotion / promotion event
739 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
741 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
742 "local mirror uuid", true, 345, 1})},
743 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
744 librbd::Journal<>::ORPHAN_MIRROR_UUID,
747 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
748 expect_journal_get_tag_tid(mock_journal, 346);
749 expect_journal_get_tag_data(mock_journal,
750 {librbd::Journal<>::ORPHAN_MIRROR_UUID,
751 librbd::Journal<>::LOCAL_MIRROR_UUID,
754 MockCloseImageRequest mock_close_image_request;
755 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
758 MockInstanceWatcher mock_instance_watcher;
759 MockBootstrapRequest *request = create_request(
760 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
761 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
762 "remote mirror uuid", &ctx);
764 ASSERT_EQ(0, ctx.wait());
767 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
768 create_local_image();
772 // lookup remote image tag class
773 cls::journal::Client client;
774 librbd::journal::ClientData client_data{
775 librbd::journal::ImageClientMeta{123}};
776 ::encode(client_data, client.data);
777 ::journal::MockJournaler mock_journaler;
778 expect_journaler_get_client(mock_journaler,
779 librbd::Journal<>::IMAGE_CLIENT_ID,
782 // open the remote image
783 librbd::MockJournal mock_journal;
784 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
785 MockOpenImageRequest mock_open_image_request;
786 expect_open_image(mock_open_image_request, m_remote_io_ctx,
787 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
789 // lookup local peer in remote journal
790 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
791 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
792 mock_local_image_ctx.id};
793 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
794 client_data.client_meta = mirror_peer_client_meta;
796 ::encode(client_data, client.data);
797 expect_journaler_get_client(mock_journaler, "local mirror uuid",
800 // test if remote image is primary
801 MockIsPrimaryRequest mock_is_primary_request;
802 expect_is_primary(mock_is_primary_request, true, 0);
804 // open the local image
805 mock_local_image_ctx.journal = &mock_journal;
806 MockOpenLocalImageRequest mock_open_local_image_request;
807 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
808 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
809 expect_is_resync_requested(mock_journal, false, 0);
811 // remote demotion / promotion event
813 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
814 librbd::Journal<>::LOCAL_MIRROR_UUID,
816 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
817 librbd::Journal<>::LOCAL_MIRROR_UUID,
820 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
821 expect_journal_get_tag_tid(mock_journal, 345);
822 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
823 librbd::Journal<>::ORPHAN_MIRROR_UUID,
826 MockCloseImageRequest mock_close_image_request;
827 expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
828 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
831 MockInstanceWatcher mock_instance_watcher;
832 MockBootstrapRequest *request = create_request(
833 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
834 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
835 "remote mirror uuid", &ctx);
837 ASSERT_EQ(-EEXIST, ctx.wait());
838 ASSERT_EQ(NULL, m_local_test_image_ctx);
841 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
842 create_local_image();
846 // lookup remote image tag class
847 cls::journal::Client client;
848 librbd::journal::ClientData client_data{
849 librbd::journal::ImageClientMeta{123}};
850 ::encode(client_data, client.data);
851 ::journal::MockJournaler mock_journaler;
852 expect_journaler_get_client(mock_journaler,
853 librbd::Journal<>::IMAGE_CLIENT_ID,
856 // open the remote image
857 librbd::MockJournal mock_journal;
858 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
859 MockOpenImageRequest mock_open_image_request;
860 expect_open_image(mock_open_image_request, m_remote_io_ctx,
861 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
863 // lookup local peer in remote journal
864 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
865 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
866 mock_local_image_ctx.id};
867 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
868 client_data.client_meta = mirror_peer_client_meta;
870 ::encode(client_data, client.data);
871 expect_journaler_get_client(mock_journaler, "local mirror uuid",
874 // test if remote image is primary
875 MockIsPrimaryRequest mock_is_primary_request;
876 expect_is_primary(mock_is_primary_request, true, 0);
878 // open the local image
879 mock_local_image_ctx.journal = &mock_journal;
880 MockOpenLocalImageRequest mock_open_local_image_request;
881 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
882 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
884 // resync is requested
885 expect_is_resync_requested(mock_journal, true, 0);
888 MockCloseImageRequest mock_close_image_request;
889 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
892 MockInstanceWatcher mock_instance_watcher;
893 MockBootstrapRequest *request = create_request(
894 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
895 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
896 "remote mirror uuid", &ctx);
899 ASSERT_EQ(0, ctx.wait());
900 ASSERT_TRUE(m_do_resync);
903 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
904 create_local_image();
908 // lookup remote image tag class
909 cls::journal::Client client;
910 librbd::journal::ClientData client_data{
911 librbd::journal::ImageClientMeta{123}};
912 ::encode(client_data, client.data);
913 ::journal::MockJournaler mock_journaler;
914 expect_journaler_get_client(mock_journaler,
915 librbd::Journal<>::IMAGE_CLIENT_ID,
918 // open the remote image
919 librbd::MockJournal mock_journal;
920 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
921 MockOpenImageRequest mock_open_image_request;
922 expect_open_image(mock_open_image_request, m_remote_io_ctx,
923 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
925 // lookup local peer in remote journal
927 expect_journaler_get_client(mock_journaler, "local mirror uuid",
930 // register missing client in remote journal
931 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
932 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
933 client_data.client_meta = mirror_peer_client_meta;
934 expect_journaler_register_client(mock_journaler, client_data, 0);
936 // test if remote image is primary
937 MockIsPrimaryRequest mock_is_primary_request;
938 expect_is_primary(mock_is_primary_request, true, 0);
940 // update client state back to syncing
941 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
942 mock_local_image_ctx.journal = &mock_journal;
944 librbd::util::s_image_id = mock_local_image_ctx.id;
945 mirror_peer_client_meta = {mock_local_image_ctx.id};
946 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
947 client_data.client_meta = mirror_peer_client_meta;
949 ::encode(client_data, client.data);
950 expect_journaler_update_client(mock_journaler, client_data, 0);
952 // create the local image
953 MockCreateImageRequest mock_create_image_request;
954 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
956 // open the local image
957 MockOpenLocalImageRequest mock_open_local_image_request;
958 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
959 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
960 expect_is_resync_requested(mock_journal, false, 0);
962 // sync the remote image to the local image
963 MockImageSync mock_image_sync;
964 expect_image_sync(mock_image_sync, 0);
966 MockCloseImageRequest mock_close_image_request;
967 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
970 MockInstanceWatcher mock_instance_watcher;
971 MockBootstrapRequest *request = create_request(
972 &mock_instance_watcher, mock_journaler, "",
973 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
974 "remote mirror uuid", &ctx);
976 ASSERT_EQ(0, ctx.wait());
979 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
980 create_local_image();
984 // lookup remote image tag class
985 cls::journal::Client client;
986 librbd::journal::ClientData client_data{
987 librbd::journal::ImageClientMeta{123}};
988 ::encode(client_data, client.data);
989 ::journal::MockJournaler mock_journaler;
990 expect_journaler_get_client(mock_journaler,
991 librbd::Journal<>::IMAGE_CLIENT_ID,
994 // open the remote image
995 librbd::MockJournal mock_journal;
996 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
997 MockOpenImageRequest mock_open_image_request;
998 expect_open_image(mock_open_image_request, m_remote_io_ctx,
999 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
1001 // lookup local peer in remote journal
1002 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
1003 "missing image id"};
1004 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1005 client_data.client_meta = mirror_peer_client_meta;
1006 client.data.clear();
1007 ::encode(client_data, client.data);
1008 expect_journaler_get_client(mock_journaler, "local mirror uuid",
1011 // test if remote image is primary
1012 MockIsPrimaryRequest mock_is_primary_request;
1013 expect_is_primary(mock_is_primary_request, true, 0);
1015 // open the missing local image
1016 MockOpenLocalImageRequest mock_open_local_image_request;
1017 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1018 "missing image id", nullptr, -ENOENT);
1020 // re-register the client
1021 expect_journaler_unregister_client(mock_journaler, 0);
1022 mirror_peer_client_meta = {};
1023 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1024 client_data.client_meta = mirror_peer_client_meta;
1025 expect_journaler_register_client(mock_journaler, client_data, 0);
1027 // test if remote image is primary
1028 expect_is_primary(mock_is_primary_request, true, 0);
1030 // update client state back to syncing
1031 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
1032 mock_local_image_ctx.journal = &mock_journal;
1034 librbd::util::s_image_id = mock_local_image_ctx.id;
1035 mirror_peer_client_meta = {mock_local_image_ctx.id};
1036 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
1037 client_data.client_meta = mirror_peer_client_meta;
1038 client.data.clear();
1039 ::encode(client_data, client.data);
1040 expect_journaler_update_client(mock_journaler, client_data, 0);
1042 // create the missing local image
1043 MockCreateImageRequest mock_create_image_request;
1044 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
1046 // open the local image
1047 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1048 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
1049 expect_is_resync_requested(mock_journal, false, 0);
1051 // sync the remote image to the local image
1052 MockImageSync mock_image_sync;
1053 expect_image_sync(mock_image_sync, 0);
1055 MockCloseImageRequest mock_close_image_request;
1056 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1059 MockInstanceWatcher mock_instance_watcher;
1060 MockBootstrapRequest *request = create_request(
1061 &mock_instance_watcher, mock_journaler, "",
1062 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
1063 "remote mirror uuid", &ctx);
1065 ASSERT_EQ(0, ctx.wait());
1068 } // namespace image_replayer
1069 } // namespace mirror