auto state = snapshot_extent.get_val().state;
// ignore DNE object (and parent)
- if (key == io::WriteReadSnapIds{0, 0} &&
- state != io::SPARSE_EXTENT_STATE_DATA) {
+ if ((state == io::SPARSE_EXTENT_STATE_DNE) ||
+ (key == io::INITIAL_WRITE_READ_SNAP_IDS &&
+ state == io::SPARSE_EXTENT_STATE_ZEROED)) {
continue;
}
io::WriteReadSnapIds write_read_snap_ids{key};
// advance the src write snap id to the first valid snap id
- if (write_read_snap_ids != io::INITIAL_WRITE_READ_SNAP_IDS) {
+ if (write_read_snap_ids.first > m_src_snap_id_start) {
// don't attempt to read from snapshots that shouldn't exist in
// case the OSD fails to give a correct snap list
auto snap_map_it = m_snap_map.find(write_read_snap_ids.first);
auto state = image_interval.get_val().state;
switch (state) {
case io::SPARSE_EXTENT_STATE_DNE:
- ceph_assert(write_read_snap_ids == io::INITIAL_WRITE_READ_SNAP_IDS);
- if (read_from_parent) {
- // special-case for DNE object-extents since when flattening we need
- // to read data from the parent images extents
+ if (write_read_snap_ids == io::INITIAL_WRITE_READ_SNAP_IDS &&
+ read_from_parent) {
+ // special-case for DNE initial object-extents since when flattening
+ // we need to read data from the parent images extents
ldout(m_cct, 20) << "DNE extent: "
<< image_interval.get_off() << "~"
<< image_interval.get_len() << dendl;
auto state = image_interval.get_val().state;
switch (state) {
case io::SPARSE_EXTENT_STATE_ZEROED:
- if (write_read_snap_ids != io::WriteReadSnapIds{0, 0}) {
+ if (write_read_snap_ids.first > m_src_snap_id_start) {
ldout(m_cct, 20) << "zeroed extent: "
<< "src_snap_seq=" << src_snap_seq << " "
<< image_interval.get_off() << "~"
<< image_interval.get_len() << dendl;
m_dst_zero_interval[src_snap_seq].union_insert(
image_interval.get_off(), image_interval.get_len());
- } else if (hide_parent) {
+ } else if (write_read_snap_ids == io::INITIAL_WRITE_READ_SNAP_IDS &&
+ hide_parent) {
auto first_src_snap_id = m_snap_map.begin()->first;
ldout(m_cct, 20) << "zeroed (hide parent) extent: "
<< "src_snap_seq=" << first_src_snap_id << " "
m_snapshot_delta->clear();
auto& snapshot_delta = *m_snapshot_delta;
+ ceph_assert(!m_snap_ids.empty());
+ librados::snap_t start_snap_id = 0;
+ librados::snap_t first_snap_id = *m_snap_ids.begin();
+ librados::snap_t last_snap_id = *m_snap_ids.rbegin();
+
if (r == -ENOENT) {
// the object does not exist -- mark the missing extents
- zero_initial_extent(true);
+ zero_extent(first_snap_id, true);
list_from_parent();
return;
} else if (r < 0) {
librados::snap_set_t snap_set;
convert_snap_set(m_snap_set, &snap_set);
- ceph_assert(!m_snap_ids.empty());
- librados::snap_t start_snap_id = 0;
- librados::snap_t first_snap_id = *m_snap_ids.begin();
- librados::snap_t last_snap_id = *m_snap_ids.rbegin();
-
bool initial_extents_written = false;
interval_set<uint64_t> object_interval;
bool snapshot_delta_empty = snapshot_delta.empty();
if (!initial_extents_written) {
- zero_initial_extent(false);
+ zero_extent(first_snap_id, first_snap_id > 0);
}
ldout(cct, 20) << "snapshot_delta=" << snapshot_delta << dendl;
<< "parent_snapshot_delta=" << m_parent_snapshot_delta
<< dendl;
- // ignore special-case of fully empty dataset
- m_parent_snapshot_delta.erase(INITIAL_WRITE_READ_SNAP_IDS);
+ // ignore special-case of fully empty dataset (we ignore zeroes)
if (m_parent_snapshot_delta.empty()) {
this->finish(0);
return;
}
template <typename I>
-void ObjectListSnapsRequest<I>::zero_initial_extent(bool dne) {
+void ObjectListSnapsRequest<I>::zero_extent(uint64_t snap_id, bool dne) {
I *image_ctx = this->m_ictx;
auto cct = image_ctx->cct;
- ceph_assert(!m_snap_ids.empty());
- librados::snap_t snap_id_start = *m_snap_ids.begin();
-
// the object does not exist or is (partially) under whiteout -- mark the
// missing extents which would be any portion of the object that does not
// have data in the initial snapshot set
- if ((snap_id_start == 0) &&
- ((m_list_snaps_flags & LIST_SNAPS_FLAG_IGNORE_ZEROED_EXTENTS) == 0)) {
+ if ((m_list_snaps_flags & LIST_SNAPS_FLAG_IGNORE_ZEROED_EXTENTS) == 0) {
interval_set<uint64_t> interval;
for (auto [object_offset, object_length] : m_object_extents) {
interval.insert(object_offset, object_length);
}
for (auto [offset, length] : interval) {
- ldout(cct, 20) << "zeroing initial extent " << offset << "~" << length
- << dendl;
- (*m_snapshot_delta)[INITIAL_WRITE_READ_SNAP_IDS].insert(
+ ldout(cct, 20) << "snapshot " << snap_id << ": "
+ << (dne ? "DNE" : "zeroed") << " extent "
+ << offset << "~" << length << dendl;
+ (*m_snapshot_delta)[{snap_id, snap_id}].insert(
offset, length,
SparseExtent(
(dne ? SPARSE_EXTENT_STATE_DNE : SPARSE_EXTENT_STATE_ZEROED),
void list_from_parent();
void handle_list_from_parent(int r);
- void zero_initial_extent(bool dne);
+ void zero_extent(uint64_t snap_id, bool dne);
};
} // namespace io
ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
}
-TEST_F(TestMockIoObjectRequest, ListSnapsDNE) {
+TEST_F(TestMockIoObjectRequest, ListSnapsENOENT) {
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
}
+TEST_F(TestMockIoObjectRequest, ListSnapsDNE) {
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ mock_image_ctx.snaps = {2, 3, 4};
+
+ librados::snap_set_t snap_set;
+ snap_set.seq = 6;
+ librados::clone_info_t clone_info;
+
+ clone_info.cloneid = 4;
+ clone_info.snaps = {3, 4};
+ clone_info.overlap = std::vector<std::pair<uint64_t,uint64_t>>{
+ {0, 4194304}};
+ clone_info.size = 4194304;
+ snap_set.clones.push_back(clone_info);
+
+ expect_list_snaps(mock_image_ctx, snap_set, 0);
+
+ SnapshotDelta snapshot_delta;
+ C_SaferCond ctx;
+ auto req = MockObjectListSnapsRequest::create(
+ &mock_image_ctx, 0,
+ {{440320, 1024}},
+ {2, 3, 4}, 0, {}, &snapshot_delta, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ SnapshotDelta expected_snapshot_delta;
+ expected_snapshot_delta[{2,2}].insert(
+ 440320, 1024, {SPARSE_EXTENT_STATE_DNE, 1024});
+ expected_snapshot_delta[{3,4}].insert(
+ 440320, 1024, {SPARSE_EXTENT_STATE_DATA, 1024});
+ ASSERT_EQ(expected_snapshot_delta, snapshot_delta);
+}
+
TEST_F(TestMockIoObjectRequest, ListSnapsEmpty) {
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));