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
> {
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
);
164 : m_lock("TestMockImageMap::m_lock"),
165 m_notify_update_count(0),
166 m_map_update_count(0) {
169 void SetUp() override
{
170 TestFixture::SetUp();
172 m_local_instance_id
= stringify(m_local_io_ctx
.get_instance_id());
174 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_migration_throttle",
176 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_type", "simple"));
179 void TearDown() override
{
180 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_type", "none"));
182 TestFixture::TearDown();
185 void expect_work_queue(MockThreads
&mock_threads
) {
186 EXPECT_CALL(*mock_threads
.work_queue
, queue(_
, _
))
187 .WillRepeatedly(Invoke([this](Context
*ctx
, int r
) {
188 m_threads
->work_queue
->queue(ctx
, r
);
192 void expect_add_event(MockThreads
&mock_threads
) {
193 EXPECT_CALL(*mock_threads
.timer
, add_event_after(_
,_
))
194 .WillOnce(DoAll(WithArg
<1>(Invoke([this](Context
*ctx
) {
195 auto wrapped_ctx
= new FunctionContext([this, ctx
](int r
) {
196 Mutex::Locker
timer_locker(m_threads
->timer_lock
);
199 m_threads
->work_queue
->queue(wrapped_ctx
, 0);
200 })), ReturnArg
<1>()));
203 void expect_rebalance_event(MockThreads
&mock_threads
) {
204 EXPECT_CALL(*mock_threads
.timer
, add_event_after(_
,_
))
205 .WillOnce(DoAll(WithArg
<1>(Invoke([this](Context
*ctx
) {
206 // disable rebalance so as to not reschedule it again
207 CephContext
*cct
= reinterpret_cast<CephContext
*>(m_local_io_ctx
.cct());
208 cct
->_conf
.set_val("rbd_mirror_image_policy_rebalance_timeout", "0");
210 auto wrapped_ctx
= new FunctionContext([this, ctx
](int r
) {
211 Mutex::Locker
timer_locker(m_threads
->timer_lock
);
214 m_threads
->work_queue
->queue(wrapped_ctx
, 0);
215 })), ReturnArg
<1>()));
218 void expect_load_request(MockLoadRequest
&request
, int r
) {
219 EXPECT_CALL(request
, send())
220 .WillOnce(Invoke([&request
, r
]() {
221 request
.on_finish
->complete(r
);
225 void expect_update_request(MockUpdateRequest
&request
, int r
) {
226 EXPECT_CALL(request
, send())
227 .WillOnce(Invoke([this, &request
, r
]() {
228 request
.on_finish
->complete(r
);
230 Mutex::Locker
locker(m_lock
);
231 ++m_map_update_count
;
237 void expect_listener_acquire_image(MockListener
&mock_listener
,
238 const std::string
&global_image_id
,
239 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
240 EXPECT_CALL(mock_listener
, mock_acquire_image(global_image_id
, _
))
241 .WillOnce(WithArg
<1>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
242 Mutex::Locker
locker(m_lock
);
243 peer_ack_ctxs
->insert({global_image_id
, ctx
});
244 ++m_notify_update_count
;
249 void expect_listener_release_image(MockListener
&mock_listener
,
250 const std::string
&global_image_id
,
251 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
252 EXPECT_CALL(mock_listener
, mock_release_image(global_image_id
, _
))
253 .WillOnce(WithArg
<1>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
254 Mutex::Locker
locker(m_lock
);
255 peer_ack_ctxs
->insert({global_image_id
, ctx
});
256 ++m_notify_update_count
;
261 void expect_listener_remove_image(MockListener
&mock_listener
,
262 const std::string
&mirror_uuid
,
263 const std::string
&global_image_id
,
264 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
265 EXPECT_CALL(mock_listener
,
266 mock_remove_image(mirror_uuid
, global_image_id
, _
))
267 .WillOnce(WithArg
<2>(Invoke([this, global_image_id
, peer_ack_ctxs
](Context
* ctx
) {
268 Mutex::Locker
locker(m_lock
);
269 peer_ack_ctxs
->insert({global_image_id
, ctx
});
270 ++m_notify_update_count
;
275 void expect_listener_images_unmapped(MockListener
&mock_listener
, size_t count
,
276 std::set
<std::string
> *global_image_ids
,
277 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
278 EXPECT_CALL(mock_listener
, mock_release_image(_
, _
))
280 .WillRepeatedly(Invoke([this, global_image_ids
, peer_ack_ctxs
](std::string global_image_id
, Context
* ctx
) {
281 Mutex::Locker
locker(m_lock
);
282 global_image_ids
->emplace(global_image_id
);
283 peer_ack_ctxs
->insert({global_image_id
, ctx
});
284 ++m_notify_update_count
;
289 void remote_peer_ack_nowait(MockImageMap
*image_map
,
290 const std::set
<std::string
> &global_image_ids
,
292 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
293 for (auto& global_image_id
: global_image_ids
) {
294 auto it
= peer_ack_ctxs
->find(global_image_id
);
295 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
296 auto ack_ctx
= it
->second
;
297 peer_ack_ctxs
->erase(it
);
298 ack_ctx
->complete(ret
);
299 wait_for_scheduled_task();
303 void remote_peer_ack_wait(MockImageMap
*image_map
,
304 const std::set
<std::string
> &global_image_ids
,
306 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
307 for (auto& global_image_id
: global_image_ids
) {
308 auto it
= peer_ack_ctxs
->find(global_image_id
);
309 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
310 auto ack_ctx
= it
->second
;
311 peer_ack_ctxs
->erase(it
);
312 ack_ctx
->complete(ret
);
313 wait_for_scheduled_task();
314 ASSERT_TRUE(wait_for_map_update(1));
318 void remote_peer_ack_listener_wait(MockImageMap
*image_map
,
319 const std::set
<std::string
> &global_image_ids
,
321 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
322 for (auto& global_image_id
: global_image_ids
) {
323 auto it
= peer_ack_ctxs
->find(global_image_id
);
324 ASSERT_TRUE(it
!= peer_ack_ctxs
->end());
325 auto ack_ctx
= it
->second
;
326 peer_ack_ctxs
->erase(it
);
327 ack_ctx
->complete(ret
);
328 ASSERT_TRUE(wait_for_map_update(1));
329 ASSERT_TRUE(wait_for_listener_notify(1));
333 void update_map_and_acquire(MockThreads
&mock_threads
,
334 MockUpdateRequest
&mock_update_request
,
335 MockListener
&mock_listener
,
336 const std::set
<std::string
> &global_image_ids
,
338 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
339 for (auto const &global_image_id
: global_image_ids
) {
340 expect_add_event(mock_threads
);
341 expect_update_request(mock_update_request
, ret
);
342 expect_add_event(mock_threads
);
343 expect_listener_acquire_image(mock_listener
, global_image_id
,
348 void update_map_request(MockThreads
&mock_threads
,
349 MockUpdateRequest
&mock_update_request
,
350 const std::set
<std::string
> &global_image_ids
, int ret
) {
351 for (uint32_t i
= 0; i
< global_image_ids
.size(); ++i
) {
352 expect_add_event(mock_threads
);
353 expect_update_request(mock_update_request
, ret
);
357 void wait_for_scheduled_task() {
358 m_threads
->work_queue
->drain();
361 bool wait_for_listener_notify(uint32_t count
) {
362 Mutex::Locker
locker(m_lock
);
363 while (m_notify_update_count
< count
) {
364 if (m_cond
.WaitInterval(m_lock
, utime_t(10, 0)) != 0) {
369 if (m_notify_update_count
< count
) {
373 m_notify_update_count
-= count
;
377 bool wait_for_map_update(uint32_t count
) {
378 Mutex::Locker
locker(m_lock
);
379 while (m_map_update_count
< count
) {
380 if (m_cond
.WaitInterval(m_lock
, utime_t(10, 0)) != 0) {
385 if (m_map_update_count
< count
) {
389 m_map_update_count
-= count
;
393 int when_shut_down(MockImageMap
*image_map
) {
395 image_map
->shut_down(&ctx
);
399 void listener_acquire_images(MockListener
&mock_listener
,
400 const std::set
<std::string
> &global_image_ids
,
401 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
402 for (auto const &global_image_id
: global_image_ids
) {
403 expect_listener_acquire_image(mock_listener
, global_image_id
,
408 void listener_release_images(MockListener
&mock_listener
,
409 const std::set
<std::string
> &global_image_ids
,
410 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
411 for (auto const &global_image_id
: global_image_ids
) {
412 expect_listener_release_image(mock_listener
, global_image_id
,
417 void listener_remove_images(MockListener
&mock_listener
,
418 const std::string
&mirror_uuid
,
419 std::set
<std::string
> &global_image_ids
,
420 std::map
<std::string
, Context
*> *peer_ack_ctxs
) {
421 for (auto const &global_image_id
: global_image_ids
) {
422 expect_listener_remove_image(mock_listener
, mirror_uuid
, global_image_id
,
429 uint32_t m_notify_update_count
;
430 uint32_t m_map_update_count
;
431 std::string m_local_instance_id
;
434 TEST_F(TestMockImageMap
, SetLocalImages
) {
435 MockThreads
mock_threads(m_threads
);
436 expect_work_queue(mock_threads
);
440 MockLoadRequest mock_load_request
;
441 expect_load_request(mock_load_request
, 0);
443 MockListener
mock_listener(this);
445 std::unique_ptr
<MockImageMap
> mock_image_map
{
446 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
450 mock_image_map
->init(&cond
);
451 ASSERT_EQ(0, cond
.wait());
453 std::set
<std::string
> global_image_ids
{
454 "global id 1", "global id 2"
456 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
458 // UPDATE_MAPPING+ACQUIRE
459 expect_add_event(mock_threads
);
460 MockUpdateRequest mock_update_request
;
461 expect_update_request(mock_update_request
, 0);
462 expect_add_event(mock_threads
);
463 std::map
<std::string
, Context
*> peer_ack_ctxs
;
464 listener_acquire_images(mock_listener
, global_image_ids
, &peer_ack_ctxs
);
466 // initial image list
467 mock_image_map
->update_images("", std::move(global_image_ids
), {});
469 ASSERT_TRUE(wait_for_map_update(1));
470 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
472 // remote peer ACKs image acquire request
473 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
476 wait_for_scheduled_task();
477 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
480 TEST_F(TestMockImageMap
, AddRemoveLocalImage
) {
481 MockThreads
mock_threads(m_threads
);
482 expect_work_queue(mock_threads
);
486 MockLoadRequest mock_load_request
;
487 expect_load_request(mock_load_request
, 0);
489 MockListener
mock_listener(this);
491 std::unique_ptr
<MockImageMap
> mock_image_map
{
492 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
496 mock_image_map
->init(&cond
);
497 ASSERT_EQ(0, cond
.wait());
499 std::set
<std::string
> initial_global_image_ids
{
500 "global id 1", "global id 2"
502 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
504 std::set
<std::string
> remove_global_image_ids
{
505 "global id 1", "global id 2"
507 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
509 // UPDATE_MAPPING+ACQUIRE
510 expect_add_event(mock_threads
);
511 MockUpdateRequest mock_update_request
;
512 expect_update_request(mock_update_request
, 0);
513 expect_add_event(mock_threads
);
514 std::map
<std::string
, Context
*> peer_ack_ctxs
;
515 listener_acquire_images(mock_listener
, initial_global_image_ids
,
518 // initial image list
519 mock_image_map
->update_images("", std::move(initial_global_image_ids
), {});
521 ASSERT_TRUE(wait_for_map_update(1));
522 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
524 // remote peer ACKs image acquire request
525 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
528 // RELEASE+REMOVE_MAPPING
529 expect_add_event(mock_threads
);
530 listener_release_images(mock_listener
, remove_global_image_ids
,
532 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
,
536 mock_image_map
->update_images("", {}, std::move(remove_global_image_ids
));
537 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size()));
539 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
542 wait_for_scheduled_task();
543 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
546 TEST_F(TestMockImageMap
, AddRemoveRemoteImage
) {
547 MockThreads
mock_threads(m_threads
);
548 expect_work_queue(mock_threads
);
552 MockLoadRequest mock_load_request
;
553 expect_load_request(mock_load_request
, 0);
555 MockListener
mock_listener(this);
557 std::unique_ptr
<MockImageMap
> mock_image_map
{
558 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
562 mock_image_map
->init(&cond
);
563 ASSERT_EQ(0, cond
.wait());
565 std::set
<std::string
> initial_global_image_ids
{
566 "global id 1", "global id 2"
568 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
570 std::set
<std::string
> remove_global_image_ids
{
571 "global id 1", "global id 2"
573 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
575 // UPDATE_MAPPING+ACQUIRE
576 expect_add_event(mock_threads
);
577 MockUpdateRequest mock_update_request
;
578 expect_update_request(mock_update_request
, 0);
579 expect_add_event(mock_threads
);
580 std::map
<std::string
, Context
*> peer_ack_ctxs
;
581 listener_acquire_images(mock_listener
, initial_global_image_ids
,
584 // initial image list
585 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
),
588 ASSERT_TRUE(wait_for_map_update(1));
589 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
591 // remote peer ACKs image acquire request
592 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
595 // RELEASE+REMOVE_MAPPING
596 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
597 listener_remove_images(mock_listener
, "uuid1", remove_global_image_ids
,
598 &peer_remove_ack_ctxs
);
599 expect_add_event(mock_threads
);
600 listener_release_images(mock_listener
, remove_global_image_ids
,
602 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
,
606 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids
));
607 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size() * 2));
609 remote_peer_ack_nowait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
610 &peer_remove_ack_ctxs
);
611 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
614 wait_for_scheduled_task();
615 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
618 TEST_F(TestMockImageMap
, AddRemoveRemoteImageDuplicateNotification
) {
619 MockThreads
mock_threads(m_threads
);
620 expect_work_queue(mock_threads
);
624 MockLoadRequest mock_load_request
;
625 expect_load_request(mock_load_request
, 0);
627 MockListener
mock_listener(this);
629 std::unique_ptr
<MockImageMap
> mock_image_map
{
630 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
634 mock_image_map
->init(&cond
);
635 ASSERT_EQ(0, cond
.wait());
637 std::set
<std::string
> initial_global_image_ids
{
638 "global id 1", "global id 2"
640 std::set
<std::string
> initial_global_image_ids_dup(initial_global_image_ids
);
641 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
643 std::set
<std::string
> remove_global_image_ids
{
644 "global id 1", "global id 2"
646 std::set
<std::string
> remove_global_image_ids_dup(remove_global_image_ids
);
647 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
649 // UPDATE_MAPPING+ACQUIRE
650 expect_add_event(mock_threads
);
651 MockUpdateRequest mock_update_request
;
652 expect_update_request(mock_update_request
, 0);
653 expect_add_event(mock_threads
);
654 std::map
<std::string
, Context
*> peer_ack_ctxs
;
655 listener_acquire_images(mock_listener
, initial_global_image_ids
,
658 // initial image list
659 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
), {});
661 ASSERT_TRUE(wait_for_map_update(1));
662 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
664 // trigger duplicate "add" event
665 wait_for_scheduled_task();
666 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids_dup
), {});
668 // remote peer ACKs image acquire request
669 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
672 // RELEASE+REMOVE_MAPPING
673 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
674 listener_remove_images(mock_listener
, "uuid1", remove_global_image_ids
,
675 &peer_remove_ack_ctxs
);
676 expect_add_event(mock_threads
);
677 listener_release_images(mock_listener
, remove_global_image_ids
,
679 update_map_request(mock_threads
, mock_update_request
, remove_global_image_ids
, 0);
682 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids
));
683 ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack
.size() * 2));
685 remote_peer_ack_nowait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
686 &peer_remove_ack_ctxs
);
687 remote_peer_ack_wait(mock_image_map
.get(), remove_global_image_ids_ack
, 0,
690 // trigger duplicate "remove" notification
691 mock_image_map
->update_images("uuid1", {}, std::move(remove_global_image_ids_dup
));
693 wait_for_scheduled_task();
694 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
697 TEST_F(TestMockImageMap
, AcquireImageErrorRetry
) {
698 MockThreads
mock_threads(m_threads
);
699 expect_work_queue(mock_threads
);
703 MockLoadRequest mock_load_request
;
704 expect_load_request(mock_load_request
, 0);
706 MockListener
mock_listener(this);
708 std::unique_ptr
<MockImageMap
> mock_image_map
{
709 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
713 mock_image_map
->init(&cond
);
714 ASSERT_EQ(0, cond
.wait());
716 std::set
<std::string
> initial_global_image_ids
{
717 "global id 1", "global id 2"
719 std::set
<std::string
> initial_global_image_ids_ack(initial_global_image_ids
);
721 // UPDATE_MAPPING failure
722 expect_add_event(mock_threads
);
723 MockUpdateRequest mock_update_request
;
724 expect_update_request(mock_update_request
, -EIO
);
726 // UPDATE_MAPPING+ACQUIRE
727 expect_add_event(mock_threads
);
728 expect_update_request(mock_update_request
, 0);
729 expect_add_event(mock_threads
);
730 std::map
<std::string
, Context
*> peer_ack_ctxs
;
731 listener_acquire_images(mock_listener
, initial_global_image_ids
,
734 // initial image list
735 mock_image_map
->update_images("uuid1", std::move(initial_global_image_ids
), {});
737 ASSERT_TRUE(wait_for_map_update(1));
738 ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack
.size()));
740 // remote peer ACKs image acquire request
741 remote_peer_ack_nowait(mock_image_map
.get(), initial_global_image_ids_ack
, 0,
744 wait_for_scheduled_task();
745 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
748 TEST_F(TestMockImageMap
, RemoveRemoteAndLocalImage
) {
749 MockThreads
mock_threads(m_threads
);
750 expect_work_queue(mock_threads
);
754 MockLoadRequest mock_load_request
;
755 expect_load_request(mock_load_request
, 0);
757 MockListener
mock_listener(this);
759 std::unique_ptr
<MockImageMap
> mock_image_map
{
760 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
764 mock_image_map
->init(&cond
);
765 ASSERT_EQ(0, cond
.wait());
768 std::set
<std::string
> initial_remote_global_image_ids
{
771 std::set
<std::string
> initial_remote_global_image_ids_ack(initial_remote_global_image_ids
);
774 std::set
<std::string
> initial_local_global_image_ids
{
778 // remote/local images to remove
779 std::set
<std::string
> remote_remove_global_image_ids
{
782 std::set
<std::string
> remote_remove_global_image_ids_ack(remote_remove_global_image_ids
);
784 std::set
<std::string
> local_remove_global_image_ids
{
787 std::set
<std::string
> local_remove_global_image_ids_ack(local_remove_global_image_ids
);
789 // UPDATE_MAPPING+ACQUIRE
790 expect_add_event(mock_threads
);
791 MockUpdateRequest mock_update_request
;
792 expect_update_request(mock_update_request
, 0);
793 expect_add_event(mock_threads
);
794 std::map
<std::string
, Context
*> peer_ack_ctxs
;
795 listener_acquire_images(mock_listener
, initial_remote_global_image_ids
,
798 // initial remote image list
799 mock_image_map
->update_images("uuid1", std::move(initial_remote_global_image_ids
), {});
801 ASSERT_TRUE(wait_for_map_update(1));
802 ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack
.size()));
804 // remote peer ACKs image acquire request
805 remote_peer_ack_nowait(mock_image_map
.get(),
806 initial_remote_global_image_ids_ack
, 0,
809 // set initial local image list -- this is a no-op from policy pov
810 mock_image_map
->update_images("", std::move(initial_local_global_image_ids
), {});
812 // remove remote images -- this should be a no-op from policy pov
813 // except the listener notification
814 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
815 listener_remove_images(mock_listener
, "uuid1", remote_remove_global_image_ids
,
816 &peer_ack_remove_ctxs
);
818 mock_image_map
->update_images("uuid1", {}, std::move(remote_remove_global_image_ids
));
819 ASSERT_TRUE(wait_for_listener_notify(remote_remove_global_image_ids_ack
.size()));
821 // RELEASE+REMOVE_MAPPING
822 expect_add_event(mock_threads
);
823 listener_release_images(mock_listener
, local_remove_global_image_ids
,
825 update_map_request(mock_threads
, mock_update_request
, local_remove_global_image_ids
, 0);
827 // remove local images
828 mock_image_map
->update_images("", {}, std::move(local_remove_global_image_ids
));
829 ASSERT_TRUE(wait_for_listener_notify(local_remove_global_image_ids_ack
.size()));
831 remote_peer_ack_nowait(mock_image_map
.get(), local_remove_global_image_ids_ack
,
832 0, &peer_ack_remove_ctxs
);
833 remote_peer_ack_wait(mock_image_map
.get(), local_remove_global_image_ids_ack
,
836 wait_for_scheduled_task();
837 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
840 TEST_F(TestMockImageMap
, AddInstance
) {
841 MockThreads
mock_threads(m_threads
);
842 expect_work_queue(mock_threads
);
846 MockLoadRequest mock_load_request
;
847 expect_load_request(mock_load_request
, 0);
849 MockListener
mock_listener(this);
851 std::unique_ptr
<MockImageMap
> mock_image_map
{
852 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
856 mock_image_map
->init(&cond
);
857 ASSERT_EQ(0, cond
.wait());
859 std::set
<std::string
> global_image_ids
{
860 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
862 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
864 // UPDATE_MAPPING+ACQUIRE
865 expect_add_event(mock_threads
);
866 MockUpdateRequest mock_update_request
;
867 expect_update_request(mock_update_request
, 0);
868 expect_add_event(mock_threads
);
869 std::map
<std::string
, Context
*> peer_ack_ctxs
;
870 listener_acquire_images(mock_listener
, global_image_ids
,
873 // initial image list
874 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
876 ASSERT_TRUE(wait_for_map_update(1));
877 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
879 // remote peer ACKs image acquire request
880 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
882 wait_for_scheduled_task();
884 mock_image_map
->update_instances_added({m_local_instance_id
});
886 std::set
<std::string
> shuffled_global_image_ids
;
888 // RELEASE+UPDATE_MAPPING+ACQUIRE
889 expect_add_event(mock_threads
);
890 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
893 mock_image_map
->update_instances_added({"9876"});
895 wait_for_scheduled_task();
896 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
898 update_map_and_acquire(mock_threads
, mock_update_request
,
899 mock_listener
, shuffled_global_image_ids
, 0,
901 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
904 // completion shuffle action for now (re)mapped images
905 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
908 wait_for_scheduled_task();
909 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
912 TEST_F(TestMockImageMap
, RemoveInstance
) {
913 MockThreads
mock_threads(m_threads
);
914 expect_work_queue(mock_threads
);
918 MockLoadRequest mock_load_request
;
919 expect_load_request(mock_load_request
, 0);
921 MockListener
mock_listener(this);
923 std::unique_ptr
<MockImageMap
> mock_image_map
{
924 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
928 mock_image_map
->init(&cond
);
929 ASSERT_EQ(0, cond
.wait());
931 std::set
<std::string
> global_image_ids
{
932 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
934 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
936 expect_add_event(mock_threads
);
938 // UPDATE_MAPPING+ACQUIRE
939 MockUpdateRequest mock_update_request
;
940 expect_update_request(mock_update_request
, 0);
941 expect_add_event(mock_threads
);
942 std::map
<std::string
, Context
*> peer_ack_ctxs
;
943 listener_acquire_images(mock_listener
, global_image_ids
,
946 // set initial image list
947 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
949 ASSERT_TRUE(wait_for_map_update(1));
950 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
952 // remote peer ACKs image acquire request -- completing action
953 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
955 wait_for_scheduled_task();
957 mock_image_map
->update_instances_added({m_local_instance_id
});
959 std::set
<std::string
> shuffled_global_image_ids
;
961 // RELEASE+UPDATE_MAPPING+ACQUIRE
962 expect_add_event(mock_threads
);
963 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
966 mock_image_map
->update_instances_added({"9876"});
968 wait_for_scheduled_task();
969 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
971 update_map_and_acquire(mock_threads
, mock_update_request
,
972 mock_listener
, shuffled_global_image_ids
, 0,
974 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
977 // completion shuffle action for now (re)mapped images
978 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
980 wait_for_scheduled_task();
982 shuffled_global_image_ids
.clear();
984 // remove added instance
985 expect_add_event(mock_threads
);
986 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
989 mock_image_map
->update_instances_removed({"9876"});
991 wait_for_scheduled_task();
992 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
994 update_map_and_acquire(mock_threads
, mock_update_request
,
995 mock_listener
, shuffled_global_image_ids
, 0,
997 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1000 // completion shuffle action for now (re)mapped images
1001 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1004 wait_for_scheduled_task();
1005 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1008 TEST_F(TestMockImageMap
, AddInstancePingPongImageTest
) {
1009 EXPECT_EQ(0, _rados
->conf_set("rbd_mirror_image_policy_migration_throttle", "600"));
1011 MockThreads
mock_threads(m_threads
);
1012 expect_work_queue(mock_threads
);
1016 std::set
<std::string
> global_image_ids
{
1017 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5",
1018 "global id 6", "global id 7", "global id 8", "global id 9", "global id 10",
1019 "global id 11", "global id 12", "global id 13", "global id 14"
1022 std::map
<std::string
, cls::rbd::MirrorImageMap
> image_mapping
;
1023 for (auto& global_image_id
: global_image_ids
) {
1024 image_mapping
[global_image_id
] = {m_local_instance_id
, {}, {}};
1028 MockLoadRequest mock_load_request
;
1029 EXPECT_CALL(mock_load_request
, send()).WillOnce(
1030 Invoke([&mock_load_request
, &image_mapping
]() {
1031 *mock_load_request
.image_map
= image_mapping
;
1032 mock_load_request
.on_finish
->complete(0);
1035 expect_add_event(mock_threads
);
1036 MockListener
mock_listener(this);
1037 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1038 listener_acquire_images(mock_listener
, global_image_ids
,
1041 std::unique_ptr
<MockImageMap
> mock_image_map
{
1042 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1046 mock_image_map
->init(&cond
);
1047 ASSERT_EQ(0, cond
.wait());
1049 mock_image_map
->update_instances_added({m_local_instance_id
});
1051 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1053 // remote peer ACKs image acquire request -- completing action
1054 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1055 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1057 wait_for_scheduled_task();
1059 // RELEASE+UPDATE_MAPPING+ACQUIRE
1060 expect_add_event(mock_threads
);
1061 MockUpdateRequest mock_update_request
;
1062 expect_update_request(mock_update_request
, 0);
1063 expect_add_event(mock_threads
);
1064 listener_acquire_images(mock_listener
, global_image_ids
,
1067 // set initial image list
1068 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1070 ASSERT_TRUE(wait_for_map_update(1));
1071 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1073 // remote peer ACKs image acquire request -- completing action
1074 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1076 wait_for_scheduled_task();
1078 std::set
<std::string
> shuffled_global_image_ids
;
1080 // RELEASE+UPDATE_MAPPING+ACQUIRE
1081 expect_add_event(mock_threads
);
1082 expect_listener_images_unmapped(mock_listener
, 7, &shuffled_global_image_ids
,
1085 mock_image_map
->update_instances_added({"9876"});
1087 wait_for_scheduled_task();
1088 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1090 update_map_and_acquire(mock_threads
, mock_update_request
,
1091 mock_listener
, shuffled_global_image_ids
, 0,
1093 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1096 // completion shuffle action for now (re)mapped images
1097 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1099 wait_for_scheduled_task();
1101 std::set
<std::string
> migrated_global_image_ids(shuffled_global_image_ids
);
1102 shuffled_global_image_ids
.clear();
1104 // RELEASE+UPDATE_MAPPING+ACQUIRE
1105 expect_add_event(mock_threads
);
1106 expect_listener_images_unmapped(mock_listener
, 3, &shuffled_global_image_ids
,
1109 // add another instance
1110 mock_image_map
->update_instances_added({"5432"});
1112 wait_for_scheduled_task();
1113 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1115 update_map_and_acquire(mock_threads
, mock_update_request
,
1116 mock_listener
, shuffled_global_image_ids
, 0,
1118 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1121 // completion shuffle action for now (re)mapped images
1122 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1125 // shuffle set should be distinct
1126 std::set
<std::string
> reshuffled
;
1127 std::set_intersection(migrated_global_image_ids
.begin(), migrated_global_image_ids
.end(),
1128 shuffled_global_image_ids
.begin(), shuffled_global_image_ids
.end(),
1129 std::inserter(reshuffled
, reshuffled
.begin()));
1130 ASSERT_TRUE(reshuffled
.empty());
1132 wait_for_scheduled_task();
1133 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1136 TEST_F(TestMockImageMap
, RemoveInstanceWithRemoveImage
) {
1137 MockThreads
mock_threads(m_threads
);
1138 expect_work_queue(mock_threads
);
1142 MockLoadRequest mock_load_request
;
1143 expect_load_request(mock_load_request
, 0);
1145 MockListener
mock_listener(this);
1147 std::unique_ptr
<MockImageMap
> mock_image_map
{
1148 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1152 mock_image_map
->init(&cond
);
1153 ASSERT_EQ(0, cond
.wait());
1155 std::set
<std::string
> global_image_ids
{
1156 "global id 1", "global id 2", "global id 3", "remote id 4",
1158 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1160 std::set
<std::string
> remove_global_image_ids
{
1163 std::set
<std::string
> remove_global_image_ids_ack(remove_global_image_ids
);
1165 expect_add_event(mock_threads
);
1166 // UPDATE_MAPPING+ACQUIRE
1167 MockUpdateRequest mock_update_request
;
1168 expect_update_request(mock_update_request
, 0);
1169 expect_add_event(mock_threads
);
1170 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1171 listener_acquire_images(mock_listener
, global_image_ids
,
1174 // initial image list
1175 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1177 ASSERT_TRUE(wait_for_map_update(1));
1178 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1180 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1182 wait_for_scheduled_task();
1184 mock_image_map
->update_instances_added({m_local_instance_id
});
1186 std::set
<std::string
> shuffled_global_image_ids
;
1188 // RELEASE+UPDATE_MAPPING+ACQUIRE
1189 expect_add_event(mock_threads
);
1190 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1193 mock_image_map
->update_instances_added({"9876"});
1195 wait_for_scheduled_task();
1196 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1198 update_map_and_acquire(mock_threads
, mock_update_request
,
1199 mock_listener
, shuffled_global_image_ids
, 0,
1201 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1204 // completion shuffle action for now (re)mapped images
1205 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1207 wait_for_scheduled_task();
1209 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1213 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
1214 listener_remove_images(mock_listener
, "uuid1", shuffled_global_image_ids
,
1215 &peer_ack_remove_ctxs
);
1216 expect_add_event(mock_threads
);
1217 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1219 expect_add_event(mock_threads
);
1220 expect_update_request(mock_update_request
, 0);
1221 expect_add_event(mock_threads
);
1222 expect_update_request(mock_update_request
, 0);
1224 mock_image_map
->update_images("uuid1", {}, std::move(shuffled_global_image_ids
));
1225 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size() * 2));
1227 // instance failed -- update policy for instance removal
1228 mock_image_map
->update_instances_removed({"9876"});
1230 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
,
1231 -ENOENT
, &peer_ack_remove_ctxs
);
1232 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1233 -EBLACKLISTED
, &peer_ack_ctxs
);
1235 wait_for_scheduled_task();
1236 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1239 TEST_F(TestMockImageMap
, AddErrorAndRemoveImage
) {
1240 MockThreads
mock_threads(m_threads
);
1241 expect_work_queue(mock_threads
);
1245 MockLoadRequest mock_load_request
;
1246 expect_load_request(mock_load_request
, 0);
1248 MockListener
mock_listener(this);
1250 std::unique_ptr
<MockImageMap
> mock_image_map
{
1251 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1255 mock_image_map
->init(&cond
);
1256 ASSERT_EQ(0, cond
.wait());
1258 mock_image_map
->update_instances_added({m_local_instance_id
});
1260 std::set
<std::string
> global_image_ids
{
1261 "global id 1", "global id 2", "global id 3", "remote id 4",
1263 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1265 // UPDATE_MAPPING+ACQUIRE
1266 expect_add_event(mock_threads
);
1267 MockUpdateRequest mock_update_request
;
1268 expect_update_request(mock_update_request
, 0);
1269 expect_add_event(mock_threads
);
1270 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1271 listener_acquire_images(mock_listener
, global_image_ids
,
1274 // initial image list
1275 mock_image_map
->update_images("uuid1", std::move(global_image_ids
), {});
1277 ASSERT_TRUE(wait_for_map_update(1));
1278 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1280 // remote peer ACKs image acquire request
1281 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1283 wait_for_scheduled_task();
1285 std::set
<std::string
> shuffled_global_image_ids
;
1287 // RELEASE+UPDATE_MAPPING+ACQUIRE
1288 expect_add_event(mock_threads
);
1289 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1292 mock_image_map
->update_instances_added({"9876"});
1294 wait_for_scheduled_task();
1295 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1297 update_map_and_acquire(mock_threads
, mock_update_request
,
1298 mock_listener
, shuffled_global_image_ids
, 0,
1300 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1302 wait_for_scheduled_task();
1304 mock_image_map
->update_instances_removed({"9876"});
1306 std::set
<std::string
> released_global_image_ids
;
1307 std::map
<std::string
, Context
*> release_peer_ack_ctxs
;
1308 expect_add_event(mock_threads
);
1309 expect_listener_images_unmapped(mock_listener
, 1, &released_global_image_ids
,
1310 &release_peer_ack_ctxs
);
1311 expect_add_event(mock_threads
);
1312 expect_listener_images_unmapped(mock_listener
, 1, &released_global_image_ids
,
1313 &release_peer_ack_ctxs
);
1315 // instance blacklisted -- ACQUIRE request fails
1316 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
,
1317 -EBLACKLISTED
, &peer_ack_ctxs
);
1318 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1320 std::map
<std::string
, Context
*> remap_peer_ack_ctxs
;
1321 update_map_and_acquire(mock_threads
, mock_update_request
,
1322 mock_listener
, shuffled_global_image_ids
, 0,
1323 &remap_peer_ack_ctxs
);
1325 // instance blacklisted -- RELEASE request fails
1326 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1327 -ENOENT
, &release_peer_ack_ctxs
);
1328 wait_for_scheduled_task();
1330 // new peer acks acquire request
1331 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1332 &remap_peer_ack_ctxs
);
1333 wait_for_scheduled_task();
1335 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1338 std::map
<std::string
, Context
*> peer_ack_remove_ctxs
;
1339 listener_remove_images(mock_listener
, "uuid1", shuffled_global_image_ids
,
1340 &peer_ack_remove_ctxs
);
1341 expect_add_event(mock_threads
);
1342 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1344 update_map_request(mock_threads
, mock_update_request
, shuffled_global_image_ids
, 0);
1346 mock_image_map
->update_images("uuid1", {}, std::move(shuffled_global_image_ids
));
1347 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size() * 2));
1349 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1350 &peer_ack_remove_ctxs
);
1351 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1354 wait_for_scheduled_task();
1355 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1358 TEST_F(TestMockImageMap
, MirrorUUIDUpdated
) {
1359 MockThreads
mock_threads(m_threads
);
1360 expect_work_queue(mock_threads
);
1364 MockLoadRequest mock_load_request
;
1365 expect_load_request(mock_load_request
, 0);
1367 MockListener
mock_listener(this);
1369 std::unique_ptr
<MockImageMap
> mock_image_map
{
1370 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1374 mock_image_map
->init(&cond
);
1375 ASSERT_EQ(0, cond
.wait());
1378 std::set
<std::string
> initial_remote_global_image_ids
{
1379 "global id 1", "global id 2", "global id 3"
1381 std::set
<std::string
> initial_remote_global_image_ids_ack(initial_remote_global_image_ids
);
1383 // remote/local images to remove
1384 std::set
<std::string
> remote_removed_global_image_ids
{
1385 "global id 1", "global id 2", "global id 3"
1387 std::set
<std::string
> remote_removed_global_image_ids_ack(remote_removed_global_image_ids
);
1389 std::set
<std::string
> remote_added_global_image_ids
{
1390 "global id 1", "global id 2", "global id 3"
1392 std::set
<std::string
> remote_added_global_image_ids_ack(remote_added_global_image_ids
);
1394 // UPDATE_MAPPING+ACQUIRE
1395 expect_add_event(mock_threads
);
1396 MockUpdateRequest mock_update_request
;
1397 expect_update_request(mock_update_request
, 0);
1398 expect_add_event(mock_threads
);
1399 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1400 listener_acquire_images(mock_listener
, initial_remote_global_image_ids
,
1403 // initial remote image list
1404 mock_image_map
->update_images("uuid1", std::move(initial_remote_global_image_ids
), {});
1406 ASSERT_TRUE(wait_for_map_update(1));
1407 ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack
.size()));
1409 // remote peer ACKs image acquire request
1410 remote_peer_ack_nowait(mock_image_map
.get(),
1411 initial_remote_global_image_ids_ack
, 0,
1413 wait_for_scheduled_task();
1415 // RELEASE+REMOVE_MAPPING
1416 std::map
<std::string
, Context
*> peer_remove_ack_ctxs
;
1417 listener_remove_images(mock_listener
, "uuid1", remote_removed_global_image_ids
,
1418 &peer_remove_ack_ctxs
);
1419 expect_add_event(mock_threads
);
1420 listener_release_images(mock_listener
, remote_removed_global_image_ids
,
1422 update_map_request(mock_threads
, mock_update_request
, remote_removed_global_image_ids
, 0);
1424 mock_image_map
->update_images("uuid1", {}, std::move(remote_removed_global_image_ids
));
1425 ASSERT_TRUE(wait_for_listener_notify(remote_removed_global_image_ids_ack
.size() * 2));
1427 remote_peer_ack_nowait(mock_image_map
.get(),
1428 remote_removed_global_image_ids_ack
, 0,
1429 &peer_remove_ack_ctxs
);
1430 remote_peer_ack_wait(mock_image_map
.get(),
1431 remote_removed_global_image_ids_ack
, 0,
1434 // UPDATE_MAPPING+ACQUIRE
1435 expect_add_event(mock_threads
);
1436 expect_update_request(mock_update_request
, 0);
1437 expect_add_event(mock_threads
);
1438 listener_acquire_images(mock_listener
, remote_added_global_image_ids
,
1441 mock_image_map
->update_images("uuid2", std::move(remote_added_global_image_ids
), {});
1443 ASSERT_TRUE(wait_for_map_update(1));
1444 ASSERT_TRUE(wait_for_listener_notify(remote_added_global_image_ids_ack
.size()));
1446 // remote peer ACKs image acquire request
1447 remote_peer_ack_nowait(mock_image_map
.get(),
1448 remote_added_global_image_ids_ack
, 0,
1451 wait_for_scheduled_task();
1452 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1455 TEST_F(TestMockImageMap
, RebalanceImageMap
) {
1456 MockThreads
mock_threads(m_threads
);
1457 expect_work_queue(mock_threads
);
1461 MockLoadRequest mock_load_request
;
1462 expect_load_request(mock_load_request
, 0);
1464 MockListener
mock_listener(this);
1466 std::unique_ptr
<MockImageMap
> mock_image_map
{
1467 MockImageMap::create(m_local_io_ctx
, &mock_threads
, m_local_instance_id
,
1471 mock_image_map
->init(&cond
);
1472 ASSERT_EQ(0, cond
.wait());
1474 std::set
<std::string
> global_image_ids
{
1475 "global id 1", "global id 2", "global id 3", "global id 4", "global id 5",
1476 "global id 6", "global id 7", "global id 8", "global id 9", "global id 10",
1478 std::set
<std::string
> global_image_ids_ack(global_image_ids
);
1480 // UPDATE_MAPPING+ACQUIRE
1481 expect_add_event(mock_threads
);
1482 MockUpdateRequest mock_update_request
;
1483 expect_update_request(mock_update_request
, 0);
1484 expect_add_event(mock_threads
);
1485 std::map
<std::string
, Context
*> peer_ack_ctxs
;
1486 listener_acquire_images(mock_listener
, global_image_ids
,
1489 // initial image list
1490 mock_image_map
->update_images("", std::move(global_image_ids
), {});
1492 ASSERT_TRUE(wait_for_map_update(1));
1493 ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack
.size()));
1495 // remote peer ACKs image acquire request
1496 remote_peer_ack_nowait(mock_image_map
.get(), global_image_ids_ack
, 0,
1498 wait_for_scheduled_task();
1500 mock_image_map
->update_instances_added({m_local_instance_id
});
1502 std::set
<std::string
> shuffled_global_image_ids
;
1504 // RELEASE+UPDATE_MAPPING+ACQUIRE
1505 expect_add_event(mock_threads
);
1506 expect_listener_images_unmapped(mock_listener
, 5, &shuffled_global_image_ids
,
1509 mock_image_map
->update_instances_added({"9876"});
1511 wait_for_scheduled_task();
1512 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1514 update_map_and_acquire(mock_threads
, mock_update_request
,
1515 mock_listener
, shuffled_global_image_ids
, 0,
1517 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1520 // completion shuffle action for now (re)mapped images
1521 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1524 wait_for_scheduled_task();
1526 // remove all shuffled images -- make way for rebalance
1527 std::set
<std::string
> shuffled_global_image_ids_ack(shuffled_global_image_ids
);
1529 // RELEASE+REMOVE_MAPPING
1530 expect_add_event(mock_threads
);
1531 listener_release_images(mock_listener
, shuffled_global_image_ids
,
1533 update_map_request(mock_threads
, mock_update_request
, shuffled_global_image_ids
,
1536 mock_image_map
->update_images("", {}, std::move(shuffled_global_image_ids
));
1537 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack
.size()));
1539 remote_peer_ack_wait(mock_image_map
.get(), shuffled_global_image_ids_ack
, 0,
1541 wait_for_scheduled_task();
1543 shuffled_global_image_ids
.clear();
1544 shuffled_global_image_ids_ack
.clear();
1546 std::set
<std::string
> new_global_image_ids
= {
1549 std::set
<std::string
> new_global_image_ids_ack(new_global_image_ids
);
1551 expect_add_event(mock_threads
);
1552 expect_update_request(mock_update_request
, 0);
1553 expect_add_event(mock_threads
);
1554 listener_acquire_images(mock_listener
, new_global_image_ids
, &peer_ack_ctxs
);
1556 expect_rebalance_event(mock_threads
); // rebalance task
1557 expect_add_event(mock_threads
); // update task scheduled by
1559 expect_listener_images_unmapped(mock_listener
, 2, &shuffled_global_image_ids
,
1562 mock_image_map
->update_images("", std::move(new_global_image_ids
), {});
1564 ASSERT_TRUE(wait_for_map_update(1));
1565 ASSERT_TRUE(wait_for_listener_notify(new_global_image_ids_ack
.size()));
1567 // set rebalance interval
1568 CephContext
*cct
= reinterpret_cast<CephContext
*>(m_local_io_ctx
.cct());
1569 cct
->_conf
.set_val("rbd_mirror_image_policy_rebalance_timeout", "5");
1570 remote_peer_ack_nowait(mock_image_map
.get(), new_global_image_ids_ack
, 0,
1573 wait_for_scheduled_task();
1574 ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids
.size()));
1576 update_map_and_acquire(mock_threads
, mock_update_request
,
1577 mock_listener
, shuffled_global_image_ids
, 0,
1579 remote_peer_ack_listener_wait(mock_image_map
.get(), shuffled_global_image_ids
,
1582 // completion shuffle action for now (re)mapped images
1583 remote_peer_ack_nowait(mock_image_map
.get(), shuffled_global_image_ids
, 0,
1586 wait_for_scheduled_task();
1587 ASSERT_EQ(0, when_shut_down(mock_image_map
.get()));
1590 } // namespace mirror