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 "test/librados_test_stub/MockTestMemIoCtxImpl.h"
6 #include "test/librados_test_stub/MockTestMemRadosClient.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/rbd_mirror/mock/MockContextWQ.h"
9 #include "test/rbd_mirror/mock/MockSafeTimer.h"
10 #include "librbd/MirroringWatcher.h"
11 #include "tools/rbd_mirror/Threads.h"
12 #include "tools/rbd_mirror/ImageMap.h"
13 #include "tools/rbd_mirror/image_map/LoadRequest.h"
14 #include "tools/rbd_mirror/image_map/UpdateRequest.h"
15 #include "tools/rbd_mirror/image_map/Types.h"
16 #include "include/stringify.h"
21 struct MockTestImageCtx
: public librbd::MockImageCtx
{
22 MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
23 : librbd::MockImageCtx(image_ctx
) {
27 } // anonymous namespace
35 struct Threads
<librbd::MockTestImageCtx
> {
37 ceph::mutex
&timer_lock
;
39 MockContextWQ
*work_queue
;
41 Threads(Threads
<librbd::ImageCtx
> *threads
)
42 : timer(new MockSafeTimer()),
43 timer_lock(threads
->timer_lock
),
44 work_queue(new MockContextWQ()) {
55 struct LoadRequest
<librbd::MockTestImageCtx
> {
56 std::map
<std::string
, cls::rbd::MirrorImageMap
> *image_map
;
57 Context
*on_finish
= nullptr;
59 static LoadRequest
*s_instance
;
60 static LoadRequest
*create(librados::IoCtx
&ioctx
,
61 std::map
<std::string
, cls::rbd::MirrorImageMap
> *image_map
,
63 ceph_assert(s_instance
!= nullptr);
64 s_instance
->image_map
= image_map
;
65 s_instance
->on_finish
= on_finish
;
69 MOCK_METHOD0(send
, void());
77 struct UpdateRequest
<librbd::MockTestImageCtx
> {
78 Context
*on_finish
= nullptr;
79 static UpdateRequest
*s_instance
;
80 static UpdateRequest
*create(librados::IoCtx
&ioctx
,
81 std::map
<std::string
, cls::rbd::MirrorImageMap
> &&update_mapping
,
82 std::set
<std::string
> &&global_image_ids
,
84 ceph_assert(s_instance
!= nullptr);
85 s_instance
->on_finish
= on_finish
;
89 MOCK_METHOD0(send
, void());
96 LoadRequest
<librbd::MockTestImageCtx
> *
97 LoadRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
98 UpdateRequest
<librbd::MockTestImageCtx
> *
99 UpdateRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
101 } // namespace image_map
103 } // namespace mirror
106 // template definitions
107 #include "tools/rbd_mirror/ImageMap.cc"
113 using ::testing::DoAll
;
114 using ::testing::WithArg
;
115 using ::testing::AtLeast
;
116 using ::testing::InSequence
;
117 using ::testing::Invoke
;
118 using ::testing::ReturnArg
;
119 using ::testing::StrEq
;
121 using image_map::Listener
;
122 using image_map::LoadRequest
;
123 using image_map::UpdateRequest
;
125 using ::rbd::mirror::Threads
;
127 class TestMockImageMap
: public TestMockFixture
{
129 typedef Threads
<librbd::MockTestImageCtx
> MockThreads
;
130 typedef ImageMap
<librbd::MockTestImageCtx
> MockImageMap
;
131 typedef LoadRequest
<librbd::MockTestImageCtx
> MockLoadRequest
;
132 typedef UpdateRequest
<librbd::MockTestImageCtx
> MockUpdateRequest
;
134 struct MockListener
: Listener
{
135 TestMockImageMap
*test_mock_image_map
;
137 MockListener(TestMockImageMap
*test_mock_image_map
)
138 : test_mock_image_map(test_mock_image_map
) {
141 MOCK_METHOD2(mock_acquire_image
, void(const std::string
&, Context
*));
142 MOCK_METHOD2(mock_release_image
, void(const std::string
&, Context
*));
143 MOCK_METHOD3(mock_remove_image
, void(const std::string
&,
144 const std::string
&, Context
*));
146 void acquire_image(const std::string
&global_image_id
,
147 const std::string
&instance_id
, Context
* on_finish
) {
148 mock_acquire_image(global_image_id
, on_finish
);
151 void release_image(const std::string
&global_image_id
,
152 const std::string
&instance_id
, Context
* on_finish
) {
153 mock_release_image(global_image_id
, on_finish
);
156 void remove_image(const std::string
&mirror_uuid
,
157 const std::string
&global_image_id
,
158 const std::string
&instance_id
, Context
* on_finish
) {
159 mock_remove_image(mirror_uuid
, global_image_id
, on_finish
);
163 TestMockImageMap() = default;
165 void SetUp() override
{
166 TestFixture::SetUp();
168 m_local_instance_id
= stringify(m_local_io_ctx
.get_instance_id());
170 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_migration_throttle",
172 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_type", "simple"));
175 void TearDown() override
{
176 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_type", "none"));
178 TestFixture::TearDown();
181 void expect_work_queue(MockThreads
&mock_threads
) {
182 EXPECT_CALL(*mock_threads
.work_queue
, queue(_
, _
))
183 .WillRepeatedly(Invoke([this](Context
*ctx
, int r
) {
184 m_threads
->work_queue
->queue(ctx
, r
);
188 void expect_add_event(MockThreads
&mock_threads
) {
189 EXPECT_CALL(*mock_threads
.timer
, add_event_after(_
,_
))
190 .WillOnce(DoAll(WithArg
<1>(Invoke([this](Context
*ctx
) {
191 auto wrapped_ctx
= new LambdaContext([this, ctx
](int r
) {
192 std::lock_guard timer_locker
{m_threads
->timer_lock
};
195 m_threads
->work_queue
->queue(wrapped_ctx
, 0);
196 })), ReturnArg
<1>()));
199 void expect_rebalance_event(MockThreads
&mock_threads
) {
200 EXPECT_CALL(*mock_threads
.timer
, add_event_after(_
,_
))
201 .WillOnce(DoAll(WithArg
<1>(Invoke([this](Context
*ctx
) {
202 // disable rebalance so as to not reschedule it again
203 CephContext
*cct
= reinterpret_cast<CephContext
*>(m_local_io_ctx
.cct());
204 cct
->_conf
.set_val("rbd_mirror_image_policy_rebalance_timeout", "0");
206 auto wrapped_ctx
= new LambdaContext([this, ctx
](int r
) {
207 std::lock_guard timer_locker
{m_threads
->timer_lock
};
210 m_threads
->work_queue
->queue(wrapped_ctx
, 0);
211 })), ReturnArg
<1>()));
214 void expect_load_request(MockLoadRequest
&request
, int r
) {
215 EXPECT_CALL(request
, send())
216 .WillOnce(Invoke([&request
, r
]() {
217 request
.on_finish
->complete(r
);
221 void expect_update_request(MockUpdateRequest
&request
, int r
) {
222 EXPECT_CALL(request
, send())
223 .WillOnce(Invoke([this, &request
, r
]() {
224 request
.on_finish
->complete(r
);
226 std::lock_guard locker
{m_lock
};
227 ++m_map_update_count
;
233 void expect_listener_acquire_image(MockListener
&mock_listener
,
234 const std::string
&global_image_id
,
235 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
236 EXPECT_CALL(mock_listener
, mock_acquire_image(global_image_id
, _
))
237 .WillOnce(WithArg
<1>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
238 std::lock_guard locker
{m_lock
};
239 peer_ack_ctxs
->insert({global_image_id
, ctx
});
240 ++m_notify_update_count
;
245 void expect_listener_release_image(MockListener
&mock_listener
,
246 const std::string
&global_image_id
,
247 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
248 EXPECT_CALL(mock_listener
, mock_release_image(global_image_id
, _
))
249 .WillOnce(WithArg
<1>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
250 std::lock_guard locker
{m_lock
};
251 peer_ack_ctxs
->insert({global_image_id
, ctx
});
252 ++m_notify_update_count
;
257 void expect_listener_remove_image(MockListener
&mock_listener
,
258 const std::string
&mirror_uuid
,
259 const std::string
&global_image_id
,
260 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
261 EXPECT_CALL(mock_listener
,
262 mock_remove_image(mirror_uuid
, global_image_id
, _
))
263 .WillOnce(WithArg
<2>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
264 std::lock_guard locker
{m_lock
};
265 peer_ack_ctxs
->insert({global_image_id
, ctx
});
266 ++m_notify_update_count
;
271 void expect_listener_images_unmapped(MockListener
&mock_listener
, size_t count
,
272 std::set
<std::string
> *global_image_ids
,
273 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
274 EXPECT_CALL(mock_listener
, mock_release_image(_
, _
))
276 .WillRepeatedly(Invoke([this, global_image_ids
, peer_ack_ctxs
](std::string global_image_id
, Context
* ctx
) {
277 std::lock_guard locker
{m_lock
};
278 global_image_ids
->emplace(global_image_id
);
279 peer_ack_ctxs
->insert({global_image_id
, ctx
});
280 ++m_notify_update_count
;
285 void remote_peer_ack_nowait(MockImageMap
*image_map
,
286 const std::set
<std::string
> &global_image_ids
,
288 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
289 for (auto& global_image_id
: global_image_ids
) {
290 auto it
= peer_ack_ctxs
->find(global_image_id
);
291 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
292 auto ack_ctx
= it
->second
;
293 peer_ack_ctxs
->erase(it
);
294 ack_ctx
->complete(ret
);
295 wait_for_scheduled_task();
299 void remote_peer_ack_wait(MockImageMap
*image_map
,
300 const std::set
<std::string
> &global_image_ids
,
302 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
303 for (auto& global_image_id
: global_image_ids
) {
304 auto it
= peer_ack_ctxs
->find(global_image_id
);
305 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
306 auto ack_ctx
= it
->second
;
307 peer_ack_ctxs
->erase(it
);
308 ack_ctx
->complete(ret
);
309 wait_for_scheduled_task();
310 ASSERT_TRUE(wait_for_map_update(1));
314 void remote_peer_ack_listener_wait(MockImageMap
*image_map
,
315 const std::set
<std::string
> &global_image_ids
,
317 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
318 for (auto& global_image_id
: global_image_ids
) {
319 auto it
= peer_ack_ctxs
->find(global_image_id
);
320 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
321 auto ack_ctx
= it
->second
;
322 peer_ack_ctxs
->erase(it
);
323 ack_ctx
->complete(ret
);
324 ASSERT_TRUE(wait_for_map_update(1));
325 ASSERT_TRUE(wait_for_listener_notify(1));
329 void update_map_and_acquire(MockThreads
&mock_threads
,
330 MockUpdateRequest
&mock_update_request
,
331 MockListener
&mock_listener
,
332 const std::set
<std::string
> &global_image_ids
,
334 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
335 for (auto const &global_image_id
: global_image_ids
) {
336 expect_add_event(mock_threads
);
337 expect_update_request(mock_update_request
, ret
);
338 expect_add_event(mock_threads
);
339 expect_listener_acquire_image(mock_listener
, global_image_id
,
344 void update_map_request(MockThreads
&mock_threads
,
345 MockUpdateRequest
&mock_update_request
,
346 const std::set
<std::string
> &global_image_ids
, int ret
) {
347 for (uint32_t i
= 0; i
< global_image_ids
.size(); ++i
) {
348 expect_add_event(mock_threads
);
349 expect_update_request(mock_update_request
, ret
);
353 void wait_for_scheduled_task() {
354 m_threads
->work_queue
->drain();
357 bool wait_for_listener_notify(uint32_t count
) {
358 std::unique_lock locker
{m_lock
};
359 while (m_notify_update_count
< count
) {
360 if (m_cond
.wait_for(locker
, 10s
) == std::cv_status::timeout
) {
365 if (m_notify_update_count
< count
) {
369 m_notify_update_count
-= count
;
373 bool wait_for_map_update(uint32_t count
) {
374 std::unique_lock locker
{m_lock
};
375 while (m_map_update_count
< count
) {
376 if (m_cond
.wait_for(locker
, 10s
) == std::cv_status::timeout
) {
381 if (m_map_update_count
< count
) {
385 m_map_update_count
-= count
;
389 int when_shut_down(MockImageMap
*image_map
) {
391 image_map
->shut_down(&ctx
);
395 void listener_acquire_images(MockListener
&mock_listener
,
396 const std::set
<std::string
> &global_image_ids
,
397 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
398 for (auto const &global_image_id
: global_image_ids
) {
399 expect_listener_acquire_image(mock_listener
, global_image_id
,
404 void listener_release_images(MockListener
&mock_listener
,
405 const std::set
<std::string
> &global_image_ids
,
406 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
407 for (auto const &global_image_id
: global_image_ids
) {
408 expect_listener_release_image(mock_listener
, global_image_id
,
413 void listener_remove_images(MockListener
&mock_listener
,
414 const std::string
&mirror_uuid
,
415 std::set
<std::string
> &global_image_ids
,
416 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
417 for (auto const &global_image_id
: global_image_ids
) {
418 expect_listener_remove_image(mock_listener
, mirror_uuid
, global_image_id
,
423 ceph::mutex m_lock
= ceph::make_mutex("TestMockImageMap::m_lock");
424 ceph::condition_variable m_cond
;
425 uint32_t m_notify_update_count
= 0;
426 uint32_t m_map_update_count
= 0;
427 std::string m_local_instance_id
;
430 TEST_F(TestMockImageMap
, SetLocalImages
) {
431 MockThreads
mock_threads(m_threads
);
432 expect_work_queue(mock_threads
);
436 MockLoadRequest mock_load_request
;
437 expect_load_request(mock_load_request
, 0);
439 MockListener
mock_listener(this);
441 std::unique_ptr
<MockImageMap
> mock_image_map
{
442 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
446 mock_image_map
->init(&cond
);
447 ASSERT_EQ(0, cond
.wait());
449 std::set
<std::string
> global_image_ids
{
450 "global id 1", "global id 2"
452 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
454 // UPDATE_MAPPING+ACQUIRE
455 expect_add_event(mock_threads
);
456 MockUpdateRequest mock_update_request
;
457 expect_update_request(mock_update_request
, 0);
458 expect_add_event(mock_threads
);
459 std::map
<std::string
, Context
*> peer_ack_ctxs
;
460 listener_acquire_images(mock_listener
, global_image_ids
, &peer_ack_ctxs
);
462 // initial image list
463 mock_image_map
->update_images("", std::move(global_image_ids
), {});
465 ASSERT_TRUE(wait_for_map_update(1));
466 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
468 // remote peer ACKs image acquire request
469 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
472 wait_for_scheduled_task();
473 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
476 TEST_F(TestMockImageMap
, AddRemoveLocalImage
) {
477 MockThreads
mock_threads(m_threads
);
478 expect_work_queue(mock_threads
);
482 MockLoadRequest mock_load_request
;
483 expect_load_request(mock_load_request
, 0);
485 MockListener
mock_listener(this);
487 std::unique_ptr
<MockImageMap
> mock_image_map
{
488 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
492 mock_image_map
->init(&cond
);
493 ASSERT_EQ(0, cond
.wait());
495 std::set
<std::string
> initial_global_image_ids
{
496 "global id 1", "global id 2"
498 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
500 std::set
<std::string
> remove_global_image_ids
{
501 "global id 1", "global id 2"
503 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
505 // UPDATE_MAPPING+ACQUIRE
506 expect_add_event(mock_threads
);
507 MockUpdateRequest mock_update_request
;
508 expect_update_request(mock_update_request
, 0);
509 expect_add_event(mock_threads
);
510 std::map
<std::string
, Context
*> peer_ack_ctxs
;
511 listener_acquire_images(mock_listener
, initial_global_image_ids
,
514 // initial image list
515 mock_image_map
->update_images("", std::move(initial_global_image_ids
), {});
517 ASSERT_TRUE(wait_for_map_update(1));
518 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
520 // remote peer ACKs image acquire request
521 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
524 // RELEASE+REMOVE_MAPPING
525 expect_add_event(mock_threads
);
526 listener_release_images(mock_listener
, remove_global_image_ids
,
528 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
,
532 mock_image_map
->update_images("", {}, std::move(remove_global_image_ids
));
533 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size()));
535 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
538 wait_for_scheduled_task();
539 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
542 TEST_F(TestMockImageMap
, AddRemoveRemoteImage
) {
543 MockThreads
mock_threads(m_threads
);
544 expect_work_queue(mock_threads
);
548 MockLoadRequest mock_load_request
;
549 expect_load_request(mock_load_request
, 0);
551 MockListener
mock_listener(this);
553 std::unique_ptr
<MockImageMap
> mock_image_map
{
554 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
558 mock_image_map
->init(&cond
);
559 ASSERT_EQ(0, cond
.wait());
561 std::set
<std::string
> initial_global_image_ids
{
562 "global id 1", "global id 2"
564 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
566 std::set
<std::string
> remove_global_image_ids
{
567 "global id 1", "global id 2"
569 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
571 // UPDATE_MAPPING+ACQUIRE
572 expect_add_event(mock_threads
);
573 MockUpdateRequest mock_update_request
;
574 expect_update_request(mock_update_request
, 0);
575 expect_add_event(mock_threads
);
576 std::map
<std::string
, Context
*> peer_ack_ctxs
;
577 listener_acquire_images(mock_listener
, initial_global_image_ids
,
580 // initial image list
581 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
),
584 ASSERT_TRUE(wait_for_map_update(1));
585 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
587 // remote peer ACKs image acquire request
588 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
591 // RELEASE+REMOVE_MAPPING
592 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
593 listener_remove_images(mock_listener
, "uuid1", remove_global_image_ids
,
594 &peer_remove_ack_ctxs
);
595 expect_add_event(mock_threads
);
596 listener_release_images(mock_listener
, remove_global_image_ids
,
598 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
,
602 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids
));
603 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size() * 2));
605 remote_peer_ack_nowait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
606 &peer_remove_ack_ctxs
);
607 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
610 wait_for_scheduled_task();
611 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
614 TEST_F(TestMockImageMap
, AddRemoveRemoteImageDuplicateNotification
) {
615 MockThreads
mock_threads(m_threads
);
616 expect_work_queue(mock_threads
);
620 MockLoadRequest mock_load_request
;
621 expect_load_request(mock_load_request
, 0);
623 MockListener
mock_listener(this);
625 std::unique_ptr
<MockImageMap
> mock_image_map
{
626 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
630 mock_image_map
->init(&cond
);
631 ASSERT_EQ(0, cond
.wait());
633 std::set
<std::string
> initial_global_image_ids
{
634 "global id 1", "global id 2"
636 std::set
<std::string
> initial_global_image_ids_dup(initial_global_image_ids
);
637 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
639 std::set
<std::string
> remove_global_image_ids
{
640 "global id 1", "global id 2"
642 std::set
<std::string
> remove_global_image_ids_dup(remove_global_image_ids
);
643 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
645 // UPDATE_MAPPING+ACQUIRE
646 expect_add_event(mock_threads
);
647 MockUpdateRequest mock_update_request
;
648 expect_update_request(mock_update_request
, 0);
649 expect_add_event(mock_threads
);
650 std::map
<std::string
, Context
*> peer_ack_ctxs
;
651 listener_acquire_images(mock_listener
, initial_global_image_ids
,
654 // initial image list
655 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
), {});
657 ASSERT_TRUE(wait_for_map_update(1));
658 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
660 // trigger duplicate "add" event
661 wait_for_scheduled_task();
662 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids_dup
), {});
664 // remote peer ACKs image acquire request
665 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
668 // RELEASE+REMOVE_MAPPING
669 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
670 listener_remove_images(mock_listener
, "uuid1", remove_global_image_ids
,
671 &peer_remove_ack_ctxs
);
672 expect_add_event(mock_threads
);
673 listener_release_images(mock_listener
, remove_global_image_ids
,
675 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
, 0);
678 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids
));
679 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size() * 2));
681 remote_peer_ack_nowait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
682 &peer_remove_ack_ctxs
);
683 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
686 // trigger duplicate "remove" notification
687 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids_dup
));
689 wait_for_scheduled_task();
690 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
693 TEST_F(TestMockImageMap
, AcquireImageErrorRetry
) {
694 MockThreads
mock_threads(m_threads
);
695 expect_work_queue(mock_threads
);
699 MockLoadRequest mock_load_request
;
700 expect_load_request(mock_load_request
, 0);
702 MockListener
mock_listener(this);
704 std::unique_ptr
<MockImageMap
> mock_image_map
{
705 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
709 mock_image_map
->init(&cond
);
710 ASSERT_EQ(0, cond
.wait());
712 std::set
<std::string
> initial_global_image_ids
{
713 "global id 1", "global id 2"
715 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
717 // UPDATE_MAPPING failure
718 expect_add_event(mock_threads
);
719 MockUpdateRequest mock_update_request
;
720 expect_update_request(mock_update_request
, -EIO
);
722 // UPDATE_MAPPING+ACQUIRE
723 expect_add_event(mock_threads
);
724 expect_update_request(mock_update_request
, 0);
725 expect_add_event(mock_threads
);
726 std::map
<std::string
, Context
*> peer_ack_ctxs
;
727 listener_acquire_images(mock_listener
, initial_global_image_ids
,
730 // initial image list
731 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
), {});
733 ASSERT_TRUE(wait_for_map_update(1));
734 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
736 // remote peer ACKs image acquire request
737 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
740 wait_for_scheduled_task();
741 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
744 TEST_F(TestMockImageMap
, RemoveRemoteAndLocalImage
) {
745 MockThreads
mock_threads(m_threads
);
746 expect_work_queue(mock_threads
);
750 MockLoadRequest mock_load_request
;
751 expect_load_request(mock_load_request
, 0);
753 MockListener
mock_listener(this);
755 std::unique_ptr
<MockImageMap
> mock_image_map
{
756 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
760 mock_image_map
->init(&cond
);
761 ASSERT_EQ(0, cond
.wait());
764 std::set
<std::string
> initial_remote_global_image_ids
{
767 std::set
<std::string
> initial_remote_global_image_ids_ack(initial_remote_global_image_ids
);
770 std::set
<std::string
> initial_local_global_image_ids
{
774 // remote/local images to remove
775 std::set
<std::string
> remote_remove_global_image_ids
{
778 std::set
<std::string
> remote_remove_global_image_ids_ack(remote_remove_global_image_ids
);
780 std::set
<std::string
> local_remove_global_image_ids
{
783 std::set
<std::string
> local_remove_global_image_ids_ack(local_remove_global_image_ids
);
785 // UPDATE_MAPPING+ACQUIRE
786 expect_add_event(mock_threads
);
787 MockUpdateRequest mock_update_request
;
788 expect_update_request(mock_update_request
, 0);
789 expect_add_event(mock_threads
);
790 std::map
<std::string
, Context
*> peer_ack_ctxs
;
791 listener_acquire_images(mock_listener
, initial_remote_global_image_ids
,
794 // initial remote image list
795 mock_image_map
->update_images("uuid1", std::move(initial_remote_global_image_ids
), {});
797 ASSERT_TRUE(wait_for_map_update(1));
798 ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack
.size()));
800 // remote peer ACKs image acquire request
801 remote_peer_ack_nowait(mock_image_map
.get(),
802 initial_remote_global_image_ids_ack
, 0,
805 // set initial local image list -- this is a no-op from policy pov
806 mock_image_map
->update_images("", std::move(initial_local_global_image_ids
), {});
808 // remove remote images -- this should be a no-op from policy pov
809 // except the listener notification
810 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
811 listener_remove_images(mock_listener
, "uuid1", remote_remove_global_image_ids
,
812 &peer_ack_remove_ctxs
);
814 mock_image_map
->update_images("uuid1", {}, std::move(remote_remove_global_image_ids
));
815 ASSERT_TRUE(wait_for_listener_notify(remote_remove_global_image_ids_ack
.size()));
817 // RELEASE+REMOVE_MAPPING
818 expect_add_event(mock_threads
);
819 listener_release_images(mock_listener
, local_remove_global_image_ids
,
821 update_map_request(mock_threads
, mock_update_request
, local_remove_global_image_ids
, 0);
823 // remove local images
824 mock_image_map
->update_images("", {}, std::move(local_remove_global_image_ids
));
825 ASSERT_TRUE(wait_for_listener_notify(local_remove_global_image_ids_ack
.size()));
827 remote_peer_ack_nowait(mock_image_map
.get(), local_remove_global_image_ids_ack
,
828 0, &peer_ack_remove_ctxs
);
829 remote_peer_ack_wait(mock_image_map
.get(), local_remove_global_image_ids_ack
,
832 wait_for_scheduled_task();
833 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
836 TEST_F(TestMockImageMap
, AddInstance
) {
837 MockThreads
mock_threads(m_threads
);
838 expect_work_queue(mock_threads
);
842 MockLoadRequest mock_load_request
;
843 expect_load_request(mock_load_request
, 0);
845 MockListener
mock_listener(this);
847 std::unique_ptr
<MockImageMap
> mock_image_map
{
848 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
852 mock_image_map
->init(&cond
);
853 ASSERT_EQ(0, cond
.wait());
855 std::set
<std::string
> global_image_ids
{
856 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
858 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
860 // UPDATE_MAPPING+ACQUIRE
861 expect_add_event(mock_threads
);
862 MockUpdateRequest mock_update_request
;
863 expect_update_request(mock_update_request
, 0);
864 expect_add_event(mock_threads
);
865 std::map
<std::string
, Context
*> peer_ack_ctxs
;
866 listener_acquire_images(mock_listener
, global_image_ids
,
869 // initial image list
870 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
872 ASSERT_TRUE(wait_for_map_update(1));
873 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
875 // remote peer ACKs image acquire request
876 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
878 wait_for_scheduled_task();
880 mock_image_map
->update_instances_added({m_local_instance_id
});
882 std::set
<std::string
> shuffled_global_image_ids
;
884 // RELEASE+UPDATE_MAPPING+ACQUIRE
885 expect_add_event(mock_threads
);
886 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
889 mock_image_map
->update_instances_added({"9876"});
891 wait_for_scheduled_task();
892 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
894 update_map_and_acquire(mock_threads
, mock_update_request
,
895 mock_listener
, shuffled_global_image_ids
, 0,
897 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
900 // completion shuffle action for now (re)mapped images
901 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
904 wait_for_scheduled_task();
905 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
908 TEST_F(TestMockImageMap
, RemoveInstance
) {
909 MockThreads
mock_threads(m_threads
);
910 expect_work_queue(mock_threads
);
914 MockLoadRequest mock_load_request
;
915 expect_load_request(mock_load_request
, 0);
917 MockListener
mock_listener(this);
919 std::unique_ptr
<MockImageMap
> mock_image_map
{
920 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
924 mock_image_map
->init(&cond
);
925 ASSERT_EQ(0, cond
.wait());
927 std::set
<std::string
> global_image_ids
{
928 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
930 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
932 expect_add_event(mock_threads
);
934 // UPDATE_MAPPING+ACQUIRE
935 MockUpdateRequest mock_update_request
;
936 expect_update_request(mock_update_request
, 0);
937 expect_add_event(mock_threads
);
938 std::map
<std::string
, Context
*> peer_ack_ctxs
;
939 listener_acquire_images(mock_listener
, global_image_ids
,
942 // set initial image list
943 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
945 ASSERT_TRUE(wait_for_map_update(1));
946 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
948 // remote peer ACKs image acquire request -- completing action
949 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
951 wait_for_scheduled_task();
953 mock_image_map
->update_instances_added({m_local_instance_id
});
955 std::set
<std::string
> shuffled_global_image_ids
;
957 // RELEASE+UPDATE_MAPPING+ACQUIRE
958 expect_add_event(mock_threads
);
959 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
962 mock_image_map
->update_instances_added({"9876"});
964 wait_for_scheduled_task();
965 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
967 update_map_and_acquire(mock_threads
, mock_update_request
,
968 mock_listener
, shuffled_global_image_ids
, 0,
970 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
973 // completion shuffle action for now (re)mapped images
974 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
976 wait_for_scheduled_task();
978 shuffled_global_image_ids
.clear();
980 // remove added instance
981 expect_add_event(mock_threads
);
982 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
985 mock_image_map
->update_instances_removed({"9876"});
987 wait_for_scheduled_task();
988 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
990 update_map_and_acquire(mock_threads
, mock_update_request
,
991 mock_listener
, shuffled_global_image_ids
, 0,
993 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
996 // completion shuffle action for now (re)mapped images
997 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1000 wait_for_scheduled_task();
1001 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1004 TEST_F(TestMockImageMap
, AddInstancePingPongImageTest
) {
1005 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_migration_throttle", "600"));
1007 MockThreads
mock_threads(m_threads
);
1008 expect_work_queue(mock_threads
);
1012 std::set
<std::string
> global_image_ids
{
1013 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5",
1014 "global id 6", "global id 7", "global id 8", "global id 9", "global id 10",
1015 "global id 11", "global id 12", "global id 13", "global id 14"
1018 std::map
<std::string
, cls::rbd::MirrorImageMap
> image_mapping
;
1019 for (auto& global_image_id
: global_image_ids
) {
1020 image_mapping
[global_image_id
] = {m_local_instance_id
, {}, {}};
1024 MockLoadRequest mock_load_request
;
1025 EXPECT_CALL(mock_load_request
, send()).WillOnce(
1026 Invoke([&mock_load_request
, &image_mapping
]() {
1027 *mock_load_request
.image_map
= image_mapping
;
1028 mock_load_request
.on_finish
->complete(0);
1031 expect_add_event(mock_threads
);
1032 MockListener
mock_listener(this);
1033 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1034 listener_acquire_images(mock_listener
, global_image_ids
,
1037 std::unique_ptr
<MockImageMap
> mock_image_map
{
1038 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1042 mock_image_map
->init(&cond
);
1043 ASSERT_EQ(0, cond
.wait());
1045 mock_image_map
->update_instances_added({m_local_instance_id
});
1047 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1049 // remote peer ACKs image acquire request -- completing action
1050 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1051 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1053 wait_for_scheduled_task();
1055 // RELEASE+UPDATE_MAPPING+ACQUIRE
1056 expect_add_event(mock_threads
);
1057 MockUpdateRequest mock_update_request
;
1058 expect_update_request(mock_update_request
, 0);
1059 expect_add_event(mock_threads
);
1060 listener_acquire_images(mock_listener
, global_image_ids
,
1063 // set initial image list
1064 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1066 ASSERT_TRUE(wait_for_map_update(1));
1067 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1069 // remote peer ACKs image acquire request -- completing action
1070 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1072 wait_for_scheduled_task();
1074 std::set
<std::string
> shuffled_global_image_ids
;
1076 // RELEASE+UPDATE_MAPPING+ACQUIRE
1077 expect_add_event(mock_threads
);
1078 expect_listener_images_unmapped(mock_listener
, 7, &shuffled_global_image_ids
,
1081 mock_image_map
->update_instances_added({"9876"});
1083 wait_for_scheduled_task();
1084 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1086 update_map_and_acquire(mock_threads
, mock_update_request
,
1087 mock_listener
, shuffled_global_image_ids
, 0,
1089 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1092 // completion shuffle action for now (re)mapped images
1093 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1095 wait_for_scheduled_task();
1097 std::set
<std::string
> migrated_global_image_ids(shuffled_global_image_ids
);
1098 shuffled_global_image_ids
.clear();
1100 // RELEASE+UPDATE_MAPPING+ACQUIRE
1101 expect_add_event(mock_threads
);
1102 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
1105 // add another instance
1106 mock_image_map
->update_instances_added({"5432"});
1108 wait_for_scheduled_task();
1109 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1111 update_map_and_acquire(mock_threads
, mock_update_request
,
1112 mock_listener
, shuffled_global_image_ids
, 0,
1114 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1117 // completion shuffle action for now (re)mapped images
1118 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1121 // shuffle set should be distinct
1122 std::set
<std::string
> reshuffled
;
1123 std::set_intersection(migrated_global_image_ids
.begin(), migrated_global_image_ids
.end(),
1124 shuffled_global_image_ids
.begin(), shuffled_global_image_ids
.end(),
1125 std::inserter(reshuffled
, reshuffled
.begin()));
1126 ASSERT_TRUE(reshuffled
.empty());
1128 wait_for_scheduled_task();
1129 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1132 TEST_F(TestMockImageMap
, RemoveInstanceWithRemoveImage
) {
1133 MockThreads
mock_threads(m_threads
);
1134 expect_work_queue(mock_threads
);
1138 MockLoadRequest mock_load_request
;
1139 expect_load_request(mock_load_request
, 0);
1141 MockListener
mock_listener(this);
1143 std::unique_ptr
<MockImageMap
> mock_image_map
{
1144 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1148 mock_image_map
->init(&cond
);
1149 ASSERT_EQ(0, cond
.wait());
1151 std::set
<std::string
> global_image_ids
{
1152 "global id 1", "global id 2", "global id 3", "remote id 4",
1154 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1156 std::set
<std::string
> remove_global_image_ids
{
1159 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
1161 expect_add_event(mock_threads
);
1162 // UPDATE_MAPPING+ACQUIRE
1163 MockUpdateRequest mock_update_request
;
1164 expect_update_request(mock_update_request
, 0);
1165 expect_add_event(mock_threads
);
1166 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1167 listener_acquire_images(mock_listener
, global_image_ids
,
1170 // initial image list
1171 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1173 ASSERT_TRUE(wait_for_map_update(1));
1174 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1176 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1178 wait_for_scheduled_task();
1180 mock_image_map
->update_instances_added({m_local_instance_id
});
1182 std::set
<std::string
> shuffled_global_image_ids
;
1184 // RELEASE+UPDATE_MAPPING+ACQUIRE
1185 expect_add_event(mock_threads
);
1186 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1189 mock_image_map
->update_instances_added({"9876"});
1191 wait_for_scheduled_task();
1192 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1194 update_map_and_acquire(mock_threads
, mock_update_request
,
1195 mock_listener
, shuffled_global_image_ids
, 0,
1197 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1200 // completion shuffle action for now (re)mapped images
1201 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1203 wait_for_scheduled_task();
1205 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1209 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
1210 listener_remove_images(mock_listener
, "uuid1", shuffled_global_image_ids
,
1211 &peer_ack_remove_ctxs
);
1212 expect_add_event(mock_threads
);
1213 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1215 expect_add_event(mock_threads
);
1216 expect_update_request(mock_update_request
, 0);
1217 expect_add_event(mock_threads
);
1218 expect_update_request(mock_update_request
, 0);
1220 mock_image_map
->update_images("uuid1", {}, std::move(shuffled_global_image_ids
));
1221 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size() * 2));
1223 // instance failed -- update policy for instance removal
1224 mock_image_map
->update_instances_removed({"9876"});
1226 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
,
1227 -ENOENT
, &peer_ack_remove_ctxs
);
1228 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1229 -EBLOCKLISTED
, &peer_ack_ctxs
);
1231 wait_for_scheduled_task();
1232 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1235 TEST_F(TestMockImageMap
, AddErrorAndRemoveImage
) {
1236 MockThreads
mock_threads(m_threads
);
1237 expect_work_queue(mock_threads
);
1241 MockLoadRequest mock_load_request
;
1242 expect_load_request(mock_load_request
, 0);
1244 MockListener
mock_listener(this);
1246 std::unique_ptr
<MockImageMap
> mock_image_map
{
1247 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1251 mock_image_map
->init(&cond
);
1252 ASSERT_EQ(0, cond
.wait());
1254 mock_image_map
->update_instances_added({m_local_instance_id
});
1256 std::set
<std::string
> global_image_ids
{
1257 "global id 1", "global id 2", "global id 3", "remote id 4",
1259 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1261 // UPDATE_MAPPING+ACQUIRE
1262 expect_add_event(mock_threads
);
1263 MockUpdateRequest mock_update_request
;
1264 expect_update_request(mock_update_request
, 0);
1265 expect_add_event(mock_threads
);
1266 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1267 listener_acquire_images(mock_listener
, global_image_ids
,
1270 // initial image list
1271 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1273 ASSERT_TRUE(wait_for_map_update(1));
1274 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1276 // remote peer ACKs image acquire request
1277 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1279 wait_for_scheduled_task();
1281 std::set
<std::string
> shuffled_global_image_ids
;
1283 // RELEASE+UPDATE_MAPPING+ACQUIRE
1284 expect_add_event(mock_threads
);
1285 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1288 mock_image_map
->update_instances_added({"9876"});
1290 wait_for_scheduled_task();
1291 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1293 update_map_and_acquire(mock_threads
, mock_update_request
,
1294 mock_listener
, shuffled_global_image_ids
, 0,
1296 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1298 wait_for_scheduled_task();
1300 mock_image_map
->update_instances_removed({"9876"});
1302 std::set
<std::string
> released_global_image_ids
;
1303 std::map
<std::string
, Context
*> release_peer_ack_ctxs
;
1304 expect_add_event(mock_threads
);
1305 expect_listener_images_unmapped(mock_listener
, 1, &released_global_image_ids
,
1306 &release_peer_ack_ctxs
);
1307 expect_add_event(mock_threads
);
1308 expect_listener_images_unmapped(mock_listener
, 1, &released_global_image_ids
,
1309 &release_peer_ack_ctxs
);
1311 // instance blocklisted -- ACQUIRE request fails
1312 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
,
1313 -EBLOCKLISTED
, &peer_ack_ctxs
);
1314 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1316 std::map
<std::string
, Context
*> remap_peer_ack_ctxs
;
1317 update_map_and_acquire(mock_threads
, mock_update_request
,
1318 mock_listener
, shuffled_global_image_ids
, 0,
1319 &remap_peer_ack_ctxs
);
1321 // instance blocklisted -- RELEASE request fails
1322 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1323 -ENOENT
, &release_peer_ack_ctxs
);
1324 wait_for_scheduled_task();
1326 // new peer acks acquire request
1327 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1328 &remap_peer_ack_ctxs
);
1329 wait_for_scheduled_task();
1331 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1334 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
1335 listener_remove_images(mock_listener
, "uuid1", shuffled_global_image_ids
,
1336 &peer_ack_remove_ctxs
);
1337 expect_add_event(mock_threads
);
1338 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1340 update_map_request(mock_threads
, mock_update_request
, shuffled_global_image_ids
, 0);
1342 mock_image_map
->update_images("uuid1", {}, std::move(shuffled_global_image_ids
));
1343 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size() * 2));
1345 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1346 &peer_ack_remove_ctxs
);
1347 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1350 wait_for_scheduled_task();
1351 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1354 TEST_F(TestMockImageMap
, MirrorUUIDUpdated
) {
1355 MockThreads
mock_threads(m_threads
);
1356 expect_work_queue(mock_threads
);
1360 MockLoadRequest mock_load_request
;
1361 expect_load_request(mock_load_request
, 0);
1363 MockListener
mock_listener(this);
1365 std::unique_ptr
<MockImageMap
> mock_image_map
{
1366 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1370 mock_image_map
->init(&cond
);
1371 ASSERT_EQ(0, cond
.wait());
1374 std::set
<std::string
> initial_remote_global_image_ids
{
1375 "global id 1", "global id 2", "global id 3"
1377 std::set
<std::string
> initial_remote_global_image_ids_ack(initial_remote_global_image_ids
);
1379 // remote/local images to remove
1380 std::set
<std::string
> remote_removed_global_image_ids
{
1381 "global id 1", "global id 2", "global id 3"
1383 std::set
<std::string
> remote_removed_global_image_ids_ack(remote_removed_global_image_ids
);
1385 std::set
<std::string
> remote_added_global_image_ids
{
1386 "global id 1", "global id 2", "global id 3"
1388 std::set
<std::string
> remote_added_global_image_ids_ack(remote_added_global_image_ids
);
1390 // UPDATE_MAPPING+ACQUIRE
1391 expect_add_event(mock_threads
);
1392 MockUpdateRequest mock_update_request
;
1393 expect_update_request(mock_update_request
, 0);
1394 expect_add_event(mock_threads
);
1395 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1396 listener_acquire_images(mock_listener
, initial_remote_global_image_ids
,
1399 // initial remote image list
1400 mock_image_map
->update_images("uuid1", std::move(initial_remote_global_image_ids
), {});
1402 ASSERT_TRUE(wait_for_map_update(1));
1403 ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack
.size()));
1405 // remote peer ACKs image acquire request
1406 remote_peer_ack_nowait(mock_image_map
.get(),
1407 initial_remote_global_image_ids_ack
, 0,
1409 wait_for_scheduled_task();
1411 // RELEASE+REMOVE_MAPPING
1412 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
1413 listener_remove_images(mock_listener
, "uuid1", remote_removed_global_image_ids
,
1414 &peer_remove_ack_ctxs
);
1415 expect_add_event(mock_threads
);
1416 listener_release_images(mock_listener
, remote_removed_global_image_ids
,
1418 update_map_request(mock_threads
, mock_update_request
, remote_removed_global_image_ids
, 0);
1420 mock_image_map
->update_images("uuid1", {}, std::move(remote_removed_global_image_ids
));
1421 ASSERT_TRUE(wait_for_listener_notify(remote_removed_global_image_ids_ack
.size() * 2));
1423 remote_peer_ack_nowait(mock_image_map
.get(),
1424 remote_removed_global_image_ids_ack
, 0,
1425 &peer_remove_ack_ctxs
);
1426 remote_peer_ack_wait(mock_image_map
.get(),
1427 remote_removed_global_image_ids_ack
, 0,
1430 // UPDATE_MAPPING+ACQUIRE
1431 expect_add_event(mock_threads
);
1432 expect_update_request(mock_update_request
, 0);
1433 expect_add_event(mock_threads
);
1434 listener_acquire_images(mock_listener
, remote_added_global_image_ids
,
1437 mock_image_map
->update_images("uuid2", std::move(remote_added_global_image_ids
), {});
1439 ASSERT_TRUE(wait_for_map_update(1));
1440 ASSERT_TRUE(wait_for_listener_notify(remote_added_global_image_ids_ack
.size()));
1442 // remote peer ACKs image acquire request
1443 remote_peer_ack_nowait(mock_image_map
.get(),
1444 remote_added_global_image_ids_ack
, 0,
1447 wait_for_scheduled_task();
1448 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1451 TEST_F(TestMockImageMap
, RebalanceImageMap
) {
1452 MockThreads
mock_threads(m_threads
);
1453 expect_work_queue(mock_threads
);
1457 MockLoadRequest mock_load_request
;
1458 expect_load_request(mock_load_request
, 0);
1460 MockListener
mock_listener(this);
1462 std::unique_ptr
<MockImageMap
> mock_image_map
{
1463 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1467 mock_image_map
->init(&cond
);
1468 ASSERT_EQ(0, cond
.wait());
1470 std::set
<std::string
> global_image_ids
{
1471 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5",
1472 "global id 6", "global id 7", "global id 8", "global id 9", "global id 10",
1474 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1476 // UPDATE_MAPPING+ACQUIRE
1477 expect_add_event(mock_threads
);
1478 MockUpdateRequest mock_update_request
;
1479 expect_update_request(mock_update_request
, 0);
1480 expect_add_event(mock_threads
);
1481 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1482 listener_acquire_images(mock_listener
, global_image_ids
,
1485 // initial image list
1486 mock_image_map
->update_images("", std::move(global_image_ids
), {});
1488 ASSERT_TRUE(wait_for_map_update(1));
1489 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1491 // remote peer ACKs image acquire request
1492 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1494 wait_for_scheduled_task();
1496 mock_image_map
->update_instances_added({m_local_instance_id
});
1498 std::set
<std::string
> shuffled_global_image_ids
;
1500 // RELEASE+UPDATE_MAPPING+ACQUIRE
1501 expect_add_event(mock_threads
);
1502 expect_listener_images_unmapped(mock_listener
, 5, &shuffled_global_image_ids
,
1505 mock_image_map
->update_instances_added({"9876"});
1507 wait_for_scheduled_task();
1508 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1510 update_map_and_acquire(mock_threads
, mock_update_request
,
1511 mock_listener
, shuffled_global_image_ids
, 0,
1513 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1516 // completion shuffle action for now (re)mapped images
1517 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1520 wait_for_scheduled_task();
1522 // remove all shuffled images -- make way for rebalance
1523 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1525 // RELEASE+REMOVE_MAPPING
1526 expect_add_event(mock_threads
);
1527 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1529 update_map_request(mock_threads
, mock_update_request
, shuffled_global_image_ids
,
1532 mock_image_map
->update_images("", {}, std::move(shuffled_global_image_ids
));
1533 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size()));
1535 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1537 wait_for_scheduled_task();
1539 shuffled_global_image_ids
.clear();
1540 shuffled_global_image_ids_ack
.clear();
1542 std::set
<std::string
> new_global_image_ids
= {
1545 std::set
<std::string
> new_global_image_ids_ack(new_global_image_ids
);
1547 expect_add_event(mock_threads
);
1548 expect_update_request(mock_update_request
, 0);
1549 expect_add_event(mock_threads
);
1550 listener_acquire_images(mock_listener
, new_global_image_ids
, &peer_ack_ctxs
);
1552 expect_rebalance_event(mock_threads
); // rebalance task
1553 expect_add_event(mock_threads
); // update task scheduled by
1555 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1558 mock_image_map
->update_images("", std::move(new_global_image_ids
), {});
1560 ASSERT_TRUE(wait_for_map_update(1));
1561 ASSERT_TRUE(wait_for_listener_notify(new_global_image_ids_ack
.size()));
1563 // set rebalance interval
1564 CephContext
*cct
= reinterpret_cast<CephContext
*>(m_local_io_ctx
.cct());
1565 cct
->_conf
.set_val("rbd_mirror_image_policy_rebalance_timeout", "5");
1566 remote_peer_ack_nowait(mock_image_map
.get(), new_global_image_ids_ack
, 0,
1569 wait_for_scheduled_task();
1570 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1572 update_map_and_acquire(mock_threads
, mock_update_request
,
1573 mock_listener
, shuffled_global_image_ids
, 0,
1575 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1578 // completion shuffle action for now (re)mapped images
1579 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1582 wait_for_scheduled_task();
1583 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1586 } // namespace mirror