diff options
Diffstat (limited to 'src/test/librbd/test_librbd.cc')
-rw-r--r-- | src/test/librbd/test_librbd.cc | 873 |
1 files changed, 752 insertions, 121 deletions
diff --git a/src/test/librbd/test_librbd.cc b/src/test/librbd/test_librbd.cc index b09b67793..8ad5c5aa5 100644 --- a/src/test/librbd/test_librbd.cc +++ b/src/test/librbd/test_librbd.cc @@ -1902,6 +1902,8 @@ TEST_F(TestLibRBD, TestGetSnapShotTimeStamp) ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order)); ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + ASSERT_EQ(-ENOENT, rbd_snap_get_timestamp(image, 0, NULL)); + ASSERT_EQ(0, rbd_snap_create(image, "snap1")); num_snaps = rbd_snap_list(image, snaps, &max_size); ASSERT_EQ(1, num_snaps); @@ -7358,61 +7360,6 @@ interval_set<uint64_t> round_diff_interval(const interval_set<uint64_t>& diff, return rounded_diff; } -TEST_F(TestLibRBD, SnapDiff) -{ - REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); - - rados_ioctx_t ioctx; - rados_ioctx_create(_cluster, m_pool_name.c_str(), &ioctx); - - rbd_image_t image; - int order = 0; - std::string image_name = get_temp_image_name(); - uint64_t size = 100 << 20; - ASSERT_EQ(0, create_image(ioctx, image_name.c_str(), size, &order)); - ASSERT_EQ(0, rbd_open(ioctx, image_name.c_str(), &image, nullptr)); - - char test_data[TEST_IO_SIZE + 1]; - for (size_t i = 0; i < TEST_IO_SIZE; ++i) { - test_data[i] = (char) (rand() % (126 - 33) + 33); - } - test_data[TEST_IO_SIZE] = '\0'; - - ASSERT_PASSED(write_test_data, image, test_data, 0, - TEST_IO_SIZE, LIBRADOS_OP_FLAG_FADVISE_NOCACHE); - - interval_set<uint64_t> diff; - ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true, - iterate_cb, &diff)); - EXPECT_EQ(1 << order, diff.size()); - - ASSERT_EQ(0, rbd_snap_create(image, "snap1")); - ASSERT_EQ(0, rbd_snap_create(image, "snap2")); - - diff.clear(); - ASSERT_EQ(0, rbd_diff_iterate2(image, nullptr, 0, size, true, true, - iterate_cb, &diff)); - EXPECT_EQ(1 << order, diff.size()); - - diff.clear(); - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap1", 0, size, true, true, - iterate_cb, &diff)); - EXPECT_EQ(0, diff.size()); - - diff.clear(); - ASSERT_EQ(0, rbd_diff_iterate2(image, "snap2", 0, size, true, true, - iterate_cb, &diff)); - EXPECT_EQ(0, diff.size()); - - ASSERT_EQ(0, rbd_snap_remove(image, "snap1")); - ASSERT_EQ(0, rbd_snap_remove(image, "snap2")); - - ASSERT_EQ(0, rbd_close(image)); - ASSERT_EQ(0, rbd_remove(ioctx, image_name.c_str())); - - rados_ioctx_destroy(ioctx); -} - template <typename T> class DiffIterateTest : public TestLibRBD { public: @@ -7501,20 +7448,155 @@ ostream& operator<<(ostream & o, const diff_extent& e) { int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg) { - cout << "iterate_cb " << off << "~" << len << std::endl; + //cout << "iterate_cb " << off << "~" << len << std::endl; vector<diff_extent> *diff = static_cast<vector<diff_extent> *>(arg); diff->push_back(diff_extent(off, len, exists, 0)); return 0; } -TYPED_TEST(DiffIterateTest, DiffIterateDiscard) +TYPED_TEST(DiffIterateTest, DiffIterateDeterministic) { + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + + rados_ioctx_t ioctx; + ASSERT_EQ(0, rados_ioctx_create(this->_cluster, this->m_pool_name.c_str(), + &ioctx)); + + rbd_image_t image; + int order = 22; + std::string name = this->get_temp_image_name(); + uint64_t size = 20 << 20; + + ASSERT_EQ(0, create_image(ioctx, name.c_str(), size, &order)); + ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL)); + + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } + + std::vector<diff_extent> 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_EQ(0, rbd_snap_create(image, "snap1")); + + 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(); + + ASSERT_EQ(0, rbd_snap_create(image, "snap2")); + + 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_EQ(0, rbd_snap_create(image, "snap3")); + + // 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(); + + // 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(); + + // 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(); + + // 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(this->validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap3")); + + // 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(); + + // 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(); + + // 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(); + + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap2")); + + // 8. 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(); + + // 9. 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(); + + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, rbd_snap_set(image, "snap1")); + + // 10. 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()); + + ASSERT_PASSED(this->validate_object_map, image); + + ASSERT_EQ(0, rbd_close(image)); + rados_ioctx_destroy(ioctx); +} + +TYPED_TEST(DiffIterateTest, DiffIterateDeterministicPP) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + librados::IoCtx ioctx; ASSERT_EQ(0, this->_rados.ioctx_create(this->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; @@ -7525,57 +7607,573 @@ TYPED_TEST(DiffIterateTest, DiffIterateDiscard) if (this->whole_object) { object_size = 1 << order; } - vector<diff_extent> extents; - ceph::bufferlist bl; + std::vector<diff_extent> extents; ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); + vector_iterate_cb, &extents)); ASSERT_EQ(0u, extents.size()); - char data[256]; - memset(data, 1, sizeof(data)); - bl.append(data, 256); + ASSERT_EQ(0, image.snap_create("snap1")); + + 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, (void *) &extents)); + vector_iterate_cb, &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); + extents.clear(); - int obj_ofs = 256; - ASSERT_EQ(1 << order, image.discard(0, 1 << order)); + ASSERT_EQ(0, image.snap_create("snap2")); + 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(); + + ASSERT_EQ(0, image.snap_create("snap3")); + + // 1. beginning of time -> HEAD ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); + 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(); + + // 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(); + + // 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(); + + // 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()); - ASSERT_EQ(0, image.snap_create("snap1")); - ASSERT_EQ(256, image.write(0, 256, bl)); + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap3")); + + // 5. beginning of time -> snap3 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); - ASSERT_EQ(1u, extents.size()); + vector_iterate_cb, &extents)); + ASSERT_EQ(2u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - ASSERT_EQ(0, image.snap_create("snap2")); + ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[1]); + extents.clear(); - ASSERT_EQ(obj_ofs, image.discard(0, obj_ofs)); + // 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(); + // 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(); + + ASSERT_PASSED(this->validate_object_map, image); ASSERT_EQ(0, image.snap_set("snap2")); + + // 8. 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(); + + // 9. snap1 -> snap2 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); + vector_iterate_cb, &extents)); ASSERT_EQ(1u, extents.size()); ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); + extents.clear(); + + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap1")); + + // 10. 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()); + + ASSERT_PASSED(this->validate_object_map, image); +} + +TYPED_TEST(DiffIterateTest, DiffIterateDiscard) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + librbd::RBD rbd; + librbd::Image image; + 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, rbd.open(ioctx, image, name.c_str(), NULL)); + + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } + + std::vector<diff_extent> extents; + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); + + ceph::bufferlist bl; + bl.append(std::string(256, '1')); + ASSERT_EQ(256, image.write(0, 256, bl)); + 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(); + + ASSERT_EQ(size, image.discard(0, size)); + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); + + ASSERT_EQ(0, image.snap_create("snap1")); + + ASSERT_EQ(256, image.write(0, 256, bl)); + 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(); + + ASSERT_EQ(0, image.snap_create("snap2")); - ASSERT_EQ(0, image.snap_set(NULL)); ASSERT_EQ(1 << order, image.discard(0, 1 << order)); + 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(1 << order, 256, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.snap_create("snap3")); + + // 1. beginning of time -> HEAD + 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(1 << order, 256, true, object_size), extents[0]); + extents.clear(); + + // 2. snap1 -> HEAD + 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(1 << order, 256, true, object_size), extents[0]); + extents.clear(); + + // 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(0, 256, false, object_size), extents[0]); + extents.clear(); + + // 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()); + + ASSERT_PASSED(this->validate_object_map, image); ASSERT_EQ(0, image.snap_set("snap3")); + // 5. beginning of time -> snap3 + 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(1 << order, 256, true, object_size), extents[0]); extents.clear(); + + // 6. snap1 -> snap3 ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(1 << order, 256, true, object_size), extents[0]); + extents.clear(); + + // 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(0, 256, false, object_size), extents[0]); + extents.clear(); + + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap2")); + + // 8. beginning of time -> snap2 + 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(); + + // 9. snap1 -> snap2 + 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(); + + ASSERT_PASSED(this->validate_object_map, image); + ASSERT_EQ(0, image.snap_set("snap1")); + + // 10. 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()); + + ASSERT_PASSED(this->validate_object_map, image); +} + +TYPED_TEST(DiffIterateTest, DiffIterateTruncate) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + librbd::RBD rbd; + librbd::Image image; + 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, rbd.open(ioctx, image, name.c_str(), NULL)); + + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } + + ASSERT_EQ(0, image.snap_create("snap0")); + + ceph::bufferlist bl; + bl.append(std::string(512 << 10, '1')); + ASSERT_EQ(512 << 10, image.write(0, 512 << 10, bl)); + ASSERT_EQ(0, image.snap_create("snap1")); + ASSERT_EQ(512 << 10, image.write(512 << 10, 512 << 10, bl)); + ASSERT_EQ(0, image.snap_create("snap2")); + + std::vector<diff_extent> extents; + 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, 1024 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 1024 << 10, true, object_size), extents[0]); + extents.clear(); + 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(512 << 10, 512 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); + + ASSERT_EQ(256 << 10, image.discard(768 << 10, 256 << 10)); + 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, 768 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 768 << 10, true, object_size), extents[0]); + extents.clear(); + 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(512 << 10, 256 << 10, true, object_size), extents[0]); + extents.clear(); + 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(768 << 10, 256 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + + ASSERT_EQ(256 << 10, image.discard(512 << 10, 256 << 10)); + 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, 512 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 512 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object && + (is_feature_enabled(RBD_FEATURE_OBJECT_MAP) || + is_feature_enabled(RBD_FEATURE_FAST_DIFF))) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + extents.clear(); + } else { + ASSERT_EQ(0u, extents.size()); + } + 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(512 << 10, 512 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + + ASSERT_EQ(256 << 10, image.discard(256 << 10, 256 << 10)); + 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 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 256 << 10, true, object_size), extents[0]); + extents.clear(); + 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(256 << 10, 256 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + 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(256 << 10, 768 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + + ASSERT_EQ(256 << 10, image.discard(0, 256 << 10)); + ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object && + (is_feature_enabled(RBD_FEATURE_OBJECT_MAP) || + is_feature_enabled(RBD_FEATURE_FAST_DIFF))) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + extents.clear(); + } else { + ASSERT_EQ(0u, extents.size()); + } + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object && + (is_feature_enabled(RBD_FEATURE_OBJECT_MAP) || + is_feature_enabled(RBD_FEATURE_FAST_DIFF))) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + extents.clear(); + } else { + ASSERT_EQ(0u, extents.size()); + } + 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, 512 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + 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(0, 1024 << 10, this->whole_object, object_size), + extents[0]); + extents.clear(); + + ASSERT_PASSED(this->validate_object_map, image); +} + +TYPED_TEST(DiffIterateTest, DiffIterateWriteAndTruncate) +{ + REQUIRE(!is_feature_enabled(RBD_FEATURE_STRIPINGV2)); + + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + librbd::RBD rbd; + librbd::Image image; + 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, rbd.open(ioctx, image, name.c_str(), NULL)); + + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } + + ASSERT_EQ(0, image.snap_create("snap0")); + + ceph::bufferlist bl; + bl.append(std::string(512 << 10, '1')); + ASSERT_EQ(512 << 10, image.write(0, 512 << 10, bl)); + ASSERT_EQ(0, image.snap_create("snap1")); + ASSERT_EQ(512 << 10, image.write(512 << 10, 512 << 10, bl)); + ASSERT_EQ(0, image.snap_create("snap2")); + + std::vector<diff_extent> extents; + 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, 1024 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 1024 << 10, true, object_size), extents[0]); + extents.clear(); + 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(512 << 10, 512 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(0u, extents.size()); + + ASSERT_EQ(1 << 10, image.write(767 << 10, 1 << 10, bl)); + ASSERT_EQ(256 << 10, image.discard(768 << 10, 256 << 10)); + 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, 768 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 768 << 10, true, object_size), extents[0]); + extents.clear(); + 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(512 << 10, 256 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + } else { + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(767 << 10, 1 << 10, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(768 << 10, 256 << 10, false, object_size), + extents[1]); + } + extents.clear(); + + ASSERT_EQ(2 << 10, image.write(510 << 10, 2 << 10, bl)); + ASSERT_EQ(256 << 10, image.discard(512 << 10, 256 << 10)); + 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, 512 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 512 << 10, true, object_size), extents[0]); + extents.clear(); + 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(510 << 10, 2 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + } else { + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(510 << 10, 2 << 10, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(512 << 10, 512 << 10, false, object_size), + extents[1]); + } + extents.clear(); + + ASSERT_EQ(3 << 10, image.write(253 << 10, 3 << 10, bl)); + ASSERT_EQ(256 << 10, image.discard(256 << 10, 256 << 10)); + 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 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap0", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 256 << 10, true, object_size), extents[0]); + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap1", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + } else { + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(253 << 10, 3 << 10, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(256 << 10, 256 << 10, false, object_size), + extents[1]); + } + extents.clear(); + ASSERT_EQ(0, image.diff_iterate2("snap2", 0, size, true, this->whole_object, + vector_iterate_cb, &extents)); + if (this->whole_object) { + ASSERT_EQ(1u, extents.size()); + ASSERT_EQ(diff_extent(0, 0, true, object_size), extents[0]); + } else { + ASSERT_EQ(2u, extents.size()); + ASSERT_EQ(diff_extent(253 << 10, 3 << 10, true, object_size), extents[0]); + ASSERT_EQ(diff_extent(256 << 10, 768 << 10, false, object_size), + extents[1]); + } + extents.clear(); + ASSERT_PASSED(this->validate_object_map, image); } @@ -7655,50 +8253,6 @@ TYPED_TEST(DiffIterateTest, DiffIterateStress) ASSERT_PASSED(this->validate_object_map, image); } -TYPED_TEST(DiffIterateTest, DiffIterateRegression6926) -{ - librados::IoCtx ioctx; - ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); - - librbd::RBD rbd; - librbd::Image image; - int order = 0; - 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, rbd.open(ioctx, image, name.c_str(), NULL)); - - uint64_t object_size = 0; - if (this->whole_object) { - object_size = 1 << order; - } - vector<diff_extent> extents; - ceph::bufferlist bl; - - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); - ASSERT_EQ(0u, extents.size()); - - ASSERT_EQ(0, image.snap_create("snap1")); - char data[256]; - memset(data, 1, sizeof(data)); - bl.append(data, 256); - ASSERT_EQ(256, image.write(0, 256, bl)); - - extents.clear(); - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); - ASSERT_EQ(1u, extents.size()); - ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]); - - ASSERT_EQ(0, image.snap_set("snap1")); - extents.clear(); - ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, true, this->whole_object, - vector_iterate_cb, (void *) &extents)); - ASSERT_EQ(static_cast<size_t>(0), extents.size()); -} - TYPED_TEST(DiffIterateTest, DiffIterateParent) { REQUIRE_FEATURE(RBD_FEATURE_LAYERING); @@ -7968,6 +8522,83 @@ TYPED_TEST(DiffIterateTest, DiffIterateUnaligned) ioctx.close(); } +TYPED_TEST(DiffIterateTest, DiffIterateTryAcquireLock) +{ + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librados::IoCtx ioctx; + ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx)); + + { + librbd::RBD rbd; + int order = 22; + std::string name = this->get_temp_image_name(); + ssize_t size = 20 << 20; + + uint64_t object_size = 0; + if (this->whole_object) { + object_size = 1 << order; + } + + ASSERT_EQ(0, create_image_pp(rbd, ioctx, name.c_str(), size, &order)); + + librbd::Image image1; + ASSERT_EQ(0, rbd.open(ioctx, image1, name.c_str(), NULL)); + + ceph::bufferlist bl; + bl.append(std::string(256, '1')); + ASSERT_EQ(256, image1.write(0, 256, bl)); + ASSERT_EQ(0, image1.flush()); + + bool lock_owner; + ASSERT_EQ(0, image1.is_exclusive_lock_owner(&lock_owner)); + ASSERT_TRUE(lock_owner); + + librbd::Image image2; + ASSERT_EQ(0, rbd.open(ioctx, image2, name.c_str(), NULL)); + + std::vector<diff_extent> extents; + ASSERT_EQ(0, image2.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, image2.is_exclusive_lock_owner(&lock_owner)); + ASSERT_FALSE(lock_owner); + + ASSERT_EQ(0, image1.close()); + ASSERT_EQ(0, image2.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, image2.is_exclusive_lock_owner(&lock_owner)); + ASSERT_FALSE(lock_owner); + + sleep(5); + ASSERT_EQ(0, image2.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, image2.is_exclusive_lock_owner(&lock_owner)); + if (this->whole_object && + (is_feature_enabled(RBD_FEATURE_OBJECT_MAP) || + is_feature_enabled(RBD_FEATURE_FAST_DIFF))) { + ASSERT_TRUE(lock_owner); + } else { + ASSERT_FALSE(lock_owner); + } + + ASSERT_PASSED(this->validate_object_map, image2); + } + + ioctx.close(); +} + TYPED_TEST(DiffIterateTest, DiffIterateStriping) { REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2); |