From 1df87998dc30be6e3b4c90f5833539c7ccc70911 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 21 Jun 2024 15:53:05 +0200 Subject: [PATCH] test/librbd: refactor DiffIterateTest.DiffIterateDeterministic{,PP} In preparation for extending coverage, extract test logic into a couple of parametrized helpers. Signed-off-by: Ilya Dryomov --- src/test/librbd/test_librbd.cc | 709 +++++++++++++++++---------------- 1 file changed, 372 insertions(+), 337 deletions(-) diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index fe47b7985d640..3c7864676cabc 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -7346,6 +7346,28 @@ TEST_F(TestLibRBD, FlushAioPP) ioctx.close(); } +struct diff_extent { + diff_extent(uint64_t _offset, uint64_t _length, bool _exists, + uint64_t object_size) : + offset(_offset), length(_length), exists(_exists) + { + if (object_size != 0) { + offset -= offset % object_size; + length = object_size; + } + } + uint64_t offset; + uint64_t length; + bool exists; + bool operator==(const diff_extent& o) const { + return offset == o.offset && length == o.length && exists == o.exists; + } +}; + +ostream& operator<<(ostream & o, const diff_extent& e) { + return o << '(' << e.offset << '~' << e.length << ' ' + << (e.exists ? "true" : "false") << ')'; +} int iterate_cb(uint64_t off, size_t len, int exists, void *arg) { @@ -7355,6 +7377,13 @@ int iterate_cb(uint64_t off, size_t len, int exists, void *arg) return 0; } +int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg) +{ + auto diff = static_cast*>(arg); + diff->push_back(diff_extent(off, len, exists, 0)); + return 0; +} + static int iterate_error_cb(uint64_t off, size_t len, int exists, void *arg) { return -EINVAL; @@ -7429,426 +7458,432 @@ template class DiffIterateTest : public TestLibRBD { public: static const uint8_t whole_object = T::whole_object; -}; -template -class DiffIterateParams { -public: - static const uint8_t whole_object = _whole_object; -}; + void test_deterministic(uint64_t object_off, uint64_t len) { + rados_ioctx_t ioctx; + ASSERT_EQ(0, rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx)); -typedef ::testing::Types, - DiffIterateParams > DiffIterateTypes; -TYPED_TEST_SUITE(DiffIterateTest, DiffIterateTypes); + rbd_image_t image; + int order = 22; + std::string name = this->get_temp_image_name(); + ASSERT_EQ(0, create_image(ioctx, name.c_str(), 20 << 20, &order)); + ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + test_deterministic(image, object_off, len, 1); -TYPED_TEST(DiffIterateTest, DiffIterate) -{ - librados::IoCtx ioctx; - ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + ASSERT_EQ(0, rbd_close(image)); + rados_ioctx_destroy(ioctx); + } + + void test_deterministic_pp(uint64_t object_off, uint64_t len) { + librados::IoCtx ioctx; + ASSERT_EQ(0, _rados.ioctx_create(m_pool_name.c_str(), ioctx)); - { librbd::RBD rbd; librbd::Image image; - int order = 0; + int order = 22; std::string name = this->get_temp_image_name(); - uint64_t size = 20 << 20; - - ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), 20 << 20, &order)); ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + test_deterministic_pp(image, object_off, len, 1); + } - bool skip_discard = this->is_skip_partial_discard_enabled(image); +private: + void test_deterministic(rbd_image_t image, uint64_t object_off, + uint64_t len, uint64_t block_size) { + uint64_t off1 = 0; + uint64_t off2 = 4 << 20; + uint64_t size = 20 << 20; + uint64_t extent_len = round_up_to(object_off + len, block_size); + + rbd_image_info_t info; + ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info))); + ASSERT_EQ(size, info.size); + ASSERT_EQ(5, info.num_objs); + ASSERT_EQ(4 << 20, info.obj_size); + ASSERT_EQ(22, info.order); uint64_t object_size = 0; - if (this->whole_object) { - object_size = 1 << order; + if (whole_object) { + object_size = 1 << info.order; } - interval_set exists; - interval_set one, two; - scribble(image, 10, 102400, skip_discard, &exists, &one); - cout << " wrote " << one << std::endl; - ASSERT_EQ(0, image.snap_create("one")); - scribble(image, 10, 102400, skip_discard, &exists, &two); + std::vector extents; + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - two = round_diff_interval(two, object_size); - cout << " wrote " << two << std::endl; + ASSERT_EQ(-ENOENT, rbd_diff_iterate2(image, "snap1", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - interval_set diff; - ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object, - iterate_cb, (void *)&diff)); - cout << " diff was " << diff << std::endl; - if (!two.subset_of(diff)) { - interval_set i; - i.intersection_of(two, diff); - interval_set l = two; - l.subtract(i); - cout << " ... two - (two*diff) = " << l << std::endl; - } - ASSERT_TRUE(two.subset_of(diff)); - } - ioctx.close(); -} + ASSERT_EQ(0, rbd_snap_create(image, "snap1")); -struct diff_extent { - diff_extent(uint64_t _offset, uint64_t _length, bool _exists, - uint64_t object_size) : - offset(_offset), length(_length), exists(_exists) - { - if (object_size != 0) { - offset -= offset % object_size; - length = object_size; - } - } - uint64_t offset; - uint64_t length; - bool exists; - bool operator==(const diff_extent& o) const { - return offset == o.offset && length == o.length && exists == o.exists; - } -}; + std::string buf(len, '1'); + ASSERT_EQ(len, rbd_write(image, off1 + object_off, len, buf.data())); + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); -ostream& operator<<(ostream & o, const diff_extent& e) { - return o << '(' << e.offset << '~' << e.length << ' ' << (e.exists ? "true" : "false") << ')'; -} + ASSERT_EQ(0, rbd_snap_create(image, "snap2")); -int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg) -{ - //cout << "iterate_cb " << off << "~" << len << std::endl; - vector *diff = static_cast *>(arg); - diff->push_back(diff_extent(off, len, exists, 0)); - return 0; -} + ASSERT_EQ(len, rbd_write(image, off2 + object_off, len, buf.data())); + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); -TYPED_TEST(DiffIterateTest, DiffIterateDeterministic) -{ - REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + ASSERT_EQ(0, rbd_snap_create(image, "snap3")); - rados_ioctx_t ioctx; - ASSERT_EQ(0, rados_ioctx_create(this->_cluster, this->m_pool_name.c_str(), - &ioctx)); + // 1. beginning of time -> HEAD + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - rbd_image_t image; - int order = 22; - std::string name = this->get_temp_image_name(); - uint64_t size = 20 << 20; + // 2. snap1 -> HEAD + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order)); - ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + // 3. snap2 -> HEAD + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[0]); + extents.clear(); - uint64_t object_size = 0; - if (this->whole_object) { - object_size = 1 << order; - } + // 4. snap3 -> HEAD + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap3", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - std::vector extents; - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap3")); - ASSERT_EQ(-ENOENT, rbd_diff_iterate2(image, "snap1", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + // 5. beginning of time -> snap3 + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - ASSERT_EQ(0, rbd_snap_create(image, "snap1")); + // 6. snap1 -> snap3 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - std::string buf(256, '1'); - ASSERT_EQ(256, rbd_write(image, 0, 256, buf.data())); - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + // 7. snap2 -> snap3 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[0]); + extents.clear(); - ASSERT_EQ(0, rbd_snap_create(image, "snap2")); + // 8. snap3 -> snap3 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap3", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - ASSERT_EQ(256, rbd_write(image, 1 << order, 256, buf.data())); - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap2")); - ASSERT_EQ(0, rbd_snap_create(image, "snap3")); + // 9. beginning of time -> snap2 + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); - // 1. beginning of time -> HEAD - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 10. snap1 -> snap2 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); - // 2. snap1 -> HEAD - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 11. snap2 -> snap2 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 3. snap2 -> HEAD - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[0]); - extents.clear(); + // 12. snap3 -> snap2 + ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap3", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - // 4. snap3 -> HEAD - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap3", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap1")); - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, rbd_snap_set(image, "snap3")); + // 13. beginning of time -> snap1 + ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 5. beginning of time -> snap3 - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 14. snap1 -> snap1 + ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 6. snap1 -> snap3 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 15. snap2 -> snap1 + ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap2", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - // 7. snap2 -> snap3 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[0]); - extents.clear(); + // 16. snap3 -> snap1 + ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap3", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - // 8. snap3 -> snap3 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap3", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + ASSERT_PASSED(validate_object_map, image); + } - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, rbd_snap_set(image, "snap2")); + void test_deterministic_pp(librbd::Image& image, uint64_t object_off, + uint64_t len, uint64_t block_size) { + uint64_t off1 = 0 << 20; + uint64_t off2 = 4 << 20; + uint64_t size = 20 << 20; + uint64_t extent_len = round_up_to(object_off + len, block_size); - // 9. beginning of time -> snap2 - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + librbd::image_info_t info; + ASSERT_EQ(0, image.stat(info, sizeof(info))); + ASSERT_EQ(size, info.size); + ASSERT_EQ(5, info.num_objs); + ASSERT_EQ(4 << 20, info.obj_size); + ASSERT_EQ(22, info.order); - // 10. snap1 -> snap2 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + uint64_t object_size = 0; + if (whole_object) { + object_size = 1 << info.order; + } - // 11. snap2 -> snap2 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + std::vector extents; + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 12. snap3 -> snap2 - ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap3", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + ASSERT_EQ(-ENOENT, image.diff_iterate2("snap1", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, rbd_snap_set(image, "snap1")); + ASSERT_EQ(0, image.snap_create("snap1")); - // 13. beginning of time -> snap1 - ASSERT_EQ(0, rbd_diff_iterate2(image, NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + ceph::bufferlist bl; + bl.append(std::string(len, '1')); + ASSERT_EQ(len, image.write(off1 + object_off, len, bl)); + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); - // 14. snap1 -> snap1 - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + ASSERT_EQ(0, image.snap_create("snap2")); - // 15. snap2 -> snap1 - ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap2", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + ASSERT_EQ(len, image.write(off2 + object_off, len, bl)); + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - // 16. snap3 -> snap1 - ASSERT_EQ(-EINVAL, rbd_diff_iterate2(image, "snap3", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + ASSERT_EQ(0, image.snap_create("snap3")); - ASSERT_PASSED(this->validate_object_map, image); + // 1. beginning of time -> HEAD + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - ASSERT_EQ(0, rbd_close(image)); - rados_ioctx_destroy(ioctx); -} + // 2. snap1 -> HEAD + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); -TYPED_TEST(DiffIterateTest, DiffIterateDeterministicPP) -{ - REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + // 3. snap2 -> HEAD + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[0]); + extents.clear(); - librados::IoCtx ioctx; - ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + // 4. snap3 -> HEAD + ASSERT_EQ(0, image.diff_iterate2("snap3", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - librbd::RBD rbd; - librbd::Image image; - int order = 22; - std::string name = this->get_temp_image_name(); - uint64_t size = 20 << 20; + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap3")); - ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); - ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); + // 5. beginning of time -> snap3 + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - uint64_t object_size = 0; - if (this->whole_object) { - object_size = 1 << order; - } + // 6. snap1 -> snap3 + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[1]); + extents.clear(); - std::vector extents; - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + // 7. snap2 -> snap3 + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off2, extent_len, true, object_size), extents[0]); + extents.clear(); - ASSERT_EQ(-ENOENT, image.diff_iterate2("snap1", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + // 8. snap3 -> snap3 + ASSERT_EQ(0, image.diff_iterate2("snap3", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - ASSERT_EQ(0, image.snap_create("snap1")); + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap2")); - ceph::bufferlist bl; - bl.append(std::string(256, '1')); - ASSERT_EQ(256, image.write(0, 256, bl)); - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + // 9. beginning of time -> snap2 + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); - ASSERT_EQ(0, image.snap_create("snap2")); + // 10. snap1 -> snap2 + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(off1, extent_len, true, object_size), extents[0]); + extents.clear(); - ASSERT_EQ(256, image.write(1 << order, 256, bl)); - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 11. snap2 -> snap2 + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - ASSERT_EQ(0, image.snap_create("snap3")); + // 12. snap3 -> snap2 + ASSERT_EQ(-EINVAL, image.diff_iterate2("snap3", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - // 1. beginning of time -> HEAD - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + ASSERT_PASSED(validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap1")); - // 2. snap1 -> HEAD - ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + // 13. beginning of time -> snap1 + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 3. snap2 -> HEAD - ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[0]); - extents.clear(); + // 14. snap1 -> snap1 + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); - // 4. snap3 -> HEAD - ASSERT_EQ(0, image.diff_iterate2("snap3", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + // 15. snap2 -> snap1 + ASSERT_EQ(-EINVAL, image.diff_iterate2("snap2", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, image.snap_set("snap3")); + // 16. snap3 -> snap1 + ASSERT_EQ(-EINVAL, image.diff_iterate2("snap3", 0, size, true, + whole_object, vector_iterate_cb, + &extents)); - // 5. beginning of time -> snap3 - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); + ASSERT_PASSED(validate_object_map, image); + } +}; - // 6. snap1 -> snap3 - ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(2u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); - extents.clear(); +template +class DiffIterateParams { +public: + static const uint8_t whole_object = _whole_object; +}; - // 7. snap2 -> snap3 - ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[0]); - extents.clear(); +typedef ::testing::Types, + DiffIterateParams > DiffIterateTypes; +TYPED_TEST_SUITE(DiffIterateTest, DiffIterateTypes); - // 8. snap3 -> snap3 - ASSERT_EQ(0, image.diff_iterate2("snap3", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); +TYPED_TEST(DiffIterateTest, DiffIterate) +{ + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, image.snap_set("snap2")); + { + librbd::RBD rbd; + librbd::Image image; + int order = 0; + std::string name = this->get_temp_image_name(); + uint64_t size = 20 << 20; - // 9. beginning of time -> snap2 - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL)); - // 10. snap1 -> snap2 - ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - extents.clear(); + bool skip_discard = this->is_skip_partial_discard_enabled(image); - // 11. snap2 -> snap2 - ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } - // 12. snap3 -> snap2 - ASSERT_EQ(-EINVAL, image.diff_iterate2("snap3", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + interval_set exists; + interval_set one, two; + scribble(image, 10, 102400, skip_discard, &exists, &one); + cout << " wrote " << one << std::endl; + ASSERT_EQ(0, image.snap_create("one")); + scribble(image, 10, 102400, skip_discard, &exists, &two); - ASSERT_PASSED(this->validate_object_map, image); - ASSERT_EQ(0, image.snap_set("snap1")); + two = round_diff_interval(two, object_size); + cout << " wrote " << two << std::endl; - // 13. beginning of time -> snap1 - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); + interval_set diff; + ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object, + iterate_cb, (void *)&diff)); + cout << " diff was " << diff << std::endl; + if (!two.subset_of(diff)) { + interval_set i; + i.intersection_of(two, diff); + interval_set l = two; + l.subtract(i); + cout << " ... two - (two*diff) = " << l << std::endl; + } + ASSERT_TRUE(two.subset_of(diff)); + } + ioctx.close(); +} - // 14. snap1 -> snap1 - ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, &extents)); - ASSERT_EQ(0u, extents.size()); +TYPED_TEST(DiffIterateTest, DiffIterateDeterministic) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); - // 15. snap2 -> snap1 - ASSERT_EQ(-EINVAL, image.diff_iterate2("snap2", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); + this->test_deterministic(0, 256); +} - // 16. snap3 -> snap1 - ASSERT_EQ(-EINVAL, image.diff_iterate2("snap3", 0, size, true, - this->whole_object, vector_iterate_cb, - &extents)); +TYPED_TEST(DiffIterateTest, DiffIterateDeterministicPP) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); - ASSERT_PASSED(this->validate_object_map, image); + this->test_deterministic_pp(0, 256); } TYPED_TEST(DiffIterateTest, DiffIterateDiscard) -- 2.39.5