From e9c78c6c0c97dfb4e0ca211db33b9e3942dfd97c Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 21 May 2015 12:36:55 -0400 Subject: [PATCH] librbd: move diff_iterate logic to its own class In preparation for parallelizing the diff_iterate logic, move all existing logic to its own class. No functional changes have been made. Signed-off-by: Jason Dillaman --- src/librbd/DiffIterate.cc | 337 ++++++++++++++++++++++++++++++++++++++ src/librbd/DiffIterate.h | 47 ++++++ src/librbd/Makefile.am | 2 + src/librbd/internal.cc | 320 +----------------------------------- 4 files changed, 394 insertions(+), 312 deletions(-) create mode 100644 src/librbd/DiffIterate.cc create mode 100644 src/librbd/DiffIterate.h diff --git a/src/librbd/DiffIterate.cc b/src/librbd/DiffIterate.cc new file mode 100644 index 0000000000000..905e4ae3f9d99 --- /dev/null +++ b/src/librbd/DiffIterate.cc @@ -0,0 +1,337 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/DiffIterate.h" +#include "librbd/ImageCtx.h" +#include "include/rados/librados.hpp" +#include "include/interval_set.h" +#include "librados/snap_set_diff.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::DiffIterate: " + +namespace librbd { + +namespace { + +enum ObjectDiffState { + OBJECT_DIFF_STATE_NONE = 0, + OBJECT_DIFF_STATE_UPDATED = 1, + OBJECT_DIFF_STATE_HOLE = 2 +}; + +} // anonymous namespace + +int DiffIterate::execute() { + librados::IoCtx head_ctx; + + m_image_ctx.md_lock.get_read(); + m_image_ctx.snap_lock.get_read(); + head_ctx.dup(m_image_ctx.data_ctx); + librados::snap_t from_snap_id = 0; + uint64_t from_size = 0; + if (m_from_snap_name) { + from_snap_id = m_image_ctx.get_snap_id(m_from_snap_name); + from_size = m_image_ctx.get_image_size(from_snap_id); + } + librados::snap_t end_snap_id = m_image_ctx.snap_id; + uint64_t end_size = m_image_ctx.get_image_size(end_snap_id); + m_image_ctx.snap_lock.put_read(); + m_image_ctx.md_lock.put_read(); + if (from_snap_id == CEPH_NOSNAP) { + return -ENOENT; + } + if (from_snap_id == end_snap_id) { + // no diff. + return 0; + } + if (from_snap_id >= end_snap_id) { + return -EINVAL; + } + + int r; + bool fast_diff_enabled = false; + BitVector<2> object_diff_state; + { + RWLock::RLocker snap_locker(m_image_ctx.snap_lock); + if (m_whole_object && (m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) { + r = diff_object_map(from_snap_id, end_snap_id, &object_diff_state); + if (r < 0) { + ldout(m_image_ctx.cct, 5) << "diff_iterate fast diff disabled" << dendl; + } else { + ldout(m_image_ctx.cct, 5) << "diff_iterate fast diff enabled" << dendl; + fast_diff_enabled = true; + } + } + } + + // we must list snaps via the head, not end snap + head_ctx.snap_set_read(CEPH_SNAPDIR); + + ldout(m_image_ctx.cct, 5) << "diff_iterate from " << from_snap_id << " to " + << end_snap_id << " size from " << from_size + << " to " << end_size << dendl; + + // FIXME: if end_size > from_size, we could read_iterate for the + // final part, and skip the listsnaps op. + + // check parent overlap only if we are comparing to the beginning of time + interval_set parent_diff; + if (m_include_parent && from_snap_id == 0) { + RWLock::RLocker l(m_image_ctx.snap_lock); + RWLock::RLocker l2(m_image_ctx.parent_lock); + uint64_t overlap = end_size; + m_image_ctx.get_parent_overlap(from_snap_id, &overlap); + r = 0; + if (m_image_ctx.parent && overlap > 0) { + ldout(m_image_ctx.cct, 10) << " first getting parent diff" << dendl; + DiffIterate diff_parent(*m_image_ctx.parent, NULL, 0, overlap, + m_include_parent, m_whole_object, + &DiffIterate::simple_diff_cb, + &diff_context.parent_diff); + r = diff_parent.execute(); + } + if (r < 0) + return r; + } + + uint64_t period = m_image_ctx.get_stripe_period(); + uint64_t off = m_offset; + uint64_t left = m_length; + + while (left > 0) { + uint64_t period_off = off - (off % period); + uint64_t read_len = min(period_off + period - off, left); + + // map to extents + map > object_extents; + Striper::file_to_extents(m_image_ctx.cct, m_image_ctx.format_string, + &m_image_ctx.layout, off, read_len, 0, + object_extents, 0); + + // get snap info for each object + for (map >::iterator p = + object_extents.begin(); + p != object_extents.end(); ++p) { + ldout(m_image_ctx.cct, 20) << "diff_iterate object " << p->first << dendl; + + if (fast_diff_enabled) { + const uint64_t object_no = p->second.front().objectno; + if (object_diff_state[object_no] != OBJECT_DIFF_STATE_NONE) { + bool updated = (object_diff_state[object_no] == + OBJECT_DIFF_STATE_UPDATED); + for (std::vector::iterator q = p->second.begin(); + q != p->second.end(); ++q) { + m_callback(off + q->offset, q->length, updated, m_callback_arg); + } + } + continue; + } + + librados::snap_set_t snap_set; + r = head_ctx.list_snaps(p->first.name, &snap_set); + if (r == -ENOENT) { + if (from_snap_id == 0 && !parent_diff.empty()) { + // report parent diff instead + for (vector::iterator q = p->second.begin(); + q != p->second.end(); ++q) { + for (vector >::iterator r = + q->buffer_extents.begin(); + r != q->buffer_extents.end(); ++r) { + interval_set o; + o.insert(off + r->first, r->second); + o.intersection_of(parent_diff); + ldout(m_image_ctx.cct, 20) << " reporting parent overlap " << o + << dendl; + for (interval_set::iterator s = o.begin(); s != o.end(); + ++s) { + m_callback(s.get_start(), s.get_len(), true, m_callback_arg); + } + } + } + } + continue; + } + if (r < 0) + return r; + + // calc diff from from_snap_id -> to_snap_id + interval_set diff; + bool end_exists; + calc_snap_set_diff(m_image_ctx.cct, snap_set, from_snap_id, end_snap_id, + &diff, &end_exists); + ldout(m_image_ctx.cct, 20) << " diff " << diff << " end_exists=" + << end_exists << dendl; + if (diff.empty()) { + continue; + } else if (m_whole_object) { + // provide the full object extents to the callback + for (vector::iterator q = p->second.begin(); + q != p->second.end(); ++q) { + m_callback(off + q->offset, q->length, end_exists, m_callback_arg); + } + continue; + } + + for (vector::iterator q = p->second.begin(); + q != p->second.end(); ++q) { + ldout(m_image_ctx.cct, 20) << "diff_iterate object " << p->first + << " extent " << q->offset << "~" + << q->length << " from " << q->buffer_extents + << dendl; + uint64_t opos = q->offset; + for (vector >::iterator r = + q->buffer_extents.begin(); + r != q->buffer_extents.end(); ++r) { + interval_set overlap; // object extents + overlap.insert(opos, r->second); + overlap.intersection_of(diff); + ldout(m_image_ctx.cct, 20) << " opos " << opos + << " buf " << r->first << "~" << r->second + << " overlap " << overlap << dendl; + for (interval_set::iterator s = overlap.begin(); + s != overlap.end(); ++s) { + uint64_t su_off = s.get_start() - opos; + uint64_t logical_off = off + r->first + su_off; + ldout(m_image_ctx.cct, 20) << " overlap extent " << s.get_start() + << "~" << s.get_len() << " logical " + << logical_off << "~" << s.get_len() << dendl; + m_callback(logical_off, s.get_len(), end_exists, m_callback_arg); + } + opos += r->second; + } + assert(opos == q->offset + q->length); + } + } + + left -= read_len; + off += read_len; + } + + return 0; +} + +int DiffIterate::diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, + BitVector<2>* object_diff_state) { + assert(m_image_ctx.snap_lock.is_locked()); + CephContext* cct = m_image_ctx.cct; + + bool diff_from_start = (from_snap_id == 0); + if (from_snap_id == 0) { + if (!m_image_ctx.snaps.empty()) { + from_snap_id = m_image_ctx.snaps.back(); + } else { + from_snap_id = CEPH_NOSNAP; + } + } + + object_diff_state->clear(); + int r; + uint64_t current_snap_id = from_snap_id; + uint64_t next_snap_id = to_snap_id; + BitVector<2> prev_object_map; + bool prev_object_map_valid = false; + while (true) { + uint64_t current_size = m_image_ctx.size; + if (current_snap_id != CEPH_NOSNAP) { + std::map::const_iterator snap_it = + m_image_ctx.snap_info.find(current_snap_id); + assert(snap_it != m_image_ctx.snap_info.end()); + current_size = snap_it->second.size; + + ++snap_it; + if (snap_it != m_image_ctx.snap_info.end()) { + next_snap_id = snap_it->first; + } else { + next_snap_id = CEPH_NOSNAP; + } + } + + uint64_t flags; + r = m_image_ctx.get_flags(from_snap_id, &flags); + if (r < 0) { + lderr(cct) << "diff_object_map: failed to retrieve image flags" << dendl; + return r; + } + if ((flags & RBD_FLAG_FAST_DIFF_INVALID) != 0) { + ldout(cct, 1) << "diff_object_map: cannot perform fast diff on invalid " + << "object map" << dendl; + return -EINVAL; + } + + BitVector<2> object_map; + std::string oid(ObjectMap::object_map_name(m_image_ctx.id, + current_snap_id)); + r = cls_client::object_map_load(&m_image_ctx.md_ctx, oid, &object_map); + if (r < 0) { + lderr(cct) << "diff_object_map: failed to load object map " << oid + << dendl; + return r; + } + ldout(cct, 20) << "diff_object_map: loaded object map " << oid << dendl; + + uint64_t num_objs = Striper::get_num_objects(m_image_ctx.layout, + current_size); + if (object_map.size() < num_objs) { + ldout(cct, 1) << "diff_object_map: object map too small: " + << object_map.size() << " < " << num_objs << dendl; + return -EINVAL; + } + object_map.resize(num_objs); + + uint64_t overlap = MIN(object_map.size(), prev_object_map.size()); + for (uint64_t i = 0; i < overlap; ++i) { + ldout(cct, 20) << __func__ << ": object state: " << i << " " + << static_cast(prev_object_map[i]) + << "->" << static_cast(object_map[i]) << dendl; + if (object_map[i] == OBJECT_NONEXISTENT) { + if (prev_object_map[i] != OBJECT_NONEXISTENT) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_HOLE; + } + } else if (object_map[i] == OBJECT_EXISTS || + (prev_object_map[i] != object_map[i] && + !(prev_object_map[i] == OBJECT_EXISTS && + object_map[i] == OBJECT_EXISTS_CLEAN))) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; + } + } + ldout(cct, 20) << "diff_object_map: computed overlap diffs" << dendl; + + object_diff_state->resize(object_map.size()); + if (object_map.size() > prev_object_map.size() && + (diff_from_start || prev_object_map_valid)) { + for (uint64_t i = overlap; i < object_diff_state->size(); ++i) { + ldout(cct, 20) << __func__ << ": object state: " << i << " " + << "->" << static_cast(object_map[i]) << dendl; + if (object_map[i] == OBJECT_NONEXISTENT) { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_NONE; + } else { + (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; + } + } + } + ldout(cct, 20) << "diff_object_map: computed resize diffs" << dendl; + + if (current_snap_id == next_snap_id || next_snap_id > to_snap_id) { + break; + } + current_snap_id = next_snap_id; + prev_object_map = object_map; + prev_object_map_valid = true; + } + return 0; +} + +int DiffIterate::simple_diff_cb(uint64_t off, size_t len, int exists, + void *arg) { + // This reads the existing extents in a parent from the beginning + // of time. Since images are thin-provisioned, the extents will + // always represent data, not holes. + assert(exists); + interval_set *diff = static_cast *>(arg); + diff->insert(off, len); + return 0; +} + +} // namespace librbd diff --git a/src/librbd/DiffIterate.h b/src/librbd/DiffIterate.h new file mode 100644 index 0000000000000..6b80af3ad68b6 --- /dev/null +++ b/src/librbd/DiffIterate.h @@ -0,0 +1,47 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#ifndef CEPH_LIBRBD_DIFF_ITERATE_H +#define CEPH_LIBRBD_DIFF_ITERATE_H + +#include "include/int_types.h" +#include "common/bit_vector.hpp" + +namespace librbd { + +class ImageCtx; + +class DiffIterate { +public: + typedef int (*Callback)(uint64_t, size_t, int, void *); + + DiffIterate(ImageCtx &image_ctx, const char *from_snap_name, uint64_t off, + uint64_t len, bool include_parent, bool whole_object, + Callback callback, void *callback_arg) + : m_image_ctx(image_ctx), m_from_snap_name(from_snap_name), m_offset(off), + m_length(len), m_include_parent(include_parent), + m_whole_object(whole_object), m_callback(callback), + m_callback_arg(callback_arg) + { + } + + int execute(); + +private: + ImageCtx &m_image_ctx; + const char* m_from_snap_name; + uint64_t m_offset; + uint64_t m_length; + bool m_include_parent; + bool m_whole_object; + Callback m_callback; + void *m_callback_arg; + + int diff_object_map(uint64_t from_snap_id, uint64_t to_snap_id, + BitVector<2>* object_diff_state); + + static int simple_diff_cb(uint64_t off, size_t len, int exists, void *arg); +}; + +} // namespace librbd + +#endif // CEPH_LIBRBD_DIFF_ITERATE_H diff --git a/src/librbd/Makefile.am b/src/librbd/Makefile.am index 2a8133f18999f..201577ac44ec0 100644 --- a/src/librbd/Makefile.am +++ b/src/librbd/Makefile.am @@ -16,6 +16,7 @@ librbd_internal_la_SOURCES = \ librbd/AsyncResizeRequest.cc \ librbd/AsyncTrimRequest.cc \ librbd/CopyupRequest.cc \ + librbd/DiffIterate.cc \ librbd/ImageCtx.cc \ librbd/ImageWatcher.cc \ librbd/internal.cc \ @@ -59,6 +60,7 @@ noinst_HEADERS += \ librbd/AsyncResizeRequest.h \ librbd/AsyncTrimRequest.h \ librbd/CopyupRequest.h \ + librbd/DiffIterate.h \ librbd/ImageCtx.h \ librbd/ImageWatcher.h \ librbd/internal.h \ diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index fbdbaa2437a9c..e1bccdc516dd5 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -22,6 +22,7 @@ #include "librbd/AsyncResizeRequest.h" #include "librbd/AsyncTrimRequest.h" #include "librbd/CopyupRequest.h" +#include "librbd/DiffIterate.h" #include "librbd/ImageCtx.h" #include "librbd/ImageWatcher.h" #include "librbd/internal.h" @@ -30,8 +31,6 @@ #include "librbd/RebuildObjectMapRequest.h" #include "include/util.h" -#include "librados/snap_set_diff.h" - #include #include #include "include/assert.h" @@ -58,121 +57,6 @@ namespace librbd { namespace { -enum ObjectDiffState { - OBJECT_DIFF_STATE_NONE = 0, - OBJECT_DIFF_STATE_UPDATED = 1, - OBJECT_DIFF_STATE_HOLE = 2 -}; - -int diff_object_map(ImageCtx* ictx, uint64_t from_snap_id, uint64_t to_snap_id, - BitVector<2>* object_diff_state) { - assert(ictx->snap_lock.is_locked()); - CephContext* cct = ictx->cct; - - bool diff_from_start = (from_snap_id == 0); - if (from_snap_id == 0) { - if (!ictx->snaps.empty()) { - from_snap_id = ictx->snaps.back(); - } else { - from_snap_id = CEPH_NOSNAP; - } - } - - object_diff_state->clear(); - int r; - uint64_t current_snap_id = from_snap_id; - uint64_t next_snap_id = to_snap_id; - BitVector<2> prev_object_map; - bool prev_object_map_valid = false; - while (true) { - uint64_t current_size = ictx->size; - if (current_snap_id != CEPH_NOSNAP) { - std::map::const_iterator snap_it = - ictx->snap_info.find(current_snap_id); - assert(snap_it != ictx->snap_info.end()); - current_size = snap_it->second.size; - - ++snap_it; - if (snap_it != ictx->snap_info.end()) { - next_snap_id = snap_it->first; - } else { - next_snap_id = CEPH_NOSNAP; - } - } - - uint64_t flags; - r = ictx->get_flags(from_snap_id, &flags); - if (r < 0) { - lderr(cct) << "diff_object_map: failed to retrieve image flags" << dendl; - return r; - } - if ((flags & RBD_FLAG_FAST_DIFF_INVALID) != 0) { - ldout(cct, 1) << "diff_object_map: cannot perform fast diff on invalid " - << "object map" << dendl; - return -EINVAL; - } - - BitVector<2> object_map; - std::string oid(ObjectMap::object_map_name(ictx->id, current_snap_id)); - r = cls_client::object_map_load(&ictx->md_ctx, oid, &object_map); - if (r < 0) { - lderr(cct) << "diff_object_map: failed to load object map " << oid - << dendl; - return r; - } - ldout(cct, 20) << "diff_object_map: loaded object map " << oid << dendl; - - uint64_t num_objs = Striper::get_num_objects(ictx->layout, current_size); - if (object_map.size() < num_objs) { - ldout(cct, 1) << "diff_object_map: object map too small: " - << object_map.size() << " < " << num_objs << dendl; - return -EINVAL; - } - object_map.resize(num_objs); - - uint64_t overlap = MIN(object_map.size(), prev_object_map.size()); - for (uint64_t i = 0; i < overlap; ++i) { - ldout(cct, 20) << __func__ << ": object state: " << i << " " - << static_cast(prev_object_map[i]) - << "->" << static_cast(object_map[i]) << dendl; - if (object_map[i] == OBJECT_NONEXISTENT) { - if (prev_object_map[i] != OBJECT_NONEXISTENT) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_HOLE; - } - } else if (object_map[i] == OBJECT_EXISTS || - (prev_object_map[i] != object_map[i] && - !(prev_object_map[i] == OBJECT_EXISTS && - object_map[i] == OBJECT_EXISTS_CLEAN))) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; - } - } - ldout(cct, 20) << "diff_object_map: computed overlap diffs" << dendl; - - object_diff_state->resize(object_map.size()); - if (object_map.size() > prev_object_map.size() && - (diff_from_start || prev_object_map_valid)) { - for (uint64_t i = overlap; i < object_diff_state->size(); ++i) { - ldout(cct, 20) << __func__ << ": object state: " << i << " " - << "->" << static_cast(object_map[i]) << dendl; - if (object_map[i] == OBJECT_NONEXISTENT) { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_NONE; - } else { - (*object_diff_state)[i] = OBJECT_DIFF_STATE_UPDATED; - } - } - } - ldout(cct, 20) << "diff_object_map: computed resize diffs" << dendl; - - if (current_snap_id == next_snap_id || next_snap_id > to_snap_id) { - break; - } - current_snap_id = next_snap_id; - prev_object_map = object_map; - prev_object_map_valid = true; - } - return 0; -} - int remove_object_map(ImageCtx *ictx) { assert(ictx->snap_lock.is_locked()); CephContext *cct = ictx->cct; @@ -3244,24 +3128,10 @@ reprotect_and_return_err: return total_read; } - int simple_diff_cb(uint64_t off, size_t len, int exists, void *arg) - { - // This reads the existing extents in a parent from the beginning - // of time. Since images are thin-provisioned, the extents will - // always represent data, not holes. - assert(exists); - interval_set *diff = static_cast *>(arg); - diff->insert(off, len); - return 0; - } - - int diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, uint64_t len, bool include_parent, bool whole_object, int (*cb)(uint64_t, size_t, int, void *), void *arg) { - utime_t start_time, elapsed; - ldout(ictx->cct, 20) << "diff_iterate " << ictx << " off = " << off << " len = " << len << dendl; @@ -3272,195 +3142,21 @@ reprotect_and_return_err: } int r = ictx_check(ictx); - if (r < 0) + if (r < 0) { return r; + } ictx->snap_lock.get_read(); r = clip_io(ictx, off, &len); ictx->snap_lock.put_read(); - if (r < 0) + if (r < 0) { return r; - - librados::IoCtx head_ctx; - - ictx->md_lock.get_read(); - ictx->snap_lock.get_read(); - head_ctx.dup(ictx->data_ctx); - snap_t from_snap_id = 0; - uint64_t from_size = 0; - if (fromsnapname) { - from_snap_id = ictx->get_snap_id(fromsnapname); - from_size = ictx->get_image_size(from_snap_id); - } - snap_t end_snap_id = ictx->snap_id; - uint64_t end_size = ictx->get_image_size(end_snap_id); - ictx->snap_lock.put_read(); - ictx->md_lock.put_read(); - if (from_snap_id == CEPH_NOSNAP) { - return -ENOENT; } - if (from_snap_id == end_snap_id) { - // no diff. - return 0; - } - if (from_snap_id >= end_snap_id) { - return -EINVAL; - } - - bool fast_diff_enabled = false; - BitVector<2> object_diff_state; - { - RWLock::RLocker snap_locker(ictx->snap_lock); - if (whole_object && (ictx->features & RBD_FEATURE_FAST_DIFF) != 0) { - r = diff_object_map(ictx, from_snap_id, end_snap_id, - &object_diff_state); - if (r < 0) { - ldout(ictx->cct, 1) << "diff_iterate fast diff disabled" << dendl; - } else { - ldout(ictx->cct, 1) << "diff_iterate fast diff enabled" << dendl; - fast_diff_enabled = true; - } - } - } - - // we must list snaps via the head, not end snap - head_ctx.snap_set_read(CEPH_SNAPDIR); - - ldout(ictx->cct, 20) << "diff_iterate from " << from_snap_id << " to " << end_snap_id - << " size from " << from_size << " to " << end_size << dendl; - - // FIXME: if end_size > from_size, we could read_iterate for the - // final part, and skip the listsnaps op. - - // check parent overlap only if we are comparing to the beginning of time - interval_set parent_diff; - if (include_parent && from_snap_id == 0) { - RWLock::RLocker l(ictx->snap_lock); - RWLock::RLocker l2(ictx->parent_lock); - uint64_t overlap = end_size; - ictx->get_parent_overlap(from_snap_id, &overlap); - r = 0; - if (ictx->parent && overlap > 0) { - ldout(ictx->cct, 10) << " first getting parent diff" << dendl; - r = diff_iterate(ictx->parent, NULL, 0, overlap, include_parent, - whole_object, simple_diff_cb, &parent_diff); - } - if (r < 0) - return r; - } - - uint64_t period = ictx->get_stripe_period(); - uint64_t left = len; - - while (left > 0) { - uint64_t period_off = off - (off % period); - uint64_t read_len = min(period_off + period - off, left); - // map to extents - map > object_extents; - Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, - off, read_len, 0, object_extents, 0); - - // get snap info for each object - for (map >::iterator p = object_extents.begin(); - p != object_extents.end(); - ++p) { - ldout(ictx->cct, 20) << "diff_iterate object " << p->first << dendl; - - if (fast_diff_enabled) { - const uint64_t object_no = p->second.front().objectno; - if (object_diff_state[object_no] != OBJECT_DIFF_STATE_NONE) { - bool updated = (object_diff_state[object_no] == - OBJECT_DIFF_STATE_UPDATED); - for (std::vector::iterator q = p->second.begin(); - q != p->second.end(); ++q) { - cb(off + q->offset, q->length, updated, arg); - } - } - continue; - } - - librados::snap_set_t snap_set; - r = head_ctx.list_snaps(p->first.name, &snap_set); - if (r == -ENOENT) { - if (from_snap_id == 0 && !parent_diff.empty()) { - // report parent diff instead - for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { - for (vector >::iterator r = q->buffer_extents.begin(); - r != q->buffer_extents.end(); - ++r) { - interval_set o; - o.insert(off + r->first, r->second); - o.intersection_of(parent_diff); - ldout(ictx->cct, 20) << " reporting parent overlap " << o << dendl; - for (interval_set::iterator s = o.begin(); s != o.end(); ++s) { - cb(s.get_start(), s.get_len(), true, arg); - } - } - } - } - continue; - } - if (r < 0) - return r; - - // calc diff from from_snap_id -> to_snap_id - interval_set diff; - bool end_exists; - calc_snap_set_diff(ictx->cct, snap_set, - from_snap_id, - end_snap_id, - &diff, &end_exists); - ldout(ictx->cct, 20) << " diff " << diff << " end_exists=" << end_exists << dendl; - if (diff.empty()) { - continue; - } else if (whole_object) { - // provide the full object extents to the callback - for (vector::iterator q = p->second.begin(); - q != p->second.end(); ++q) { - cb(off + q->offset, q->length, end_exists, arg); - } - continue; - } - - for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { - ldout(ictx->cct, 20) << "diff_iterate object " << p->first - << " extent " << q->offset << "~" << q->length - << " from " << q->buffer_extents - << dendl; - uint64_t opos = q->offset; - for (vector >::iterator r = q->buffer_extents.begin(); - r != q->buffer_extents.end(); - ++r) { - interval_set overlap; // object extents - overlap.insert(opos, r->second); - overlap.intersection_of(diff); - ldout(ictx->cct, 20) << " opos " << opos - << " buf " << r->first << "~" << r->second - << " overlap " << overlap - << dendl; - for (interval_set::iterator s = overlap.begin(); - s != overlap.end(); - ++s) { - uint64_t su_off = s.get_start() - opos; - uint64_t logical_off = off + r->first + su_off; - ldout(ictx->cct, 20) << " overlap extent " << s.get_start() << "~" << s.get_len() - << " logical " - << logical_off << "~" << s.get_len() - << dendl; - cb(logical_off, s.get_len(), end_exists, arg); - } - opos += r->second; - } - assert(opos == q->offset + q->length); - } - } - - left -= read_len; - off += read_len; - } - - return 0; + DiffIterate command(*ictx, fromsnapname, off, len, include_parent, + whole_object, cb, arg); + r = command.execute(); + return r; } int simple_read_cb(uint64_t ofs, size_t len, const char *buf, void *arg) -- 2.39.5