]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
import ceph quincy 17.2.4
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_ImageCopyRequest.cc
CommitLineData
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"
f67539c2 6#include "librbd/AsioEngine.h"
11fdf7f2
TL
7#include "librbd/ImageCtx.h"
8#include "librbd/ImageState.h"
9f95a23c 9#include "librbd/internal.h"
11fdf7f2 10#include "librbd/Operations.h"
1911f103 11#include "librbd/deep_copy/Handler.h"
11fdf7f2
TL
12#include "librbd/deep_copy/ImageCopyRequest.h"
13#include "librbd/deep_copy/ObjectCopyRequest.h"
9f95a23c 14#include "librbd/object_map/DiffRequest.h"
11fdf7f2
TL
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
20namespace librbd {
21
22namespace {
23
24struct 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
42MockTestImageCtx* MockTestImageCtx::s_instance = nullptr;
43
44} // anonymous namespace
45
46namespace deep_copy {
47
48template <>
49struct ObjectCopyRequest<librbd::MockTestImageCtx> {
50 static ObjectCopyRequest* s_instance;
51 static ObjectCopyRequest* create(
52 librbd::MockTestImageCtx *src_image_ctx,
9f95a23c
TL
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,
cd265ab1 57 uint64_t object_number, uint32_t flags, Handler* handler,
1911f103 58 Context *on_finish) {
11fdf7f2 59 ceph_assert(s_instance != nullptr);
9f95a23c 60 std::lock_guard locker{s_instance->lock};
11fdf7f2 61 s_instance->snap_map = &snap_map;
f67539c2 62 s_instance->flags = flags;
11fdf7f2 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;
f67539c2 75 uint32_t flags = 0;
11fdf7f2 76
9f95a23c 77 ObjectCopyRequest() {
11fdf7f2
TL
78 s_instance = this;
79 }
80};
81
82ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
83
84} // namespace deep_copy
85
9f95a23c
TL
86namespace object_map {
87
88template <>
89struct 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
110DiffRequest<MockTestImageCtx>* DiffRequest<MockTestImageCtx>::s_instance = nullptr;
111
112} // namespace object_map
11fdf7f2
TL
113} // namespace librbd
114
115// template definitions
116#include "librbd/deep_copy/ImageCopyRequest.cc"
117template class librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx>;
118
20effc67
TL
119using namespace std::chrono_literals;
120
11fdf7f2
TL
121namespace librbd {
122namespace deep_copy {
123
124using ::testing::_;
125using ::testing::InSequence;
9f95a23c 126using ::testing::Invoke;
11fdf7f2
TL
127using ::testing::Return;
128
129class TestMockDeepCopyImageCopyRequest : public TestMockFixture {
130public:
131 typedef ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
132 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
9f95a23c 133 typedef object_map::DiffRequest<librbd::MockTestImageCtx> MockDiffRequest;
11fdf7f2
TL
134
135 librbd::ImageCtx *m_src_image_ctx;
136 librbd::ImageCtx *m_dst_image_ctx;
f67539c2
TL
137
138 std::shared_ptr<librbd::AsioEngine> m_asio_engine;
139 asio::ContextWQ *m_work_queue;
140
11fdf7f2
TL
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
f67539c2
TL
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();
11fdf7f2
TL
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
9f95a23c
TL
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
f67539c2
TL
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 }));
11fdf7f2
TL
182 }
183
184 bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request,
185 uint64_t object_num, Context **object_ctx, int r) {
9f95a23c 186 std::unique_lock locker{mock_object_copy_request.lock};
11fdf7f2 187 while (mock_object_copy_request.object_contexts.count(object_num) == 0) {
9f95a23c
TL
188 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
189 std::cv_status::timeout) {
11fdf7f2
TL
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) {
9f95a23c 204 std::unique_lock locker{mock_object_copy_request.lock};
11fdf7f2 205 while (mock_object_copy_request.snap_map == nullptr) {
9f95a23c
TL
206 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
207 std::cv_status::timeout) {
11fdf7f2
TL
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) {
f67539c2 216 NoOpProgressContext prog_ctx;
11fdf7f2 217 int r = image_ctx->operations->snap_create(
f67539c2 218 cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx);
11fdf7f2
TL
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
271TEST_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;
9f95a23c
TL
280 MockDiffRequest mock_diff_request;
281 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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);
f67539c2
TL
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
299TEST_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);
2a845540 315 expect_op_work_queue(mock_src_image_ctx);
f67539c2
TL
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
328TEST_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);
11fdf7f2 347
1911f103 348 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
349 C_SaferCond ctx;
350 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
351 &mock_dst_image_ctx,
9f95a23c 352 0, snap_id_end, 0, false, boost::none,
11fdf7f2
TL
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
f67539c2 361TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffExistsClean) {
9f95a23c
TL
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);
f67539c2 373 diff_state[0] = object_map::DIFF_STATE_DATA;
9f95a23c
TL
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);
f67539c2
TL
378 MockObjectCopyRequest mock_object_copy_request;
379 expect_object_copy_send(mock_object_copy_request,
380 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN);
9f95a23c 381
1911f103 382 librbd::deep_copy::NoOpHandler no_op;
9f95a23c
TL
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
f67539c2
TL
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));
9f95a23c
TL
392 ASSERT_EQ(0, ctx.wait());
393}
394
2a845540
TL
395TEST_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
11fdf7f2
TL
474TEST_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
9f95a23c
TL
492 MockDiffRequest mock_diff_request;
493 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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
1911f103 500 class Handler : public librbd::deep_copy::NoOpHandler {
11fdf7f2
TL
501 public:
502 uint64_t object_count;
503 librbd::deep_copy::ObjectNumber expected_object_number;
504
1911f103 505 Handler(uint64_t object_count)
11fdf7f2
TL
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 }
1911f103 521 } handler(object_count);
11fdf7f2
TL
522
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,
1911f103 527 m_snap_seqs, &handler, &ctx);
11fdf7f2
TL
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
549TEST_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;
9f95a23c
TL
561 MockDiffRequest mock_diff_request;
562 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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);
f67539c2 567 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 568
1911f103 569 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
570 C_SaferCond ctx;
571 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
572 &mock_dst_image_ctx,
9f95a23c 573 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
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
586TEST_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;
9f95a23c
TL
595 MockDiffRequest mock_diff_request;
596 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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);
f67539c2 599 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 600
1911f103 601 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
602 C_SaferCond ctx;
603 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
604 &mock_dst_image_ctx,
9f95a23c 605 0, snap_id_end, 0, false,
11fdf7f2
TL
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
614TEST_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;
9f95a23c
TL
631 MockDiffRequest mock_diff_request;
632 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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);
f67539c2 635 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 636
1911f103 637 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
638 C_SaferCond ctx;
639 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
640 &mock_dst_image_ctx,
9f95a23c 641 0, snap_id_end, 0, false, boost::none,
11fdf7f2
TL
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
652TEST_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;
9f95a23c
TL
669 MockDiffRequest mock_diff_request;
670 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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
1911f103 676 struct Handler : public librbd::deep_copy::NoOpHandler {
11fdf7f2
TL
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 }
1911f103 683 } handler;
11fdf7f2
TL
684
685 C_SaferCond ctx;
686 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
687 &mock_dst_image_ctx,
9f95a23c 688 0, snap_id_end, 0, false, boost::none,
1911f103 689 m_snap_seqs, &handler, &ctx);
11fdf7f2
TL
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());
1911f103 707 ASSERT_EQ(5u, handler.object_number.get());
11fdf7f2
TL
708}
709
2a845540
TL
710TEST_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
11fdf7f2
TL
736TEST_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
1911f103 740 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
741 C_SaferCond ctx;
742 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
743 &mock_dst_image_ctx,
9f95a23c 744 0, 123, 0, false, boost::none,
11fdf7f2
TL
745 m_snap_seqs, &no_op, &ctx);
746 request->send();
747 ASSERT_EQ(-EINVAL, ctx.wait());
748}
749
750TEST_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
1911f103 757 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
758 C_SaferCond ctx;
759 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
760 &mock_dst_image_ctx,
9f95a23c
TL
761 123, snap_id_end, 0, false,
762 boost::none, m_snap_seqs, &no_op,
763 &ctx);
11fdf7f2
TL
764 request->send();
765 ASSERT_EQ(-EINVAL, ctx.wait());
766}
767
768TEST_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
1911f103 777 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
778 C_SaferCond ctx;
779 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
780 &mock_dst_image_ctx,
9f95a23c 781 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
782 boost::none, {{0, 0}}, &no_op, &ctx);
783 request->send();
784 ASSERT_EQ(-EINVAL, ctx.wait());
785}
786
787TEST_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
1911f103 796 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
797 C_SaferCond ctx;
798 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
799 &mock_dst_image_ctx,
9f95a23c 800 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
801 boost::none, {}, &no_op, &ctx);
802 request->send();
803 ASSERT_EQ(-EINVAL, ctx.wait());
804}
805
806} // namespace deep_copy
807} // namespace librbd