summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/librbd/io')
-rw-r--r--src/test/librbd/io/test_mock_ImageRequest.cc31
-rw-r--r--src/test/librbd/io/test_mock_ObjectRequest.cc804
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