Merge pull request #45601 from idryomov/wip-diff-iterate-striping-fix

librbd: make diff-iterate in fast-diff mode sort and merge reported extents

Reviewed-by: Christopher Hoffman <choffman@redhat.com>
This commit is contained in:
Ilya Dryomov 2022-03-25 09:45:26 +01:00 committed by GitHub
commit b89b099893
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 15 deletions

View File

@ -300,12 +300,15 @@ int DiffIterate<I>::execute() {
&m_image_ctx.layout, off, read_len, 0,
object_extents, 0);
// get snap info for each object
// get diff info for each object and merge adjacent stripe units
// into an aggregate (this also sorts them)
io::SparseExtents aggregate_sparse_extents;
for (auto& [object, extents] : object_extents) {
ldout(cct, 20) << "object " << object << dendl;
const uint64_t object_no = extents.front().objectno;
uint8_t diff_state = object_diff_state[object_no];
ldout(cct, 20) << "object " << object << ": diff_state="
<< (int)diff_state << dendl;
if (diff_state == object_map::DIFF_STATE_HOLE &&
from_snap_id == 0 && !parent_diff.empty()) {
// no data in child object -- report parent diff instead
@ -316,29 +319,36 @@ int DiffIterate<I>::execute() {
o.intersection_of(parent_diff);
ldout(cct, 20) << " reporting parent overlap " << o << dendl;
for (auto e = o.begin(); e != o.end(); ++e) {
r = m_callback(e.get_start(), e.get_len(), true,
m_callback_arg);
if (r < 0) {
return r;
}
aggregate_sparse_extents.insert(e.get_start(), e.get_len(),
{io::SPARSE_EXTENT_STATE_DATA,
e.get_len()});
}
}
}
} else if (diff_state == object_map::DIFF_STATE_HOLE_UPDATED ||
diff_state == object_map::DIFF_STATE_DATA_UPDATED) {
bool updated = (diff_state == object_map::DIFF_STATE_DATA_UPDATED);
auto state = (diff_state == object_map::DIFF_STATE_HOLE_UPDATED ?
io::SPARSE_EXTENT_STATE_ZEROED : io::SPARSE_EXTENT_STATE_DATA);
for (auto& oe : extents) {
for (auto& be : oe.buffer_extents) {
r = m_callback(off + be.first, be.second, updated,
m_callback_arg);
if (r < 0) {
return r;
}
aggregate_sparse_extents.insert(off + be.first, be.second,
{state, be.second});
}
}
}
}
} else {
for (const auto& se : aggregate_sparse_extents) {
ldout(cct, 20) << "off=" << se.get_off() << ", len=" << se.get_len()
<< ", state=" << se.get_val().state << dendl;
r = m_callback(se.get_off(), se.get_len(),
se.get_val().state == io::SPARSE_EXTENT_STATE_DATA,
m_callback_arg);
if (r < 0) {
return r;
}
}
} else {
auto diff_object = new C_DiffObject<I>(m_image_ctx, diff_context, off,
read_len);
diff_object->send();

View File

@ -4845,6 +4845,77 @@ TYPED_TEST(DiffIterateTest, DiffIterateUnaligned)
ioctx.close();
}
TYPED_TEST(DiffIterateTest, DiffIterateStriping)
{
REQUIRE_FEATURE(RBD_FEATURE_STRIPINGV2);
librados::IoCtx ioctx;
ASSERT_EQ(0, this->_rados.ioctx_create(this->m_pool_name.c_str(), ioctx));
bool old_format;
uint64_t features;
ASSERT_EQ(0, get_features(&old_format, &features));
ASSERT_FALSE(old_format);
{
librbd::RBD rbd;
librbd::Image image;
int order = 22;
std::string name = this->get_temp_image_name();
ssize_t size = 24 << 20;
ASSERT_EQ(0, rbd.create3(ioctx, name.c_str(), size, features, &order,
1 << 20, 3));
ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
ceph::bufferlist bl;
bl.append(std::string(size, '1'));
ASSERT_EQ(size, image.write(0, size, bl));
std::vector<diff_extent> extents;
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, 12 << 20, true, 0), extents[0]);
ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[1]);
extents.clear();
ASSERT_EQ(0, image.snap_create("one"));
ASSERT_EQ(size, image.discard(0, size));
ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
vector_iterate_cb, &extents));
ASSERT_EQ(2u, extents.size());
ASSERT_EQ(diff_extent(0, 12 << 20, false, 0), extents[0]);
ASSERT_EQ(diff_extent(12 << 20, 12 << 20, false, 0), extents[1]);
extents.clear();
ASSERT_EQ(1 << 20, image.write(0, 1 << 20, bl));
ASSERT_EQ(2 << 20, image.write(2 << 20, 2 << 20, bl));
ASSERT_EQ(2 << 20, image.write(5 << 20, 2 << 20, bl));
ASSERT_EQ(2 << 20, image.write(8 << 20, 2 << 20, bl));
ASSERT_EQ(13 << 20, image.write(11 << 20, 13 << 20, bl));
ASSERT_EQ(0, image.diff_iterate2("one", 0, size, true, this->whole_object,
vector_iterate_cb, &extents));
ASSERT_EQ(10u, extents.size());
ASSERT_EQ(diff_extent(0, 1 << 20, true, 0), extents[0]);
ASSERT_EQ(diff_extent(1 << 20, 1 << 20, false, 0), extents[1]);
ASSERT_EQ(diff_extent(2 << 20, 2 << 20, true, 0), extents[2]);
ASSERT_EQ(diff_extent(4 << 20, 1 << 20, false, 0), extents[3]);
ASSERT_EQ(diff_extent(5 << 20, 2 << 20, true, 0), extents[4]);
ASSERT_EQ(diff_extent(7 << 20, 1 << 20, false, 0), extents[5]);
ASSERT_EQ(diff_extent(8 << 20, 2 << 20, true, 0), extents[6]);
ASSERT_EQ(diff_extent(10 << 20, 1 << 20, false, 0), extents[7]);
ASSERT_EQ(diff_extent(11 << 20, 1 << 20, true, 0), extents[8]);
ASSERT_EQ(diff_extent(12 << 20, 12 << 20, true, 0), extents[9]);
ASSERT_PASSED(this->validate_object_map, image);
}
ioctx.close();
}
TEST_F(TestLibRBD, ZeroLengthWrite)
{
rados_ioctx_t ioctx;