From c4e439dcdd3365cbf80e9cd671b636e55dbcc14e Mon Sep 17 00:00:00 2001 From: Venky Shankar Date: Tue, 5 Jul 2016 18:50:31 +0530 Subject: [PATCH] librbd / journal: async journal removal state machine Signed-off-by: Venky Shankar --- src/librbd/CMakeLists.txt | 1 + src/librbd/Journal.cc | 41 ++----- src/librbd/Makefile.am | 2 + src/librbd/journal/RemoveRequest.cc | 155 +++++++++++++++++++++++++++ src/librbd/journal/RemoveRequest.h | 82 ++++++++++++++ src/test/librbd/test_mock_Journal.cc | 31 ++++++ 6 files changed, 281 insertions(+), 31 deletions(-) create mode 100644 src/librbd/journal/RemoveRequest.cc create mode 100644 src/librbd/journal/RemoveRequest.h diff --git a/src/librbd/CMakeLists.txt b/src/librbd/CMakeLists.txt index 216f76d666f5c..889ff5488f2de 100644 --- a/src/librbd/CMakeLists.txt +++ b/src/librbd/CMakeLists.txt @@ -36,6 +36,7 @@ set(librbd_internal_srcs image/SetSnapRequest.cc image_watcher/Notifier.cc image_watcher/NotifyLockOwner.cc + journal/RemoveRequest.cc journal/Replay.cc journal/StandardPolicy.cc object_map/InvalidateRequest.cc diff --git a/src/librbd/Journal.cc b/src/librbd/Journal.cc index d807af7160632..74a4f96fa89fe 100644 --- a/src/librbd/Journal.cc +++ b/src/librbd/Journal.cc @@ -17,6 +17,7 @@ #include "common/Timer.h" #include "common/WorkQueue.h" #include "include/rados/librados.hpp" +#include "librbd/journal/RemoveRequest.h" #include @@ -394,40 +395,18 @@ int Journal::remove(librados::IoCtx &io_ctx, const std::string &image_id) { CephContext *cct = reinterpret_cast(io_ctx.cct()); ldout(cct, 5) << __func__ << ": image=" << image_id << dendl; - Journaler journaler(io_ctx, image_id, IMAGE_CLIENT_ID, {}); - - bool journal_exists; - int r = journaler.exists(&journal_exists); - if (r < 0) { - lderr(cct) << __func__ << ": " - << "failed to stat journal header: " << cpp_strerror(r) << dendl; - return r; - } else if (!journal_exists) { - return 0; - } - C_SaferCond cond; - journaler.init(&cond); - BOOST_SCOPE_EXIT_ALL(&journaler) { - journaler.shut_down(); - }; + ContextWQ op_work_queue("librbd::op_work_queue", + cct->_conf->rbd_op_thread_timeout, + ImageCtx::get_thread_pool_instance(cct)); + journal::RemoveRequest *req = journal::RemoveRequest::create( + io_ctx, image_id, IMAGE_CLIENT_ID, &op_work_queue, &cond); + req->send(); - r = cond.wait(); - if (r == -ENOENT) { - return 0; - } else if (r < 0) { - lderr(cct) << __func__ << ": " - << "failed to initialize journal: " << cpp_strerror(r) << dendl; - return r; - } + int r = cond.wait(); + op_work_queue.drain(); - r = journaler.remove(true); - if (r < 0) { - lderr(cct) << __func__ << ": " - << "failed to remove journal: " << cpp_strerror(r) << dendl; - return r; - } - return 0; + return r; } template diff --git a/src/librbd/Makefile.am b/src/librbd/Makefile.am index f5b036232aaa9..d961203f43226 100644 --- a/src/librbd/Makefile.am +++ b/src/librbd/Makefile.am @@ -41,6 +41,7 @@ librbd_internal_la_SOURCES = \ librbd/image/SetSnapRequest.cc \ librbd/image_watcher/Notifier.cc \ librbd/image_watcher/NotifyLockOwner.cc \ + librbd/journal/RemoveRequest.cc \ librbd/journal/Replay.cc \ librbd/journal/StandardPolicy.cc \ librbd/object_map/InvalidateRequest.cc \ @@ -129,6 +130,7 @@ noinst_HEADERS += \ librbd/image/SetSnapRequest.h \ librbd/image_watcher/Notifier.h \ librbd/image_watcher/NotifyLockOwner.h \ + librbd/journal/RemoveRequest.h \ librbd/journal/Policy.h \ librbd/journal/Replay.h \ librbd/journal/StandardPolicy.h \ diff --git a/src/librbd/journal/RemoveRequest.cc b/src/librbd/journal/RemoveRequest.cc new file mode 100644 index 0000000000000..c9dd020b63412 --- /dev/null +++ b/src/librbd/journal/RemoveRequest.cc @@ -0,0 +1,155 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/dout.h" +#include "common/errno.h" +#include "common/Timer.h" +#include "common/WorkQueue.h" +#include "journal/Settings.h" +#include "include/assert.h" +#include "librbd/Utils.h" +#include "librbd/journal/RemoveRequest.h" + +#define dout_subsys ceph_subsys_rbd +#undef dout_prefix +#define dout_prefix *_dout << "librbd::Journal::RemoveRequest: " + +namespace librbd { + +using util::create_context_callback; + +namespace journal { + +template +RemoveRequest::RemoveRequest(IoCtx &ioctx, const std::string &image_id, + const std::string &client_id, + ContextWQ *op_work_queue, + Context *on_finish) + : m_image_id(image_id), m_image_client_id(client_id), + m_op_work_queue(op_work_queue), m_on_finish(on_finish) { + m_ioctx.dup(ioctx); + m_cct = reinterpret_cast(m_ioctx.cct()); +} + +template +void RemoveRequest::send() { + ldout(m_cct, 20) << this << " " << __func__ << dendl; + + stat_journal(); +} + +template +void RemoveRequest::stat_journal() { + ldout(m_cct, 20) << this << " " << __func__ << dendl; + + ImageCtx::get_timer_instance(m_cct, &m_timer, &m_timer_lock); + m_journaler = new Journaler(m_op_work_queue, m_timer, m_timer_lock, + m_ioctx, m_image_id, m_image_client_id, {}); + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_journaler->exists(ctx); +} + +template +Context *RemoveRequest::handle_stat_journal(int *result) { + ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "failed to stat journal header: " << cpp_strerror(*result) << dendl; + shut_down_journaler(*result); + return nullptr; + } + + if (*result == -ENOENT) { + shut_down_journaler(0); + return nullptr; + } + + init_journaler(); + return nullptr; +} + +template +void RemoveRequest::init_journaler() { + ldout(m_cct, 20) << this << " " << __func__ << dendl; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_journaler->init(ctx); +} + +template +Context *RemoveRequest::handle_init_journaler(int *result) { + ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl; + + if ((*result < 0) && (*result != -ENOENT)) { + lderr(m_cct) << "failed to init journaler: " << cpp_strerror(*result) << dendl; + shut_down_journaler(*result); + return nullptr; + } + + remove_journal(); + return nullptr; +} + +template +void RemoveRequest::remove_journal() { + ldout(m_cct, 20) << this << " " << __func__ << dendl; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_journaler->remove(true, ctx); +} + +template +Context *RemoveRequest::handle_remove_journal(int *result) { + ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "failed to remove journal: " << cpp_strerror(*result) << dendl; + } + + shut_down_journaler(*result); + return nullptr; +} + +template +void RemoveRequest::shut_down_journaler(int r) { + ldout(m_cct, 20) << this << " " << __func__ << dendl; + + m_r_saved = r; + + using klass = RemoveRequest; + Context *ctx = create_context_callback(this); + + m_journaler->shut_down(ctx); +} + +template +Context *RemoveRequest::handle_journaler_shutdown(int *result) { + ldout(m_cct, 20) << __func__ << ": r=" << *result << dendl; + + if (*result < 0) { + lderr(m_cct) << "failed to shut down journaler: " << cpp_strerror(*result) << dendl; + } + + delete m_journaler; + + if (m_r_saved == 0) { + ldout(m_cct, 20) << "done." << dendl; + } + + m_on_finish->complete(m_r_saved); + delete this; + + return nullptr; +} + +} // namespace journal +} // namespace librbd + +template class librbd::journal::RemoveRequest; diff --git a/src/librbd/journal/RemoveRequest.h b/src/librbd/journal/RemoveRequest.h new file mode 100644 index 0000000000000..e710a131d753e --- /dev/null +++ b/src/librbd/journal/RemoveRequest.h @@ -0,0 +1,82 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_JOURNAL_REMOVE_REQUEST_H +#define CEPH_LIBRBD_JOURNAL_REMOVE_REQUEST_H + +#include "include/int_types.h" +#include "include/buffer.h" +#include "include/rados/librados.hpp" +#include "include/rbd/librbd.hpp" +#include "common/Mutex.h" +#include "librbd/ImageCtx.h" +#include "journal/Journaler.h" +#include "librbd/journal/TypeTraits.h" + +using librados::IoCtx; +using journal::Journaler; + +class Context; +class ContextWQ; +class SafeTimer; + +namespace journal { + class Journaler; +} + +namespace librbd { + +class ImageCtx; + +namespace journal { + +template +class RemoveRequest { +public: + static RemoveRequest *create(IoCtx &ioctx, const std::string &image_id, + const std::string &client_id, + ContextWQ *op_work_queue, Context *on_finish) { + return new RemoveRequest(ioctx, image_id, client_id, + op_work_queue, on_finish); + } + + void send(); + +private: + typedef typename TypeTraits::Journaler Journaler; + + RemoveRequest(IoCtx &ioctx, const std::string &image_id, + const std::string &client_id, + ContextWQ *op_work_queue, Context *on_finish); + + IoCtx m_ioctx; + std::string m_image_id; + std::string m_image_client_id; + ContextWQ *m_op_work_queue; + Context *m_on_finish; + + CephContext *m_cct; + Journaler *m_journaler; + SafeTimer *m_timer; + Mutex *m_timer_lock; + int m_r_saved; + + void stat_journal(); + Context *handle_stat_journal(int *result); + + void init_journaler(); + Context *handle_init_journaler(int *result); + + void remove_journal(); + Context *handle_remove_journal(int *result); + + void shut_down_journaler(int r); + Context *handle_journaler_shutdown(int *result); +}; + +} // namespace journal +} // namespace librbd + +extern template class librbd::journal::RemoveRequest; + +#endif // CEPH_LIBRBD_JOURNAL_REMOVE_REQUEST_H diff --git a/src/test/librbd/test_mock_Journal.cc b/src/test/librbd/test_mock_Journal.cc index 3785f2ce783e2..1a8f5817519bd 100644 --- a/src/test/librbd/test_mock_Journal.cc +++ b/src/test/librbd/test_mock_Journal.cc @@ -15,6 +15,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "librbd/journal/Replay.h" +#include "librbd/journal/RemoveRequest.h" #include "librbd/journal/Types.h" #include "librbd/journal/TypeTraits.h" #include "gmock/gmock.h" @@ -89,6 +90,36 @@ public: MockReplay *MockReplay::s_instance = nullptr; +struct MockRemove { + static MockRemove *s_instance; + static MockRemove &get_instance() { + assert(s_instance != nullptr); + return *s_instance; + } + + MockRemove() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +template <> +class RemoveRequest { +public: + static RemoveRequest *create(IoCtx &ioctx, const std::string &imageid, + const std::string &client_id, + ContextWQ *op_work_queue, Context *on_finish) { + return new RemoveRequest(); + } + + void send() { + MockRemove::get_instance().send(); + } +}; + +MockRemove *MockRemove::s_instance = nullptr; + } // namespace journal } // namespace librbd -- 2.39.5