From: Ilya Dryomov Date: Sat, 6 Jan 2024 16:05:39 +0000 (+0100) Subject: librbd/object_map: potentially use in-memory object map in DiffRequest X-Git-Tag: v17.2.8~538^2~2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=f5b2af58a1ae931a8e6497e133e3b079e9ebccaa;p=ceph.git librbd/object_map: potentially use in-memory object map in DiffRequest If the object map for the end version is around (already loaded in memory, either due to the end version being a snapshot or due to exclusive lock being held), use it to run diff-iterate against the beginning of time. Since it's the only object map needed in that case, such calls would be satisfied locally. Fixes: https://tracker.ceph.com/issues/63341 Signed-off-by: Ilya Dryomov (cherry picked from commit 0c4bb58c900efa2356ea8526d3432b2922787afa) --- diff --git a/src/librbd/ObjectMap.h b/src/librbd/ObjectMap.h index 8b5b352ef8aa4..35ea4cb88f93a 100644 --- a/src/librbd/ObjectMap.h +++ b/src/librbd/ObjectMap.h @@ -45,6 +45,12 @@ public: return m_object_map.size(); } + template + auto with_object_map(F&& f, Args&&... args) const { + std::shared_lock locker(m_lock); + return std::forward(f)(m_object_map, std::forward(args)...); + } + inline void set_state(uint64_t object_no, uint8_t new_state, const boost::optional ¤t_state) { std::unique_lock locker{m_lock}; diff --git a/src/librbd/object_map/DiffRequest.cc b/src/librbd/object_map/DiffRequest.cc index 7da6152058b0e..acaf31a39bfbf 100644 --- a/src/librbd/object_map/DiffRequest.cc +++ b/src/librbd/object_map/DiffRequest.cc @@ -240,10 +240,30 @@ void DiffRequest::send() { return; } + std::shared_lock image_locker{m_image_ctx->image_lock}; + if (is_diff_iterate() && + m_snap_id_start == 0 && + m_snap_id_end == m_image_ctx->snap_id && + m_image_ctx->object_map != nullptr) { + ldout(cct, 10) << "using in-memory object map" << dendl; + m_current_snap_id = m_snap_id_end; + + int r = prepare_for_object_map(); + if (r == 0) { + r = m_image_ctx->object_map->with_object_map( + [this](const BitVector<2>& object_map) { + return process_object_map(object_map); + }); + } + image_locker.unlock(); + + finish(r); + return; + } + // collect all the snap ids in the provided range (inclusive) unless // this is diff-iterate against the beginning of time, in which case // only the end version matters - std::shared_lock image_locker{m_image_ctx->image_lock}; if (!is_diff_iterate() || m_snap_id_start != 0) { if (m_snap_id_start != 0) { m_snap_ids.insert(m_snap_id_start); diff --git a/src/test/librbd/mock/MockObjectMap.h b/src/test/librbd/mock/MockObjectMap.h index 2a1adbcaebab3..5e3235cf023d1 100644 --- a/src/test/librbd/mock/MockObjectMap.h +++ b/src/test/librbd/mock/MockObjectMap.h @@ -4,19 +4,27 @@ #ifndef CEPH_TEST_LIBRBD_MOCK_OBJECT_MAP_H #define CEPH_TEST_LIBRBD_MOCK_OBJECT_MAP_H +#include "common/bit_vector.hpp" #include "librbd/Utils.h" #include "gmock/gmock.h" namespace librbd { struct MockObjectMap { - MOCK_METHOD1(at, uint8_t(uint64_t)); - uint8_t operator[](uint64_t object_no) { + MOCK_CONST_METHOD1(at, uint8_t(uint64_t)); + uint8_t operator[](uint64_t object_no) const { return at(object_no); } MOCK_CONST_METHOD0(size, uint64_t()); + MOCK_CONST_METHOD0(with, ceph::BitVector<2>()); + template + auto with_object_map(F&& f, Args&&... args) const { + const ceph::BitVector<2> object_map = with(); + return std::forward(f)(object_map, std::forward(args)...); + } + MOCK_METHOD1(open, void(Context *on_finish)); MOCK_METHOD1(close, void(Context *on_finish)); diff --git a/src/test/librbd/object_map/test_mock_DiffRequest.cc b/src/test/librbd/object_map/test_mock_DiffRequest.cc index 8d6ee2d27b1cd..9b88f0d75ca9e 100644 --- a/src/test/librbd/object_map/test_mock_DiffRequest.cc +++ b/src/test/librbd/object_map/test_mock_DiffRequest.cc @@ -28,6 +28,7 @@ void noop(MockTestImageCtx&) {} using ::testing::_; using ::testing::Invoke; using ::testing::InSequence; +using ::testing::Return; using ::testing::StrEq; using ::testing::WithArg; @@ -207,12 +208,23 @@ 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 - int do_diff(F&& f, uint64_t start_snap_id, uint64_t end_snap_id, + 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)(mock_image_ctx); C_SaferCond ctx; @@ -224,13 +236,14 @@ public: } template - void test_diff_iterate(F&& f, uint64_t start_snap_id, uint64_t end_snap_id, + 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(std::forward(f), start_snap_id, end_snap_id, - i, j)); + ASSERT_EQ(0, do_diff(want_object_map, std::forward(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]); @@ -239,16 +252,17 @@ public: } // unranged -- equivalent to i=0, j=expected_diff_state.size() range - ASSERT_EQ(0, do_diff(std::forward(f), start_snap_id, end_snap_id, - 0, UINT64_MAX - 1)); + ASSERT_EQ(0, do_diff(want_object_map, std::forward(f), + start_snap_id, end_snap_id, 0, UINT64_MAX - 1)); ASSERT_EQ(expected_diff_state, m_diff_state); } template - void test_deep_copy(F&& f, uint64_t start_snap_id, uint64_t end_snap_id, + 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(std::forward(f), start_snap_id, end_snap_id, - 0, UINT64_MAX)); + ASSERT_EQ(0, do_diff(want_object_map, std::forward(f), + start_snap_id, end_snap_id, 0, UINT64_MAX)); ASSERT_EQ(expected_diff_state, m_diff_state); } @@ -258,17 +272,21 @@ public: TEST_P(TestMockObjectMapDiffRequest, InvalidStartSnap) { if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(noop, CEPH_NOSNAP, CEPH_NOSNAP, 123, 456)); + 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(noop, CEPH_NOSNAP, CEPH_NOSNAP, 0, UINT64_MAX)); + 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(noop, 2, 1, 123, 456)); + 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(noop, 2, 1, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(false, noop, 2, 1, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(true, noop, 2, 1, 0, UINT64_MAX)); } } @@ -276,24 +294,32 @@ TEST_P(TestMockObjectMapDiffRequest, StartEndSnapEqual) { BitVector<2> expected_diff_state; if (is_diff_iterate()) { - ASSERT_EQ(0, do_diff(noop, 1, 1, 123, 456)); + 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(noop, 1, 1, 0, UINT64_MAX)); + 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); } - ASSERT_EQ(expected_diff_state, m_diff_state); } TEST_P(TestMockObjectMapDiffRequest, InvalidStartObject) { if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(noop, 0, 1, UINT64_MAX, UINT64_MAX)); + 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(noop, 0, 1, 123, UINT64_MAX)); + 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_P(TestMockObjectMapDiffRequest, InvalidEndObject) { if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(noop, 0, 1, 456, 123)); + ASSERT_EQ(-EINVAL, do_diff(false, noop, 0, 1, 456, 123)); + ASSERT_EQ(-EINVAL, do_diff(true, noop, 0, 1, 456, 123)); } else { SUCCEED(); } @@ -303,7 +329,9 @@ TEST_P(TestMockObjectMapDiffRequest, StartEndObjectEqual) { BitVector<2> expected_diff_state; if (is_diff_iterate()) { - ASSERT_EQ(0, do_diff(noop, 0, 1, 123, 123)); + 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(); @@ -315,9 +343,11 @@ TEST_P(TestMockObjectMapDiffRequest, FastDiffDisabled) { REQUIRE(!is_feature_enabled(RBD_FEATURE_OBJECT_MAP)); if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(noop, 0, CEPH_NOSNAP, 123, 456)); + 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(noop, 0, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -345,9 +375,15 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnap) { expect_load_map(mock_image_ctx, 1, object_map_1, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 0, 1, expected_diff_state); + 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(load, 0, 1, expected_diff_state); + test_deep_copy(false, load, 0, 1, expected_diff_state); + test_deep_copy(true, load, 0, 1, expected_diff_state); } } @@ -367,9 +403,15 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapEmpty) { expect_load_map(mock_image_ctx, 1, object_map_1, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 0, 1, expected_diff_state); + 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(load, 0, 1, expected_diff_state); + test_deep_copy(false, load, 0, 1, expected_diff_state); + test_deep_copy(true, load, 0, 1, expected_diff_state); } } @@ -406,7 +448,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnap) { expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_diff_iterate(load, 0, 2, expected_diff_state); + 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); @@ -414,7 +461,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnap) { expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_deep_copy(load, 0, 2, expected_diff_state); + test_deep_copy(false, load, 0, 2, expected_diff_state); + test_deep_copy(true, load, 0, 2, expected_diff_state); } } @@ -456,7 +504,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrow) { expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_diff_iterate(load, 0, 2, expected_diff_state); + 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); @@ -464,7 +517,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrow) { expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_deep_copy(load, 0, 2, expected_diff_state); + test_deep_copy(false, load, 0, 2, expected_diff_state); + test_deep_copy(true, load, 0, 2, expected_diff_state); } } @@ -494,7 +548,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrowFrom expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_diff_iterate(load, 0, 2, expected_diff_state); + 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); @@ -502,7 +561,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapGrowFrom expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_deep_copy(load, 0, 2, expected_diff_state); + test_deep_copy(false, load, 0, 2, expected_diff_state); + test_deep_copy(true, load, 0, 2, expected_diff_state); } } @@ -550,7 +610,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrink) expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_diff_iterate(load, 0, 2, expected_diff_state); + 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); @@ -558,7 +623,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrink) expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_deep_copy(load, 0, 2, expected_diff_state); + test_deep_copy(false, load, 0, 2, expected_diff_state); + test_deep_copy(true, load, 0, 2, expected_diff_state); } } @@ -592,7 +658,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrinkTo expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_diff_iterate(load, 0, 2, expected_diff_state); + 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); @@ -600,7 +671,41 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnapIntermediateSnapShrinkTo expect_get_flags(mock_image_ctx, 2, 0, 0); expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; - test_deep_copy(load, 0, 2, expected_diff_state); + test_deep_copy(false, load, 0, 2, expected_diff_state); + test_deep_copy(true, load, 0, 2, expected_diff_state); + } +} + +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); } } @@ -624,9 +729,15 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHead) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -643,9 +754,15 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadEmpty) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -680,7 +797,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnap) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -688,7 +810,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnap) { 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -728,7 +851,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrow) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -736,7 +864,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrow) { 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -764,7 +893,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrowFrom expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -772,7 +906,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapGrowFrom 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -818,7 +953,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrink) expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -826,7 +966,8 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrink) 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -859,7 +1000,12 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrinkTo expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -867,7 +1013,37 @@ TEST_P(TestMockObjectMapDiffRequest, FromBeginningToHeadIntermediateSnapShrinkTo 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(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); + + 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); } } @@ -902,9 +1078,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnap) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 2, expected_diff_state); + test_diff_iterate(false, load, 1, 2, expected_diff_state); + test_diff_iterate(true, load, 1, 2, expected_diff_state); } else { - test_deep_copy(load, 1, 2, expected_diff_state); + test_deep_copy(false, load, 1, 2, expected_diff_state); + test_deep_copy(true, load, 1, 2, expected_diff_state); } } @@ -944,9 +1122,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapGrow) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 2, expected_diff_state); + test_diff_iterate(false, load, 1, 2, expected_diff_state); + test_diff_iterate(true, load, 1, 2, expected_diff_state); } else { - test_deep_copy(load, 1, 2, expected_diff_state); + test_deep_copy(false, load, 1, 2, expected_diff_state); + test_deep_copy(true, load, 1, 2, expected_diff_state); } } @@ -978,9 +1158,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapGrowFromZero) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 2, expected_diff_state); + test_diff_iterate(false, load, 1, 2, expected_diff_state); + test_diff_iterate(true, load, 1, 2, expected_diff_state); } else { - test_deep_copy(load, 1, 2, expected_diff_state); + test_deep_copy(false, load, 1, 2, expected_diff_state); + test_deep_copy(true, load, 1, 2, expected_diff_state); } } @@ -1026,9 +1208,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapShrink) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 2, expected_diff_state); + test_diff_iterate(false, load, 1, 2, expected_diff_state); + test_diff_iterate(true, load, 1, 2, expected_diff_state); } else { - test_deep_copy(load, 1, 2, expected_diff_state); + test_deep_copy(false, load, 1, 2, expected_diff_state); + test_deep_copy(true, load, 1, 2, expected_diff_state); } } @@ -1064,9 +1248,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapShrinkToZero) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 2, expected_diff_state); + test_diff_iterate(false, load, 1, 2, expected_diff_state); + test_diff_iterate(true, load, 1, 2, expected_diff_state); } else { - test_deep_copy(load, 1, 2, expected_diff_state); + test_deep_copy(false, load, 1, 2, expected_diff_state); + test_deep_copy(true, load, 1, 2, expected_diff_state); } } @@ -1112,9 +1298,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToSnapIntermediateSnap) { expect_load_map(mock_image_ctx, 3, object_map_3, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, 3, expected_diff_state); + test_diff_iterate(false, load, 1, 3, expected_diff_state); + test_diff_iterate(true, load, 1, 3, expected_diff_state); } else { - test_deep_copy(load, 1, 3, expected_diff_state); + test_deep_copy(false, load, 1, 3, expected_diff_state); + test_deep_copy(true, load, 1, 3, expected_diff_state); } } @@ -1147,9 +1335,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHead) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1187,9 +1377,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadGrow) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1219,9 +1411,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadGrowFromZero) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1265,9 +1459,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadShrink) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1302,9 +1498,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadShrinkToZero) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1348,9 +1546,11 @@ TEST_P(TestMockObjectMapDiffRequest, FromSnapToHeadIntermediateSnap) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1365,9 +1565,11 @@ TEST_P(TestMockObjectMapDiffRequest, StartSnapDNE) { }; if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(noop, 1, 2, 0, object_count)); + 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(noop, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(false, noop, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(true, noop, 1, 2, 0, UINT64_MAX)); } } @@ -1385,13 +1587,15 @@ TEST_P(TestMockObjectMapDiffRequest, EndSnapDNE) { object_map_1.resize(object_count); if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(noop, 0, 2, 0, object_count)); + 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(load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(false, load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(true, load, 0, 2, 0, UINT64_MAX)); } } @@ -1421,7 +1625,12 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromBeginning) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -1430,7 +1639,8 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromBeginning) { 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -1463,9 +1673,11 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromSnap) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1488,9 +1700,11 @@ TEST_P(TestMockObjectMapDiffRequest, StartObjectMapDNE) { expect_load_map(mock_image_ctx, 1, object_map_1, -ENOENT); }; if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(load, 1, 2, 0, object_count)); + 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(load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(false, load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(true, load, 1, 2, 0, UINT64_MAX)); } } @@ -1520,7 +1734,12 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapDNE) { 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(load, 0, 2, 0, object_count)); + 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); @@ -1528,7 +1747,8 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapDNE) { 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(load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(false, load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-ENOENT, do_diff(true, load, 0, 2, 0, UINT64_MAX)); } } @@ -1555,7 +1775,12 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromBeginning) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -1563,7 +1788,8 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromBeginning) { 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } } @@ -1598,9 +1824,11 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromSnap) { expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + 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(load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 1, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 1, CEPH_NOSNAP, expected_diff_state); } } @@ -1620,9 +1848,11 @@ TEST_P(TestMockObjectMapDiffRequest, StartFastDiffInvalid) { expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0); }; if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, 2, 0, object_count)); + 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(get_flags, 1, 2, 0, UINT64_MAX)); + 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)); } } @@ -1645,14 +1875,16 @@ TEST_P(TestMockObjectMapDiffRequest, EndFastDiffInvalid) { 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(get_flags, 0, 2, 0, object_count)); + 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(get_flags, 0, 2, 0, UINT64_MAX)); + 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)); } } @@ -1678,12 +1910,18 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromBeginning) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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(get_flags, 0, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1708,9 +1946,11 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromSnap) { expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0); }; if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, CEPH_NOSNAP, 0, object_count)); + 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(get_flags, 1, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1733,9 +1973,11 @@ TEST_P(TestMockObjectMapDiffRequest, StartObjectMapLoadError) { expect_load_map(mock_image_ctx, 1, object_map_1, -EPERM); }; if (is_diff_iterate()) { - ASSERT_EQ(-EPERM, do_diff(load, 1, 2, 0, object_count)); + 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(load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EPERM, do_diff(false, load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EPERM, do_diff(true, load, 1, 2, 0, UINT64_MAX)); } } @@ -1765,7 +2007,12 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapLoadError) { 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(load, 0, 2, 0, object_count)); + 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); @@ -1773,7 +2020,8 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapLoadError) { 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(load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EPERM, do_diff(false, load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EPERM, do_diff(true, load, 0, 2, 0, UINT64_MAX)); } } @@ -1800,13 +2048,19 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromBeginning expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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(load, 0, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1833,9 +2087,11 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromSnap) { expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM); }; if (is_diff_iterate()) { - ASSERT_EQ(-EPERM, do_diff(load, 1, CEPH_NOSNAP, 0, object_count)); + 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(load, 1, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1859,9 +2115,11 @@ TEST_P(TestMockObjectMapDiffRequest, StartObjectMapTooSmall) { expect_load_map(mock_image_ctx, 1, object_map_1, 0); }; if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(load, 1, 2, 0, object_count)); + 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(load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(false, load, 1, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(true, load, 1, 2, 0, UINT64_MAX)); } } @@ -1887,7 +2145,12 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapTooSmall) { 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(load, 0, 2, 0, object_count)); + 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); @@ -1895,7 +2158,8 @@ TEST_P(TestMockObjectMapDiffRequest, EndObjectMapTooSmall) { 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(load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(false, load, 0, 2, 0, UINT64_MAX)); + ASSERT_EQ(-EINVAL, do_diff(true, load, 0, 2, 0, UINT64_MAX)); } } @@ -1923,13 +2187,19 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromBeginning) expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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(load, 0, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1957,9 +2227,11 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromSnap) { expect_load_map(mock_image_ctx, 2, object_map_2, 0); }; if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(load, 1, CEPH_NOSNAP, 0, object_count)); + 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(load, 1, CEPH_NOSNAP, 0, UINT64_MAX)); + 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)); } } @@ -1987,7 +2259,12 @@ TEST_P(TestMockObjectMapDiffRequest, ObjectMapTooLarge) { expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; - test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + 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); @@ -1995,7 +2272,8 @@ TEST_P(TestMockObjectMapDiffRequest, ObjectMapTooLarge) { 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(load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(false, load, 0, CEPH_NOSNAP, expected_diff_state); + test_deep_copy(true, load, 0, CEPH_NOSNAP, expected_diff_state); } }