]>
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/librbd/test_mock_fixture.h" | |
5 | #include "include/rbd/librbd.hpp" | |
6 | #include "librbd/ImageCtx.h" | |
7 | #include "librbd/ImageState.h" | |
9f95a23c | 8 | #include "librbd/internal.h" |
11fdf7f2 | 9 | #include "librbd/Operations.h" |
1911f103 | 10 | #include "librbd/deep_copy/Handler.h" |
11fdf7f2 TL |
11 | #include "librbd/deep_copy/ImageCopyRequest.h" |
12 | #include "librbd/deep_copy/ObjectCopyRequest.h" | |
13 | #include "librbd/image/CloseRequest.h" | |
14 | #include "librbd/image/OpenRequest.h" | |
9f95a23c | 15 | #include "librbd/object_map/DiffRequest.h" |
11fdf7f2 TL |
16 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" |
17 | #include "test/librbd/mock/MockImageCtx.h" | |
18 | #include "test/librbd/test_support.h" | |
19 | #include <boost/scope_exit.hpp> | |
20 | ||
21 | namespace librbd { | |
22 | ||
23 | namespace { | |
24 | ||
25 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
26 | static MockTestImageCtx* s_instance; | |
27 | static MockTestImageCtx* create(const std::string &image_name, | |
28 | const std::string &image_id, | |
29 | librados::snap_t snap_id, librados::IoCtx& p, | |
30 | bool read_only) { | |
31 | ceph_assert(s_instance != nullptr); | |
32 | return s_instance; | |
33 | } | |
34 | ||
35 | explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
36 | : librbd::MockImageCtx(image_ctx) { | |
37 | s_instance = this; | |
38 | } | |
39 | ||
40 | MOCK_METHOD0(destroy, void()); | |
41 | }; | |
42 | ||
43 | MockTestImageCtx* MockTestImageCtx::s_instance = nullptr; | |
44 | ||
45 | } // anonymous namespace | |
46 | ||
47 | namespace deep_copy { | |
48 | ||
49 | template <> | |
50 | struct ObjectCopyRequest<librbd::MockTestImageCtx> { | |
51 | static ObjectCopyRequest* s_instance; | |
52 | static ObjectCopyRequest* create( | |
53 | librbd::MockTestImageCtx *src_image_ctx, | |
9f95a23c TL |
54 | librbd::MockTestImageCtx *dst_image_ctx, |
55 | librados::snap_t src_snap_id_start, | |
56 | librados::snap_t dst_snap_id_start, | |
57 | const SnapMap &snap_map, | |
cd265ab1 | 58 | uint64_t object_number, uint32_t flags, Handler* handler, |
1911f103 | 59 | Context *on_finish) { |
11fdf7f2 | 60 | ceph_assert(s_instance != nullptr); |
9f95a23c | 61 | std::lock_guard locker{s_instance->lock}; |
11fdf7f2 TL |
62 | s_instance->snap_map = &snap_map; |
63 | s_instance->object_contexts[object_number] = on_finish; | |
9f95a23c | 64 | s_instance->cond.notify_all(); |
11fdf7f2 TL |
65 | return s_instance; |
66 | } | |
67 | ||
68 | MOCK_METHOD0(send, void()); | |
69 | ||
9f95a23c TL |
70 | ceph::mutex lock = ceph::make_mutex("lock"); |
71 | ceph::condition_variable cond; | |
11fdf7f2 TL |
72 | |
73 | const SnapMap *snap_map = nullptr; | |
74 | std::map<uint64_t, Context *> object_contexts; | |
75 | ||
9f95a23c | 76 | ObjectCopyRequest() { |
11fdf7f2 TL |
77 | s_instance = this; |
78 | } | |
79 | }; | |
80 | ||
81 | ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
82 | ||
83 | } // namespace deep_copy | |
84 | ||
85 | namespace image { | |
86 | ||
87 | template <> | |
88 | struct CloseRequest<MockTestImageCtx> { | |
89 | Context* on_finish = nullptr; | |
90 | static CloseRequest* s_instance; | |
91 | static CloseRequest* create(MockTestImageCtx *image_ctx, Context *on_finish) { | |
92 | ceph_assert(s_instance != nullptr); | |
93 | s_instance->on_finish = on_finish; | |
94 | return s_instance; | |
95 | } | |
96 | ||
97 | MOCK_METHOD0(send, void()); | |
98 | ||
99 | CloseRequest() { | |
100 | s_instance = this; | |
101 | } | |
102 | }; | |
103 | ||
104 | CloseRequest<MockTestImageCtx>* CloseRequest<MockTestImageCtx>::s_instance = nullptr; | |
105 | ||
106 | template <> | |
107 | struct OpenRequest<MockTestImageCtx> { | |
108 | Context* on_finish = nullptr; | |
109 | static OpenRequest* s_instance; | |
110 | static OpenRequest* create(MockTestImageCtx *image_ctx, | |
111 | bool skip_open_parent, Context *on_finish) { | |
112 | ceph_assert(s_instance != nullptr); | |
113 | s_instance->on_finish = on_finish; | |
114 | return s_instance; | |
115 | } | |
116 | ||
117 | MOCK_METHOD0(send, void()); | |
118 | ||
119 | OpenRequest() { | |
120 | s_instance = this; | |
121 | } | |
122 | }; | |
123 | ||
124 | OpenRequest<MockTestImageCtx>* OpenRequest<MockTestImageCtx>::s_instance = nullptr; | |
125 | ||
126 | } // namespace image | |
127 | ||
9f95a23c TL |
128 | namespace object_map { |
129 | ||
130 | template <> | |
131 | struct DiffRequest<MockTestImageCtx> { | |
132 | BitVector<2>* object_diff_state = nullptr; | |
133 | Context* on_finish = nullptr; | |
134 | static DiffRequest* s_instance; | |
135 | static DiffRequest* create(MockTestImageCtx *image_ctx, | |
136 | uint64_t snap_id_start, uint64_t snap_id_end, | |
137 | BitVector<2>* object_diff_state, | |
138 | Context* on_finish) { | |
139 | ceph_assert(s_instance != nullptr); | |
140 | s_instance->object_diff_state = object_diff_state; | |
141 | s_instance->on_finish = on_finish; | |
142 | return s_instance; | |
143 | } | |
144 | ||
145 | DiffRequest() { | |
146 | s_instance = this; | |
147 | } | |
148 | ||
149 | MOCK_METHOD0(send, void()); | |
150 | }; | |
151 | ||
152 | DiffRequest<MockTestImageCtx>* DiffRequest<MockTestImageCtx>::s_instance = nullptr; | |
153 | ||
154 | } // namespace object_map | |
11fdf7f2 TL |
155 | } // namespace librbd |
156 | ||
157 | // template definitions | |
158 | #include "librbd/deep_copy/ImageCopyRequest.cc" | |
159 | template class librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx>; | |
160 | ||
161 | namespace librbd { | |
162 | namespace deep_copy { | |
163 | ||
164 | using ::testing::_; | |
165 | using ::testing::InSequence; | |
9f95a23c | 166 | using ::testing::Invoke; |
11fdf7f2 TL |
167 | using ::testing::Return; |
168 | ||
169 | class TestMockDeepCopyImageCopyRequest : public TestMockFixture { | |
170 | public: | |
171 | typedef ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest; | |
172 | typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest; | |
9f95a23c | 173 | typedef object_map::DiffRequest<librbd::MockTestImageCtx> MockDiffRequest; |
11fdf7f2 TL |
174 | |
175 | librbd::ImageCtx *m_src_image_ctx; | |
176 | librbd::ImageCtx *m_dst_image_ctx; | |
177 | ThreadPool *m_thread_pool; | |
178 | ContextWQ *m_work_queue; | |
179 | librbd::SnapSeqs m_snap_seqs; | |
180 | SnapMap m_snap_map; | |
181 | ||
182 | void SetUp() override { | |
183 | TestMockFixture::SetUp(); | |
184 | ||
185 | ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx)); | |
186 | ||
187 | librbd::RBD rbd; | |
188 | std::string dst_image_name = get_temp_image_name(); | |
189 | ASSERT_EQ(0, create_image_pp(rbd, m_ioctx, dst_image_name, m_image_size)); | |
190 | ASSERT_EQ(0, open_image(dst_image_name, &m_dst_image_ctx)); | |
191 | ||
192 | librbd::ImageCtx::get_thread_pool_instance(m_src_image_ctx->cct, | |
193 | &m_thread_pool, &m_work_queue); | |
194 | } | |
195 | ||
196 | void expect_get_image_size(librbd::MockTestImageCtx &mock_image_ctx, | |
197 | uint64_t size) { | |
198 | EXPECT_CALL(mock_image_ctx, get_image_size(_)) | |
199 | .WillOnce(Return(size)).RetiresOnSaturation(); | |
200 | } | |
201 | ||
9f95a23c TL |
202 | void expect_diff_send(MockDiffRequest& mock_request, |
203 | const BitVector<2>& diff_state, int r) { | |
204 | EXPECT_CALL(mock_request, send()) | |
205 | .WillOnce(Invoke([this, &mock_request, diff_state, r]() { | |
206 | if (r >= 0) { | |
207 | *mock_request.object_diff_state = diff_state; | |
208 | } | |
209 | m_work_queue->queue(mock_request.on_finish, r); | |
210 | })); | |
211 | } | |
212 | ||
11fdf7f2 TL |
213 | void expect_object_copy_send(MockObjectCopyRequest &mock_object_copy_request) { |
214 | EXPECT_CALL(mock_object_copy_request, send()); | |
215 | } | |
216 | ||
217 | bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request, | |
218 | uint64_t object_num, Context **object_ctx, int r) { | |
9f95a23c | 219 | std::unique_lock locker{mock_object_copy_request.lock}; |
11fdf7f2 | 220 | while (mock_object_copy_request.object_contexts.count(object_num) == 0) { |
9f95a23c TL |
221 | if (mock_object_copy_request.cond.wait_for(locker, 10s) == |
222 | std::cv_status::timeout) { | |
11fdf7f2 TL |
223 | return false; |
224 | } | |
225 | } | |
226 | ||
227 | if (object_ctx != nullptr) { | |
228 | *object_ctx = mock_object_copy_request.object_contexts[object_num]; | |
229 | } else { | |
230 | m_work_queue->queue(mock_object_copy_request.object_contexts[object_num], | |
231 | r); | |
232 | } | |
233 | return true; | |
234 | } | |
235 | ||
236 | SnapMap wait_for_snap_map(MockObjectCopyRequest &mock_object_copy_request) { | |
9f95a23c | 237 | std::unique_lock locker{mock_object_copy_request.lock}; |
11fdf7f2 | 238 | while (mock_object_copy_request.snap_map == nullptr) { |
9f95a23c TL |
239 | if (mock_object_copy_request.cond.wait_for(locker, 10s) == |
240 | std::cv_status::timeout) { | |
11fdf7f2 TL |
241 | return SnapMap(); |
242 | } | |
243 | } | |
244 | return *mock_object_copy_request.snap_map; | |
245 | } | |
246 | ||
247 | int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name, | |
248 | librados::snap_t *snap_id) { | |
249 | int r = image_ctx->operations->snap_create( | |
250 | cls::rbd::UserSnapshotNamespace(), snap_name); | |
251 | if (r < 0) { | |
252 | return r; | |
253 | } | |
254 | ||
255 | r = image_ctx->state->refresh(); | |
256 | if (r < 0) { | |
257 | return r; | |
258 | } | |
259 | ||
260 | if (image_ctx->snap_ids.count({cls::rbd::UserSnapshotNamespace(), | |
261 | snap_name}) == 0) { | |
262 | return -ENOENT; | |
263 | } | |
264 | ||
265 | if (snap_id != nullptr) { | |
266 | *snap_id = image_ctx->snap_ids[{cls::rbd::UserSnapshotNamespace(), | |
267 | snap_name}]; | |
268 | } | |
269 | return 0; | |
270 | } | |
271 | ||
272 | int create_snap(const char* snap_name, | |
273 | librados::snap_t *src_snap_id_ = nullptr) { | |
274 | librados::snap_t src_snap_id; | |
275 | int r = create_snap(m_src_image_ctx, snap_name, &src_snap_id); | |
276 | if (r < 0) { | |
277 | return r; | |
278 | } | |
279 | ||
280 | if (src_snap_id_ != nullptr) { | |
281 | *src_snap_id_ = src_snap_id; | |
282 | } | |
283 | ||
284 | librados::snap_t dst_snap_id; | |
285 | r = create_snap(m_dst_image_ctx, snap_name, &dst_snap_id); | |
286 | if (r < 0) { | |
287 | return r; | |
288 | } | |
289 | ||
290 | // collection of all existing snaps in dst image | |
291 | SnapIds dst_snap_ids({dst_snap_id}); | |
292 | if (!m_snap_map.empty()) { | |
293 | dst_snap_ids.insert(dst_snap_ids.end(), | |
294 | m_snap_map.rbegin()->second.begin(), | |
295 | m_snap_map.rbegin()->second.end()); | |
296 | } | |
297 | m_snap_map[src_snap_id] = dst_snap_ids; | |
298 | m_snap_seqs[src_snap_id] = dst_snap_id; | |
299 | return 0; | |
300 | } | |
301 | }; | |
302 | ||
303 | TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) { | |
304 | librados::snap_t snap_id_end; | |
305 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
306 | ||
307 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
308 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
309 | MockObjectCopyRequest mock_object_copy_request; | |
310 | ||
311 | InSequence seq; | |
9f95a23c TL |
312 | MockDiffRequest mock_diff_request; |
313 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
314 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); |
315 | expect_get_image_size(mock_src_image_ctx, 0); | |
316 | expect_object_copy_send(mock_object_copy_request); | |
317 | ||
1911f103 | 318 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
319 | C_SaferCond ctx; |
320 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
321 | &mock_dst_image_ctx, | |
9f95a23c | 322 | 0, snap_id_end, 0, false, boost::none, |
11fdf7f2 TL |
323 | m_snap_seqs, &no_op, &ctx); |
324 | request->send(); | |
325 | ||
326 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
327 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
328 | ASSERT_EQ(0, ctx.wait()); | |
329 | } | |
330 | ||
9f95a23c TL |
331 | TEST_F(TestMockDeepCopyImageCopyRequest, FastDiff) { |
332 | librados::snap_t snap_id_end; | |
333 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
334 | ||
335 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
336 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
337 | ||
338 | InSequence seq; | |
339 | ||
340 | MockDiffRequest mock_diff_request; | |
341 | BitVector<2> diff_state; | |
342 | diff_state.resize(1); | |
343 | expect_diff_send(mock_diff_request, diff_state, 0); | |
344 | ||
345 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); | |
346 | expect_get_image_size(mock_src_image_ctx, 0); | |
347 | ||
1911f103 | 348 | librbd::deep_copy::NoOpHandler no_op; |
9f95a23c TL |
349 | C_SaferCond ctx; |
350 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
351 | &mock_dst_image_ctx, | |
352 | 0, snap_id_end, 0, false, boost::none, | |
353 | m_snap_seqs, &no_op, &ctx); | |
354 | request->send(); | |
355 | ||
356 | ASSERT_EQ(0, ctx.wait()); | |
357 | } | |
358 | ||
11fdf7f2 TL |
359 | TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) { |
360 | std::string max_ops_str; | |
361 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
362 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "10")); | |
363 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
364 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
365 | max_ops_str.c_str())); | |
366 | } BOOST_SCOPE_EXIT_END; | |
367 | ||
368 | librados::snap_t snap_id_end; | |
369 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
370 | ||
371 | uint64_t object_count = 55; | |
372 | ||
373 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
374 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
375 | MockObjectCopyRequest mock_object_copy_request; | |
376 | ||
9f95a23c TL |
377 | MockDiffRequest mock_diff_request; |
378 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
379 | expect_get_image_size(mock_src_image_ctx, |
380 | object_count * (1 << m_src_image_ctx->order)); | |
381 | expect_get_image_size(mock_src_image_ctx, 0); | |
382 | ||
383 | EXPECT_CALL(mock_object_copy_request, send()).Times(object_count); | |
384 | ||
1911f103 | 385 | class Handler : public librbd::deep_copy::NoOpHandler { |
11fdf7f2 TL |
386 | public: |
387 | uint64_t object_count; | |
388 | librbd::deep_copy::ObjectNumber expected_object_number; | |
389 | ||
1911f103 | 390 | Handler(uint64_t object_count) |
11fdf7f2 TL |
391 | : object_count(object_count) { |
392 | } | |
393 | ||
394 | int update_progress(uint64_t object_no, uint64_t end_object_no) override { | |
395 | EXPECT_LE(object_no, object_count); | |
396 | EXPECT_EQ(end_object_no, object_count); | |
397 | if (!expected_object_number) { | |
398 | expected_object_number = 0; | |
399 | } else { | |
400 | expected_object_number = *expected_object_number + 1; | |
401 | } | |
402 | EXPECT_EQ(*expected_object_number, object_no - 1); | |
403 | ||
404 | return 0; | |
405 | } | |
1911f103 | 406 | } handler(object_count); |
11fdf7f2 TL |
407 | |
408 | C_SaferCond ctx; | |
409 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
410 | &mock_dst_image_ctx, | |
9f95a23c | 411 | 0, snap_id_end, 0, false, boost::none, |
1911f103 | 412 | m_snap_seqs, &handler, &ctx); |
11fdf7f2 TL |
413 | request->send(); |
414 | ||
415 | std::map<uint64_t, Context*> copy_contexts; | |
416 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
417 | for (uint64_t i = 0; i < object_count; ++i) { | |
418 | if (i % 10 == 0) { | |
419 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, | |
420 | ©_contexts[i], 0)); | |
421 | } else { | |
422 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, nullptr, | |
423 | 0)); | |
424 | } | |
425 | } | |
426 | ||
427 | for (auto& pair : copy_contexts) { | |
428 | pair.second->complete(0); | |
429 | } | |
430 | ||
431 | ASSERT_EQ(0, ctx.wait()); | |
432 | } | |
433 | ||
434 | TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) { | |
435 | librados::snap_t snap_id_start; | |
436 | librados::snap_t snap_id_end; | |
437 | ASSERT_EQ(0, create_snap("snap1")); | |
438 | ASSERT_EQ(0, create_snap("snap2", &snap_id_start)); | |
439 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
440 | ||
441 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
442 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
443 | MockObjectCopyRequest mock_object_copy_request; | |
444 | ||
445 | InSequence seq; | |
9f95a23c TL |
446 | MockDiffRequest mock_diff_request; |
447 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
448 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); |
449 | expect_get_image_size(mock_src_image_ctx, 0); | |
450 | expect_get_image_size(mock_src_image_ctx, 0); | |
451 | expect_get_image_size(mock_src_image_ctx, 0); | |
452 | expect_object_copy_send(mock_object_copy_request); | |
453 | ||
1911f103 | 454 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
455 | C_SaferCond ctx; |
456 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
457 | &mock_dst_image_ctx, | |
9f95a23c | 458 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
459 | boost::none, m_snap_seqs, &no_op, |
460 | &ctx); | |
461 | request->send(); | |
462 | ||
463 | SnapMap snap_map(m_snap_map); | |
464 | snap_map.erase(snap_map.begin()); | |
465 | ASSERT_EQ(snap_map, wait_for_snap_map(mock_object_copy_request)); | |
466 | ||
467 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
468 | ASSERT_EQ(0, ctx.wait()); | |
469 | } | |
470 | ||
471 | TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) { | |
472 | librados::snap_t snap_id_end; | |
473 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
474 | ||
475 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
476 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
477 | MockObjectCopyRequest mock_object_copy_request; | |
478 | ||
479 | InSequence seq; | |
9f95a23c TL |
480 | MockDiffRequest mock_diff_request; |
481 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
482 | expect_get_image_size(mock_src_image_ctx, 2 * (1 << m_src_image_ctx->order)); |
483 | expect_get_image_size(mock_src_image_ctx, 0); | |
484 | expect_object_copy_send(mock_object_copy_request); | |
485 | ||
1911f103 | 486 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
487 | C_SaferCond ctx; |
488 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
489 | &mock_dst_image_ctx, | |
9f95a23c | 490 | 0, snap_id_end, 0, false, |
11fdf7f2 TL |
491 | librbd::deep_copy::ObjectNumber{0U}, |
492 | m_snap_seqs, &no_op, &ctx); | |
493 | request->send(); | |
494 | ||
495 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0)); | |
496 | ASSERT_EQ(0, ctx.wait()); | |
497 | } | |
498 | ||
499 | TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) { | |
500 | std::string max_ops_str; | |
501 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
502 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "1")); | |
503 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
504 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
505 | max_ops_str.c_str())); | |
506 | } BOOST_SCOPE_EXIT_END; | |
507 | ||
508 | librados::snap_t snap_id_end; | |
509 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
510 | ||
511 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
512 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
513 | MockObjectCopyRequest mock_object_copy_request; | |
514 | ||
515 | InSequence seq; | |
9f95a23c TL |
516 | MockDiffRequest mock_diff_request; |
517 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
518 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); |
519 | expect_get_image_size(mock_src_image_ctx, 0); | |
520 | expect_object_copy_send(mock_object_copy_request); | |
521 | ||
1911f103 | 522 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
523 | C_SaferCond ctx; |
524 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
525 | &mock_dst_image_ctx, | |
9f95a23c | 526 | 0, snap_id_end, 0, false, boost::none, |
11fdf7f2 TL |
527 | m_snap_seqs, &no_op, &ctx); |
528 | request->send(); | |
529 | ||
530 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
531 | request->cancel(); | |
532 | ||
533 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
534 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
535 | } | |
536 | ||
537 | TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) { | |
538 | std::string max_ops_str; | |
539 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
540 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "3")); | |
541 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
542 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
543 | max_ops_str.c_str())); | |
544 | } BOOST_SCOPE_EXIT_END; | |
545 | ||
546 | librados::snap_t snap_id_end; | |
547 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
548 | ||
549 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
550 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
551 | MockObjectCopyRequest mock_object_copy_request; | |
552 | ||
553 | InSequence seq; | |
9f95a23c TL |
554 | MockDiffRequest mock_diff_request; |
555 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
556 | expect_get_image_size(mock_src_image_ctx, 6 * (1 << m_src_image_ctx->order)); |
557 | expect_get_image_size(mock_src_image_ctx, m_image_size); | |
558 | ||
559 | EXPECT_CALL(mock_object_copy_request, send()).Times(6); | |
560 | ||
1911f103 | 561 | struct Handler : public librbd::deep_copy::NoOpHandler { |
11fdf7f2 TL |
562 | librbd::deep_copy::ObjectNumber object_number; |
563 | ||
564 | int update_progress(uint64_t object_no, uint64_t end_object_no) override { | |
565 | object_number = object_number ? *object_number + 1 : 0; | |
566 | return 0; | |
567 | } | |
1911f103 | 568 | } handler; |
11fdf7f2 TL |
569 | |
570 | C_SaferCond ctx; | |
571 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
572 | &mock_dst_image_ctx, | |
9f95a23c | 573 | 0, snap_id_end, 0, false, boost::none, |
1911f103 | 574 | m_snap_seqs, &handler, &ctx); |
11fdf7f2 TL |
575 | request->send(); |
576 | ||
577 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
578 | ||
579 | Context *cancel_ctx = nullptr; | |
580 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
581 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0)); | |
582 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, nullptr, 0)); | |
583 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, &cancel_ctx, | |
584 | 0)); | |
585 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, nullptr, 0)); | |
586 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, nullptr, 0)); | |
587 | ||
588 | request->cancel(); | |
589 | cancel_ctx->complete(0); | |
590 | ||
591 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
1911f103 | 592 | ASSERT_EQ(5u, handler.object_number.get()); |
11fdf7f2 TL |
593 | } |
594 | ||
595 | TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) { | |
596 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
597 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
598 | ||
1911f103 | 599 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
600 | C_SaferCond ctx; |
601 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
602 | &mock_dst_image_ctx, | |
9f95a23c | 603 | 0, 123, 0, false, boost::none, |
11fdf7f2 TL |
604 | m_snap_seqs, &no_op, &ctx); |
605 | request->send(); | |
606 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
607 | } | |
608 | ||
609 | TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) { | |
610 | librados::snap_t snap_id_end; | |
611 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
612 | ||
613 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
614 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
615 | ||
1911f103 | 616 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
617 | C_SaferCond ctx; |
618 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
619 | &mock_dst_image_ctx, | |
9f95a23c TL |
620 | 123, snap_id_end, 0, false, |
621 | boost::none, m_snap_seqs, &no_op, | |
622 | &ctx); | |
11fdf7f2 TL |
623 | request->send(); |
624 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
625 | } | |
626 | ||
627 | TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapMap) { | |
628 | librados::snap_t snap_id_start; | |
629 | librados::snap_t snap_id_end; | |
630 | ASSERT_EQ(0, create_snap("snap1", &snap_id_start)); | |
631 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
632 | ||
633 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
634 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
635 | ||
1911f103 | 636 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
637 | C_SaferCond ctx; |
638 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
639 | &mock_dst_image_ctx, | |
9f95a23c | 640 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
641 | boost::none, {{0, 0}}, &no_op, &ctx); |
642 | request->send(); | |
643 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
644 | } | |
645 | ||
646 | TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapSeqs) { | |
647 | librados::snap_t snap_id_start; | |
648 | librados::snap_t snap_id_end; | |
649 | ASSERT_EQ(0, create_snap("snap1", &snap_id_start)); | |
650 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
651 | ||
652 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
653 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
654 | ||
1911f103 | 655 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
656 | C_SaferCond ctx; |
657 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
658 | &mock_dst_image_ctx, | |
9f95a23c | 659 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
660 | boost::none, {}, &no_op, &ctx); |
661 | request->send(); | |
662 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
663 | } | |
664 | ||
665 | } // namespace deep_copy | |
666 | } // namespace librbd |