]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
update sources to 12.2.7
[ceph.git] / ceph / src / test / rbd_mirror / image_replayer / test_mock_BootstrapRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
18
19 namespace librbd {
20
21 namespace {
22
23 struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
26 }
27 };
28
29 } // anonymous namespace
30
31 namespace journal {
32
33 template <>
34 struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
36 };
37
38 } // namespace journal
39
40 namespace util {
41
42 static std::string s_image_id;
43
44 template <>
45 std::string generate_image_id<MockTestImageCtx>(librados::IoCtx&) {
46 assert(!s_image_id.empty());
47 return s_image_id;
48 }
49
50 } // namespace util
51 } // namespace librbd
52
53 namespace rbd {
54 namespace mirror {
55
56 class ProgressContext;
57
58 template<>
59 struct ImageSync<librbd::MockTestImageCtx> {
60 static ImageSync* s_instance;
61 Context *on_finish = nullptr;
62
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;
73 return s_instance;
74 }
75
76 ImageSync() {
77 assert(s_instance == nullptr);
78 s_instance = this;
79 }
80 ~ImageSync() {
81 s_instance = nullptr;
82 }
83
84 MOCK_METHOD0(get, void());
85 MOCK_METHOD0(put, void());
86 MOCK_METHOD0(send, void());
87 MOCK_METHOD0(cancel, void());
88 };
89
90 ImageSync<librbd::MockTestImageCtx>*
91 ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr;
92
93 template<>
94 struct InstanceWatcher<librbd::MockTestImageCtx> {
95 };
96
97 namespace image_replayer {
98
99 template<>
100 struct CloseImageRequest<librbd::MockTestImageCtx> {
101 static CloseImageRequest* s_instance;
102 librbd::MockTestImageCtx **image_ctx = nullptr;
103 Context *on_finish = nullptr;
104
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);
111 return s_instance;
112 }
113
114 CloseImageRequest() {
115 assert(s_instance == nullptr);
116 s_instance = this;
117 }
118 ~CloseImageRequest() {
119 s_instance = nullptr;
120 }
121
122 MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx));
123 MOCK_METHOD0(send, void());
124 };
125
126 template<>
127 struct CreateImageRequest<librbd::MockTestImageCtx> {
128 static CreateImageRequest* s_instance;
129 Context *on_finish = nullptr;
130
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);
142 return s_instance;
143 }
144
145 CreateImageRequest() {
146 assert(s_instance == nullptr);
147 s_instance = this;
148 }
149 ~CreateImageRequest() {
150 s_instance = nullptr;
151 }
152
153 MOCK_METHOD1(construct, void(const std::string&));
154 MOCK_METHOD0(send, void());
155 };
156
157 template<>
158 struct IsPrimaryRequest<librbd::MockTestImageCtx> {
159 static IsPrimaryRequest* s_instance;
160 bool *primary = nullptr;
161 Context *on_finish = nullptr;
162
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;
168 return s_instance;
169 }
170
171 IsPrimaryRequest() {
172 assert(s_instance == nullptr);
173 s_instance = this;
174 }
175 ~IsPrimaryRequest() {
176 s_instance = nullptr;
177 }
178
179 MOCK_METHOD0(send, void());
180 };
181
182 template<>
183 struct OpenImageRequest<librbd::MockTestImageCtx> {
184 static OpenImageRequest* s_instance;
185 librbd::MockTestImageCtx **image_ctx = nullptr;
186 Context *on_finish = nullptr;
187
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);
196 return s_instance;
197 }
198
199 OpenImageRequest() {
200 assert(s_instance == nullptr);
201 s_instance = this;
202 }
203 ~OpenImageRequest() {
204 s_instance = nullptr;
205 }
206
207 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
208 const std::string &image_id));
209 MOCK_METHOD0(send, void());
210 };
211
212 template<>
213 struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
214 static OpenLocalImageRequest* s_instance;
215 librbd::MockTestImageCtx **image_ctx = nullptr;
216 Context *on_finish = nullptr;
217
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);
227 return s_instance;
228 }
229
230 OpenLocalImageRequest() {
231 assert(s_instance == nullptr);
232 s_instance = this;
233 }
234 ~OpenLocalImageRequest() {
235 s_instance = nullptr;
236 }
237
238 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
239 const std::string &image_id));
240 MOCK_METHOD0(send, void());
241 };
242
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;
253
254 } // namespace image_replayer
255 } // namespace mirror
256 } // namespace rbd
257
258 // template definitions
259 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
260
261 namespace rbd {
262 namespace mirror {
263 namespace image_replayer {
264
265 using ::testing::_;
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;
273
274 MATCHER_P(IsSameIoCtx, io_ctx, "") {
275 return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
276 }
277
278 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
279 public:
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;
289
290 void SetUp() override {
291 TestMockFixture::SetUp();
292
293 librbd::RBD rbd;
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));
296 }
297
298 void create_local_image() {
299 librbd::RBD rbd;
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));
302 }
303
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;
310 })),
311 WithArg<2>(Invoke([this, r](Context *on_finish) {
312 m_threads->work_queue->queue(on_finish, r);
313 }))));
314 }
315
316 void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
317 uint64_t tag_class, const Tags& tags,
318 int r) {
319 EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
320 .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
321 *out_tags = tags;
322 })),
323 WithArg<2>(Invoke([this, r](Context *on_finish) {
324 m_threads->work_queue->queue(on_finish, r);
325 }))));
326 }
327
328 void expect_journaler_register_client(::journal::MockJournaler &mock_journaler,
329 const librbd::journal::ClientData &client_data,
330 int r) {
331 bufferlist bl;
332 ::encode(client_data, bl);
333
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);
337 })));
338 }
339
340 void expect_journaler_unregister_client(::journal::MockJournaler &mock_journaler,
341 int r) {
342 EXPECT_CALL(mock_journaler, unregister_client(_))
343 .WillOnce(Invoke([this, r](Context *on_finish) {
344 m_threads->work_queue->queue(on_finish, r);
345 }));
346 }
347
348 void expect_journaler_update_client(::journal::MockJournaler &mock_journaler,
349 const librbd::journal::ClientData &client_data,
350 int r) {
351 bufferlist bl;
352 ::encode(client_data, bl);
353
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);
357 })));
358 }
359
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);
368 }));
369 }
370
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,
380 r);
381 }));
382 }
383
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);
391 }));
392 }
393
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);
400 }));
401 }
402
403 void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
404 uint64_t tag_tid) {
405 EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
406 }
407
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));
411 }
412
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),
417 Return(r)));
418 }
419
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);
426 }));
427 }
428
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);
434 }));
435 EXPECT_CALL(mock_image_sync, put());
436 }
437
438 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
439 bufferlist bl;
440 ::encode(tag_data, bl);
441 return bl;
442 }
443
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 cls::journal::ClientState *client_state,
452 librbd::journal::MirrorPeerClientMeta *mirror_peer_client_meta,
453 Context *on_finish) {
454 return new MockBootstrapRequest(m_local_io_ctx,
455 m_remote_io_ctx,
456 mock_instance_watcher,
457 &m_local_test_image_ctx,
458 local_image_id,
459 remote_image_id,
460 global_image_id,
461 m_threads->work_queue,
462 m_threads->timer,
463 &m_threads->timer_lock,
464 local_mirror_uuid,
465 remote_mirror_uuid,
466 &mock_journaler,
467 client_state, mirror_peer_client_meta,
468 on_finish, &m_do_resync);
469 }
470
471 librbd::ImageCtx *m_remote_image_ctx;
472 librbd::ImageCtx *m_local_image_ctx = nullptr;
473 librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
474 bool m_do_resync;
475 };
476
477 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
478 create_local_image();
479
480 InSequence seq;
481
482 // lookup remote image tag class
483 cls::journal::Client client;
484 librbd::journal::ClientData client_data{
485 librbd::journal::ImageClientMeta{123}};
486 ::encode(client_data, client.data);
487 ::journal::MockJournaler mock_journaler;
488 expect_journaler_get_client(mock_journaler,
489 librbd::Journal<>::IMAGE_CLIENT_ID,
490 client, 0);
491
492 // open the remote image
493 librbd::MockJournal mock_journal;
494 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
495 MockOpenImageRequest mock_open_image_request;
496 expect_open_image(mock_open_image_request, m_remote_io_ctx,
497 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
498
499 // test if remote image is primary
500 MockIsPrimaryRequest mock_is_primary_request;
501 expect_is_primary(mock_is_primary_request, false, 0);
502
503 // switch the state to replaying
504 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
505 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
506 mock_local_image_ctx.id};
507 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
508 client_data.client_meta = mirror_peer_client_meta;
509 expect_journaler_update_client(mock_journaler, client_data, 0);
510
511 MockCloseImageRequest mock_close_image_request;
512 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
513
514 C_SaferCond ctx;
515 MockInstanceWatcher mock_instance_watcher;
516 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
517 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
518 MockBootstrapRequest *request = create_request(
519 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
520 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
521 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
522 request->send();
523 ASSERT_EQ(-EREMOTEIO, ctx.wait());
524 }
525
526 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteNotTagOwner) {
527 create_local_image();
528
529 InSequence seq;
530
531 // lookup remote image tag class
532 cls::journal::Client client;
533 librbd::journal::ClientData client_data{
534 librbd::journal::ImageClientMeta{123}};
535 encode(client_data, client.data);
536 ::journal::MockJournaler mock_journaler;
537 expect_journaler_get_client(mock_journaler,
538 librbd::Journal<>::IMAGE_CLIENT_ID,
539 client, 0);
540
541 // open the remote image
542 librbd::MockJournal mock_journal;
543 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
544 MockOpenImageRequest mock_open_image_request;
545 expect_open_image(mock_open_image_request, m_remote_io_ctx,
546 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
547
548 // test if remote image is primary
549 MockIsPrimaryRequest mock_is_primary_request;
550 expect_is_primary(mock_is_primary_request, false, 0);
551
552 // open the local image
553 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
554 mock_local_image_ctx.journal = &mock_journal;
555 MockOpenLocalImageRequest mock_open_local_image_request;
556 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
557 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
558 expect_is_resync_requested(mock_journal, false, 0);
559
560 expect_journal_get_tag_tid(mock_journal, 345);
561 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
562 librbd::Journal<>::ORPHAN_MIRROR_UUID,
563 true, 344, 0});
564
565 MockCloseImageRequest mock_close_image_request;
566 expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
567 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
568
569 C_SaferCond ctx;
570 MockInstanceWatcher mock_instance_watcher;
571 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
572 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
573 mock_local_image_ctx.id};
574 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
575 MockBootstrapRequest *request = create_request(
576 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
577 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
578 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
579 request->send();
580 ASSERT_EQ(-EREMOTEIO, ctx.wait());
581 }
582
583 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
584 create_local_image();
585
586 InSequence seq;
587
588 // lookup remote image tag class
589 cls::journal::Client client;
590 librbd::journal::ClientData client_data{
591 librbd::journal::ImageClientMeta{123}};
592 ::encode(client_data, client.data);
593 ::journal::MockJournaler mock_journaler;
594 expect_journaler_get_client(mock_journaler,
595 librbd::Journal<>::IMAGE_CLIENT_ID,
596 client, 0);
597
598 // open the remote image
599 librbd::MockJournal mock_journal;
600 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
601 MockOpenImageRequest mock_open_image_request;
602 expect_open_image(mock_open_image_request, m_remote_io_ctx,
603 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
604
605 // test if remote image is primary
606 MockIsPrimaryRequest mock_is_primary_request;
607 expect_is_primary(mock_is_primary_request, false, 0);
608
609 // open the local image
610 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
611 mock_local_image_ctx.journal = &mock_journal;
612 MockOpenLocalImageRequest mock_open_local_image_request;
613 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
614 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
615 expect_is_resync_requested(mock_journal, false, 0);
616
617 expect_journal_get_tag_tid(mock_journal, 345);
618 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
619
620 // remote demotion / promotion event
621 Tags tags = {
622 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
623 librbd::Journal<>::LOCAL_MIRROR_UUID,
624 true, 1, 99})},
625 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
626 librbd::Journal<>::LOCAL_MIRROR_UUID,
627 true, 2, 1})},
628 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
629 librbd::Journal<>::ORPHAN_MIRROR_UUID,
630 true, 2, 1})},
631 {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
632 librbd::Journal<>::ORPHAN_MIRROR_UUID,
633 true, 4, 369})}
634 };
635 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
636
637 MockCloseImageRequest mock_close_image_request;
638 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
639
640 C_SaferCond ctx;
641 MockInstanceWatcher mock_instance_watcher;
642 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
643 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
644 mock_local_image_ctx.id};
645 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
646 MockBootstrapRequest *request = create_request(
647 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
648 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
649 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
650 request->send();
651 ASSERT_EQ(0, ctx.wait());
652 }
653
654 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
655 create_local_image();
656
657 InSequence seq;
658
659 // lookup remote image tag class
660 cls::journal::Client client;
661 librbd::journal::ClientData client_data{
662 librbd::journal::ImageClientMeta{123}};
663 ::encode(client_data, client.data);
664 ::journal::MockJournaler mock_journaler;
665 expect_journaler_get_client(mock_journaler,
666 librbd::Journal<>::IMAGE_CLIENT_ID,
667 client, 0);
668
669 // open the remote image
670 librbd::MockJournal mock_journal;
671 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
672 MockOpenImageRequest mock_open_image_request;
673 expect_open_image(mock_open_image_request, m_remote_io_ctx,
674 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
675
676 // test if remote image is primary
677 MockIsPrimaryRequest mock_is_primary_request;
678 expect_is_primary(mock_is_primary_request, true, 0);
679
680 // open the local image
681 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
682 mock_local_image_ctx.journal = &mock_journal;
683 MockOpenLocalImageRequest mock_open_local_image_request;
684 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
685 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
686 expect_is_resync_requested(mock_journal, false, 0);
687
688 expect_journal_get_tag_tid(mock_journal, 345);
689 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
690 "remote mirror uuid", true, 4, 1});
691
692 // remote demotion / promotion event
693 Tags tags = {
694 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
695 librbd::Journal<>::LOCAL_MIRROR_UUID,
696 true, 1, 99})},
697 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
698 librbd::Journal<>::LOCAL_MIRROR_UUID,
699 true, 2, 1})},
700 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
701 librbd::Journal<>::ORPHAN_MIRROR_UUID,
702 true, 3, 1})},
703 {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
704 librbd::Journal<>::LOCAL_MIRROR_UUID,
705 true, 4, 1})},
706 {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
707 librbd::Journal<>::ORPHAN_MIRROR_UUID,
708 true, 5, 1})},
709 {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
710 librbd::Journal<>::LOCAL_MIRROR_UUID,
711 true, 6, 1})},
712 {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
713 librbd::Journal<>::ORPHAN_MIRROR_UUID,
714 true, 7, 1})}
715 };
716 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
717
718 MockCloseImageRequest mock_close_image_request;
719 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
720
721 C_SaferCond ctx;
722 MockInstanceWatcher mock_instance_watcher;
723 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
724 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
725 mock_local_image_ctx.id};
726 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
727 MockBootstrapRequest *request = create_request(
728 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
729 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
730 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
731 request->send();
732 ASSERT_EQ(0, ctx.wait());
733 }
734
735 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
736 create_local_image();
737
738 InSequence seq;
739
740 // lookup remote image tag class
741 cls::journal::Client client;
742 librbd::journal::ClientData client_data{
743 librbd::journal::ImageClientMeta{123}};
744 ::encode(client_data, client.data);
745 ::journal::MockJournaler mock_journaler;
746 expect_journaler_get_client(mock_journaler,
747 librbd::Journal<>::IMAGE_CLIENT_ID,
748 client, 0);
749
750 // open the remote image
751 librbd::MockJournal mock_journal;
752 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
753 MockOpenImageRequest mock_open_image_request;
754 expect_open_image(mock_open_image_request, m_remote_io_ctx,
755 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
756
757 // test if remote image is primary
758 MockIsPrimaryRequest mock_is_primary_request;
759 expect_is_primary(mock_is_primary_request, true, 0);
760
761 // open the local image
762 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
763 mock_local_image_ctx.journal = &mock_journal;
764 MockOpenLocalImageRequest mock_open_local_image_request;
765 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
766 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
767 expect_is_resync_requested(mock_journal, false, 0);
768
769 expect_journal_get_tag_tid(mock_journal, 346);
770 expect_journal_get_tag_data(mock_journal,
771 {librbd::Journal<>::ORPHAN_MIRROR_UUID,
772 librbd::Journal<>::LOCAL_MIRROR_UUID,
773 true, 345, 1});
774
775 // remote demotion / promotion event
776 Tags tags = {
777 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
778 true, 344, 99})},
779 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
780 "local mirror uuid", true, 345, 1})},
781 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
782 librbd::Journal<>::ORPHAN_MIRROR_UUID,
783 true, 3, 1})}
784 };
785 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
786
787 MockCloseImageRequest mock_close_image_request;
788 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
789
790 C_SaferCond ctx;
791 MockInstanceWatcher mock_instance_watcher;
792 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
793 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
794 mock_local_image_ctx.id};
795 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
796 MockBootstrapRequest *request = create_request(
797 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
798 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
799 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
800 request->send();
801 ASSERT_EQ(0, ctx.wait());
802 }
803
804 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
805 create_local_image();
806
807 InSequence seq;
808
809 // lookup remote image tag class
810 cls::journal::Client client;
811 librbd::journal::ClientData client_data{
812 librbd::journal::ImageClientMeta{123}};
813 ::encode(client_data, client.data);
814 ::journal::MockJournaler mock_journaler;
815 expect_journaler_get_client(mock_journaler,
816 librbd::Journal<>::IMAGE_CLIENT_ID,
817 client, 0);
818
819 // open the remote image
820 librbd::MockJournal mock_journal;
821 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
822 MockOpenImageRequest mock_open_image_request;
823 expect_open_image(mock_open_image_request, m_remote_io_ctx,
824 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
825
826 // test if remote image is primary
827 MockIsPrimaryRequest mock_is_primary_request;
828 expect_is_primary(mock_is_primary_request, true, 0);
829
830 // open the local image
831 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
832 mock_local_image_ctx.journal = &mock_journal;
833 MockOpenLocalImageRequest mock_open_local_image_request;
834 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
835 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
836 expect_is_resync_requested(mock_journal, false, 0);
837
838 expect_journal_get_tag_tid(mock_journal, 345);
839 expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
840 librbd::Journal<>::ORPHAN_MIRROR_UUID,
841 true, 344, 0});
842
843 // remote demotion / promotion event
844 Tags tags = {
845 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
846 librbd::Journal<>::LOCAL_MIRROR_UUID,
847 true, 1, 99})},
848 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
849 librbd::Journal<>::LOCAL_MIRROR_UUID,
850 true, 2, 1})}
851 };
852 expect_journaler_get_tags(mock_journaler, 123, tags, 0);
853
854 MockCloseImageRequest mock_close_image_request;
855 expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
856 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
857
858 C_SaferCond ctx;
859 MockInstanceWatcher mock_instance_watcher;
860 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
861 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
862 mock_local_image_ctx.id};
863 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
864 MockBootstrapRequest *request = create_request(
865 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
866 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
867 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
868 request->send();
869 ASSERT_EQ(-EEXIST, ctx.wait());
870 ASSERT_EQ(NULL, m_local_test_image_ctx);
871 }
872
873 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
874 create_local_image();
875
876 InSequence seq;
877
878 // lookup remote image tag class
879 cls::journal::Client client;
880 librbd::journal::ClientData client_data{
881 librbd::journal::ImageClientMeta{123}};
882 ::encode(client_data, client.data);
883 ::journal::MockJournaler mock_journaler;
884 expect_journaler_get_client(mock_journaler,
885 librbd::Journal<>::IMAGE_CLIENT_ID,
886 client, 0);
887
888 // open the remote image
889 librbd::MockJournal mock_journal;
890 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
891 MockOpenImageRequest mock_open_image_request;
892 expect_open_image(mock_open_image_request, m_remote_io_ctx,
893 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
894
895 // test if remote image is primary
896 MockIsPrimaryRequest mock_is_primary_request;
897 expect_is_primary(mock_is_primary_request, true, 0);
898
899 // open the local image
900 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
901 mock_local_image_ctx.journal = &mock_journal;
902 MockOpenLocalImageRequest mock_open_local_image_request;
903 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
904 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
905
906 // resync is requested
907 expect_is_resync_requested(mock_journal, true, 0);
908
909 expect_journal_get_tag_tid(mock_journal, 345);
910 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
911
912 MockCloseImageRequest mock_close_image_request;
913 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
914
915 C_SaferCond ctx;
916 MockInstanceWatcher mock_instance_watcher;
917 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
918 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
919 mock_local_image_ctx.id};
920 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
921 MockBootstrapRequest *request = create_request(
922 &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
923 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
924 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
925 m_do_resync = false;
926 request->send();
927 ASSERT_EQ(0, ctx.wait());
928 ASSERT_TRUE(m_do_resync);
929 }
930
931 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
932 create_local_image();
933
934 InSequence seq;
935
936 // lookup remote image tag class
937 cls::journal::Client client;
938 librbd::journal::ClientData client_data{
939 librbd::journal::ImageClientMeta{123}};
940 ::encode(client_data, client.data);
941 ::journal::MockJournaler mock_journaler;
942 expect_journaler_get_client(mock_journaler,
943 librbd::Journal<>::IMAGE_CLIENT_ID,
944 client, 0);
945
946 // open the remote image
947 librbd::MockJournal mock_journal;
948 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
949 MockOpenImageRequest mock_open_image_request;
950 expect_open_image(mock_open_image_request, m_remote_io_ctx,
951 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
952
953 // test if remote image is primary
954 MockIsPrimaryRequest mock_is_primary_request;
955 expect_is_primary(mock_is_primary_request, true, 0);
956
957 // update client state back to syncing
958 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
959 mock_local_image_ctx.journal = &mock_journal;
960
961 librbd::util::s_image_id = mock_local_image_ctx.id;
962 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
963 mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
964 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
965 client_data.client_meta = mirror_peer_client_meta;
966 client.data.clear();
967 ::encode(client_data, client.data);
968 expect_journaler_update_client(mock_journaler, client_data, 0);
969
970 // create the local image
971 MockCreateImageRequest mock_create_image_request;
972 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
973
974 // open the local image
975 MockOpenLocalImageRequest mock_open_local_image_request;
976 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
977 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
978 expect_is_resync_requested(mock_journal, false, 0);
979
980 expect_journal_get_tag_tid(mock_journal, 345);
981 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
982
983 // sync the remote image to the local image
984 MockImageSync mock_image_sync;
985 expect_image_sync(mock_image_sync, 0);
986
987 MockCloseImageRequest mock_close_image_request;
988 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
989
990 C_SaferCond ctx;
991 MockInstanceWatcher mock_instance_watcher;
992 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
993 mirror_peer_client_meta.image_id = "";
994 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
995 MockBootstrapRequest *request = create_request(
996 &mock_instance_watcher, mock_journaler, "",
997 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
998 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
999 request->send();
1000 ASSERT_EQ(0, ctx.wait());
1001 }
1002
1003 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
1004 create_local_image();
1005
1006 InSequence seq;
1007
1008 // lookup remote image tag class
1009 cls::journal::Client client;
1010 librbd::journal::ClientData client_data{
1011 librbd::journal::ImageClientMeta{123}};
1012 ::encode(client_data, client.data);
1013 ::journal::MockJournaler mock_journaler;
1014 expect_journaler_get_client(mock_journaler,
1015 librbd::Journal<>::IMAGE_CLIENT_ID,
1016 client, 0);
1017
1018 // open the remote image
1019 librbd::MockJournal mock_journal;
1020 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
1021 MockOpenImageRequest mock_open_image_request;
1022 expect_open_image(mock_open_image_request, m_remote_io_ctx,
1023 mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
1024
1025 // test if remote image is primary
1026 MockIsPrimaryRequest mock_is_primary_request;
1027 expect_is_primary(mock_is_primary_request, true, 0);
1028
1029 // open the missing local image
1030 MockOpenLocalImageRequest mock_open_local_image_request;
1031 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1032 "missing image id", nullptr, -ENOENT);
1033
1034 // re-register the client
1035 expect_journaler_unregister_client(mock_journaler, 0);
1036 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
1037 mirror_peer_client_meta.image_id = "";
1038 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1039 client_data.client_meta = mirror_peer_client_meta;
1040 expect_journaler_register_client(mock_journaler, client_data, 0);
1041
1042 // test if remote image is primary
1043 expect_is_primary(mock_is_primary_request, true, 0);
1044
1045 // update client state back to syncing
1046 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
1047 mock_local_image_ctx.journal = &mock_journal;
1048
1049 librbd::util::s_image_id = mock_local_image_ctx.id;
1050 mirror_peer_client_meta.image_id = mock_local_image_ctx.id;
1051 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
1052 client_data.client_meta = mirror_peer_client_meta;
1053 client.data.clear();
1054 ::encode(client_data, client.data);
1055 expect_journaler_update_client(mock_journaler, client_data, 0);
1056
1057 // create the missing local image
1058 MockCreateImageRequest mock_create_image_request;
1059 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
1060
1061 // open the local image
1062 expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1063 mock_local_image_ctx.id, &mock_local_image_ctx, 0);
1064 expect_is_resync_requested(mock_journal, false, 0);
1065
1066 expect_journal_get_tag_tid(mock_journal, 345);
1067 expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
1068
1069 // sync the remote image to the local image
1070 MockImageSync mock_image_sync;
1071 expect_image_sync(mock_image_sync, 0);
1072
1073 MockCloseImageRequest mock_close_image_request;
1074 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1075
1076 C_SaferCond ctx;
1077 MockInstanceWatcher mock_instance_watcher;
1078 cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED;
1079 mirror_peer_client_meta.image_id = "missing image id";
1080 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1081 MockBootstrapRequest *request = create_request(
1082 &mock_instance_watcher, mock_journaler, "missing image id",
1083 mock_remote_image_ctx.id, "global image id", "local mirror uuid",
1084 "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx);
1085 request->send();
1086 ASSERT_EQ(0, ctx.wait());
1087 }
1088
1089 } // namespace image_replayer
1090 } // namespace mirror
1091 } // namespace rbd