From 6bd2284576ddb69e072c2b78184bf94a26d641d4 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Tue, 14 Apr 2015 12:32:37 -0400 Subject: [PATCH] librbd: rebuild object map now supports fast diff The snapshot history of each object is queried to determine whether or not the object was dirtied at a particular snapshot. Signed-off-by: Jason Dillaman --- src/librbd/RebuildObjectMapRequest.cc | 86 +++++++++++++++++++++------ 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/src/librbd/RebuildObjectMapRequest.cc b/src/librbd/RebuildObjectMapRequest.cc index b2520d0615a..2df56fab816 100644 --- a/src/librbd/RebuildObjectMapRequest.cc +++ b/src/librbd/RebuildObjectMapRequest.cc @@ -25,10 +25,13 @@ namespace { class C_VerifyObject : public C_AsyncObjectThrottle { public: C_VerifyObject(AsyncObjectThrottle &throttle, ImageCtx *image_ctx, - uint64_t object_no) + uint64_t snap_id, uint64_t object_no) : C_AsyncObjectThrottle(throttle), m_image_ctx(*image_ctx), - m_object_no(object_no), m_oid(m_image_ctx.get_object_name(m_object_no)) + m_snap_id(snap_id), m_object_no(object_no), + m_oid(m_image_ctx.get_object_name(m_object_no)) { + m_io_ctx.dup(m_image_ctx.md_ctx); + m_io_ctx.snap_set_read(CEPH_SNAPDIR); } virtual void complete(int r) { @@ -41,19 +44,26 @@ public: } virtual int send() { - send_assert_exists(); + send_list_snaps(); return 0; } private: ImageCtx &m_image_ctx; + librados::IoCtx m_io_ctx; uint64_t m_snap_id; uint64_t m_object_no; std::string m_oid; + librados::snap_set_t m_snap_set; + int m_snap_list_ret; + bool should_complete(int r) { CephContext *cct = m_image_ctx.cct; - if (r < 0 && r != -ENOENT) { + if (r == 0) { + r = m_snap_list_ret; + } + if (r < 0 && r != -ENOENT) { lderr(cct) << m_oid << " C_VerifyObject::should_complete: " << "encountered an error: " << cpp_strerror(r) << dendl; return true; @@ -61,23 +71,65 @@ private: ldout(cct, 20) << m_oid << " C_VerifyObject::should_complete: " << " r=" << r << dendl; - return update_object_map(r == 0); + return update_object_map(get_object_state()); } - void send_assert_exists() { - ldout(m_image_ctx.cct, 5) << m_oid << " C_VerifyObject::send_assert_exists" + void send_list_snaps() { + ldout(m_image_ctx.cct, 5) << m_oid << " C_VerifyObject::send_list_snaps" << dendl; librados::AioCompletion *comp = librados::Rados::aio_create_completion( this, NULL, rados_ctx_cb); librados::ObjectReadOperation op; - op.assert_exists(); - int r = m_image_ctx.data_ctx.aio_operate(m_oid, comp, &op, NULL); + op.list_snaps(&m_snap_set, &m_snap_list_ret); + + int r = m_io_ctx.aio_operate(m_oid, comp, &op, NULL); assert(r == 0); } - bool update_object_map(bool exists) { + uint8_t get_object_state() { + RWLock::RLocker snap_locker(m_image_ctx.snap_lock); + for (std::vector::const_iterator r = + m_snap_set.clones.begin(); r != m_snap_set.clones.end(); ++r) { + librados::snap_t from_snap_id; + librados::snap_t to_snap_id; + if (r->cloneid == librados::SNAP_HEAD) { + from_snap_id = next_valid_snap_id(m_snap_set.seq + 1); + to_snap_id = librados::SNAP_HEAD; + } else { + from_snap_id = next_valid_snap_id(r->snaps[0]); + to_snap_id = r->snaps[r->snaps.size()-1]; + } + + if (to_snap_id < m_snap_id) { + continue; + } else if (m_snap_id < from_snap_id) { + break; + } + + RWLock::RLocker snap_locker(m_image_ctx.snap_lock); + if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0 && + from_snap_id != m_snap_id) { + return OBJECT_EXISTS_CLEAN; + } + return OBJECT_EXISTS; + } + return OBJECT_NONEXISTENT; + } + + uint64_t next_valid_snap_id(uint64_t snap_id) { + assert(m_image_ctx.snap_lock.is_locked()); + + std::map::iterator it = + m_image_ctx.snap_info.lower_bound(snap_id); + if (it == m_image_ctx.snap_info.end()) { + return CEPH_NOSNAP; + } + return it->first; + } + + bool update_object_map(uint8_t new_state) { CephContext *cct = m_image_ctx.cct; bool lost_exclusive_lock = false; @@ -90,11 +142,10 @@ private: } else { RWLock::WLocker l(m_image_ctx.object_map_lock); uint8_t state = m_image_ctx.object_map[m_object_no]; - uint8_t new_state = state; - if (exists && state == OBJECT_NONEXISTENT) { - new_state = OBJECT_EXISTS; - } else if (!exists && state != OBJECT_NONEXISTENT) { - new_state = OBJECT_NONEXISTENT; + if (state == OBJECT_EXISTS && new_state == OBJECT_NONEXISTENT && + m_snap_id == CEPH_NOSNAP) { + // might be writing object to OSD concurrently + new_state = state; } if (new_state != state) { @@ -256,17 +307,18 @@ void RebuildObjectMapRequest::send_verify_objects() { m_state = STATE_VERIFY_OBJECTS; ldout(cct, 5) << this << " send_verify_objects" << dendl; + uint64_t snap_id; uint64_t num_objects; { RWLock::RLocker l(m_image_ctx.snap_lock); - uint64_t snap_id = m_image_ctx.snap_id; + snap_id = m_image_ctx.snap_id; num_objects = Striper::get_num_objects(m_image_ctx.layout, m_image_ctx.get_image_size(snap_id)); } AsyncObjectThrottle::ContextFactory context_factory( boost::lambda::bind(boost::lambda::new_ptr(), - boost::lambda::_1, &m_image_ctx, boost::lambda::_2)); + boost::lambda::_1, &m_image_ctx, snap_id, boost::lambda::_2)); AsyncObjectThrottle *throttle = new AsyncObjectThrottle( *this, context_factory, create_callback_context(), m_prog_ctx, 0, num_objects);