summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/io/test_mock_ObjectRequest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/librbd/io/test_mock_ObjectRequest.cc')
-rw-r--r--src/test/librbd/io/test_mock_ObjectRequest.cc804
1 files changed, 800 insertions, 4 deletions
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