1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
22 struct MockTestImageCtx : public librbd::MockImageCtx {
23 MockTestImageCtx(librbd::ImageCtx &image_ctx)
24 : librbd::MockImageCtx(image_ctx) {
28 } // anonymous namespace
31 // template definitions
32 #include "tools/rbd_mirror/image_sync/ObjectCopyRequest.cc"
33 template class rbd::mirror::image_sync::ObjectCopyRequest<librbd::MockTestImageCtx>;
35 bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
36 return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
41 namespace image_sync {
44 using ::testing::DoAll;
45 using ::testing::DoDefault;
46 using ::testing::InSequence;
47 using ::testing::Invoke;
48 using ::testing::Return;
49 using ::testing::ReturnNew;
50 using ::testing::WithArg;
54 void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size,
55 interval_set<uint64_t> *what)
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;
63 bl.append(std::string(len, '1'));
65 int r = image_ctx->io_work_queue->write(off, len, std::move(bl), 0);
66 ASSERT_EQ(static_cast<int>(len), r);
68 interval_set<uint64_t> w;
72 std::cout << " wrote " << *what << std::endl;
75 } // anonymous namespace
77 class TestMockImageSyncObjectCopyRequest : public TestMockFixture {
79 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
81 void SetUp() override {
82 TestMockFixture::SetUp();
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));
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));
92 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
93 EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
94 ReturnNew<FunctionContext>([](int) {}));
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;
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),
116 expect.WillOnce(Return(r));
118 expect.WillOnce(DoDefault());
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)));
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,
137 void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
139 EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id));
142 void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset,
143 uint64_t length, int r) {
145 auto &expect = EXPECT_CALL(mock_io_ctx, sparse_read(_, offset, length, _, _));
147 expect.WillOnce(Return(r));
149 expect.WillOnce(DoDefault());
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);
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));
168 expect.WillOnce(Return(r));
170 expect.WillOnce(DoDefault());
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);
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, _));
189 expect.WillOnce(Return(r));
191 expect.WillOnce(DoDefault());
195 void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
196 auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _));
198 expect.WillOnce(Return(r));
200 expect.WillOnce(DoDefault());
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,
208 if (mock_image_ctx.image_ctx->object_map != nullptr) {
209 auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, _));
211 expect.WillOnce(DoAll(WithArg<6>(Invoke([this, r](Context *ctx) {
212 m_threads->work_queue->queue(ctx, r);
216 expect.WillOnce(DoAll(WithArg<6>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) {
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>(
220 snap_id, 0, 1, state, boost::none, {}, ctx);
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);
235 librados::snap_t local_snap_id;
236 r = create_snap(m_local_image_ctx, snap_name, &local_snap_id);
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());
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);
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,
261 librados::snap_t> &pair) {
262 return (pair.second == snap_id);
264 if (it == image_ctx->snap_ids.end()) {
267 return it->first.second;
270 int compare_objects() {
271 MockObjectCopyRequest::SnapMap snap_map(m_snap_map);
272 if (snap_map.empty()) {
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());
283 std::string snap_name = get_snap_name(m_remote_image_ctx, remote_snap_id);
284 if (snap_name.empty()) {
288 std::cout << "comparing '" << snap_name << " (" << remote_snap_id
289 << " to " << local_snap_id << ")" << std::endl;
291 r = librbd::snap_set(m_remote_image_ctx,
292 cls::rbd::UserSnapshotNamespace(),
298 r = librbd::snap_set(m_local_image_ctx,
299 cls::rbd::UserSnapshotNamespace(),
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);
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);
321 if (!remote_bl.contents_equal(local_bl)) {
326 r = librbd::snap_set(m_remote_image_ctx,
327 cls::rbd::UserSnapshotNamespace(),
332 r = librbd::snap_set(m_local_image_ctx,
333 cls::rbd::UserSnapshotNamespace(),
342 librbd::ImageCtx *m_remote_image_ctx;
343 librbd::ImageCtx *m_local_image_ctx;
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;
350 TEST_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);
355 librbd::MockExclusiveLock mock_exclusive_lock;
356 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
358 librbd::MockObjectMap mock_object_map;
359 mock_local_image_ctx.object_map = &mock_object_map;
360 expect_test_features(mock_local_image_ctx);
363 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
364 mock_local_image_ctx, &ctx);
366 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
367 request->get_remote_io_ctx()));
370 expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, -ENOENT);
373 ASSERT_EQ(0, ctx.wait());
376 TEST_F(TestMockImageSyncObjectCopyRequest, Write) {
377 // scribble some data
378 interval_set<uint64_t> one;
379 scribble(m_remote_image_ctx, 10, 102400, &one);
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);
385 librbd::MockExclusiveLock mock_exclusive_lock;
386 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
388 librbd::MockObjectMap mock_object_map;
389 mock_local_image_ctx.object_map = &mock_object_map;
391 expect_test_features(mock_local_image_ctx);
394 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
395 mock_local_image_ctx, &ctx);
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()));
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);
406 expect_start_op(mock_exclusive_lock);
407 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
408 expect_start_op(mock_exclusive_lock);
409 expect_update_object_map(mock_local_image_ctx, mock_object_map,
410 m_local_snap_ids[0], OBJECT_EXISTS, 0);
413 ASSERT_EQ(0, ctx.wait());
414 ASSERT_EQ(0, compare_objects());
417 TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingStaleSnapSet) {
418 ASSERT_EQ(0, create_snap("one"));
419 ASSERT_EQ(0, create_snap("two"));
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"));
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);
430 librbd::MockExclusiveLock mock_exclusive_lock;
431 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
433 librbd::MockObjectMap mock_object_map;
434 mock_local_image_ctx.object_map = &mock_object_map;
436 expect_test_features(mock_local_image_ctx);
439 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
440 mock_local_image_ctx, &ctx);
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()));
447 librados::clone_info_t dummy_clone_info;
448 dummy_clone_info.cloneid = librados::SNAP_HEAD;
449 dummy_clone_info.size = 123;
451 librados::snap_set_t dummy_snap_set1;
452 dummy_snap_set1.clones.push_back(dummy_clone_info);
454 dummy_clone_info.size = 234;
455 librados::snap_set_t dummy_snap_set2;
456 dummy_snap_set2.clones.push_back(dummy_clone_info);
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);
468 expect_start_op(mock_exclusive_lock);
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]}},
473 expect_start_op(mock_exclusive_lock);
474 expect_update_object_map(mock_local_image_ctx, mock_object_map,
475 m_local_snap_ids[2], OBJECT_EXISTS, 0);
476 expect_start_op(mock_exclusive_lock);
477 expect_update_object_map(mock_local_image_ctx, mock_object_map,
478 m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0);
481 ASSERT_EQ(0, ctx.wait());
482 ASSERT_EQ(0, compare_objects());
485 TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingUpToDateSnapMap) {
486 // scribble some data
487 interval_set<uint64_t> one;
488 scribble(m_remote_image_ctx, 10, 102400, &one);
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);
494 librbd::MockExclusiveLock mock_exclusive_lock;
495 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
497 librbd::MockObjectMap mock_object_map;
498 mock_local_image_ctx.object_map = &mock_object_map;
500 expect_test_features(mock_local_image_ctx);
503 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
504 mock_local_image_ctx, &ctx);
506 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
507 request->get_remote_io_ctx()));
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);
516 ASSERT_EQ(-ENOENT, ctx.wait());
519 TEST_F(TestMockImageSyncObjectCopyRequest, ReadError) {
520 // scribble some data
521 interval_set<uint64_t> one;
522 scribble(m_remote_image_ctx, 10, 102400, &one);
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);
528 librbd::MockExclusiveLock mock_exclusive_lock;
529 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
531 librbd::MockObjectMap mock_object_map;
532 mock_local_image_ctx.object_map = &mock_object_map;
534 expect_test_features(mock_local_image_ctx);
537 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
538 mock_local_image_ctx, &ctx);
540 librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
541 request->get_remote_io_ctx()));
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);
549 ASSERT_EQ(-EINVAL, ctx.wait());
552 TEST_F(TestMockImageSyncObjectCopyRequest, WriteError) {
553 // scribble some data
554 interval_set<uint64_t> one;
555 scribble(m_remote_image_ctx, 10, 102400, &one);
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);
561 librbd::MockExclusiveLock mock_exclusive_lock;
562 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
564 librbd::MockObjectMap mock_object_map;
565 mock_local_image_ctx.object_map = &mock_object_map;
567 expect_test_features(mock_local_image_ctx);
570 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
571 mock_local_image_ctx, &ctx);
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()));
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);
582 expect_start_op(mock_exclusive_lock);
583 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
586 ASSERT_EQ(-EINVAL, ctx.wait());
589 TEST_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"));
595 interval_set<uint64_t> two;
596 scribble(m_remote_image_ctx, 10, 102400, &two);
597 ASSERT_EQ(0, create_snap("two"));
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);
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);
609 librbd::MockExclusiveLock mock_exclusive_lock;
610 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
612 librbd::MockObjectMap mock_object_map;
613 mock_local_image_ctx.object_map = &mock_object_map;
615 expect_test_features(mock_local_image_ctx);
618 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
619 mock_local_image_ctx, &ctx);
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()));
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);
630 expect_start_op(mock_exclusive_lock);
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);
634 expect_start_op(mock_exclusive_lock);
635 expect_write(mock_local_io_ctx, two,
636 {m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0);
637 expect_start_op(mock_exclusive_lock);
638 expect_update_object_map(mock_local_image_ctx, mock_object_map,
639 m_local_snap_ids[0], OBJECT_EXISTS, 0);
640 expect_start_op(mock_exclusive_lock);
641 expect_update_object_map(mock_local_image_ctx, mock_object_map,
642 m_local_snap_ids[1], OBJECT_EXISTS, 0);
643 expect_start_op(mock_exclusive_lock);
644 expect_update_object_map(mock_local_image_ctx, mock_object_map,
645 m_local_snap_ids[2], OBJECT_EXISTS_CLEAN, 0);
648 ASSERT_EQ(0, ctx.wait());
649 ASSERT_EQ(0, compare_objects());
652 TEST_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"));
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"));
666 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
667 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
669 librbd::MockExclusiveLock mock_exclusive_lock;
670 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
672 librbd::MockObjectMap mock_object_map;
673 mock_local_image_ctx.object_map = &mock_object_map;
675 expect_test_features(mock_local_image_ctx);
678 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
679 mock_local_image_ctx, &ctx);
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()));
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);
690 expect_start_op(mock_exclusive_lock);
691 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
692 expect_start_op(mock_exclusive_lock);
693 expect_truncate(mock_local_io_ctx, trim_offset, 0);
694 expect_start_op(mock_exclusive_lock);
695 expect_update_object_map(mock_local_image_ctx, mock_object_map,
696 m_local_snap_ids[0], OBJECT_EXISTS, 0);
697 expect_start_op(mock_exclusive_lock);
698 expect_update_object_map(mock_local_image_ctx, mock_object_map,
699 m_local_snap_ids[1], OBJECT_EXISTS, 0);
702 ASSERT_EQ(0, ctx.wait());
703 ASSERT_EQ(0, compare_objects());
706 TEST_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"));
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);
720 librbd::MockExclusiveLock mock_exclusive_lock;
721 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
723 librbd::MockObjectMap mock_object_map;
724 mock_local_image_ctx.object_map = &mock_object_map;
726 expect_test_features(mock_local_image_ctx);
729 MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
730 mock_local_image_ctx, &ctx);
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()));
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);
741 expect_start_op(mock_exclusive_lock);
742 expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
743 expect_start_op(mock_exclusive_lock);
744 expect_remove(mock_local_io_ctx, 0);
745 expect_start_op(mock_exclusive_lock);
746 expect_update_object_map(mock_local_image_ctx, mock_object_map,
747 m_local_snap_ids[0], OBJECT_EXISTS, 0);
748 expect_start_op(mock_exclusive_lock);
749 expect_update_object_map(mock_local_image_ctx, mock_object_map,
750 m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0);
753 ASSERT_EQ(0, ctx.wait());
754 ASSERT_EQ(0, compare_objects());
757 } // namespace image_sync
758 } // namespace mirror