]>
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" | |
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 | ||
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, | |
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 | ||
82 | ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
83 | ||
84 | } // namespace deep_copy | |
85 | ||
9f95a23c TL |
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 | |
11fdf7f2 TL |
113 | } // namespace librbd |
114 | ||
115 | // template definitions | |
116 | #include "librbd/deep_copy/ImageCopyRequest.cc" | |
117 | template class librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx>; | |
118 | ||
20effc67 TL |
119 | using namespace std::chrono_literals; |
120 | ||
11fdf7f2 TL |
121 | namespace librbd { |
122 | namespace deep_copy { | |
123 | ||
124 | using ::testing::_; | |
125 | using ::testing::InSequence; | |
9f95a23c | 126 | using ::testing::Invoke; |
11fdf7f2 TL |
127 | using ::testing::Return; |
128 | ||
129 | class TestMockDeepCopyImageCopyRequest : public TestMockFixture { | |
130 | public: | |
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 | ||
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; | |
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 | ||
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 | ||
316 | librbd::deep_copy::NoOpHandler no_op; | |
317 | C_SaferCond ctx; | |
318 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
319 | &mock_dst_image_ctx, | |
320 | 0, snap_id_end, 0, false, boost::none, | |
321 | m_snap_seqs, &no_op, &ctx); | |
322 | request->send(); | |
323 | ||
324 | ASSERT_EQ(0, ctx.wait()); | |
325 | } | |
326 | ||
327 | TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffExistsDirty) { | |
328 | librados::snap_t snap_id_end; | |
329 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
330 | ||
331 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
332 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
333 | ||
334 | InSequence seq; | |
335 | ||
336 | MockDiffRequest mock_diff_request; | |
337 | BitVector<2> diff_state; | |
338 | diff_state.resize(1); | |
339 | diff_state[0] = object_map::DIFF_STATE_DATA_UPDATED; | |
340 | expect_diff_send(mock_diff_request, diff_state, 0); | |
341 | ||
342 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); | |
343 | expect_get_image_size(mock_src_image_ctx, 0); | |
344 | MockObjectCopyRequest mock_object_copy_request; | |
345 | expect_object_copy_send(mock_object_copy_request, 0); | |
11fdf7f2 | 346 | |
1911f103 | 347 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
348 | C_SaferCond ctx; |
349 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
350 | &mock_dst_image_ctx, | |
9f95a23c | 351 | 0, snap_id_end, 0, false, boost::none, |
11fdf7f2 TL |
352 | m_snap_seqs, &no_op, &ctx); |
353 | request->send(); | |
354 | ||
355 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
356 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
357 | ASSERT_EQ(0, ctx.wait()); | |
358 | } | |
359 | ||
f67539c2 | 360 | TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffExistsClean) { |
9f95a23c TL |
361 | librados::snap_t snap_id_end; |
362 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
363 | ||
364 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
365 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
366 | ||
367 | InSequence seq; | |
368 | ||
369 | MockDiffRequest mock_diff_request; | |
370 | BitVector<2> diff_state; | |
371 | diff_state.resize(1); | |
f67539c2 | 372 | diff_state[0] = object_map::DIFF_STATE_DATA; |
9f95a23c TL |
373 | expect_diff_send(mock_diff_request, diff_state, 0); |
374 | ||
375 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); | |
376 | expect_get_image_size(mock_src_image_ctx, 0); | |
f67539c2 TL |
377 | MockObjectCopyRequest mock_object_copy_request; |
378 | expect_object_copy_send(mock_object_copy_request, | |
379 | OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN); | |
9f95a23c | 380 | |
1911f103 | 381 | librbd::deep_copy::NoOpHandler no_op; |
9f95a23c TL |
382 | C_SaferCond ctx; |
383 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
384 | &mock_dst_image_ctx, | |
385 | 0, snap_id_end, 0, false, boost::none, | |
386 | m_snap_seqs, &no_op, &ctx); | |
387 | request->send(); | |
388 | ||
f67539c2 TL |
389 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); |
390 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
9f95a23c TL |
391 | ASSERT_EQ(0, ctx.wait()); |
392 | } | |
393 | ||
11fdf7f2 TL |
394 | TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) { |
395 | std::string max_ops_str; | |
396 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
397 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "10")); | |
398 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
399 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
400 | max_ops_str.c_str())); | |
401 | } BOOST_SCOPE_EXIT_END; | |
402 | ||
403 | librados::snap_t snap_id_end; | |
404 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
405 | ||
406 | uint64_t object_count = 55; | |
407 | ||
408 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
409 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
410 | MockObjectCopyRequest mock_object_copy_request; | |
411 | ||
9f95a23c TL |
412 | MockDiffRequest mock_diff_request; |
413 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
414 | expect_get_image_size(mock_src_image_ctx, |
415 | object_count * (1 << m_src_image_ctx->order)); | |
416 | expect_get_image_size(mock_src_image_ctx, 0); | |
417 | ||
418 | EXPECT_CALL(mock_object_copy_request, send()).Times(object_count); | |
419 | ||
1911f103 | 420 | class Handler : public librbd::deep_copy::NoOpHandler { |
11fdf7f2 TL |
421 | public: |
422 | uint64_t object_count; | |
423 | librbd::deep_copy::ObjectNumber expected_object_number; | |
424 | ||
1911f103 | 425 | Handler(uint64_t object_count) |
11fdf7f2 TL |
426 | : object_count(object_count) { |
427 | } | |
428 | ||
429 | int update_progress(uint64_t object_no, uint64_t end_object_no) override { | |
430 | EXPECT_LE(object_no, object_count); | |
431 | EXPECT_EQ(end_object_no, object_count); | |
432 | if (!expected_object_number) { | |
433 | expected_object_number = 0; | |
434 | } else { | |
435 | expected_object_number = *expected_object_number + 1; | |
436 | } | |
437 | EXPECT_EQ(*expected_object_number, object_no - 1); | |
438 | ||
439 | return 0; | |
440 | } | |
1911f103 | 441 | } handler(object_count); |
11fdf7f2 TL |
442 | |
443 | C_SaferCond ctx; | |
444 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
445 | &mock_dst_image_ctx, | |
9f95a23c | 446 | 0, snap_id_end, 0, false, boost::none, |
1911f103 | 447 | m_snap_seqs, &handler, &ctx); |
11fdf7f2 TL |
448 | request->send(); |
449 | ||
450 | std::map<uint64_t, Context*> copy_contexts; | |
451 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
452 | for (uint64_t i = 0; i < object_count; ++i) { | |
453 | if (i % 10 == 0) { | |
454 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, | |
455 | ©_contexts[i], 0)); | |
456 | } else { | |
457 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, nullptr, | |
458 | 0)); | |
459 | } | |
460 | } | |
461 | ||
462 | for (auto& pair : copy_contexts) { | |
463 | pair.second->complete(0); | |
464 | } | |
465 | ||
466 | ASSERT_EQ(0, ctx.wait()); | |
467 | } | |
468 | ||
469 | TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) { | |
470 | librados::snap_t snap_id_start; | |
471 | librados::snap_t snap_id_end; | |
472 | ASSERT_EQ(0, create_snap("snap1")); | |
473 | ASSERT_EQ(0, create_snap("snap2", &snap_id_start)); | |
474 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
475 | ||
476 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
477 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
478 | MockObjectCopyRequest mock_object_copy_request; | |
479 | ||
480 | InSequence seq; | |
9f95a23c TL |
481 | MockDiffRequest mock_diff_request; |
482 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
483 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); |
484 | expect_get_image_size(mock_src_image_ctx, 0); | |
485 | expect_get_image_size(mock_src_image_ctx, 0); | |
486 | expect_get_image_size(mock_src_image_ctx, 0); | |
f67539c2 | 487 | expect_object_copy_send(mock_object_copy_request, 0); |
11fdf7f2 | 488 | |
1911f103 | 489 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
490 | C_SaferCond ctx; |
491 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
492 | &mock_dst_image_ctx, | |
9f95a23c | 493 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
494 | boost::none, m_snap_seqs, &no_op, |
495 | &ctx); | |
496 | request->send(); | |
497 | ||
498 | SnapMap snap_map(m_snap_map); | |
499 | snap_map.erase(snap_map.begin()); | |
500 | ASSERT_EQ(snap_map, wait_for_snap_map(mock_object_copy_request)); | |
501 | ||
502 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
503 | ASSERT_EQ(0, ctx.wait()); | |
504 | } | |
505 | ||
506 | TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) { | |
507 | librados::snap_t snap_id_end; | |
508 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
509 | ||
510 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
511 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
512 | MockObjectCopyRequest mock_object_copy_request; | |
513 | ||
514 | InSequence seq; | |
9f95a23c TL |
515 | MockDiffRequest mock_diff_request; |
516 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
517 | expect_get_image_size(mock_src_image_ctx, 2 * (1 << m_src_image_ctx->order)); |
518 | expect_get_image_size(mock_src_image_ctx, 0); | |
f67539c2 | 519 | expect_object_copy_send(mock_object_copy_request, 0); |
11fdf7f2 | 520 | |
1911f103 | 521 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
522 | C_SaferCond ctx; |
523 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
524 | &mock_dst_image_ctx, | |
9f95a23c | 525 | 0, snap_id_end, 0, false, |
11fdf7f2 TL |
526 | librbd::deep_copy::ObjectNumber{0U}, |
527 | m_snap_seqs, &no_op, &ctx); | |
528 | request->send(); | |
529 | ||
530 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0)); | |
531 | ASSERT_EQ(0, ctx.wait()); | |
532 | } | |
533 | ||
534 | TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) { | |
535 | std::string max_ops_str; | |
536 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
537 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "1")); | |
538 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
539 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
540 | max_ops_str.c_str())); | |
541 | } BOOST_SCOPE_EXIT_END; | |
542 | ||
543 | librados::snap_t snap_id_end; | |
544 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
545 | ||
546 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
547 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
548 | MockObjectCopyRequest mock_object_copy_request; | |
549 | ||
550 | InSequence seq; | |
9f95a23c TL |
551 | MockDiffRequest mock_diff_request; |
552 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
553 | expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order); |
554 | expect_get_image_size(mock_src_image_ctx, 0); | |
f67539c2 | 555 | expect_object_copy_send(mock_object_copy_request, 0); |
11fdf7f2 | 556 | |
1911f103 | 557 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
558 | C_SaferCond ctx; |
559 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
560 | &mock_dst_image_ctx, | |
9f95a23c | 561 | 0, snap_id_end, 0, false, boost::none, |
11fdf7f2 TL |
562 | m_snap_seqs, &no_op, &ctx); |
563 | request->send(); | |
564 | ||
565 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
566 | request->cancel(); | |
567 | ||
568 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
569 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
570 | } | |
571 | ||
572 | TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) { | |
573 | std::string max_ops_str; | |
574 | ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str)); | |
575 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "3")); | |
576 | BOOST_SCOPE_EXIT( (max_ops_str) ) { | |
577 | ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", | |
578 | max_ops_str.c_str())); | |
579 | } BOOST_SCOPE_EXIT_END; | |
580 | ||
581 | librados::snap_t snap_id_end; | |
582 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
583 | ||
584 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
585 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
586 | MockObjectCopyRequest mock_object_copy_request; | |
587 | ||
588 | InSequence seq; | |
9f95a23c TL |
589 | MockDiffRequest mock_diff_request; |
590 | expect_diff_send(mock_diff_request, {}, -EINVAL); | |
11fdf7f2 TL |
591 | expect_get_image_size(mock_src_image_ctx, 6 * (1 << m_src_image_ctx->order)); |
592 | expect_get_image_size(mock_src_image_ctx, m_image_size); | |
593 | ||
594 | EXPECT_CALL(mock_object_copy_request, send()).Times(6); | |
595 | ||
1911f103 | 596 | struct Handler : public librbd::deep_copy::NoOpHandler { |
11fdf7f2 TL |
597 | librbd::deep_copy::ObjectNumber object_number; |
598 | ||
599 | int update_progress(uint64_t object_no, uint64_t end_object_no) override { | |
600 | object_number = object_number ? *object_number + 1 : 0; | |
601 | return 0; | |
602 | } | |
1911f103 | 603 | } handler; |
11fdf7f2 TL |
604 | |
605 | C_SaferCond ctx; | |
606 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
607 | &mock_dst_image_ctx, | |
9f95a23c | 608 | 0, snap_id_end, 0, false, boost::none, |
1911f103 | 609 | m_snap_seqs, &handler, &ctx); |
11fdf7f2 TL |
610 | request->send(); |
611 | ||
612 | ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request)); | |
613 | ||
614 | Context *cancel_ctx = nullptr; | |
615 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0)); | |
616 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0)); | |
617 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, nullptr, 0)); | |
618 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, &cancel_ctx, | |
619 | 0)); | |
620 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, nullptr, 0)); | |
621 | ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, nullptr, 0)); | |
622 | ||
623 | request->cancel(); | |
624 | cancel_ctx->complete(0); | |
625 | ||
626 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
1911f103 | 627 | ASSERT_EQ(5u, handler.object_number.get()); |
11fdf7f2 TL |
628 | } |
629 | ||
630 | TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) { | |
631 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
632 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
633 | ||
1911f103 | 634 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
635 | C_SaferCond ctx; |
636 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
637 | &mock_dst_image_ctx, | |
9f95a23c | 638 | 0, 123, 0, false, boost::none, |
11fdf7f2 TL |
639 | m_snap_seqs, &no_op, &ctx); |
640 | request->send(); | |
641 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
642 | } | |
643 | ||
644 | TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) { | |
645 | librados::snap_t snap_id_end; | |
646 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
647 | ||
648 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
649 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
650 | ||
1911f103 | 651 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
652 | C_SaferCond ctx; |
653 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
654 | &mock_dst_image_ctx, | |
9f95a23c TL |
655 | 123, snap_id_end, 0, false, |
656 | boost::none, m_snap_seqs, &no_op, | |
657 | &ctx); | |
11fdf7f2 TL |
658 | request->send(); |
659 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
660 | } | |
661 | ||
662 | TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapMap) { | |
663 | librados::snap_t snap_id_start; | |
664 | librados::snap_t snap_id_end; | |
665 | ASSERT_EQ(0, create_snap("snap1", &snap_id_start)); | |
666 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
667 | ||
668 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
669 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
670 | ||
1911f103 | 671 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
672 | C_SaferCond ctx; |
673 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
674 | &mock_dst_image_ctx, | |
9f95a23c | 675 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
676 | boost::none, {{0, 0}}, &no_op, &ctx); |
677 | request->send(); | |
678 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
679 | } | |
680 | ||
681 | TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapSeqs) { | |
682 | librados::snap_t snap_id_start; | |
683 | librados::snap_t snap_id_end; | |
684 | ASSERT_EQ(0, create_snap("snap1", &snap_id_start)); | |
685 | ASSERT_EQ(0, create_snap("copy", &snap_id_end)); | |
686 | ||
687 | librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx); | |
688 | librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx); | |
689 | ||
1911f103 | 690 | librbd::deep_copy::NoOpHandler no_op; |
11fdf7f2 TL |
691 | C_SaferCond ctx; |
692 | auto request = new MockImageCopyRequest(&mock_src_image_ctx, | |
693 | &mock_dst_image_ctx, | |
9f95a23c | 694 | snap_id_start, snap_id_end, 0, false, |
11fdf7f2 TL |
695 | boost::none, {}, &no_op, &ctx); |
696 | request->send(); | |
697 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
698 | } | |
699 | ||
700 | } // namespace deep_copy | |
701 | } // namespace librbd |