diff options
Diffstat (limited to 'src/test/librbd/io')
-rw-r--r-- | src/test/librbd/io/test_mock_ImageRequest.cc | 31 | ||||
-rw-r--r-- | src/test/librbd/io/test_mock_ObjectRequest.cc | 804 |
2 files changed, 817 insertions, 18 deletions
diff --git a/src/test/librbd/io/test_mock_ImageRequest.cc b/src/test/librbd/io/test_mock_ImageRequest.cc index 9d6423d66..6ee67fe5f 100644 --- a/src/test/librbd/io/test_mock_ImageRequest.cc +++ b/src/test/librbd/io/test_mock_ImageRequest.cc @@ -16,12 +16,15 @@ namespace { struct MockTestImageCtx; struct MockTestJournal : public MockJournal { - MOCK_METHOD4(append_write_event, uint64_t(uint64_t, size_t, + MOCK_METHOD3(append_write_event, uint64_t(const io::Extents&, const bufferlist &, bool)); + MOCK_METHOD3(append_write_same_event, uint64_t(const io::Extents&, + const bufferlist &, bool)); MOCK_METHOD5(append_compare_and_write_event, uint64_t(uint64_t, size_t, const bufferlist &, const bufferlist &, bool)); + MOCK_METHOD3(append_discard_event, uint64_t(const io::Extents&, uint32_t, bool)); MOCK_METHOD5(append_io_event_mock, uint64_t(const journal::EventEntry&, uint64_t, size_t, bool, int)); uint64_t append_io_event(journal::EventEntry &&event_entry, @@ -119,9 +122,10 @@ struct TestMockIoImageRequest : public TestMockFixture { } } - void expect_journal_append_io_event(MockTestJournal &mock_journal, uint64_t journal_tid, - uint64_t offset, size_t length) { - EXPECT_CALL(mock_journal, append_io_event_mock(_, offset, length, _, _)) + void expect_journal_append_discard_event(MockTestJournal &mock_journal, + uint64_t journal_tid, + const io::Extents& extents) { + EXPECT_CALL(mock_journal, append_discard_event(extents, _, _)) .WillOnce(Return(journal_tid)); } @@ -386,8 +390,8 @@ TEST_F(TestMockIoImageRequest, PartialDiscardJournalAppendEnabled) { InSequence seq; expect_get_modify_timestamp(mock_image_ctx, false); expect_is_journal_appending(mock_journal, true); - expect_journal_append_io_event(mock_journal, 0, 16, 63); - expect_journal_append_io_event(mock_journal, 1, 84, 100); + expect_journal_append_discard_event(mock_journal, 0, + {{16, 63}, {84, 100}}); expect_object_discard_request(mock_image_ctx, 0, 16, 63, 0); expect_object_discard_request(mock_image_ctx, 0, 84, 100, 0); @@ -419,8 +423,8 @@ TEST_F(TestMockIoImageRequest, TailDiscardJournalAppendEnabled) { InSequence seq; expect_get_modify_timestamp(mock_image_ctx, false); expect_is_journal_appending(mock_journal, true); - expect_journal_append_io_event( - mock_journal, 0, ictx->layout.object_size - 1024, 1024); + expect_journal_append_discard_event( + mock_journal, 0, {{ictx->layout.object_size - 1024, 1024}}); expect_object_discard_request( mock_image_ctx, 0, ictx->layout.object_size - 1024, 1024, 0); @@ -452,7 +456,7 @@ TEST_F(TestMockIoImageRequest, PruneRequiredDiscardJournalAppendEnabled) { InSequence seq; expect_get_modify_timestamp(mock_image_ctx, false); expect_is_journal_appending(mock_journal, true); - EXPECT_CALL(mock_journal, append_io_event_mock(_, _, _, _, _)).Times(0); + EXPECT_CALL(mock_journal, append_discard_event(_, _, _)).Times(0); EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, send(_)).Times(0); C_SaferCond aio_comp_ctx; @@ -482,7 +486,7 @@ TEST_F(TestMockIoImageRequest, LengthModifiedDiscardJournalAppendEnabled) { InSequence seq; expect_get_modify_timestamp(mock_image_ctx, false); expect_is_journal_appending(mock_journal, true); - expect_journal_append_io_event(mock_journal, 0, 32, 32); + expect_journal_append_discard_event(mock_journal, 0, {{32, 32}}); expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0); C_SaferCond aio_comp_ctx; @@ -513,10 +517,9 @@ TEST_F(TestMockIoImageRequest, DiscardGranularityJournalAppendEnabled) { InSequence seq; expect_get_modify_timestamp(mock_image_ctx, false); expect_is_journal_appending(mock_journal, true); - expect_journal_append_io_event(mock_journal, 0, 32, 32); - expect_journal_append_io_event(mock_journal, 1, 96, 64); - expect_journal_append_io_event( - mock_journal, 2, ictx->layout.object_size - 32, 32); + expect_journal_append_discard_event( + mock_journal, 0, + {{32, 32}, {96, 64}, {ictx->layout.object_size - 32, 32}}); expect_object_discard_request(mock_image_ctx, 0, 32, 32, 0); expect_object_discard_request(mock_image_ctx, 0, 96, 64, 0); expect_object_discard_request( diff --git a/src/test/librbd/io/test_mock_ObjectRequest.cc b/src/test/librbd/io/test_mock_ObjectRequest.cc index 0690b7722..97cf63bf4 100644 --- a/src/test/librbd/io/test_mock_ObjectRequest.cc +++ b/src/test/librbd/io/test_mock_ObjectRequest.cc @@ -1784,6 +1784,432 @@ TEST_F(TestMockIoObjectRequest, ListSnaps) { ASSERT_EQ(expected_snapshot_delta, snapshot_delta); } +TEST_F(TestMockIoObjectRequest, ListSnapsGrowFromSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4}; + + librados::snap_set_t snap_set; + snap_set.seq = 4; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2048}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 3072; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsTruncateFromSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4}; + + librados::snap_set_t snap_set; + snap_set.seq = 4; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1536}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 1536; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1536, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1536, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsTruncateFromBelowSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4, 5}; + + librados::snap_set_t snap_set; + snap_set.seq = 5; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1536}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 5; + clone_info.snaps = {5}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1024}}; + clone_info.size = 1536; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 1024; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1024, 1024, {SPARSE_EXTENT_STATE_ZEROED, 1024}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, 5, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{5,5}].insert( + 1536, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1024, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsTruncateStraddlingSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4, 5}; + + librados::snap_set_t snap_set; + snap_set.seq = 5; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2048}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 5; + clone_info.snaps = {5}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1536}}; + clone_info.size = 3072; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 1536; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1536, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, 5, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{5,5}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1536, 1536, {SPARSE_EXTENT_STATE_ZEROED, 1536}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsTruncateToSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4, 5}; + + librados::snap_set_t snap_set; + snap_set.seq = 5; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2048}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 5; + clone_info.snaps = {5}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2048}}; + clone_info.size = 3072; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, 5, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{5,5}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_ZEROED, 1024}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsTruncateToAboveSizeAtStart) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3, 4, 5}; + + librados::snap_set_t snap_set; + snap_set.seq = 5; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 512}}; + clone_info.size = 512; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 4; + clone_info.snaps = {4}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2048}}; + clone_info.size = 2048; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = 5; + clone_info.snaps = {5}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 2560}}; + clone_info.size = 3072; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 2560; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 2048, 512, {SPARSE_EXTENT_STATE_DATA, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size}}, + {3, 4, 5, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{4,4}].insert( + 512, 1536, {SPARSE_EXTENT_STATE_DATA, 1536}); + expected_snapshot_delta[{5,5}].insert( + 2048, 1024, {SPARSE_EXTENT_STATE_DATA, 1024}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 2560, 512, {SPARSE_EXTENT_STATE_ZEROED, 512}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + TEST_F(TestMockIoObjectRequest, ListSnapsENOENT) { librbd::ImageCtx *ictx; ASSERT_EQ(0, open_image(m_image_name, &ictx)); @@ -1926,7 +2352,7 @@ TEST_F(TestMockIoObjectRequest, ListSnapsWholeObject) { ASSERT_EQ(0, open_image(m_image_name, &ictx)); MockTestImageCtx mock_image_ctx(*ictx); - mock_image_ctx.parent = &mock_image_ctx; + mock_image_ctx.snaps = {3}; InSequence seq; @@ -1937,13 +2363,243 @@ TEST_F(TestMockIoObjectRequest, ListSnapsWholeObject) { clone_info.cloneid = 3; clone_info.snaps = {3}; clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{{0, 1}}; - clone_info.size = 4194304; + clone_info.size = mock_image_ctx.layout.object_size; snap_set.clones.push_back(clone_info); clone_info.cloneid = CEPH_NOSNAP; clone_info.snaps = {}; clone_info.overlap = {}; - clone_info.size = 4194304; + clone_info.size = mock_image_ctx.layout.object_size; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size - 1}}, + {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1, mock_image_ctx.layout.object_size - 2, + {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 2}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size - 1}}, + {3, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 0, mock_image_ctx.layout.object_size - 1, + {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 1}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectTruncate) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3}; + + InSequence seq; + + librados::snap_set_t snap_set; + snap_set.seq = 3; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{ + {2, mock_image_ctx.layout.object_size - 4}}; + clone_info.size = mock_image_ctx.layout.object_size; + snap_set.clones.push_back(clone_info); + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = mock_image_ctx.layout.object_size - 2; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}}, + {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1, 1, {SPARSE_EXTENT_STATE_DATA, 1}); + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + mock_image_ctx.layout.object_size - 2, 1, + {SPARSE_EXTENT_STATE_ZEROED, 1}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}}, + {3, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1, mock_image_ctx.layout.object_size - 2, + {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 2}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectRemove) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3}; + + InSequence seq; + + librados::snap_set_t snap_set; + snap_set.seq = 3; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {3}; + clone_info.overlap = {}; + clone_info.size = mock_image_ctx.layout.object_size - 2; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}}, + {3, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1, mock_image_ctx.layout.object_size - 3, + {SPARSE_EXTENT_STATE_ZEROED, mock_image_ctx.layout.object_size - 3}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{1, mock_image_ctx.layout.object_size - 2}}, + {3, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + SnapshotDelta expected_snapshot_delta; + expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( + 1, mock_image_ctx.layout.object_size - 2, + {SPARSE_EXTENT_STATE_ZEROED, mock_image_ctx.layout.object_size - 2}); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsWholeObjectEndSize) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3}; + + InSequence seq; + + librados::snap_set_t snap_set; + snap_set.seq = 3; + librados::clone_info_t clone_info; + + clone_info.cloneid = CEPH_NOSNAP; + clone_info.snaps = {}; + clone_info.overlap = {}; + // smaller than object extent (i.e. the op) to test end_size handling + clone_info.size = mock_image_ctx.layout.object_size - 2; + snap_set.clones.push_back(clone_info); + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size - 1}}, + {4, CEPH_NOSNAP}, 0, {}, &snapshot_delta, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + EXPECT_TRUE(snapshot_delta.empty()); + } + + expect_list_snaps(mock_image_ctx, snap_set, 0); + + { + SnapshotDelta snapshot_delta; + C_SaferCond ctx; + auto req = MockObjectListSnapsRequest::create( + &mock_image_ctx, 0, {{0, mock_image_ctx.layout.object_size - 1}}, + {4, CEPH_NOSNAP}, LIST_SNAPS_FLAG_WHOLE_OBJECT, {}, &snapshot_delta, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + EXPECT_TRUE(snapshot_delta.empty()); + } +} + +TEST_F(TestMockIoObjectRequest, ListSnapsNoSnapsInSnapSet) { + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockTestImageCtx mock_image_ctx(*ictx); + mock_image_ctx.snaps = {3}; + + InSequence seq; + + librados::snap_set_t snap_set; + snap_set.seq = 3; + librados::clone_info_t clone_info; + + clone_info.cloneid = 3; + clone_info.snaps = {}; + clone_info.overlap = {}; + clone_info.size = 0; snap_set.clones.push_back(clone_info); expect_list_snaps(mock_image_ctx, snap_set, 0); @@ -1960,7 +2616,147 @@ TEST_F(TestMockIoObjectRequest, ListSnapsWholeObject) { expected_snapshot_delta[{CEPH_NOSNAP,CEPH_NOSNAP}].insert( 0, mock_image_ctx.layout.object_size - 1, {SPARSE_EXTENT_STATE_DATA, mock_image_ctx.layout.object_size - 1}); - ASSERT_EQ(expected_snapshot_delta, snapshot_delta); + EXPECT_EQ(expected_snapshot_delta, snapshot_delta); +} + +TEST(SparseExtents, Split) { + SparseExtents extents; + extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100}); + extents.erase(80, 30); + extents.insert(45, 10, {SPARSE_EXTENT_STATE_ZEROED, 10}); + extents.insert(140, 20, {SPARSE_EXTENT_STATE_DNE, 20}); + extents.insert(125, 5, {SPARSE_EXTENT_STATE_ZEROED, 5}); + + SparseExtents expected_extents = { + {45, {10, {SPARSE_EXTENT_STATE_ZEROED, 10}}}, + {55, {25, {SPARSE_EXTENT_STATE_DATA, 25}}}, + {110, {15, {SPARSE_EXTENT_STATE_DATA, 15}}}, + {125, {5, {SPARSE_EXTENT_STATE_ZEROED, 5}}}, + {130, {10, {SPARSE_EXTENT_STATE_DATA, 10}}}, + {140, {20, {SPARSE_EXTENT_STATE_DNE, 20}}} + }; + EXPECT_EQ(expected_extents, extents); +} + +TEST(SparseExtents, Merge) { + SparseExtents extents; + extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100}); + extents.insert(30, 15, {SPARSE_EXTENT_STATE_ZEROED, 15}); + extents.insert(45, 10, {SPARSE_EXTENT_STATE_DATA, 10}); + extents.insert(200, 40, {SPARSE_EXTENT_STATE_DNE, 40}); + extents.insert(160, 25, {SPARSE_EXTENT_STATE_DNE, 25}); + extents.insert(140, 20, {SPARSE_EXTENT_STATE_DATA, 20}); + extents.insert(25, 5, {SPARSE_EXTENT_STATE_ZEROED, 5}); + extents.insert(185, 15, {SPARSE_EXTENT_STATE_DNE, 15}); + + SparseExtents expected_extents = { + {25, {20, {SPARSE_EXTENT_STATE_ZEROED, 20}}}, + {45, {115, {SPARSE_EXTENT_STATE_DATA, 115}}}, + {160, {80, {SPARSE_EXTENT_STATE_DNE, 80}}} + }; + EXPECT_EQ(expected_extents, extents); +} + +TEST(SparseBufferlist, Split) { + bufferlist bl; + bl.append(std::string(5, '1')); + bl.append(std::string(25, '2')); + bl.append(std::string(30, '3')); + bl.append(std::string(15, '4')); + bl.append(std::string(5, '5')); + bl.append(std::string(10, '6')); + bl.append(std::string(10, '7')); + bufferlist expected_bl1; + expected_bl1.append(std::string(25, '2')); + bufferlist expected_bl2; + expected_bl2.append(std::string(15, '4')); + bufferlist expected_bl3; + expected_bl3.append(std::string(10, '6')); + + SparseBufferlist extents; + extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100, std::move(bl)}); + extents.erase(80, 30); + extents.insert(45, 10, {SPARSE_EXTENT_STATE_ZEROED, 10}); + extents.insert(140, 20, {SPARSE_EXTENT_STATE_DNE, 20}); + extents.insert(125, 5, {SPARSE_EXTENT_STATE_ZEROED, 5}); + + SparseBufferlist expected_extents = { + {45, {10, {SPARSE_EXTENT_STATE_ZEROED, 10}}}, + {55, {25, {SPARSE_EXTENT_STATE_DATA, 25, std::move(expected_bl1)}}}, + {110, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl2)}}}, + {125, {5, {SPARSE_EXTENT_STATE_ZEROED, 5}}}, + {130, {10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(expected_bl3)}}}, + {140, {20, {SPARSE_EXTENT_STATE_DNE, 20}}} + }; + EXPECT_EQ(expected_extents, extents); +} + +TEST(SparseBufferlist, SplitData) { + bufferlist bl1; + bl1.append(std::string(100, '1')); + bufferlist bl2; + bl2.append(std::string(15, '2')); + bufferlist bl3; + bl3.append(std::string(40, '3')); + bufferlist bl4; + bl4.append(std::string(10, '4')); + bufferlist expected_bl1 = bl2; + bufferlist expected_bl2; + expected_bl2.append(std::string(35, '1')); + bufferlist expected_bl3 = bl4; + bufferlist expected_bl4; + expected_bl4.append(std::string(30, '1')); + bufferlist expected_bl5; + expected_bl5.append(std::string(5, '3')); + bufferlist expected_bl6; + expected_bl6.append(std::string(15, '3')); + + SparseBufferlist extents; + extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100, std::move(bl1)}); + extents.insert(40, 15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(bl2)}); + extents.insert(130, 40, {SPARSE_EXTENT_STATE_DATA, 40, std::move(bl3)}); + extents.erase(135, 20); + extents.insert(90, 10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(bl4)}); + + SparseBufferlist expected_extents = { + {40, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl1)}}}, + {55, {35, {SPARSE_EXTENT_STATE_DATA, 35, std::move(expected_bl2)}}}, + {90, {10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(expected_bl3)}}}, + {100, {30, {SPARSE_EXTENT_STATE_DATA, 30, std::move(expected_bl4)}}}, + {130, {5, {SPARSE_EXTENT_STATE_DATA, 5, std::move(expected_bl5)}}}, + {155, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl6)}}} + }; + EXPECT_EQ(expected_extents, extents); +} + +TEST(SparseBufferlist, Merge) { + bufferlist bl1; + bl1.append(std::string(100, '1')); + bufferlist bl2; + bl2.append(std::string(10, '2')); + bufferlist bl3; + bl3.append(std::string(20, '3')); + bufferlist expected_bl; + expected_bl.append(std::string(10, '2')); + expected_bl.append(std::string(85, '1')); + expected_bl.append(std::string(20, '3')); + + SparseBufferlist extents; + extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100, std::move(bl1)}); + extents.insert(30, 15, {SPARSE_EXTENT_STATE_ZEROED, 15}); + extents.insert(45, 10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(bl2)}); + extents.insert(200, 40, {SPARSE_EXTENT_STATE_DNE, 40}); + extents.insert(160, 25, {SPARSE_EXTENT_STATE_DNE, 25}); + extents.insert(140, 20, {SPARSE_EXTENT_STATE_DATA, 20, std::move(bl3)}); + extents.insert(25, 5, {SPARSE_EXTENT_STATE_ZEROED, 5}); + extents.insert(185, 15, {SPARSE_EXTENT_STATE_DNE, 15}); + + SparseBufferlist expected_extents = { + {25, {20, {SPARSE_EXTENT_STATE_ZEROED, 20}}}, + {45, {115, {SPARSE_EXTENT_STATE_DATA, 115, std::move(expected_bl)}}}, + {160, {80, {SPARSE_EXTENT_STATE_DNE, 80}}} + }; + EXPECT_EQ(expected_extents, extents); } } // namespace io |