]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/image_sync/test_mock_ObjectCopyRequest.cc
update sources to 12.2.10
[ceph.git] / ceph / src / test / rbd_mirror / image_sync / test_mock_ObjectCopyRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "test/rbd_mirror/test_mock_fixture.h"
5#include "include/interval_set.h"
6#include "include/rbd/librbd.hpp"
7#include "include/rbd/object_map_types.h"
8#include "librbd/ImageCtx.h"
9#include "librbd/ImageState.h"
10#include "librbd/internal.h"
11#include "librbd/Operations.h"
12#include "librbd/io/ImageRequestWQ.h"
13#include "librbd/io/ReadResult.h"
14#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
15#include "test/librbd/mock/MockImageCtx.h"
16#include "tools/rbd_mirror/Threads.h"
17#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.h"
18
19namespace librbd {
20namespace {
21
22struct MockTestImageCtx : public librbd::MockImageCtx {
23 MockTestImageCtx(librbd::ImageCtx &image_ctx)
24 : librbd::MockImageCtx(image_ctx) {
25 }
26};
27
28} // anonymous namespace
29} // namespace librbd
30
31// template definitions
32#include "tools/rbd_mirror/image_sync/ObjectCopyRequest.cc"
33template class rbd::mirror::image_sync::ObjectCopyRequest<librbd::MockTestImageCtx>;
34
35bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
36 return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
37}
38
39namespace rbd {
40namespace mirror {
41namespace image_sync {
42
43using ::testing::_;
44using ::testing::DoAll;
45using ::testing::DoDefault;
46using ::testing::InSequence;
47using ::testing::Invoke;
48using ::testing::Return;
31f18b77 49using ::testing::ReturnNew;
7c673cae
FG
50using ::testing::WithArg;
51
52namespace {
53
54void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size,
55 interval_set<uint64_t> *what)
56{
57 uint64_t object_size = 1 << image_ctx->order;
58 for (int i=0; i<num_ops; i++) {
59 uint64_t off = rand() % (object_size - max_size + 1);
60 uint64_t len = 1 + rand() % max_size;
61
62 bufferlist bl;
63 bl.append(std::string(len, '1'));
64
65 int r = image_ctx->io_work_queue->write(off, len, std::move(bl), 0);
66 ASSERT_EQ(static_cast<int>(len), r);
67
68 interval_set<uint64_t> w;
69 w.insert(off, len);
70 what->union_of(w);
71 }
72 std::cout << " wrote " << *what << std::endl;
73}
74
75} // anonymous namespace
76
77class TestMockImageSyncObjectCopyRequest : public TestMockFixture {
78public:
79 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
80
81 void SetUp() override {
82 TestMockFixture::SetUp();
83
84 librbd::RBD rbd;
85 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
86 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
87
88 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
89 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
90 }
91
31f18b77 92 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
91327a77 93 EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(
31f18b77
FG
94 ReturnNew<FunctionContext>([](int) {}));
95 }
96
7c673cae
FG
97 void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
98 librados::MockTestMemIoCtxImpl &mock_io_ctx,
99 const librados::snap_set_t &snap_set) {
100 expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
101 EXPECT_CALL(mock_io_ctx,
102 list_snaps(mock_image_ctx.image_ctx->get_object_name(0), _))
103 .WillOnce(DoAll(WithArg<1>(Invoke([&snap_set](librados::snap_set_t *out_snap_set) {
104 *out_snap_set = snap_set;
105 })),
106 Return(0)));
107 }
108
109 void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
110 librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
111 expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
112 auto &expect = EXPECT_CALL(mock_io_ctx,
113 list_snaps(mock_image_ctx.image_ctx->get_object_name(0),
114 _));
115 if (r < 0) {
116 expect.WillOnce(Return(r));
117 } else {
118 expect.WillOnce(DoDefault());
119 }
120 }
121
122 void expect_get_object_name(librbd::MockTestImageCtx &mock_image_ctx) {
123 EXPECT_CALL(mock_image_ctx, get_object_name(0))
124 .WillOnce(Return(mock_image_ctx.image_ctx->get_object_name(0)));
125 }
126
127 MockObjectCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx,
128 librbd::MockTestImageCtx &mock_local_image_ctx,
129 Context *on_finish) {
130 expect_get_object_name(mock_local_image_ctx);
131 expect_get_object_name(mock_remote_image_ctx);
132 return new MockObjectCopyRequest(&mock_local_image_ctx,
133 &mock_remote_image_ctx, &m_snap_map,
134 0, on_finish);
135 }
136
137 void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
138 uint64_t snap_id) {
139 EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id));
140 }
141
142 void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset,
143 uint64_t length, int r) {
144
145 auto &expect = EXPECT_CALL(mock_io_ctx, sparse_read(_, offset, length, _, _));
146 if (r < 0) {
147 expect.WillOnce(Return(r));
148 } else {
149 expect.WillOnce(DoDefault());
150 }
151 }
152
153 void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
154 const interval_set<uint64_t> &extents, int r) {
155 for (auto extent : extents) {
156 expect_sparse_read(mock_io_ctx, extent.first, extent.second, r);
157 if (r < 0) {
158 break;
159 }
160 }
161 }
162
163 void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
164 uint64_t offset, uint64_t length,
165 const SnapContext &snapc, int r) {
166 auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc));
167 if (r < 0) {
168 expect.WillOnce(Return(r));
169 } else {
170 expect.WillOnce(DoDefault());
171 }
172 }
173
174 void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
175 const interval_set<uint64_t> &extents,
176 const SnapContext &snapc, int r) {
177 for (auto extent : extents) {
178 expect_write(mock_io_ctx, extent.first, extent.second, snapc, r);
179 if (r < 0) {
180 break;
181 }
182 }
183 }
184
185 void expect_truncate(librados::MockTestMemIoCtxImpl &mock_io_ctx,
186 uint64_t offset, int r) {
187 auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _));
188 if (r < 0) {
189 expect.WillOnce(Return(r));
190 } else {
191 expect.WillOnce(DoDefault());
192 }
193 }
194
195 void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
196 auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _));
197 if (r < 0) {
198 expect.WillOnce(Return(r));
199 } else {
200 expect.WillOnce(DoDefault());
201 }
202 }
203
204 void expect_update_object_map(librbd::MockTestImageCtx &mock_image_ctx,
205 librbd::MockObjectMap &mock_object_map,
206 librados::snap_t snap_id, uint8_t state,
207 int r) {
208 if (mock_image_ctx.image_ctx->object_map != nullptr) {
91327a77 209 auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, false, _));
7c673cae 210 if (r < 0) {
91327a77 211 expect.WillOnce(DoAll(WithArg<7>(Invoke([this, r](Context *ctx) {
7c673cae
FG
212 m_threads->work_queue->queue(ctx, r);
213 })),
214 Return(true)));
215 } else {
91327a77 216 expect.WillOnce(DoAll(WithArg<7>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) {
7c673cae
FG
217 assert(mock_image_ctx.image_ctx->snap_lock.is_locked());
218 assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked());
219 mock_image_ctx.image_ctx->object_map->aio_update<Context>(
91327a77 220 snap_id, 0, 1, state, boost::none, {}, false, ctx);
7c673cae
FG
221 })),
222 Return(true)));
223 }
224 }
225 }
226
227 using TestFixture::create_snap;
228 int create_snap(const char* snap_name) {
229 librados::snap_t remote_snap_id;
230 int r = create_snap(m_remote_image_ctx, snap_name, &remote_snap_id);
231 if (r < 0) {
232 return r;
233 }
234
235 librados::snap_t local_snap_id;
236 r = create_snap(m_local_image_ctx, snap_name, &local_snap_id);
237 if (r < 0) {
238 return r;
239 }
240
241 // collection of all existing snaps in local image
242 MockObjectCopyRequest::SnapIds local_snap_ids({local_snap_id});
243 if (!m_snap_map.empty()) {
244 local_snap_ids.insert(local_snap_ids.end(),
245 m_snap_map.rbegin()->second.begin(),
246 m_snap_map.rbegin()->second.end());
247 }
248 m_snap_map[remote_snap_id] = local_snap_ids;
249 m_remote_snap_ids.push_back(remote_snap_id);
250 m_local_snap_ids.push_back(local_snap_id);
251
252 return 0;
253 }
254
255 std::string get_snap_name(librbd::ImageCtx *image_ctx,
256 librados::snap_t snap_id) {
257 auto it = std::find_if(image_ctx->snap_ids.begin(),
258 image_ctx->snap_ids.end(),
259 [snap_id](const std::pair<std::pair<cls::rbd::SnapshotNamespace,
260 std::string>,
261 librados::snap_t> &pair) {
262 return (pair.second == snap_id);
263 });
264 if (it == image_ctx->snap_ids.end()) {
265 return "";
266 }
267 return it->first.second;
268 }
269
270 int compare_objects() {
271 MockObjectCopyRequest::SnapMap snap_map(m_snap_map);
272 if (snap_map.empty()) {
273 return -ENOENT;
274 }
275
276 int r;
277 uint64_t object_size = 1 << m_remote_image_ctx->order;
278 while (!snap_map.empty()) {
279 librados::snap_t remote_snap_id = snap_map.begin()->first;
280 librados::snap_t local_snap_id = *snap_map.begin()->second.begin();
281 snap_map.erase(snap_map.begin());
282
283 std::string snap_name = get_snap_name(m_remote_image_ctx, remote_snap_id);
284 if (snap_name.empty()) {
285 return -ENOENT;
286 }
287
288 std::cout << "comparing '" << snap_name << " (" << remote_snap_id
289 << " to " << local_snap_id << ")" << std::endl;
290
291 r = librbd::snap_set(m_remote_image_ctx,
292 cls::rbd::UserSnapshotNamespace(),
293 snap_name.c_str());
294 if (r < 0) {
295 return r;
296 }
297
298 r = librbd::snap_set(m_local_image_ctx,
299 cls::rbd::UserSnapshotNamespace(),
300 snap_name.c_str());
301 if (r < 0) {
302 return r;
303 }
304
305 bufferlist remote_bl;
306 remote_bl.append(std::string(object_size, '1'));
307 r = m_remote_image_ctx->io_work_queue->read(
308 0, object_size, librbd::io::ReadResult{&remote_bl}, 0);
309 if (r < 0) {
310 return r;
311 }
312
313 bufferlist local_bl;
314 local_bl.append(std::string(object_size, '1'));
315 r = m_local_image_ctx->io_work_queue->read(
316 0, object_size, librbd::io::ReadResult{&local_bl}, 0);
317 if (r < 0) {
318 return r;
319 }
320
321 if (!remote_bl.contents_equal(local_bl)) {
322 return -EBADMSG;
323 }
324 }
325
326 r = librbd::snap_set(m_remote_image_ctx,
327 cls::rbd::UserSnapshotNamespace(),
328 nullptr);
329 if (r < 0) {
330 return r;
331 }
332 r = librbd::snap_set(m_local_image_ctx,
333 cls::rbd::UserSnapshotNamespace(),
334 nullptr);
335 if (r < 0) {
336 return r;
337 }
338
339 return 0;
340 }
341
342 librbd::ImageCtx *m_remote_image_ctx;
343 librbd::ImageCtx *m_local_image_ctx;
344
345 MockObjectCopyRequest::SnapMap m_snap_map;
346 std::vector<librados::snap_t> m_remote_snap_ids;
347 std::vector<librados::snap_t> m_local_snap_ids;
348};
349
350TEST_F(TestMockImageSyncObjectCopyRequest, DNE) {
351 ASSERT_EQ(0, create_snap("sync"));
352 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
353 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
354
31f18b77
FG
355 librbd::MockExclusiveLock mock_exclusive_lock;
356 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
357
7c673cae
FG
358 librbd::MockObjectMap mock_object_map;
359 mock_local_image_ctx.object_map = &mock_object_map;
7c673cae
FG
360 expect_test_features(mock_local_image_ctx);
361
362 C_SaferCond ctx;
363 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
364 mock_local_image_ctx, &ctx);
365
366 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
367 request->get_remote_io_ctx()));
368
369 InSequence seq;
370 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, -ENOENT);
371
372 request->send();
373 ASSERT_EQ(0, ctx.wait());
374}
375
376TEST_F(TestMockImageSyncObjectCopyRequest, Write) {
377 // scribble some data
378 interval_set<uint64_t> one;
379 scribble(m_remote_image_ctx, 10, 102400, &one);
380
381 ASSERT_EQ(0, create_snap("sync"));
382 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
383 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
384
31f18b77
FG
385 librbd::MockExclusiveLock mock_exclusive_lock;
386 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
387
7c673cae
FG
388 librbd::MockObjectMap mock_object_map;
389 mock_local_image_ctx.object_map = &mock_object_map;
390
391 expect_test_features(mock_local_image_ctx);
392
393 C_SaferCond ctx;
394 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
395 mock_local_image_ctx, &ctx);
396
397 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
398 request->get_remote_io_ctx()));
399 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
400 request->get_local_io_ctx()));
401
402 InSequence seq;
403 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
404 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
405 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 406 expect_start_op(mock_exclusive_lock);
7c673cae 407 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
31f18b77 408 expect_start_op(mock_exclusive_lock);
7c673cae
FG
409 expect_update_object_map(mock_local_image_ctx, mock_object_map,
410 m_local_snap_ids[0], OBJECT_EXISTS, 0);
411
412 request->send();
413 ASSERT_EQ(0, ctx.wait());
414 ASSERT_EQ(0, compare_objects());
415}
416
417TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingStaleSnapSet) {
418 ASSERT_EQ(0, create_snap("one"));
419 ASSERT_EQ(0, create_snap("two"));
420
421 // scribble some data
422 interval_set<uint64_t> one;
423 scribble(m_remote_image_ctx, 10, 102400, &one);
424 ASSERT_EQ(0, create_snap("three"));
425
426 ASSERT_EQ(0, create_snap("sync"));
427 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
428 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
429
31f18b77
FG
430 librbd::MockExclusiveLock mock_exclusive_lock;
431 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
432
7c673cae
FG
433 librbd::MockObjectMap mock_object_map;
434 mock_local_image_ctx.object_map = &mock_object_map;
435
436 expect_test_features(mock_local_image_ctx);
437
438 C_SaferCond ctx;
439 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
440 mock_local_image_ctx, &ctx);
441
442 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
443 request->get_remote_io_ctx()));
444 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
445 request->get_local_io_ctx()));
446
447 librados::clone_info_t dummy_clone_info;
448 dummy_clone_info.cloneid = librados::SNAP_HEAD;
449 dummy_clone_info.size = 123;
450
451 librados::snap_set_t dummy_snap_set1;
452 dummy_snap_set1.clones.push_back(dummy_clone_info);
453
454 dummy_clone_info.size = 234;
455 librados::snap_set_t dummy_snap_set2;
456 dummy_snap_set2.clones.push_back(dummy_clone_info);
457
458 InSequence seq;
459 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set1);
460 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
461 expect_sparse_read(mock_remote_io_ctx, 0, 123, -ENOENT);
462 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set2);
463 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
464 expect_sparse_read(mock_remote_io_ctx, 0, 234, -ENOENT);
465 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
466 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
467 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 468 expect_start_op(mock_exclusive_lock);
7c673cae
FG
469 expect_write(mock_local_io_ctx, 0, one.range_end(),
470 {m_local_snap_ids[1], {m_local_snap_ids[1],
471 m_local_snap_ids[0]}},
472 0);
31f18b77 473 expect_start_op(mock_exclusive_lock);
7c673cae
FG
474 expect_update_object_map(mock_local_image_ctx, mock_object_map,
475 m_local_snap_ids[2], OBJECT_EXISTS, 0);
31f18b77 476 expect_start_op(mock_exclusive_lock);
7c673cae
FG
477 expect_update_object_map(mock_local_image_ctx, mock_object_map,
478 m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0);
479
480 request->send();
481 ASSERT_EQ(0, ctx.wait());
482 ASSERT_EQ(0, compare_objects());
483}
484
485TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingUpToDateSnapMap) {
486 // scribble some data
487 interval_set<uint64_t> one;
488 scribble(m_remote_image_ctx, 10, 102400, &one);
489
490 ASSERT_EQ(0, create_snap("sync"));
491 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
492 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
493
31f18b77
FG
494 librbd::MockExclusiveLock mock_exclusive_lock;
495 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
496
7c673cae
FG
497 librbd::MockObjectMap mock_object_map;
498 mock_local_image_ctx.object_map = &mock_object_map;
499
500 expect_test_features(mock_local_image_ctx);
501
502 C_SaferCond ctx;
503 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
504 mock_local_image_ctx, &ctx);
505
506 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
507 request->get_remote_io_ctx()));
508
509 InSequence seq;
510 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
511 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
512 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -ENOENT);
513 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
514
515 request->send();
516 ASSERT_EQ(-ENOENT, ctx.wait());
517}
518
519TEST_F(TestMockImageSyncObjectCopyRequest, ReadError) {
520 // scribble some data
521 interval_set<uint64_t> one;
522 scribble(m_remote_image_ctx, 10, 102400, &one);
523
524 ASSERT_EQ(0, create_snap("sync"));
525 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
526 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
527
31f18b77
FG
528 librbd::MockExclusiveLock mock_exclusive_lock;
529 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
530
7c673cae
FG
531 librbd::MockObjectMap mock_object_map;
532 mock_local_image_ctx.object_map = &mock_object_map;
533
534 expect_test_features(mock_local_image_ctx);
535
536 C_SaferCond ctx;
537 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
538 mock_local_image_ctx, &ctx);
539
540 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
541 request->get_remote_io_ctx()));
542
543 InSequence seq;
544 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
545 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
546 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -EINVAL);
547
548 request->send();
549 ASSERT_EQ(-EINVAL, ctx.wait());
550}
551
552TEST_F(TestMockImageSyncObjectCopyRequest, WriteError) {
553 // scribble some data
554 interval_set<uint64_t> one;
555 scribble(m_remote_image_ctx, 10, 102400, &one);
556
557 ASSERT_EQ(0, create_snap("sync"));
558 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
559 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
560
31f18b77
FG
561 librbd::MockExclusiveLock mock_exclusive_lock;
562 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
563
7c673cae
FG
564 librbd::MockObjectMap mock_object_map;
565 mock_local_image_ctx.object_map = &mock_object_map;
566
567 expect_test_features(mock_local_image_ctx);
568
569 C_SaferCond ctx;
570 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
571 mock_local_image_ctx, &ctx);
572
573 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
574 request->get_remote_io_ctx()));
575 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
576 request->get_local_io_ctx()));
577
578 InSequence seq;
579 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
580 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
581 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 582 expect_start_op(mock_exclusive_lock);
7c673cae
FG
583 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
584
585 request->send();
586 ASSERT_EQ(-EINVAL, ctx.wait());
587}
588
589TEST_F(TestMockImageSyncObjectCopyRequest, WriteSnaps) {
590 // scribble some data
591 interval_set<uint64_t> one;
592 scribble(m_remote_image_ctx, 10, 102400, &one);
593 ASSERT_EQ(0, create_snap("one"));
594
595 interval_set<uint64_t> two;
596 scribble(m_remote_image_ctx, 10, 102400, &two);
597 ASSERT_EQ(0, create_snap("two"));
598
599 if (one.range_end() < two.range_end()) {
600 interval_set<uint64_t> resize_diff;
601 resize_diff.insert(one.range_end(), two.range_end() - one.range_end());
602 two.union_of(resize_diff);
603 }
604
605 ASSERT_EQ(0, create_snap("sync"));
606 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
607 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
608
31f18b77
FG
609 librbd::MockExclusiveLock mock_exclusive_lock;
610 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
611
7c673cae
FG
612 librbd::MockObjectMap mock_object_map;
613 mock_local_image_ctx.object_map = &mock_object_map;
614
615 expect_test_features(mock_local_image_ctx);
616
617 C_SaferCond ctx;
618 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
619 mock_local_image_ctx, &ctx);
620
621 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
622 request->get_remote_io_ctx()));
623 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
624 request->get_local_io_ctx()));
625
626 InSequence seq;
627 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
628 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
629 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 630 expect_start_op(mock_exclusive_lock);
7c673cae
FG
631 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
632 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[2]);
633 expect_sparse_read(mock_remote_io_ctx, two, 0);
31f18b77 634 expect_start_op(mock_exclusive_lock);
7c673cae
FG
635 expect_write(mock_local_io_ctx, two,
636 {m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0);
31f18b77 637 expect_start_op(mock_exclusive_lock);
7c673cae
FG
638 expect_update_object_map(mock_local_image_ctx, mock_object_map,
639 m_local_snap_ids[0], OBJECT_EXISTS, 0);
31f18b77 640 expect_start_op(mock_exclusive_lock);
7c673cae
FG
641 expect_update_object_map(mock_local_image_ctx, mock_object_map,
642 m_local_snap_ids[1], OBJECT_EXISTS, 0);
31f18b77 643 expect_start_op(mock_exclusive_lock);
7c673cae
FG
644 expect_update_object_map(mock_local_image_ctx, mock_object_map,
645 m_local_snap_ids[2], OBJECT_EXISTS_CLEAN, 0);
646
647 request->send();
648 ASSERT_EQ(0, ctx.wait());
649 ASSERT_EQ(0, compare_objects());
650}
651
652TEST_F(TestMockImageSyncObjectCopyRequest, Trim) {
653 ASSERT_EQ(0, m_remote_image_ctx->operations->metadata_set(
654 "conf_rbd_skip_partial_discard", "false"));
655 // scribble some data
656 interval_set<uint64_t> one;
657 scribble(m_remote_image_ctx, 10, 102400, &one);
658 ASSERT_EQ(0, create_snap("one"));
659
660 // trim the object
661 uint64_t trim_offset = rand() % one.range_end();
662 ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard(
663 trim_offset, one.range_end() - trim_offset, m_remote_image_ctx->skip_partial_discard));
664 ASSERT_EQ(0, create_snap("sync"));
665
666 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
667 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
668
31f18b77
FG
669 librbd::MockExclusiveLock mock_exclusive_lock;
670 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
671
7c673cae
FG
672 librbd::MockObjectMap mock_object_map;
673 mock_local_image_ctx.object_map = &mock_object_map;
674
675 expect_test_features(mock_local_image_ctx);
676
677 C_SaferCond ctx;
678 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
679 mock_local_image_ctx, &ctx);
680
681 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
682 request->get_remote_io_ctx()));
683 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
684 request->get_local_io_ctx()));
685
686 InSequence seq;
687 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
688 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
689 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 690 expect_start_op(mock_exclusive_lock);
7c673cae 691 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
31f18b77 692 expect_start_op(mock_exclusive_lock);
7c673cae 693 expect_truncate(mock_local_io_ctx, trim_offset, 0);
31f18b77 694 expect_start_op(mock_exclusive_lock);
7c673cae
FG
695 expect_update_object_map(mock_local_image_ctx, mock_object_map,
696 m_local_snap_ids[0], OBJECT_EXISTS, 0);
31f18b77 697 expect_start_op(mock_exclusive_lock);
7c673cae
FG
698 expect_update_object_map(mock_local_image_ctx, mock_object_map,
699 m_local_snap_ids[1], OBJECT_EXISTS, 0);
700
701 request->send();
702 ASSERT_EQ(0, ctx.wait());
703 ASSERT_EQ(0, compare_objects());
704}
705
706TEST_F(TestMockImageSyncObjectCopyRequest, Remove) {
707 // scribble some data
708 interval_set<uint64_t> one;
709 scribble(m_remote_image_ctx, 10, 102400, &one);
710 ASSERT_EQ(0, create_snap("one"));
711 ASSERT_EQ(0, create_snap("two"));
712
713 // remove the object
714 uint64_t object_size = 1 << m_remote_image_ctx->order;
715 ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard(0, object_size, m_remote_image_ctx->skip_partial_discard));
716 ASSERT_EQ(0, create_snap("sync"));
717 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
718 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
719
31f18b77
FG
720 librbd::MockExclusiveLock mock_exclusive_lock;
721 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
722
7c673cae
FG
723 librbd::MockObjectMap mock_object_map;
724 mock_local_image_ctx.object_map = &mock_object_map;
725
726 expect_test_features(mock_local_image_ctx);
727
728 C_SaferCond ctx;
729 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
730 mock_local_image_ctx, &ctx);
731
732 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
733 request->get_remote_io_ctx()));
734 librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
735 request->get_local_io_ctx()));
736
737 InSequence seq;
738 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
739 expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[1]);
740 expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
31f18b77 741 expect_start_op(mock_exclusive_lock);
7c673cae 742 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
31f18b77 743 expect_start_op(mock_exclusive_lock);
7c673cae 744 expect_remove(mock_local_io_ctx, 0);
31f18b77 745 expect_start_op(mock_exclusive_lock);
7c673cae
FG
746 expect_update_object_map(mock_local_image_ctx, mock_object_map,
747 m_local_snap_ids[0], OBJECT_EXISTS, 0);
31f18b77 748 expect_start_op(mock_exclusive_lock);
7c673cae
FG
749 expect_update_object_map(mock_local_image_ctx, mock_object_map,
750 m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0);
751
752 request->send();
753 ASSERT_EQ(0, ctx.wait());
754 ASSERT_EQ(0, compare_objects());
755}
756
757} // namespace image_sync
758} // namespace mirror
759} // namespace rbd