From ca71a3eb121af17cb223090e528d5db82805a6d9 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Thu, 17 Dec 2015 15:28:31 -0500 Subject: [PATCH] librbd: initial integration of maintenance op journal replay Signed-off-by: Jason Dillaman --- src/librbd/journal/Replay.cc | 109 ++++++++++++++++++++++++++++++----- src/librbd/journal/Replay.h | 21 +++++-- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/src/librbd/journal/Replay.cc b/src/librbd/journal/Replay.cc index b0bb1ce573cf9..c2b5eabe07412 100644 --- a/src/librbd/journal/Replay.cc +++ b/src/librbd/journal/Replay.cc @@ -2,10 +2,13 @@ // vim: ts=8 sw=2 smarttab #include "librbd/journal/Replay.h" +#include "common/WorkQueue.h" #include "librbd/AioCompletion.h" #include "librbd/AioImageRequest.h" #include "librbd/ImageCtx.h" #include "librbd/internal.h" +#include "librbd/Operations.h" +#include "librbd/Utils.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix @@ -14,6 +17,13 @@ namespace librbd { namespace journal { +namespace { + +static NoOpProgressContext no_op_progress_callback; + +} // anonymous namespace + + template Replay::Replay(I &image_ctx) : m_image_ctx(image_ctx), m_lock("Replay::m_lock"), m_flush_ctx(nullptr), @@ -22,7 +32,7 @@ Replay::Replay(I &image_ctx) template Replay::~Replay() { - assert(m_aio_completions.empty()); + assert(m_op_contexts.empty() && m_aio_completions.empty()); } template @@ -48,12 +58,14 @@ void Replay::flush(Context *on_finish) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << dendl; + on_finish = util::create_async_context_callback( + m_image_ctx, on_finish); { Mutex::Locker locker(m_lock); assert(m_flush_ctx == nullptr); m_flush_ctx = on_finish; - if (!m_aio_completions.empty()) { + if (!m_op_contexts.empty() || !m_aio_completions.empty()) { return; } } @@ -105,6 +117,9 @@ void Replay::handle_event(const journal::SnapCreateEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap create event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_create(event.snap_name.c_str(), on_finish); } template @@ -112,6 +127,9 @@ void Replay::handle_event(const journal::SnapRemoveEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap remove event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_remove(event.snap_name.c_str(), on_finish); } template @@ -119,6 +137,10 @@ void Replay::handle_event(const journal::SnapRenameEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap rename event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_rename(event.snap_id, event.snap_name.c_str(), + on_finish); } template @@ -126,6 +148,9 @@ void Replay::handle_event(const journal::SnapProtectEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap protect event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_protect(event.snap_name.c_str(), on_finish); } template @@ -134,6 +159,9 @@ void Replay::handle_event(const journal::SnapUnprotectEvent &event, CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap unprotect event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_unprotect(event.snap_name.c_str(), on_finish); } template @@ -142,6 +170,10 @@ void Replay::handle_event(const journal::SnapRollbackEvent &event, CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Snap rollback start event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->snap_rollback(event.snap_name.c_str(), + no_op_progress_callback, on_finish); } template @@ -149,6 +181,9 @@ void Replay::handle_event(const journal::RenameEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Rename event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->rename(event.image_name.c_str(), on_finish); } template @@ -156,6 +191,10 @@ void Replay::handle_event(const journal::ResizeEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Resize start event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->resize(event.size, no_op_progress_callback, + on_finish); } template @@ -163,6 +202,9 @@ void Replay::handle_event(const journal::FlattenEvent &event, Context *on_safe) { CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": Flatten start event" << dendl; + + Context *on_finish = create_op_context_callback(on_safe); + m_image_ctx.operations->flatten(no_op_progress_callback, on_finish); } template @@ -173,6 +215,42 @@ void Replay::handle_event(const journal::UnknownEvent &event, on_safe->complete(0); } +template +Context *Replay::create_op_context_callback(Context *on_safe) { + C_OpOnFinish *on_finish; + { + on_finish = new C_OpOnFinish(this); + m_op_contexts[on_finish] = on_safe; + } + return on_finish; +} + +template +void Replay::handle_op_context_callback(Context *on_op_finish, int r) { + Context *on_safe = nullptr; + Context *on_flush = nullptr; + { + Mutex::Locker locker(m_lock); + auto it = m_op_contexts.find(on_op_finish); + assert(it != m_op_contexts.end()); + + if (m_ret_val == 0 && r < 0) { + m_ret_val = r; + } + + on_safe = it->second; + m_op_contexts.erase(it); + if (m_op_contexts.empty() && m_aio_completions.empty()) { + on_flush = m_flush_ctx; + } + } + + on_safe->complete(r); + if (on_flush != nullptr) { + on_flush->complete(m_ret_val); + } +} + template AioCompletion *Replay::create_aio_completion(Context *on_safe) { Mutex::Locker locker(m_lock); @@ -185,35 +263,34 @@ AioCompletion *Replay::create_aio_completion(Context *on_safe) { template void Replay::handle_aio_completion(AioCompletion *aio_comp) { - Context *on_finish = nullptr; + int r; + Context *on_safe = nullptr; + Context *on_flush = nullptr; { Mutex::Locker locker(m_lock); - AioCompletions::iterator it = m_aio_completions.find(aio_comp); assert(it != m_aio_completions.end()); - int r = aio_comp->get_return_value(); + r = aio_comp->get_return_value(); + if (m_ret_val == 0 && r < 0) { + m_ret_val = r; + } CephContext *cct = m_image_ctx.cct; ldout(cct, 20) << this << " " << __func__ << ": " << "aio_comp=" << aio_comp << ", " << "r=" << r << dendl; - Context *on_safe = it->second; - on_safe->complete(r); - - if (r < 0 && m_ret_val == 0) { - m_ret_val = r; - } - + on_safe = it->second; m_aio_completions.erase(it); - if (m_aio_completions.empty()) { - on_finish = m_flush_ctx; + if (m_op_contexts.empty() && m_aio_completions.empty()) { + on_flush = m_flush_ctx; } } - if (on_finish != nullptr) { - on_finish->complete(m_ret_val); + on_safe->complete(r); + if (on_flush != nullptr) { + on_flush->complete(m_ret_val); } } diff --git a/src/librbd/journal/Replay.h b/src/librbd/journal/Replay.h index 3eeb452648ad4..5a8c559866d6f 100644 --- a/src/librbd/journal/Replay.h +++ b/src/librbd/journal/Replay.h @@ -6,14 +6,14 @@ #include "include/int_types.h" #include "include/buffer_fwd.h" +#include "include/Context.h" +#include "include/unordered_map.h" #include "include/rbd/librbd.hpp" #include "common/Mutex.h" #include "librbd/journal/Entries.h" #include #include -class Context; - namespace librbd { class AioCompletion; @@ -28,14 +28,25 @@ public: return new Replay(image_ctx); } + Replay(ImageCtxT &image_ctx); ~Replay(); int process(bufferlist::iterator it, Context *on_safe = NULL); void flush(Context *on_finish); private: + typedef ceph::unordered_map OpContexts; typedef std::map AioCompletions; + struct C_OpOnFinish : public Context { + Replay *replay; + C_OpOnFinish(Replay *replay) : replay(replay) { + } + virtual void finish(int r) override { + replay->handle_op_context_callback(this, r); + } + }; + struct EventVisitor : public boost::static_visitor { Replay *replay; Context *on_safe; @@ -54,12 +65,11 @@ private: Mutex m_lock; + OpContexts m_op_contexts; AioCompletions m_aio_completions; Context *m_flush_ctx; int m_ret_val; - Replay(ImageCtxT &image_ctx); - void handle_event(const AioDiscardEvent &event, Context *on_safe); void handle_event(const AioWriteEvent &event, Context *on_safe); void handle_event(const AioFlushEvent &event, Context *on_safe); @@ -75,6 +85,9 @@ private: void handle_event(const FlattenEvent &event, Context *on_safe); void handle_event(const UnknownEvent &event, Context *on_safe); + Context *create_op_context_callback(Context *on_safe); + void handle_op_context_callback(Context *on_op_finish, int r); + AioCompletion *create_aio_completion(Context *on_safe); void handle_aio_completion(AioCompletion *aio_comp); -- 2.39.5