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, 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);
+}
+
+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 = 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());
+
+ 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, &extents));
+ ASSERT_EQ(1u, extents.size());
+ ASSERT_EQ(diff_extent(0, 256, true, object_size), extents[0]);
+ extents.clear();
+
+ 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, &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_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(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, 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, &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)
{
librados::IoCtx ioctx;