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)
{
return 0;
}
+int vector_iterate_cb(uint64_t off, size_t len, int exists, void *arg)
+{
+ auto diff = static_cast<std::vector<diff_extent>*>(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;
class DiffIterateTest : public TestLibRBD {
public:
static const uint8_t whole_object = T::whole_object;
-};
-template <bool _whole_object>
-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<false>,
- DiffIterateParams<true> > 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<uint64_t> exists;
- interval_set<uint64_t> 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<diff_extent> 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<uint64_t> 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<uint64_t> i;
- i.intersection_of(two, diff);
- interval_set<uint64_t> 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_extent> *diff = static_cast<vector<diff_extent> *>(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<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_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<diff_extent> 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<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());
+ // 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 <bool _whole_object>
+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<false>,
+ DiffIterateParams<true> > 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<uint64_t> exists;
+ interval_set<uint64_t> 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<uint64_t> 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<uint64_t> i;
+ i.intersection_of(two, diff);
+ interval_set<uint64_t> 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)