]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/rbd_mirror/test_mock_fixture.h" | |
5 | #include "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" | |
17 | ||
18 | namespace librbd { | |
19 | namespace { | |
20 | ||
21 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
22 | MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
23 | : librbd::MockImageCtx(image_ctx) { | |
24 | } | |
25 | }; | |
26 | ||
27 | } // anonymous namespace | |
28 | ||
29 | } // namespace librbd | |
30 | ||
31 | namespace rbd { | |
32 | namespace mirror { | |
33 | ||
34 | template <> | |
35 | struct Threads<librbd::MockTestImageCtx> { | |
36 | MockSafeTimer *timer; | |
9f95a23c | 37 | ceph::mutex &timer_lock; |
11fdf7f2 TL |
38 | |
39 | MockContextWQ *work_queue; | |
40 | ||
41 | Threads(Threads<librbd::ImageCtx> *threads) | |
42 | : timer(new MockSafeTimer()), | |
43 | timer_lock(threads->timer_lock), | |
44 | work_queue(new MockContextWQ()) { | |
45 | } | |
46 | ~Threads() { | |
47 | delete timer; | |
48 | delete work_queue; | |
49 | } | |
50 | }; | |
51 | ||
52 | namespace image_map { | |
53 | ||
54 | template <> | |
55 | struct LoadRequest<librbd::MockTestImageCtx> { | |
56 | std::map<std::string, cls::rbd::MirrorImageMap> *image_map; | |
57 | Context *on_finish = nullptr; | |
58 | ||
59 | static LoadRequest *s_instance; | |
60 | static LoadRequest *create(librados::IoCtx &ioctx, | |
61 | std::map<std::string, cls::rbd::MirrorImageMap> *image_map, | |
62 | Context *on_finish) { | |
63 | ceph_assert(s_instance != nullptr); | |
64 | s_instance->image_map = image_map; | |
65 | s_instance->on_finish = on_finish; | |
66 | return s_instance; | |
67 | } | |
68 | ||
69 | MOCK_METHOD0(send, void()); | |
70 | ||
71 | LoadRequest() { | |
72 | s_instance = this; | |
73 | } | |
74 | }; | |
75 | ||
76 | template <> | |
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, | |
83 | Context *on_finish) { | |
84 | ceph_assert(s_instance != nullptr); | |
85 | s_instance->on_finish = on_finish; | |
86 | return s_instance; | |
87 | } | |
88 | ||
89 | MOCK_METHOD0(send, void()); | |
90 | ||
91 | UpdateRequest() { | |
92 | s_instance = this; | |
93 | } | |
94 | }; | |
95 | ||
96 | LoadRequest<librbd::MockTestImageCtx> * | |
97 | LoadRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
98 | UpdateRequest<librbd::MockTestImageCtx> * | |
99 | UpdateRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
100 | ||
101 | } // namespace image_map | |
102 | ||
103 | } // namespace mirror | |
104 | } // namespace rbd | |
105 | ||
106 | // template definitions | |
107 | #include "tools/rbd_mirror/ImageMap.cc" | |
108 | ||
109 | namespace rbd { | |
110 | namespace mirror { | |
111 | ||
112 | using ::testing::_; | |
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; | |
120 | ||
121 | using image_map::Listener; | |
122 | using image_map::LoadRequest; | |
123 | using image_map::UpdateRequest; | |
124 | ||
125 | using ::rbd::mirror::Threads; | |
126 | ||
127 | class TestMockImageMap : public TestMockFixture { | |
128 | public: | |
129 | typedef Threads<librbd::MockTestImageCtx> MockThreads; | |
130 | typedef ImageMap<librbd::MockTestImageCtx> MockImageMap; | |
131 | typedef LoadRequest<librbd::MockTestImageCtx> MockLoadRequest; | |
132 | typedef UpdateRequest<librbd::MockTestImageCtx> MockUpdateRequest; | |
133 | ||
134 | struct MockListener : Listener { | |
135 | TestMockImageMap *test_mock_image_map; | |
136 | ||
137 | MockListener(TestMockImageMap *test_mock_image_map) | |
138 | : test_mock_image_map(test_mock_image_map) { | |
139 | } | |
140 | ||
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*)); | |
145 | ||
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); | |
149 | } | |
150 | ||
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); | |
154 | } | |
155 | ||
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); | |
160 | } | |
161 | }; | |
162 | ||
9f95a23c | 163 | TestMockImageMap() = default; |
11fdf7f2 TL |
164 | |
165 | void SetUp() override { | |
166 | TestFixture::SetUp(); | |
167 | ||
168 | m_local_instance_id = stringify(m_local_io_ctx.get_instance_id()); | |
169 | ||
170 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_image_policy_migration_throttle", | |
171 | "0")); | |
172 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_image_policy_type", "simple")); | |
173 | } | |
174 | ||
175 | void TearDown() override { | |
176 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_image_policy_type", "none")); | |
177 | ||
178 | TestFixture::TearDown(); | |
179 | } | |
180 | ||
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); | |
185 | })); | |
186 | } | |
187 | ||
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) { | |
9f95a23c TL |
191 | auto wrapped_ctx = new LambdaContext([this, ctx](int r) { |
192 | std::lock_guard timer_locker{m_threads->timer_lock}; | |
11fdf7f2 TL |
193 | ctx->complete(r); |
194 | }); | |
195 | m_threads->work_queue->queue(wrapped_ctx, 0); | |
196 | })), ReturnArg<1>())); | |
197 | } | |
198 | ||
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"); | |
205 | ||
9f95a23c TL |
206 | auto wrapped_ctx = new LambdaContext([this, ctx](int r) { |
207 | std::lock_guard timer_locker{m_threads->timer_lock}; | |
11fdf7f2 TL |
208 | ctx->complete(r); |
209 | }); | |
210 | m_threads->work_queue->queue(wrapped_ctx, 0); | |
211 | })), ReturnArg<1>())); | |
212 | } | |
213 | ||
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); | |
218 | })); | |
219 | } | |
220 | ||
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); | |
225 | if (r == 0) { | |
9f95a23c | 226 | std::lock_guard locker{m_lock}; |
11fdf7f2 | 227 | ++m_map_update_count; |
9f95a23c | 228 | m_cond.notify_all(); |
11fdf7f2 TL |
229 | } |
230 | })); | |
231 | } | |
232 | ||
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) { | |
9f95a23c | 238 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
239 | peer_ack_ctxs->insert({global_image_id, ctx}); |
240 | ++m_notify_update_count; | |
9f95a23c | 241 | m_cond.notify_all(); |
11fdf7f2 TL |
242 | }))); |
243 | } | |
244 | ||
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) { | |
9f95a23c | 250 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
251 | peer_ack_ctxs->insert({global_image_id, ctx}); |
252 | ++m_notify_update_count; | |
9f95a23c | 253 | m_cond.notify_all(); |
11fdf7f2 TL |
254 | }))); |
255 | } | |
256 | ||
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) { | |
9f95a23c | 264 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
265 | peer_ack_ctxs->insert({global_image_id, ctx}); |
266 | ++m_notify_update_count; | |
9f95a23c | 267 | m_cond.notify_all(); |
11fdf7f2 TL |
268 | }))); |
269 | } | |
270 | ||
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(_, _)) | |
275 | .Times(count) | |
276 | .WillRepeatedly(Invoke([this, global_image_ids, peer_ack_ctxs](std::string global_image_id, Context* ctx) { | |
9f95a23c | 277 | std::lock_guard locker{m_lock}; |
11fdf7f2 TL |
278 | global_image_ids->emplace(global_image_id); |
279 | peer_ack_ctxs->insert({global_image_id, ctx}); | |
280 | ++m_notify_update_count; | |
9f95a23c | 281 | m_cond.notify_all(); |
11fdf7f2 TL |
282 | })); |
283 | } | |
284 | ||
285 | void remote_peer_ack_nowait(MockImageMap *image_map, | |
286 | const std::set<std::string> &global_image_ids, | |
287 | int ret, | |
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(); | |
296 | } | |
297 | } | |
298 | ||
299 | void remote_peer_ack_wait(MockImageMap *image_map, | |
300 | const std::set<std::string> &global_image_ids, | |
301 | int ret, | |
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)); | |
311 | } | |
312 | } | |
313 | ||
314 | void remote_peer_ack_listener_wait(MockImageMap *image_map, | |
315 | const std::set<std::string> &global_image_ids, | |
316 | int ret, | |
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)); | |
326 | } | |
327 | } | |
328 | ||
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, | |
333 | int ret, | |
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, | |
340 | peer_ack_ctxs); | |
341 | } | |
342 | } | |
343 | ||
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); | |
350 | } | |
351 | } | |
352 | ||
353 | void wait_for_scheduled_task() { | |
354 | m_threads->work_queue->drain(); | |
355 | } | |
356 | ||
357 | bool wait_for_listener_notify(uint32_t count) { | |
9f95a23c | 358 | std::unique_lock locker{m_lock}; |
11fdf7f2 | 359 | while (m_notify_update_count < count) { |
9f95a23c | 360 | if (m_cond.wait_for(locker, 10s) == std::cv_status::timeout) { |
11fdf7f2 TL |
361 | break; |
362 | } | |
363 | } | |
364 | ||
365 | if (m_notify_update_count < count) { | |
366 | return false; | |
367 | } | |
368 | ||
369 | m_notify_update_count -= count; | |
370 | return true; | |
371 | } | |
372 | ||
373 | bool wait_for_map_update(uint32_t count) { | |
9f95a23c | 374 | std::unique_lock locker{m_lock}; |
11fdf7f2 | 375 | while (m_map_update_count < count) { |
9f95a23c | 376 | if (m_cond.wait_for(locker, 10s) == std::cv_status::timeout) { |
11fdf7f2 TL |
377 | break; |
378 | } | |
379 | } | |
380 | ||
381 | if (m_map_update_count < count) { | |
382 | return false; | |
383 | } | |
384 | ||
385 | m_map_update_count -= count; | |
386 | return true; | |
387 | } | |
388 | ||
389 | int when_shut_down(MockImageMap *image_map) { | |
390 | C_SaferCond ctx; | |
391 | image_map->shut_down(&ctx); | |
392 | return ctx.wait(); | |
393 | } | |
394 | ||
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, | |
400 | peer_ack_ctxs); | |
401 | } | |
402 | } | |
403 | ||
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, | |
409 | peer_ack_ctxs); | |
410 | } | |
411 | } | |
412 | ||
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, | |
419 | peer_ack_ctxs); | |
420 | } | |
421 | } | |
422 | ||
9f95a23c TL |
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; | |
11fdf7f2 TL |
427 | std::string m_local_instance_id; |
428 | }; | |
429 | ||
430 | TEST_F(TestMockImageMap, SetLocalImages) { | |
431 | MockThreads mock_threads(m_threads); | |
432 | expect_work_queue(mock_threads); | |
433 | ||
434 | InSequence seq; | |
435 | ||
436 | MockLoadRequest mock_load_request; | |
437 | expect_load_request(mock_load_request, 0); | |
438 | ||
439 | MockListener mock_listener(this); | |
440 | ||
441 | std::unique_ptr<MockImageMap> mock_image_map{ | |
442 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
443 | mock_listener)}; | |
444 | ||
445 | C_SaferCond cond; | |
446 | mock_image_map->init(&cond); | |
447 | ASSERT_EQ(0, cond.wait()); | |
448 | ||
449 | std::set<std::string> global_image_ids{ | |
450 | "global id 1", "global id 2" | |
451 | }; | |
452 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
453 | ||
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); | |
461 | ||
462 | // initial image list | |
463 | mock_image_map->update_images("", std::move(global_image_ids), {}); | |
464 | ||
465 | ASSERT_TRUE(wait_for_map_update(1)); | |
466 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
467 | ||
468 | // remote peer ACKs image acquire request | |
469 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
470 | &peer_ack_ctxs); | |
471 | ||
472 | wait_for_scheduled_task(); | |
473 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
474 | } | |
475 | ||
476 | TEST_F(TestMockImageMap, AddRemoveLocalImage) { | |
477 | MockThreads mock_threads(m_threads); | |
478 | expect_work_queue(mock_threads); | |
479 | ||
480 | InSequence seq; | |
481 | ||
482 | MockLoadRequest mock_load_request; | |
483 | expect_load_request(mock_load_request, 0); | |
484 | ||
485 | MockListener mock_listener(this); | |
486 | ||
487 | std::unique_ptr<MockImageMap> mock_image_map{ | |
488 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
489 | mock_listener)}; | |
490 | ||
491 | C_SaferCond cond; | |
492 | mock_image_map->init(&cond); | |
493 | ASSERT_EQ(0, cond.wait()); | |
494 | ||
495 | std::set<std::string> initial_global_image_ids{ | |
496 | "global id 1", "global id 2" | |
497 | }; | |
498 | std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids); | |
499 | ||
500 | std::set<std::string> remove_global_image_ids{ | |
501 | "global id 1", "global id 2" | |
502 | }; | |
503 | std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids); | |
504 | ||
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, | |
512 | &peer_ack_ctxs); | |
513 | ||
514 | // initial image list | |
515 | mock_image_map->update_images("", std::move(initial_global_image_ids), {}); | |
516 | ||
517 | ASSERT_TRUE(wait_for_map_update(1)); | |
518 | ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size())); | |
519 | ||
520 | // remote peer ACKs image acquire request | |
521 | remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0, | |
522 | &peer_ack_ctxs); | |
523 | ||
524 | // RELEASE+REMOVE_MAPPING | |
525 | expect_add_event(mock_threads); | |
526 | listener_release_images(mock_listener, remove_global_image_ids, | |
527 | &peer_ack_ctxs); | |
528 | update_map_request(mock_threads, mock_update_request, remove_global_image_ids, | |
529 | 0); | |
530 | ||
531 | // remove images | |
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())); | |
534 | ||
535 | remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids_ack, 0, | |
536 | &peer_ack_ctxs); | |
537 | ||
538 | wait_for_scheduled_task(); | |
539 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
540 | } | |
541 | ||
542 | TEST_F(TestMockImageMap, AddRemoveRemoteImage) { | |
543 | MockThreads mock_threads(m_threads); | |
544 | expect_work_queue(mock_threads); | |
545 | ||
546 | InSequence seq; | |
547 | ||
548 | MockLoadRequest mock_load_request; | |
549 | expect_load_request(mock_load_request, 0); | |
550 | ||
551 | MockListener mock_listener(this); | |
552 | ||
553 | std::unique_ptr<MockImageMap> mock_image_map{ | |
554 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
555 | mock_listener)}; | |
556 | ||
557 | C_SaferCond cond; | |
558 | mock_image_map->init(&cond); | |
559 | ASSERT_EQ(0, cond.wait()); | |
560 | ||
561 | std::set<std::string> initial_global_image_ids{ | |
562 | "global id 1", "global id 2" | |
563 | }; | |
564 | std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids); | |
565 | ||
566 | std::set<std::string> remove_global_image_ids{ | |
567 | "global id 1", "global id 2" | |
568 | }; | |
569 | std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids); | |
570 | ||
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, | |
578 | &peer_ack_ctxs); | |
579 | ||
580 | // initial image list | |
581 | mock_image_map->update_images("uuid1", std::move(initial_global_image_ids), | |
582 | {}); | |
583 | ||
584 | ASSERT_TRUE(wait_for_map_update(1)); | |
585 | ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size())); | |
586 | ||
587 | // remote peer ACKs image acquire request | |
588 | remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0, | |
589 | &peer_ack_ctxs); | |
590 | ||
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, | |
597 | &peer_ack_ctxs); | |
598 | update_map_request(mock_threads, mock_update_request, remove_global_image_ids, | |
599 | 0); | |
600 | ||
601 | // remove images | |
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)); | |
604 | ||
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, | |
608 | &peer_ack_ctxs); | |
609 | ||
610 | wait_for_scheduled_task(); | |
611 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
612 | } | |
613 | ||
614 | TEST_F(TestMockImageMap, AddRemoveRemoteImageDuplicateNotification) { | |
615 | MockThreads mock_threads(m_threads); | |
616 | expect_work_queue(mock_threads); | |
617 | ||
618 | InSequence seq; | |
619 | ||
620 | MockLoadRequest mock_load_request; | |
621 | expect_load_request(mock_load_request, 0); | |
622 | ||
623 | MockListener mock_listener(this); | |
624 | ||
625 | std::unique_ptr<MockImageMap> mock_image_map{ | |
626 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
627 | mock_listener)}; | |
628 | ||
629 | C_SaferCond cond; | |
630 | mock_image_map->init(&cond); | |
631 | ASSERT_EQ(0, cond.wait()); | |
632 | ||
633 | std::set<std::string> initial_global_image_ids{ | |
634 | "global id 1", "global id 2" | |
635 | }; | |
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); | |
638 | ||
639 | std::set<std::string> remove_global_image_ids{ | |
640 | "global id 1", "global id 2" | |
641 | }; | |
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); | |
644 | ||
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, | |
652 | &peer_ack_ctxs); | |
653 | ||
654 | // initial image list | |
655 | mock_image_map->update_images("uuid1", std::move(initial_global_image_ids), {}); | |
656 | ||
657 | ASSERT_TRUE(wait_for_map_update(1)); | |
658 | ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size())); | |
659 | ||
660 | // trigger duplicate "add" event | |
661 | wait_for_scheduled_task(); | |
662 | mock_image_map->update_images("uuid1", std::move(initial_global_image_ids_dup), {}); | |
663 | ||
664 | // remote peer ACKs image acquire request | |
665 | remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0, | |
666 | &peer_ack_ctxs); | |
667 | ||
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, | |
674 | &peer_ack_ctxs); | |
675 | update_map_request(mock_threads, mock_update_request, remove_global_image_ids, 0); | |
676 | ||
677 | // remove images | |
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)); | |
680 | ||
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, | |
684 | &peer_ack_ctxs); | |
685 | ||
686 | // trigger duplicate "remove" notification | |
687 | mock_image_map->update_images("uuid1", {}, std::move(remove_global_image_ids_dup)); | |
688 | ||
689 | wait_for_scheduled_task(); | |
690 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
691 | } | |
692 | ||
693 | TEST_F(TestMockImageMap, AcquireImageErrorRetry) { | |
694 | MockThreads mock_threads(m_threads); | |
695 | expect_work_queue(mock_threads); | |
696 | ||
697 | InSequence seq; | |
698 | ||
699 | MockLoadRequest mock_load_request; | |
700 | expect_load_request(mock_load_request, 0); | |
701 | ||
702 | MockListener mock_listener(this); | |
703 | ||
704 | std::unique_ptr<MockImageMap> mock_image_map{ | |
705 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
706 | mock_listener)}; | |
707 | ||
708 | C_SaferCond cond; | |
709 | mock_image_map->init(&cond); | |
710 | ASSERT_EQ(0, cond.wait()); | |
711 | ||
712 | std::set<std::string> initial_global_image_ids{ | |
713 | "global id 1", "global id 2" | |
714 | }; | |
715 | std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids); | |
716 | ||
717 | // UPDATE_MAPPING failure | |
718 | expect_add_event(mock_threads); | |
719 | MockUpdateRequest mock_update_request; | |
720 | expect_update_request(mock_update_request, -EIO); | |
721 | ||
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, | |
728 | &peer_ack_ctxs); | |
729 | ||
730 | // initial image list | |
731 | mock_image_map->update_images("uuid1", std::move(initial_global_image_ids), {}); | |
732 | ||
733 | ASSERT_TRUE(wait_for_map_update(1)); | |
734 | ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size())); | |
735 | ||
736 | // remote peer ACKs image acquire request | |
737 | remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0, | |
738 | &peer_ack_ctxs); | |
739 | ||
740 | wait_for_scheduled_task(); | |
741 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
742 | } | |
743 | ||
744 | TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) { | |
745 | MockThreads mock_threads(m_threads); | |
746 | expect_work_queue(mock_threads); | |
747 | ||
748 | InSequence seq; | |
749 | ||
750 | MockLoadRequest mock_load_request; | |
751 | expect_load_request(mock_load_request, 0); | |
752 | ||
753 | MockListener mock_listener(this); | |
754 | ||
755 | std::unique_ptr<MockImageMap> mock_image_map{ | |
756 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
757 | mock_listener)}; | |
758 | ||
759 | C_SaferCond cond; | |
760 | mock_image_map->init(&cond); | |
761 | ASSERT_EQ(0, cond.wait()); | |
762 | ||
763 | // remote image set | |
764 | std::set<std::string> initial_remote_global_image_ids{ | |
765 | "global id 1" | |
766 | }; | |
767 | std::set<std::string> initial_remote_global_image_ids_ack(initial_remote_global_image_ids); | |
768 | ||
769 | // local image set | |
770 | std::set<std::string> initial_local_global_image_ids{ | |
771 | "global id 1" | |
772 | }; | |
773 | ||
774 | // remote/local images to remove | |
775 | std::set<std::string> remote_remove_global_image_ids{ | |
776 | "global id 1" | |
777 | }; | |
778 | std::set<std::string> remote_remove_global_image_ids_ack(remote_remove_global_image_ids); | |
779 | ||
780 | std::set<std::string> local_remove_global_image_ids{ | |
781 | "global id 1" | |
782 | }; | |
783 | std::set<std::string> local_remove_global_image_ids_ack(local_remove_global_image_ids); | |
784 | ||
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, | |
792 | &peer_ack_ctxs); | |
793 | ||
794 | // initial remote image list | |
795 | mock_image_map->update_images("uuid1", std::move(initial_remote_global_image_ids), {}); | |
796 | ||
797 | ASSERT_TRUE(wait_for_map_update(1)); | |
798 | ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack.size())); | |
799 | ||
800 | // remote peer ACKs image acquire request | |
801 | remote_peer_ack_nowait(mock_image_map.get(), | |
802 | initial_remote_global_image_ids_ack, 0, | |
803 | &peer_ack_ctxs); | |
804 | ||
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), {}); | |
807 | ||
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); | |
813 | ||
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())); | |
816 | ||
817 | // RELEASE+REMOVE_MAPPING | |
818 | expect_add_event(mock_threads); | |
819 | listener_release_images(mock_listener, local_remove_global_image_ids, | |
820 | &peer_ack_ctxs); | |
821 | update_map_request(mock_threads, mock_update_request, local_remove_global_image_ids, 0); | |
822 | ||
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())); | |
826 | ||
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, | |
830 | 0, &peer_ack_ctxs); | |
831 | ||
832 | wait_for_scheduled_task(); | |
833 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
834 | } | |
835 | ||
836 | TEST_F(TestMockImageMap, AddInstance) { | |
837 | MockThreads mock_threads(m_threads); | |
838 | expect_work_queue(mock_threads); | |
839 | ||
840 | InSequence seq; | |
841 | ||
842 | MockLoadRequest mock_load_request; | |
843 | expect_load_request(mock_load_request, 0); | |
844 | ||
845 | MockListener mock_listener(this); | |
846 | ||
847 | std::unique_ptr<MockImageMap> mock_image_map{ | |
848 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
849 | mock_listener)}; | |
850 | ||
851 | C_SaferCond cond; | |
852 | mock_image_map->init(&cond); | |
853 | ASSERT_EQ(0, cond.wait()); | |
854 | ||
855 | std::set<std::string> global_image_ids{ | |
856 | "global id 1", "global id 2", "global id 3", "global id 4", "global id 5" | |
857 | }; | |
858 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
859 | ||
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, | |
867 | &peer_ack_ctxs); | |
868 | ||
869 | // initial image list | |
870 | mock_image_map->update_images("uuid1", std::move(global_image_ids), {}); | |
871 | ||
872 | ASSERT_TRUE(wait_for_map_update(1)); | |
873 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
874 | ||
875 | // remote peer ACKs image acquire request | |
876 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
877 | &peer_ack_ctxs); | |
878 | wait_for_scheduled_task(); | |
879 | ||
880 | mock_image_map->update_instances_added({m_local_instance_id}); | |
881 | ||
882 | std::set<std::string> shuffled_global_image_ids; | |
883 | ||
884 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
885 | expect_add_event(mock_threads); | |
886 | expect_listener_images_unmapped(mock_listener, 3, &shuffled_global_image_ids, | |
887 | &peer_ack_ctxs); | |
888 | ||
889 | mock_image_map->update_instances_added({"9876"}); | |
890 | ||
891 | wait_for_scheduled_task(); | |
892 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
893 | ||
894 | update_map_and_acquire(mock_threads, mock_update_request, | |
895 | mock_listener, shuffled_global_image_ids, 0, | |
896 | &peer_ack_ctxs); | |
897 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
898 | 0, &peer_ack_ctxs); | |
899 | ||
900 | // completion shuffle action for now (re)mapped images | |
901 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
902 | &peer_ack_ctxs); | |
903 | ||
904 | wait_for_scheduled_task(); | |
905 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
906 | } | |
907 | ||
908 | TEST_F(TestMockImageMap, RemoveInstance) { | |
909 | MockThreads mock_threads(m_threads); | |
910 | expect_work_queue(mock_threads); | |
911 | ||
912 | InSequence seq; | |
913 | ||
914 | MockLoadRequest mock_load_request; | |
915 | expect_load_request(mock_load_request, 0); | |
916 | ||
917 | MockListener mock_listener(this); | |
918 | ||
919 | std::unique_ptr<MockImageMap> mock_image_map{ | |
920 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
921 | mock_listener)}; | |
922 | ||
923 | C_SaferCond cond; | |
924 | mock_image_map->init(&cond); | |
925 | ASSERT_EQ(0, cond.wait()); | |
926 | ||
927 | std::set<std::string> global_image_ids{ | |
928 | "global id 1", "global id 2", "global id 3", "global id 4", "global id 5" | |
929 | }; | |
930 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
931 | ||
932 | expect_add_event(mock_threads); | |
933 | ||
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, | |
940 | &peer_ack_ctxs); | |
941 | ||
942 | // set initial image list | |
943 | mock_image_map->update_images("uuid1", std::move(global_image_ids), {}); | |
944 | ||
945 | ASSERT_TRUE(wait_for_map_update(1)); | |
946 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
947 | ||
948 | // remote peer ACKs image acquire request -- completing action | |
949 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
950 | &peer_ack_ctxs); | |
951 | wait_for_scheduled_task(); | |
952 | ||
953 | mock_image_map->update_instances_added({m_local_instance_id}); | |
954 | ||
955 | std::set<std::string> shuffled_global_image_ids; | |
956 | ||
957 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
958 | expect_add_event(mock_threads); | |
959 | expect_listener_images_unmapped(mock_listener, 3, &shuffled_global_image_ids, | |
960 | &peer_ack_ctxs); | |
961 | ||
962 | mock_image_map->update_instances_added({"9876"}); | |
963 | ||
964 | wait_for_scheduled_task(); | |
965 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
966 | ||
967 | update_map_and_acquire(mock_threads, mock_update_request, | |
968 | mock_listener, shuffled_global_image_ids, 0, | |
969 | &peer_ack_ctxs); | |
970 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
971 | 0, &peer_ack_ctxs); | |
972 | ||
973 | // completion shuffle action for now (re)mapped images | |
974 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
975 | &peer_ack_ctxs); | |
976 | wait_for_scheduled_task(); | |
977 | ||
978 | shuffled_global_image_ids.clear(); | |
979 | ||
980 | // remove added instance | |
981 | expect_add_event(mock_threads); | |
982 | expect_listener_images_unmapped(mock_listener, 2, &shuffled_global_image_ids, | |
983 | &peer_ack_ctxs); | |
984 | ||
985 | mock_image_map->update_instances_removed({"9876"}); | |
986 | ||
987 | wait_for_scheduled_task(); | |
988 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
989 | ||
990 | update_map_and_acquire(mock_threads, mock_update_request, | |
991 | mock_listener, shuffled_global_image_ids, 0, | |
992 | &peer_ack_ctxs); | |
993 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
994 | 0, &peer_ack_ctxs); | |
995 | ||
996 | // completion shuffle action for now (re)mapped images | |
997 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
998 | &peer_ack_ctxs); | |
999 | ||
1000 | wait_for_scheduled_task(); | |
1001 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1002 | } | |
1003 | ||
1004 | TEST_F(TestMockImageMap, AddInstancePingPongImageTest) { | |
1005 | EXPECT_EQ(0, _rados->conf_set("rbd_mirror_image_policy_migration_throttle", "600")); | |
1006 | ||
1007 | MockThreads mock_threads(m_threads); | |
1008 | expect_work_queue(mock_threads); | |
1009 | ||
1010 | InSequence seq; | |
1011 | ||
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" | |
1016 | }; | |
1017 | ||
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, {}, {}}; | |
1021 | } | |
1022 | ||
1023 | // ACQUIRE | |
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); | |
1029 | })); | |
1030 | ||
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, | |
1035 | &peer_ack_ctxs); | |
1036 | ||
1037 | std::unique_ptr<MockImageMap> mock_image_map{ | |
1038 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
1039 | mock_listener)}; | |
1040 | ||
1041 | C_SaferCond cond; | |
1042 | mock_image_map->init(&cond); | |
1043 | ASSERT_EQ(0, cond.wait()); | |
1044 | ||
1045 | mock_image_map->update_instances_added({m_local_instance_id}); | |
1046 | ||
1047 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
1048 | ||
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, | |
1052 | &peer_ack_ctxs); | |
1053 | wait_for_scheduled_task(); | |
1054 | ||
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, | |
1061 | &peer_ack_ctxs); | |
1062 | ||
1063 | // set initial image list | |
1064 | mock_image_map->update_images("uuid1", std::move(global_image_ids), {}); | |
1065 | ||
1066 | ASSERT_TRUE(wait_for_map_update(1)); | |
1067 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
1068 | ||
1069 | // remote peer ACKs image acquire request -- completing action | |
1070 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
1071 | &peer_ack_ctxs); | |
1072 | wait_for_scheduled_task(); | |
1073 | ||
1074 | std::set<std::string> shuffled_global_image_ids; | |
1075 | ||
1076 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
1077 | expect_add_event(mock_threads); | |
1078 | expect_listener_images_unmapped(mock_listener, 7, &shuffled_global_image_ids, | |
1079 | &peer_ack_ctxs); | |
1080 | ||
1081 | mock_image_map->update_instances_added({"9876"}); | |
1082 | ||
1083 | wait_for_scheduled_task(); | |
1084 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1085 | ||
1086 | update_map_and_acquire(mock_threads, mock_update_request, | |
1087 | mock_listener, shuffled_global_image_ids, 0, | |
1088 | &peer_ack_ctxs); | |
1089 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1090 | 0, &peer_ack_ctxs); | |
1091 | ||
1092 | // completion shuffle action for now (re)mapped images | |
1093 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
1094 | &peer_ack_ctxs); | |
1095 | wait_for_scheduled_task(); | |
1096 | ||
1097 | std::set<std::string> migrated_global_image_ids(shuffled_global_image_ids); | |
1098 | shuffled_global_image_ids.clear(); | |
1099 | ||
1100 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
1101 | expect_add_event(mock_threads); | |
1102 | expect_listener_images_unmapped(mock_listener, 3, &shuffled_global_image_ids, | |
1103 | &peer_ack_ctxs); | |
1104 | ||
1105 | // add another instance | |
1106 | mock_image_map->update_instances_added({"5432"}); | |
1107 | ||
1108 | wait_for_scheduled_task(); | |
1109 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1110 | ||
1111 | update_map_and_acquire(mock_threads, mock_update_request, | |
1112 | mock_listener, shuffled_global_image_ids, 0, | |
1113 | &peer_ack_ctxs); | |
1114 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1115 | 0, &peer_ack_ctxs); | |
1116 | ||
1117 | // completion shuffle action for now (re)mapped images | |
1118 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
1119 | &peer_ack_ctxs); | |
1120 | ||
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()); | |
1127 | ||
1128 | wait_for_scheduled_task(); | |
1129 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1130 | } | |
1131 | ||
1132 | TEST_F(TestMockImageMap, RemoveInstanceWithRemoveImage) { | |
1133 | MockThreads mock_threads(m_threads); | |
1134 | expect_work_queue(mock_threads); | |
1135 | ||
1136 | InSequence seq; | |
1137 | ||
1138 | MockLoadRequest mock_load_request; | |
1139 | expect_load_request(mock_load_request, 0); | |
1140 | ||
1141 | MockListener mock_listener(this); | |
1142 | ||
1143 | std::unique_ptr<MockImageMap> mock_image_map{ | |
1144 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
1145 | mock_listener)}; | |
1146 | ||
1147 | C_SaferCond cond; | |
1148 | mock_image_map->init(&cond); | |
1149 | ASSERT_EQ(0, cond.wait()); | |
1150 | ||
1151 | std::set<std::string> global_image_ids{ | |
1152 | "global id 1", "global id 2", "global id 3", "remote id 4", | |
1153 | }; | |
1154 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
1155 | ||
1156 | std::set<std::string> remove_global_image_ids{ | |
1157 | "global id 1" | |
1158 | }; | |
1159 | std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids); | |
1160 | ||
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, | |
1168 | &peer_ack_ctxs); | |
1169 | ||
1170 | // initial image list | |
1171 | mock_image_map->update_images("uuid1", std::move(global_image_ids), {}); | |
1172 | ||
1173 | ASSERT_TRUE(wait_for_map_update(1)); | |
1174 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
1175 | ||
1176 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
1177 | &peer_ack_ctxs); | |
1178 | wait_for_scheduled_task(); | |
1179 | ||
1180 | mock_image_map->update_instances_added({m_local_instance_id}); | |
1181 | ||
1182 | std::set<std::string> shuffled_global_image_ids; | |
1183 | ||
1184 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
1185 | expect_add_event(mock_threads); | |
1186 | expect_listener_images_unmapped(mock_listener, 2, &shuffled_global_image_ids, | |
1187 | &peer_ack_ctxs); | |
1188 | ||
1189 | mock_image_map->update_instances_added({"9876"}); | |
1190 | ||
1191 | wait_for_scheduled_task(); | |
1192 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1193 | ||
1194 | update_map_and_acquire(mock_threads, mock_update_request, | |
1195 | mock_listener, shuffled_global_image_ids, 0, | |
1196 | &peer_ack_ctxs); | |
1197 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1198 | 0, &peer_ack_ctxs); | |
1199 | ||
1200 | // completion shuffle action for now (re)mapped images | |
1201 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
1202 | &peer_ack_ctxs); | |
1203 | wait_for_scheduled_task(); | |
1204 | ||
1205 | std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids); | |
1206 | ||
1207 | // RELEASE | |
1208 | ||
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, | |
1214 | &peer_ack_ctxs); | |
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); | |
1219 | ||
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)); | |
1222 | ||
1223 | // instance failed -- update policy for instance removal | |
1224 | mock_image_map->update_instances_removed({"9876"}); | |
1225 | ||
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, | |
f67539c2 | 1229 | -EBLOCKLISTED, &peer_ack_ctxs); |
11fdf7f2 TL |
1230 | |
1231 | wait_for_scheduled_task(); | |
1232 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1233 | } | |
1234 | ||
1235 | TEST_F(TestMockImageMap, AddErrorAndRemoveImage) { | |
1236 | MockThreads mock_threads(m_threads); | |
1237 | expect_work_queue(mock_threads); | |
1238 | ||
1239 | InSequence seq; | |
1240 | ||
1241 | MockLoadRequest mock_load_request; | |
1242 | expect_load_request(mock_load_request, 0); | |
1243 | ||
1244 | MockListener mock_listener(this); | |
1245 | ||
1246 | std::unique_ptr<MockImageMap> mock_image_map{ | |
1247 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
1248 | mock_listener)}; | |
1249 | ||
1250 | C_SaferCond cond; | |
1251 | mock_image_map->init(&cond); | |
1252 | ASSERT_EQ(0, cond.wait()); | |
1253 | ||
1254 | mock_image_map->update_instances_added({m_local_instance_id}); | |
1255 | ||
1256 | std::set<std::string> global_image_ids{ | |
1257 | "global id 1", "global id 2", "global id 3", "remote id 4", | |
1258 | }; | |
1259 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
1260 | ||
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, | |
1268 | &peer_ack_ctxs); | |
1269 | ||
1270 | // initial image list | |
1271 | mock_image_map->update_images("uuid1", std::move(global_image_ids), {}); | |
1272 | ||
1273 | ASSERT_TRUE(wait_for_map_update(1)); | |
1274 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
1275 | ||
1276 | // remote peer ACKs image acquire request | |
1277 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
1278 | &peer_ack_ctxs); | |
1279 | wait_for_scheduled_task(); | |
1280 | ||
1281 | std::set<std::string> shuffled_global_image_ids; | |
1282 | ||
1283 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
1284 | expect_add_event(mock_threads); | |
1285 | expect_listener_images_unmapped(mock_listener, 2, &shuffled_global_image_ids, | |
1286 | &peer_ack_ctxs); | |
1287 | ||
1288 | mock_image_map->update_instances_added({"9876"}); | |
1289 | ||
1290 | wait_for_scheduled_task(); | |
1291 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1292 | ||
1293 | update_map_and_acquire(mock_threads, mock_update_request, | |
1294 | mock_listener, shuffled_global_image_ids, 0, | |
1295 | &peer_ack_ctxs); | |
1296 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1297 | 0, &peer_ack_ctxs); | |
1298 | wait_for_scheduled_task(); | |
1299 | ||
1300 | mock_image_map->update_instances_removed({"9876"}); | |
1301 | ||
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); | |
1310 | ||
f67539c2 | 1311 | // instance blocklisted -- ACQUIRE request fails |
11fdf7f2 | 1312 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, |
f67539c2 | 1313 | -EBLOCKLISTED, &peer_ack_ctxs); |
11fdf7f2 TL |
1314 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); |
1315 | ||
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); | |
1320 | ||
f67539c2 | 1321 | // instance blocklisted -- RELEASE request fails |
11fdf7f2 TL |
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(); | |
1325 | ||
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(); | |
1330 | ||
1331 | std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids); | |
1332 | ||
1333 | // remove image | |
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, | |
1339 | &peer_ack_ctxs); | |
1340 | update_map_request(mock_threads, mock_update_request, shuffled_global_image_ids, 0); | |
1341 | ||
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)); | |
1344 | ||
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, | |
1348 | &peer_ack_ctxs); | |
1349 | ||
1350 | wait_for_scheduled_task(); | |
1351 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1352 | } | |
1353 | ||
1354 | TEST_F(TestMockImageMap, MirrorUUIDUpdated) { | |
1355 | MockThreads mock_threads(m_threads); | |
1356 | expect_work_queue(mock_threads); | |
1357 | ||
1358 | InSequence seq; | |
1359 | ||
1360 | MockLoadRequest mock_load_request; | |
1361 | expect_load_request(mock_load_request, 0); | |
1362 | ||
1363 | MockListener mock_listener(this); | |
1364 | ||
1365 | std::unique_ptr<MockImageMap> mock_image_map{ | |
1366 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
1367 | mock_listener)}; | |
1368 | ||
1369 | C_SaferCond cond; | |
1370 | mock_image_map->init(&cond); | |
1371 | ASSERT_EQ(0, cond.wait()); | |
1372 | ||
1373 | // remote image set | |
1374 | std::set<std::string> initial_remote_global_image_ids{ | |
1375 | "global id 1", "global id 2", "global id 3" | |
1376 | }; | |
1377 | std::set<std::string> initial_remote_global_image_ids_ack(initial_remote_global_image_ids); | |
1378 | ||
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" | |
1382 | }; | |
1383 | std::set<std::string> remote_removed_global_image_ids_ack(remote_removed_global_image_ids); | |
1384 | ||
1385 | std::set<std::string> remote_added_global_image_ids{ | |
1386 | "global id 1", "global id 2", "global id 3" | |
1387 | }; | |
1388 | std::set<std::string> remote_added_global_image_ids_ack(remote_added_global_image_ids); | |
1389 | ||
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, | |
1397 | &peer_ack_ctxs); | |
1398 | ||
1399 | // initial remote image list | |
1400 | mock_image_map->update_images("uuid1", std::move(initial_remote_global_image_ids), {}); | |
1401 | ||
1402 | ASSERT_TRUE(wait_for_map_update(1)); | |
1403 | ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack.size())); | |
1404 | ||
1405 | // remote peer ACKs image acquire request | |
1406 | remote_peer_ack_nowait(mock_image_map.get(), | |
1407 | initial_remote_global_image_ids_ack, 0, | |
1408 | &peer_ack_ctxs); | |
1409 | wait_for_scheduled_task(); | |
1410 | ||
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, | |
1417 | &peer_ack_ctxs); | |
1418 | update_map_request(mock_threads, mock_update_request, remote_removed_global_image_ids, 0); | |
1419 | ||
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)); | |
1422 | ||
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, | |
1428 | &peer_ack_ctxs); | |
1429 | ||
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, | |
1435 | &peer_ack_ctxs); | |
1436 | ||
1437 | mock_image_map->update_images("uuid2", std::move(remote_added_global_image_ids), {}); | |
1438 | ||
1439 | ASSERT_TRUE(wait_for_map_update(1)); | |
1440 | ASSERT_TRUE(wait_for_listener_notify(remote_added_global_image_ids_ack.size())); | |
1441 | ||
1442 | // remote peer ACKs image acquire request | |
1443 | remote_peer_ack_nowait(mock_image_map.get(), | |
1444 | remote_added_global_image_ids_ack, 0, | |
1445 | &peer_ack_ctxs); | |
1446 | ||
1447 | wait_for_scheduled_task(); | |
1448 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1449 | } | |
1450 | ||
1451 | TEST_F(TestMockImageMap, RebalanceImageMap) { | |
1452 | MockThreads mock_threads(m_threads); | |
1453 | expect_work_queue(mock_threads); | |
1454 | ||
1455 | InSequence seq; | |
1456 | ||
1457 | MockLoadRequest mock_load_request; | |
1458 | expect_load_request(mock_load_request, 0); | |
1459 | ||
1460 | MockListener mock_listener(this); | |
1461 | ||
1462 | std::unique_ptr<MockImageMap> mock_image_map{ | |
1463 | MockImageMap::create(m_local_io_ctx, &mock_threads, m_local_instance_id, | |
1464 | mock_listener)}; | |
1465 | ||
1466 | C_SaferCond cond; | |
1467 | mock_image_map->init(&cond); | |
1468 | ASSERT_EQ(0, cond.wait()); | |
1469 | ||
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", | |
1473 | }; | |
1474 | std::set<std::string> global_image_ids_ack(global_image_ids); | |
1475 | ||
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, | |
1483 | &peer_ack_ctxs); | |
1484 | ||
1485 | // initial image list | |
1486 | mock_image_map->update_images("", std::move(global_image_ids), {}); | |
1487 | ||
1488 | ASSERT_TRUE(wait_for_map_update(1)); | |
1489 | ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size())); | |
1490 | ||
1491 | // remote peer ACKs image acquire request | |
1492 | remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0, | |
1493 | &peer_ack_ctxs); | |
1494 | wait_for_scheduled_task(); | |
1495 | ||
1496 | mock_image_map->update_instances_added({m_local_instance_id}); | |
1497 | ||
1498 | std::set<std::string> shuffled_global_image_ids; | |
1499 | ||
1500 | // RELEASE+UPDATE_MAPPING+ACQUIRE | |
1501 | expect_add_event(mock_threads); | |
1502 | expect_listener_images_unmapped(mock_listener, 5, &shuffled_global_image_ids, | |
1503 | &peer_ack_ctxs); | |
1504 | ||
1505 | mock_image_map->update_instances_added({"9876"}); | |
1506 | ||
1507 | wait_for_scheduled_task(); | |
1508 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1509 | ||
1510 | update_map_and_acquire(mock_threads, mock_update_request, | |
1511 | mock_listener, shuffled_global_image_ids, 0, | |
1512 | &peer_ack_ctxs); | |
1513 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1514 | 0, &peer_ack_ctxs); | |
1515 | ||
1516 | // completion shuffle action for now (re)mapped images | |
1517 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
1518 | &peer_ack_ctxs); | |
1519 | ||
1520 | wait_for_scheduled_task(); | |
1521 | ||
1522 | // remove all shuffled images -- make way for rebalance | |
1523 | std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids); | |
1524 | ||
1525 | // RELEASE+REMOVE_MAPPING | |
1526 | expect_add_event(mock_threads); | |
1527 | listener_release_images(mock_listener, shuffled_global_image_ids, | |
1528 | &peer_ack_ctxs); | |
1529 | update_map_request(mock_threads, mock_update_request, shuffled_global_image_ids, | |
1530 | 0); | |
1531 | ||
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())); | |
1534 | ||
1535 | remote_peer_ack_wait(mock_image_map.get(), shuffled_global_image_ids_ack, 0, | |
1536 | &peer_ack_ctxs); | |
1537 | wait_for_scheduled_task(); | |
1538 | ||
1539 | shuffled_global_image_ids.clear(); | |
1540 | shuffled_global_image_ids_ack.clear(); | |
1541 | ||
1542 | std::set<std::string> new_global_image_ids = { | |
1543 | "global id 11" | |
1544 | }; | |
1545 | std::set<std::string> new_global_image_ids_ack(new_global_image_ids); | |
1546 | ||
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); | |
1551 | ||
1552 | expect_rebalance_event(mock_threads); // rebalance task | |
1553 | expect_add_event(mock_threads); // update task scheduled by | |
1554 | // rebalance task | |
1555 | expect_listener_images_unmapped(mock_listener, 2, &shuffled_global_image_ids, | |
1556 | &peer_ack_ctxs); | |
1557 | ||
1558 | mock_image_map->update_images("", std::move(new_global_image_ids), {}); | |
1559 | ||
1560 | ASSERT_TRUE(wait_for_map_update(1)); | |
1561 | ASSERT_TRUE(wait_for_listener_notify(new_global_image_ids_ack.size())); | |
1562 | ||
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, | |
1567 | &peer_ack_ctxs); | |
1568 | ||
1569 | wait_for_scheduled_task(); | |
1570 | ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size())); | |
1571 | ||
1572 | update_map_and_acquire(mock_threads, mock_update_request, | |
1573 | mock_listener, shuffled_global_image_ids, 0, | |
1574 | &peer_ack_ctxs); | |
1575 | remote_peer_ack_listener_wait(mock_image_map.get(), shuffled_global_image_ids, | |
1576 | 0, &peer_ack_ctxs); | |
1577 | ||
1578 | // completion shuffle action for now (re)mapped images | |
1579 | remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0, | |
1580 | &peer_ack_ctxs); | |
1581 | ||
1582 | wait_for_scheduled_task(); | |
1583 | ASSERT_EQ(0, when_shut_down(mock_image_map.get())); | |
1584 | } | |
1585 | ||
1586 | } // namespace mirror | |
1587 | } // namespace rbd |