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