summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/object_map/test_mock_DiffRequest.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/test/librbd/object_map/test_mock_DiffRequest.cc2227
1 files changed, 2009 insertions, 218 deletions
diff --git a/src/test/librbd/object_map/test_mock_DiffRequest.cc b/src/test/librbd/object_map/test_mock_DiffRequest.cc
index c25ae4a95..9b88f0d75 100644
--- a/src/test/librbd/object_map/test_mock_DiffRequest.cc
+++ b/src/test/librbd/object_map/test_mock_DiffRequest.cc
@@ -18,6 +18,8 @@ struct MockTestImageCtx : public MockImageCtx {
}
};
+void noop(MockTestImageCtx&) {}
+
} // anonymous namespace
} // namespace librbd
@@ -26,13 +28,139 @@ struct MockTestImageCtx : public MockImageCtx {
using ::testing::_;
using ::testing::Invoke;
using ::testing::InSequence;
+using ::testing::Return;
using ::testing::StrEq;
using ::testing::WithArg;
namespace librbd {
namespace object_map {
-class TestMockObjectMapDiffRequest : public TestMockFixture {
+static constexpr uint8_t from_beginning_table[][2] = {
+ // to expected
+ { OBJECT_NONEXISTENT, DIFF_STATE_HOLE },
+ { OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED }
+};
+
+static constexpr uint8_t from_beginning_intermediate_table[][4] = {
+ // intermediate to diff-iterate expected deep-copy expected
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED }
+};
+
+static constexpr uint8_t from_snap_table[][3] = {
+ // from to expected
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA }
+};
+
+static constexpr uint8_t from_snap_intermediate_table[][5] = {
+ // from intermediate to diff-iterate expected deep-copy expected
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE },
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA, DIFF_STATE_DATA },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_PENDING, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_PENDING, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, OBJECT_NONEXISTENT, DIFF_STATE_HOLE_UPDATED, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, OBJECT_PENDING, DIFF_STATE_DATA_UPDATED, DIFF_STATE_DATA_UPDATED },
+ { OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, OBJECT_EXISTS_CLEAN, DIFF_STATE_DATA, DIFF_STATE_DATA }
+};
+
+static constexpr uint8_t shrink_table[][2] = {
+ // shrunk deep-copy expected
+ { OBJECT_NONEXISTENT, DIFF_STATE_HOLE },
+ { OBJECT_EXISTS, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_PENDING, DIFF_STATE_HOLE_UPDATED },
+ { OBJECT_EXISTS_CLEAN, DIFF_STATE_HOLE_UPDATED }
+};
+
+class TestMockObjectMapDiffRequest : public TestMockFixture,
+ public ::testing::WithParamInterface<bool> {
public:
typedef DiffRequest<MockTestImageCtx> MockDiffRequest;
@@ -42,6 +170,10 @@ public:
ASSERT_EQ(0, open_image(m_image_name, &m_image_ctx));
}
+ bool is_diff_iterate() const {
+ return !GetParam();
+ }
+
void expect_get_flags(MockTestImageCtx& mock_image_ctx, uint64_t snap_id,
int32_t flags, int r) {
EXPECT_CALL(mock_image_ctx, get_flags(snap_id, _))
@@ -76,418 +208,2077 @@ public:
expect_load_map(mock_image_ctx, snap_id, object_map, r, [](){});
}
+ void expect_with_map(MockTestImageCtx& mock_image_ctx,
+ const BitVector<2>& object_map) {
+ EXPECT_CALL(*mock_image_ctx.object_map, with()).WillOnce(Return(object_map));
+ }
+
+ template <typename F>
+ int do_diff(bool want_object_map, F&& f,
+ uint64_t start_snap_id, uint64_t end_snap_id,
+ uint64_t start_object_no, uint64_t end_object_no) {
+ InSequence seq;
+
+ MockTestImageCtx mock_image_ctx(*m_image_ctx);
+ MockObjectMap mock_object_map;
+ if (want_object_map) {
+ mock_image_ctx.object_map = &mock_object_map;
+ }
+ mock_image_ctx.snap_id = end_snap_id;
+ std::forward<F>(f)(mock_image_ctx);
+
+ C_SaferCond ctx;
+ auto req = new MockDiffRequest(&mock_image_ctx, start_snap_id,
+ end_snap_id, start_object_no, end_object_no,
+ &m_diff_state, &ctx);
+ req->send();
+ return ctx.wait();
+ }
+
+ template <typename F>
+ void test_diff_iterate(bool want_object_map, F&& f,
+ uint64_t start_snap_id, uint64_t end_snap_id,
+ const BitVector<2>& expected_diff_state) {
+ // ranged -- run through all ranges (substrings) in expected_diff_state
+ for (uint64_t i = 0; i < expected_diff_state.size(); i++) {
+ for (uint64_t j = i + 1; j <= expected_diff_state.size(); j++) {
+ ASSERT_EQ(0, do_diff(want_object_map, std::forward<F>(f),
+ start_snap_id, end_snap_id, i, j));
+ ASSERT_EQ(j - i, m_diff_state.size());
+ for (uint64_t k = 0; k < m_diff_state.size(); k++) {
+ ASSERT_EQ(expected_diff_state[i + k], m_diff_state[k]);
+ }
+ }
+ }
+
+ // unranged -- equivalent to i=0, j=expected_diff_state.size() range
+ ASSERT_EQ(0, do_diff(want_object_map, std::forward<F>(f),
+ start_snap_id, end_snap_id, 0, UINT64_MAX - 1));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ }
+
+ template <typename F>
+ void test_deep_copy(bool want_object_map, F&& f,
+ uint64_t start_snap_id, uint64_t end_snap_id,
+ const BitVector<2>& expected_diff_state) {
+ ASSERT_EQ(0, do_diff(want_object_map, std::forward<F>(f),
+ start_snap_id, end_snap_id, 0, UINT64_MAX));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ }
+
librbd::ImageCtx* m_image_ctx = nullptr;
- BitVector<2> m_object_diff_state;
+ BitVector<2> m_diff_state;
};
-TEST_F(TestMockObjectMapDiffRequest, InvalidStartSnap) {
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
+TEST_P(TestMockObjectMapDiffRequest, InvalidStartSnap) {
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, CEPH_NOSNAP, CEPH_NOSNAP, 123, 456));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, CEPH_NOSNAP, CEPH_NOSNAP, 123, 456));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, CEPH_NOSNAP, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, CEPH_NOSNAP, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, InvalidEndSnap) {
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 2, 1, 123, 456));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 2, 1, 123, 456));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 2, 1, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 2, 1, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, StartEndSnapEqual) {
+ BitVector<2> expected_diff_state;
- InSequence seq;
+ if (is_diff_iterate()) {
+ ASSERT_EQ(0, do_diff(false, noop, 1, 1, 123, 456));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ ASSERT_EQ(0, do_diff(true, noop, 1, 1, 123, 456));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ } else {
+ ASSERT_EQ(0, do_diff(false, noop, 1, 1, 0, UINT64_MAX));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ ASSERT_EQ(0, do_diff(true, noop, 1, 1, 0, UINT64_MAX));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ }
+}
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, CEPH_NOSNAP, 0,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
+TEST_P(TestMockObjectMapDiffRequest, InvalidStartObject) {
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, 1, UINT64_MAX, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, 1, UINT64_MAX, UINT64_MAX));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, 1, 123, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, 1, 123, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, StartEndSnapEqual) {
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
+TEST_P(TestMockObjectMapDiffRequest, InvalidEndObject) {
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, 1, 456, 123));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, 1, 456, 123));
+ } else {
+ SUCCEED();
+ }
+}
- InSequence seq;
+TEST_P(TestMockObjectMapDiffRequest, StartEndObjectEqual) {
+ BitVector<2> expected_diff_state;
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 1, 1,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
- ASSERT_EQ(0U, m_object_diff_state.size());
+ if (is_diff_iterate()) {
+ ASSERT_EQ(0, do_diff(false, noop, 0, 1, 123, 123));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ ASSERT_EQ(0, do_diff(true, noop, 0, 1, 123, 123));
+ ASSERT_EQ(expected_diff_state, m_diff_state);
+ } else {
+ SUCCEED();
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, FastDiffDisabled) {
+TEST_P(TestMockObjectMapDiffRequest, FastDiffDisabled) {
// negative test -- object-map implicitly enables fast-diff
REQUIRE(!is_feature_enabled(RBD_FEATURE_OBJECT_MAP));
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, CEPH_NOSNAP, 123, 456));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, CEPH_NOSNAP, 123, 456));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_beginning_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ if (is_diff_iterate()) {
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_1);
+ };
+ test_diff_iterate(false, load, 0, 1, expected_diff_state);
+ test_diff_iterate(true, with, 0, 1, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, 1, expected_diff_state);
+ test_deep_copy(true, load, 0, 1, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, FastDiffInvalid) {
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapEmpty) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
+ m_image_ctx->size = 0;
+ m_image_ctx->snap_info = {
{1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
};
- InSequence seq;
- expect_get_flags(mock_image_ctx, 1U, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ BitVector<2> object_map_1;
+ BitVector<2> expected_diff_state;
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ if (is_diff_iterate()) {
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_1);
+ };
+ test_diff_iterate(false, load, 0, 1, expected_diff_state);
+ test_diff_iterate(true, with, 0, 1, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, 1, expected_diff_state);
+ test_deep_copy(true, load, 0, 1, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, FullDelta) {
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnap) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- uint32_t object_count = 5;
+ uint32_t object_count = std::size(from_beginning_intermediate_table);
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
-
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}},
- {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_2[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ test_diff_iterate(false, load, 0, 2, expected_diff_state);
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ test_deep_copy(false, load, 0, 2, expected_diff_state);
+ test_deep_copy(true, load, 0, 2, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrow) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ uint32_t object_count_1 = std::size(from_beginning_intermediate_table);
+ uint32_t object_count_2 = object_count_1 + std::size(from_beginning_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
BitVector<2> object_map_1;
- object_map_1.resize(object_count);
- object_map_1[1] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count_2);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_2);
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_2[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+ for (uint32_t i = object_count_1; i < object_count_2; i++) {
+ object_map_2[i] = from_beginning_table[i - object_count_1][0];
+ expected_diff_state[i] = from_beginning_table[i - object_count_1][1];
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ test_diff_iterate(false, load, 0, 2, expected_diff_state);
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ test_deep_copy(false, load, 0, 2, expected_diff_state);
+ test_deep_copy(true, load, 0, 2, expected_diff_state);
+ }
+}
- expect_get_flags(mock_image_ctx, 2U, 0, 0);
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrowFromZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_2 = std::size(from_beginning_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+ BitVector<2> object_map_1;
BitVector<2> object_map_2;
- object_map_2.resize(object_count);
- object_map_2[1] = OBJECT_EXISTS_CLEAN;
- object_map_2[2] = OBJECT_EXISTS;
- object_map_2[3] = OBJECT_EXISTS;
- expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
+ object_map_2.resize(object_count_2);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_2);
+ for (uint32_t i = 0; i < object_count_2; i++) {
+ object_map_2[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ test_diff_iterate(false, load, 0, 2, expected_diff_state);
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ test_deep_copy(false, load, 0, 2, expected_diff_state);
+ test_deep_copy(true, load, 0, 2, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrink) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_2 = std::size(from_beginning_intermediate_table);
+ uint32_t object_count_1 = object_count_2 + std::size(shrink_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count_2);
+ BitVector<2> expected_diff_state;
+ if (is_diff_iterate()) {
+ expected_diff_state.resize(object_count_2);
+ } else {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_2; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_2[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+ for (uint32_t i = object_count_2; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i - object_count_2][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i - object_count_2][1];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ test_diff_iterate(false, load, 0, 2, expected_diff_state);
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ test_deep_copy(false, load, 0, 2, expected_diff_state);
+ test_deep_copy(true, load, 0, 2, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrinkToZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_1 = std::size(shrink_table);
+ m_image_ctx->size = 0;
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ BitVector<2> expected_diff_state;
+ if (!is_diff_iterate()) {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i][1];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ test_diff_iterate(false, load, 0, 2, expected_diff_state);
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ test_deep_copy(false, load, 0, 2, expected_diff_state);
+ test_deep_copy(true, load, 0, 2, expected_diff_state);
+ }
+}
- expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToUnsetSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_beginning_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ mock_image_ctx.snap_id = 123;
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 0, 1, expected_diff_state);
+ test_diff_iterate(true, load, 0, 1, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, 1, expected_diff_state);
+ test_deep_copy(true, load, 0, 1, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHead) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_beginning_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
BitVector<2> object_map_head;
object_map_head.resize(object_count);
- object_map_head[1] = OBJECT_EXISTS_CLEAN;
- object_map_head[2] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_head[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadEmpty) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ m_image_ctx->size = 0;
+
+ BitVector<2> object_map_head;
+ BitVector<2> expected_diff_state;
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_beginning_intermediate_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
BitVector<2> expected_diff_state;
expected_diff_state.resize(object_count);
- expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- expected_diff_state[2] = DIFF_STATE_DATA_UPDATED;
- expected_diff_state[3] = DIFF_STATE_HOLE_UPDATED;
- ASSERT_EQ(expected_diff_state, m_object_diff_state);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_head[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, IntermediateDelta) {
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrow) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- uint32_t object_count = 5;
+ uint32_t object_count_1 = std::size(from_beginning_intermediate_table);
+ uint32_t object_count_head = object_count_1 + std::size(from_beginning_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_head);
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_head[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+ for (uint32_t i = object_count_1; i < object_count_head; i++) {
+ object_map_head[i] = from_beginning_table[i - object_count_1][0];
+ expected_diff_state[i] = from_beginning_table[i - object_count_1][1];
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrowFromZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_head = std::size(from_beginning_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_head);
+ for (uint32_t i = 0; i < object_count_head; i++) {
+ object_map_head[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrink) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_head = std::size(from_beginning_intermediate_table);
+ uint32_t object_count_1 = object_count_head + std::size(shrink_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ if (is_diff_iterate()) {
+ expected_diff_state.resize(object_count_head);
+ } else {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_head; i++) {
+ object_map_1[i] = from_beginning_intermediate_table[i][0];
+ object_map_head[i] = from_beginning_intermediate_table[i][1];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][2];
+ } else {
+ expected_diff_state[i] = from_beginning_intermediate_table[i][3];
+ }
+ }
+ for (uint32_t i = object_count_head; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i - object_count_head][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i - object_count_head][1];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrinkToZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_1 = std::size(shrink_table);
+ m_image_ctx->size = 0;
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ BitVector<2> expected_diff_state;
+ if (!is_diff_iterate()) {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i][1];
+ }
+ }
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromBeginningToUnsetHead) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_beginning_table);
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_head[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ mock_image_ctx.snap_id = 123;
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_snap_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}},
- {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_2[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 2, expected_diff_state);
+ test_diff_iterate(true, load, 1, 2, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 2, expected_diff_state);
+ test_deep_copy(true, load, 1, 2, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapGrow) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_1 = std::size(from_snap_table);
+ uint32_t object_count_2 = object_count_1 + std::size(from_beginning_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
BitVector<2> object_map_1;
- object_map_1.resize(object_count);
- object_map_1[1] = OBJECT_EXISTS;
- object_map_1[2] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count_2);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_2);
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_2[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
+ for (uint32_t i = object_count_1; i < object_count_2; i++) {
+ object_map_2[i] = from_beginning_table[i - object_count_1][0];
+ expected_diff_state[i] = from_beginning_table[i - object_count_1][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 2, expected_diff_state);
+ test_diff_iterate(true, load, 1, 2, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 2, expected_diff_state);
+ test_deep_copy(true, load, 1, 2, expected_diff_state);
+ }
+}
- expect_get_flags(mock_image_ctx, 2U, 0, 0);
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapGrowFromZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+ uint32_t object_count_2 = std::size(from_beginning_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
BitVector<2> object_map_2;
- object_map_2.resize(object_count);
- object_map_2[1] = OBJECT_EXISTS_CLEAN;
- object_map_2[2] = OBJECT_EXISTS;
- object_map_2[3] = OBJECT_EXISTS;
- expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
+ object_map_2.resize(object_count_2);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_2);
+ for (uint32_t i = 0; i < object_count_2; i++) {
+ object_map_2[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 2, expected_diff_state);
+ test_diff_iterate(true, load, 1, 2, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 2, expected_diff_state);
+ test_deep_copy(true, load, 1, 2, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapShrink) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 1, 2,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
+ uint32_t object_count_2 = std::size(from_snap_table);
+ uint32_t object_count_1 = object_count_2 + std::size(shrink_table);
+ m_image_ctx->size = object_count_2 * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_2 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count_2);
BitVector<2> expected_diff_state;
- expected_diff_state.resize(object_count);
- expected_diff_state[1] = DIFF_STATE_DATA;
- expected_diff_state[2] = DIFF_STATE_DATA_UPDATED;
- expected_diff_state[3] = DIFF_STATE_DATA_UPDATED;
- ASSERT_EQ(expected_diff_state, m_object_diff_state);
+ if (is_diff_iterate()) {
+ expected_diff_state.resize(object_count_2);
+ } else {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_2; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_2[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
+ for (uint32_t i = object_count_2; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i - object_count_2][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i - object_count_2][1];
+ }
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 2, expected_diff_state);
+ test_diff_iterate(true, load, 1, 2, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 2, expected_diff_state);
+ test_deep_copy(true, load, 1, 2, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, EndDelta) {
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapShrinkToZero) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- uint32_t object_count = 5;
- m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ uint32_t object_count_1 = std::size(shrink_table);
+ m_image_ctx->size = 0;
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
+ };
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
- {}, {}, {}}},
- {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
- {}, {}, {}}}
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_2;
+ BitVector<2> expected_diff_state;
+ if (!is_diff_iterate()) {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i][1];
+ }
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
};
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 2, expected_diff_state);
+ test_diff_iterate(true, load, 1, 2, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 2, expected_diff_state);
+ test_deep_copy(true, load, 1, 2, expected_diff_state);
+ }
+}
- InSequence seq;
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapIntermediateSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, 2U, 0, 0);
+ uint32_t object_count = std::size(from_snap_intermediate_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {3U, {"snap3", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
BitVector<2> object_map_2;
object_map_2.resize(object_count);
- object_map_2[1] = OBJECT_EXISTS_CLEAN;
- object_map_2[2] = OBJECT_EXISTS;
- object_map_2[3] = OBJECT_EXISTS;
- expect_load_map(mock_image_ctx, 2U, object_map_2, 0);
+ BitVector<2> object_map_3;
+ object_map_3.resize(object_count);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_snap_intermediate_table[i][0];
+ object_map_2[i] = from_snap_intermediate_table[i][1];
+ object_map_3[i] = from_snap_intermediate_table[i][2];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_snap_intermediate_table[i][3];
+ } else {
+ expected_diff_state[i] = from_snap_intermediate_table[i][4];
+ }
+ }
- expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ expect_get_flags(mock_image_ctx, 3, 0, 0);
+ expect_load_map(mock_image_ctx, 3, object_map_3, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, 3, expected_diff_state);
+ test_diff_iterate(true, load, 1, 3, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, 3, expected_diff_state);
+ test_deep_copy(true, load, 1, 3, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHead) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+ uint32_t object_count = std::size(from_snap_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
BitVector<2> object_map_head;
object_map_head.resize(object_count);
- object_map_head[1] = OBJECT_EXISTS_CLEAN;
- object_map_head[2] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_head[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadGrow) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_1 = std::size(from_snap_table);
+ uint32_t object_count_head = object_count_1 + std::size(from_beginning_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_head);
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_head[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
+ for (uint32_t i = object_count_1; i < object_count_head; i++) {
+ object_map_head[i] = from_beginning_table[i - object_count_1][0];
+ expected_diff_state[i] = from_beginning_table[i - object_count_1][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadGrowFromZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_head = std::size(from_beginning_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, {}, {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count_head);
+ for (uint32_t i = 0; i < object_count_head; i++) {
+ object_map_head[i] = from_beginning_table[i][0];
+ expected_diff_state[i] = from_beginning_table[i][1];
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadShrink) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_head = std::size(from_snap_table);
+ uint32_t object_count_1 = object_count_head + std::size(shrink_table);
+ m_image_ctx->size = object_count_head * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count_head);
+ BitVector<2> expected_diff_state;
+ if (is_diff_iterate()) {
+ expected_diff_state.resize(object_count_head);
+ } else {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_head; i++) {
+ object_map_1[i] = from_snap_table[i][0];
+ object_map_head[i] = from_snap_table[i][1];
+ expected_diff_state[i] = from_snap_table[i][2];
+ }
+ for (uint32_t i = object_count_head; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i - object_count_head][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i - object_count_head][1];
+ }
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadShrinkToZero) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count_1 = std::size(shrink_table);
+ m_image_ctx->size = 0;
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}},
+ object_count_1 * (1 << m_image_ctx->order), {}, {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count_1);
+ BitVector<2> object_map_head;
+ BitVector<2> expected_diff_state;
+ if (!is_diff_iterate()) {
+ expected_diff_state.resize(object_count_1);
+ }
+ for (uint32_t i = 0; i < object_count_1; i++) {
+ object_map_1[i] = shrink_table[i][0];
+ if (!is_diff_iterate()) {
+ expected_diff_state[i] = shrink_table[i][1];
+ }
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 2, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
+TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadIntermediateSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = std::size(from_snap_intermediate_table);
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
BitVector<2> expected_diff_state;
expected_diff_state.resize(object_count);
- expected_diff_state[1] = DIFF_STATE_DATA;
- expected_diff_state[2] = DIFF_STATE_DATA;
- expected_diff_state[3] = DIFF_STATE_HOLE_UPDATED;
- ASSERT_EQ(expected_diff_state, m_object_diff_state);
+ for (uint32_t i = 0; i < object_count; i++) {
+ object_map_1[i] = from_snap_intermediate_table[i][0];
+ object_map_2[i] = from_snap_intermediate_table[i][1];
+ object_map_head[i] = from_snap_intermediate_table[i][2];
+ if (is_diff_iterate()) {
+ expected_diff_state[i] = from_snap_intermediate_table[i][3];
+ } else {
+ expected_diff_state[i] = from_snap_intermediate_table[i][4];
+ }
+ }
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, StartSnapDNE) {
+TEST_P(TestMockObjectMapDiffRequest, StartSnapDNE) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-ENOENT, do_diff(false, noop, 1, 2, 0, object_count));
+ ASSERT_EQ(-ENOENT, do_diff(true, noop, 1, 2, 0, object_count));
+ } else {
+ ASSERT_EQ(-ENOENT, do_diff(false, noop, 1, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-ENOENT, do_diff(true, noop, 1, 2, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, EndSnapDNE) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 1, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-ENOENT, do_diff(false, noop, 0, 2, 0, object_count));
+ ASSERT_EQ(-ENOENT, do_diff(true, noop, 0, 2, 0, object_count));
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ ASSERT_EQ(-ENOENT, do_diff(false, load, 0, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-ENOENT, do_diff(true, load, 0, 2, 0, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, EndSnapDNE) {
+TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromBeginning) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
-
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0,
+ [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); });
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_1;
object_map_1.resize(object_count);
- expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 1, 2,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0,
+ [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); });
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, IntermediateSnapDNE) {
+TEST_P(TestMockObjectMapDiffRequest, StartObjectMapDNE) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
-
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}},
- {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, -ENOENT);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-ENOENT, do_diff(false, load, 1, 2, 0, object_count));
+ ASSERT_EQ(-ENOENT, do_diff(true, load, 1, 2, 0, object_count));
+ } else {
+ ASSERT_EQ(-ENOENT, do_diff(false, load, 1, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-ENOENT, do_diff(true, load, 1, 2, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, EndObjectMapDNE) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_1;
object_map_1.resize(object_count);
- object_map_1[1] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, 1U, object_map_1, 0,
- [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); });
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count);
+ object_map_2[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ ASSERT_EQ(-ENOENT, do_diff(false, load, 0, 2, 0, object_count));
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT);
+ };
+ ASSERT_EQ(-ENOENT, do_diff(false, load, 0, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-ENOENT, do_diff(true, load, 0, 2, 0, UINT64_MAX));
+ }
+}
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromBeginning) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
BitVector<2> object_map_head;
object_map_head.resize(object_count);
object_map_head[1] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, -ENOENT);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
BitVector<2> expected_diff_state;
expected_diff_state.resize(object_count);
expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- ASSERT_EQ(expected_diff_state, m_object_diff_state);
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ if (is_diff_iterate()) {
+ test_diff_iterate(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, StartFastDiffInvalid) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ auto get_flags = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 1, 2, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 1, 2, 0, object_count));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 1, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 1, 2, 0, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapDNE) {
+TEST_P(TestMockObjectMapDiffRequest, EndFastDiffInvalid) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+
+ if (is_diff_iterate()) {
+ auto get_flags = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 0, 2, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 0, 2, 0, object_count));
+ } else {
+ auto get_flags = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 0, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 0, 2, 0, UINT64_MAX));
+ }
+}
- InSequence seq;
+TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromBeginning) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_head;
- expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, -ENOENT);
+ object_map_head.resize(object_count);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-ENOENT, ctx.wait());
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto get_flags = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, LoadIntermediateObjectMapDNE) {
+TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromSnap) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+
+ auto get_flags = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 1, CEPH_NOSNAP, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 1, CEPH_NOSNAP, 0, object_count));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, get_flags, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, get_flags, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, StartObjectMapLoadError) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, -EPERM);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EPERM, do_diff(false, load, 1, 2, 0, object_count));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 1, 2, 0, object_count));
+ } else {
+ ASSERT_EQ(-EPERM, do_diff(false, load, 1, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 1, 2, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, EndObjectMapLoadError) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_1;
- expect_load_map(mock_image_ctx, 1U, object_map_1, -ENOENT);
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count);
+ object_map_2[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ ASSERT_EQ(-EPERM, do_diff(false, load, 0, 2, 0, object_count));
+ test_diff_iterate(true, with, 0, 2, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM);
+ };
+ ASSERT_EQ(-EPERM, do_diff(false, load, 0, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 0, 2, 0, UINT64_MAX));
+ }
+}
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromBeginning) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
BitVector<2> object_map_head;
object_map_head.resize(object_count);
object_map_head[1] = OBJECT_EXISTS_CLEAN;
- expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
-
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(0, ctx.wait());
-
BitVector<2> expected_diff_state;
expected_diff_state.resize(object_count);
expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
- ASSERT_EQ(expected_diff_state, m_object_diff_state);
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, -EPERM);
+ };
+ ASSERT_EQ(-EPERM, do_diff(false, load, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, LoadObjectMapError) {
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromSnap) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
-
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EPERM, do_diff(false, load, 1, CEPH_NOSNAP, 0, object_count));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 1, CEPH_NOSNAP, 0, object_count));
+ } else {
+ ASSERT_EQ(-EPERM, do_diff(false, load, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EPERM, do_diff(true, load, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, StartObjectMapTooSmall) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_1;
- expect_load_map(mock_image_ctx, 1U, object_map_1, -EPERM);
+ object_map_1.resize(object_count - 1);
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-EPERM, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 1, 2, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 1, 2, 0, object_count));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 1, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 1, 2, 0, UINT64_MAX));
+ }
}
-TEST_F(TestMockObjectMapDiffRequest, ObjectMapTooSmall) {
+TEST_P(TestMockObjectMapDiffRequest, EndObjectMapTooSmall) {
REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
uint32_t object_count = 5;
m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
- MockTestImageCtx mock_image_ctx(*m_image_ctx);
- mock_image_ctx.snap_info = {
- {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {},
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count - 1);
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_2);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 0, 2, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, with, 0, 2, 0, object_count));
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 0, 2, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 0, 2, 0, UINT64_MAX));
+ }
+}
+
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromBeginning) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
{}, {}, {}}}
};
- InSequence seq;
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count - 1);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ };
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 0, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
+}
- expect_get_flags(mock_image_ctx, 1U, 0, 0);
+TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromSnap) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}},
+ {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
BitVector<2> object_map_1;
- expect_load_map(mock_image_ctx, 1U, object_map_1, 0);
+ object_map_1.resize(object_count);
+ BitVector<2> object_map_2;
+ object_map_2.resize(object_count - 1);
- C_SaferCond ctx;
- auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP,
- &m_object_diff_state, &ctx);
- req->send();
- ASSERT_EQ(-EINVAL, ctx.wait());
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, 2, 0, 0);
+ expect_load_map(mock_image_ctx, 2, object_map_2, 0);
+ };
+ if (is_diff_iterate()) {
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 1, CEPH_NOSNAP, 0, object_count));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 1, CEPH_NOSNAP, 0, object_count));
+ } else {
+ ASSERT_EQ(-EINVAL, do_diff(false, load, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ ASSERT_EQ(-EINVAL, do_diff(true, load, 1, CEPH_NOSNAP, 0, UINT64_MAX));
+ }
}
+TEST_P(TestMockObjectMapDiffRequest, ObjectMapTooLarge) {
+ REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF);
+
+ uint32_t object_count = 5;
+ m_image_ctx->size = object_count * (1 << m_image_ctx->order);
+ m_image_ctx->snap_info = {
+ {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {},
+ {}, {}, {}}}
+ };
+
+ BitVector<2> object_map_1;
+ object_map_1.resize(object_count + 12);
+ BitVector<2> object_map_head;
+ object_map_head.resize(object_count + 34);
+ object_map_head[1] = OBJECT_EXISTS_CLEAN;
+ BitVector<2> expected_diff_state;
+ expected_diff_state.resize(object_count);
+ expected_diff_state[1] = DIFF_STATE_DATA_UPDATED;
+
+ if (is_diff_iterate()) {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ auto with = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_with_map(mock_image_ctx, object_map_head);
+ };
+ test_diff_iterate(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_diff_iterate(true, with, 0, CEPH_NOSNAP, expected_diff_state);
+ } else {
+ auto load = [&](MockTestImageCtx& mock_image_ctx) {
+ expect_get_flags(mock_image_ctx, 1, 0, 0);
+ expect_load_map(mock_image_ctx, 1, object_map_1, 0);
+ expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0);
+ };
+ test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state);
+ test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(MockObjectMapDiffRequestTests,
+ TestMockObjectMapDiffRequest, ::testing::Bool());
+
} // namespace object_map
} // librbd