From 7aff35c987b9f0e9f0d4198d032737da0ce12b36 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Sun, 3 Dec 2023 16:39:39 +0100 Subject: [PATCH] test/librbd: redo TestMockObjectMapDiffRequest.*Delta tests Existing *Delta tests cover: - beginning of time -> HEAD, through intermediate snap - snap -> snap, directly - snap -> HEAD, directly But coverage is too weak: none of the weird OBJECT_PENDING cases and only a single diff-iterate vs deep-copy case is tested, for example. Coverage is missing completely for: - beginning of time -> HEAD, directly - beginning of time -> snap, directly - beginning of time -> snap, through intermediate snap - snap -> snap, through intermediate snap - snap -> HEAD, through intermediate snap This adds the following tests: - FromBeginningToHead - FromBeginningToHeadIntermediateSnap (expands FullDelta) - FromBeginningToSnap - FromBeginningToSnapIntermediateSnap - FromSnapToSnap (expands IntermediateDelta) - FromSnapToSnapIntermediateSnap - FromSnapToHead (expands EndDelta) - FromSnapToHeadIntermediateSnap Signed-off-by: Ilya Dryomov --- .../object_map/test_mock_DiffRequest.cc | 420 +++++++++++++++--- 1 file changed, 370 insertions(+), 50 deletions(-) diff --git a/src/test/librbd/object_map/test_mock_DiffRequest.cc b/src/test/librbd/object_map/test_mock_DiffRequest.cc index 440040e9a835a..aefebf4a05bba 100644 --- a/src/test/librbd/object_map/test_mock_DiffRequest.cc +++ b/src/test/librbd/object_map/test_mock_DiffRequest.cc @@ -32,6 +32,122 @@ using ::testing::WithArg; namespace librbd { namespace object_map { +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 } +}; + class TestMockObjectMapDiffRequest : public TestMockFixture, public ::testing::WithParamInterface { public: @@ -146,44 +262,108 @@ TEST_P(TestMockObjectMapDiffRequest, FastDiffInvalid) { ASSERT_EQ(-EINVAL, ctx.wait()); } -TEST_P(TestMockObjectMapDiffRequest, FullDelta) { +TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnap) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); - uint32_t object_count = 5; + 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, {}, - {}, {}, {}}}, - {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_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]; + } + InSequence seq; expect_get_flags(mock_image_ctx, 1U, 0, 0); + expect_load_map(mock_image_ctx, 1U, object_map_1, 0); + + C_SaferCond ctx; + auto req = new MockDiffRequest(&mock_image_ctx, 0, 1, is_diff_iterate(), + &m_object_diff_state, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ(expected_diff_state, m_object_diff_state); +} + +TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnap) { + 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); + + 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); - object_map_1[1] = OBJECT_EXISTS_CLEAN; + 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]; + } + } + + InSequence seq; + + expect_get_flags(mock_image_ctx, 1U, 0, 0); expect_load_map(mock_image_ctx, 1U, object_map_1, 0); expect_get_flags(mock_image_ctx, 2U, 0, 0); - - 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); - expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + C_SaferCond ctx; + auto req = new MockDiffRequest(&mock_image_ctx, 0, 2, is_diff_iterate(), + &m_object_diff_state, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ(expected_diff_state, m_object_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); + + MockTestImageCtx mock_image_ctx(*m_image_ctx); 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; + 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]; + } + + InSequence seq; + + expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); C_SaferCond ctx; @@ -193,18 +373,59 @@ TEST_P(TestMockObjectMapDiffRequest, FullDelta) { req->send(); ASSERT_EQ(0, ctx.wait()); + ASSERT_EQ(expected_diff_state, m_object_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); + + 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_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; + 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]; + } + } + + InSequence seq; + + expect_get_flags(mock_image_ctx, 1U, 0, 0); + expect_load_map(mock_image_ctx, 1U, 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); + + C_SaferCond ctx; + auto req = new MockDiffRequest(&mock_image_ctx, 0, CEPH_NOSNAP, + is_diff_iterate(), &m_object_diff_state, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + ASSERT_EQ(expected_diff_state, m_object_diff_state); } -TEST_P(TestMockObjectMapDiffRequest, IntermediateDelta) { +TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnap) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); - uint32_t object_count = 5; + uint32_t object_count = std::size(from_snap_table); m_image_ctx->size = object_count * (1 << m_image_ctx->order); MockTestImageCtx mock_image_ctx(*m_image_ctx); @@ -215,23 +436,24 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateDelta) { {}, {}, {}}} }; + 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]; + } + InSequence seq; expect_get_flags(mock_image_ctx, 1U, 0, 0); - - 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); expect_get_flags(mock_image_ctx, 2U, 0, 0); - - 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); C_SaferCond ctx; @@ -240,18 +462,13 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateDelta) { 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; - 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); } -TEST_P(TestMockObjectMapDiffRequest, EndDelta) { +TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapIntermediateSnap) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); - uint32_t object_count = 5; + uint32_t object_count = std::size(from_snap_intermediate_table); m_image_ctx->size = object_count * (1 << m_image_ctx->order); MockTestImageCtx mock_image_ctx(*m_image_ctx); @@ -259,40 +476,143 @@ TEST_P(TestMockObjectMapDiffRequest, EndDelta) { {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {}, {}, {}, {}}}, {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, mock_image_ctx.size, {}, + {}, {}, {}}}, + {3U, {"snap3", {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); + 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]; + } + } + InSequence seq; - expect_get_flags(mock_image_ctx, 2U, 0, 0); + expect_get_flags(mock_image_ctx, 1U, 0, 0); + expect_load_map(mock_image_ctx, 1U, object_map_1, 0); - 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_get_flags(mock_image_ctx, 2U, 0, 0); expect_load_map(mock_image_ctx, 2U, object_map_2, 0); - expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + expect_get_flags(mock_image_ctx, 3U, 0, 0); + expect_load_map(mock_image_ctx, 3U, object_map_3, 0); + C_SaferCond ctx; + auto req = new MockDiffRequest(&mock_image_ctx, 1, 3, is_diff_iterate(), + &m_object_diff_state, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ(expected_diff_state, m_object_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); + + 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_head; object_map_head.resize(object_count); - object_map_head[1] = OBJECT_EXISTS_CLEAN; - object_map_head[2] = OBJECT_EXISTS_CLEAN; + 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]; + } + + InSequence seq; + + expect_get_flags(mock_image_ctx, 1U, 0, 0); + expect_load_map(mock_image_ctx, 1U, 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); C_SaferCond ctx; - auto req = new MockDiffRequest(&mock_image_ctx, 2, CEPH_NOSNAP, + auto req = new MockDiffRequest(&mock_image_ctx, 1, CEPH_NOSNAP, is_diff_iterate(), &m_object_diff_state, &ctx); req->send(); ASSERT_EQ(0, ctx.wait()); + ASSERT_EQ(expected_diff_state, m_object_diff_state); +} + +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); + + 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); + 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; + 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]; + } + } + + InSequence seq; + + expect_get_flags(mock_image_ctx, 1U, 0, 0); + expect_load_map(mock_image_ctx, 1U, object_map_1, 0); + + expect_get_flags(mock_image_ctx, 2U, 0, 0); + expect_load_map(mock_image_ctx, 2U, 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); + + C_SaferCond ctx; + auto req = new MockDiffRequest(&mock_image_ctx, 1, CEPH_NOSNAP, + is_diff_iterate(), &m_object_diff_state, + &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); + ASSERT_EQ(expected_diff_state, m_object_diff_state); }