From: Jason Dillaman Date: Fri, 20 Dec 2019 15:43:48 +0000 (-0500) Subject: rbd-mirror: extract journal local image creation to new state machine X-Git-Tag: v15.1.0~352^2~8 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=638be259f270b2b4c77fd9e645118eba06791e87;p=ceph.git rbd-mirror: extract journal local image creation to new state machine This state machine simplifies the existing bootstrap state machine steps in that it will always unregister as a first step (might not be registered). It also take advantage of the previous fix for REPLAYING vs SYNCING state so that it always uses an initial SYNCING state. Signed-off-by: Jason Dillaman --- diff --git a/src/test/rbd_mirror/CMakeLists.txt b/src/test/rbd_mirror/CMakeLists.txt index b70bb20ac43e..32d6c16f30d1 100644 --- a/src/test/rbd_mirror/CMakeLists.txt +++ b/src/test/rbd_mirror/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(unittest_rbd_mirror image_replayer/test_mock_GetMirrorImageIdRequest.cc image_replayer/test_mock_PrepareLocalImageRequest.cc image_replayer/test_mock_PrepareRemoteImageRequest.cc + image_replayer/journal/test_mock_CreateLocalImageRequest.cc image_replayer/journal/test_mock_EventPreprocessor.cc image_replayer/journal/test_mock_Replayer.cc image_sync/test_mock_SyncPointCreateRequest.cc diff --git a/src/test/rbd_mirror/image_replayer/journal/test_mock_CreateLocalImageRequest.cc b/src/test/rbd_mirror/image_replayer/journal/test_mock_CreateLocalImageRequest.cc new file mode 100644 index 000000000000..5c310cd5c01f --- /dev/null +++ b/src/test/rbd_mirror/image_replayer/journal/test_mock_CreateLocalImageRequest.cc @@ -0,0 +1,362 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/rbd_mirror/test_mock_fixture.h" +#include "librbd/journal/Types.h" +#include "librbd/journal/TypeTraits.h" +#include "tools/rbd_mirror/Threads.h" +#include "tools/rbd_mirror/image_replayer/CreateImageRequest.h" +#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h" +#include "test/journal/mock/MockJournaler.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "test/rbd_mirror/mock/MockContextWQ.h" +#include "test/rbd_mirror/mock/MockSafeTimer.h" +#include + +namespace librbd { + +namespace { + +struct MockTestImageCtx : public librbd::MockImageCtx { + explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) + : librbd::MockImageCtx(image_ctx) { + } +}; + +} // anonymous namespace + +namespace journal { + +template <> +struct TypeTraits { + typedef ::journal::MockJournaler Journaler; +}; + +} // namespace journal + +namespace util { + +static std::string s_image_id; + +template <> +std::string generate_image_id(librados::IoCtx&) { + ceph_assert(!s_image_id.empty()); + return s_image_id; +} + +} // namespace util +} // namespace librbd + +namespace rbd { +namespace mirror { + +template <> +struct Threads { +}; + +namespace image_replayer { + +template<> +struct CreateImageRequest { + static CreateImageRequest* s_instance; + Context *on_finish = nullptr; + + static CreateImageRequest* create(Threads* threads, + librados::IoCtx &local_io_ctx, + const std::string &global_image_id, + const std::string &remote_mirror_uuid, + const std::string &local_image_name, + const std::string &local_image_id, + librbd::MockTestImageCtx *remote_image_ctx, + Context *on_finish) { + ceph_assert(s_instance != nullptr); + s_instance->on_finish = on_finish; + s_instance->construct(local_image_id); + return s_instance; + } + + CreateImageRequest() { + ceph_assert(s_instance == nullptr); + s_instance = this; + } + ~CreateImageRequest() { + s_instance = nullptr; + } + + MOCK_METHOD1(construct, void(const std::string&)); + MOCK_METHOD0(send, void()); +}; + +CreateImageRequest* + CreateImageRequest::s_instance = nullptr; + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +#include "tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.cc" + +using ::testing::_; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::WithArg; + +namespace rbd { +namespace mirror { +namespace image_replayer { +namespace journal { + +class TestMockImageReplayerJournalCreateLocalImageRequest : public TestMockFixture { +public: + typedef CreateLocalImageRequest MockCreateLocalImageRequest; + typedef Threads MockThreads; + typedef CreateImageRequest MockCreateImageRequest; + + void SetUp() override { + TestMockFixture::SetUp(); + + librbd::RBD rbd; + ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); + ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); + m_mock_remote_image_ctx = new librbd::MockTestImageCtx(*m_remote_image_ctx); + } + + void TearDown() override { + delete m_mock_remote_image_ctx; + TestMockFixture::TearDown(); + } + + void expect_journaler_register_client( + ::journal::MockJournaler& mock_journaler, + const librbd::journal::ClientData& client_data, int r) { + bufferlist bl; + encode(client_data, bl); + + EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _)) + .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + }))); + } + + void expect_journaler_unregister_client( + ::journal::MockJournaler& mock_journaler, int r) { + EXPECT_CALL(mock_journaler, unregister_client(_)) + .WillOnce(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + })); + } + + void expect_journaler_update_client( + ::journal::MockJournaler& mock_journaler, + const librbd::journal::ClientData& client_data, int r) { + bufferlist bl; + encode(client_data, bl); + + EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _)) + .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) { + m_threads->work_queue->queue(on_finish, r); + }))); + } + void expect_create_image(MockCreateImageRequest& mock_create_image_request, + const std::string& image_id, int r) { + EXPECT_CALL(mock_create_image_request, construct(image_id)); + EXPECT_CALL(mock_create_image_request, send()) + .WillOnce(Invoke([this, &mock_create_image_request, r]() { + m_threads->work_queue->queue(mock_create_image_request.on_finish, r); + })); + } + + MockCreateLocalImageRequest* create_request( + MockThreads& mock_threads, + ::journal::MockJournaler& mock_journaler, + const std::string& global_image_id, + const std::string& remote_mirror_uuid, + librbd::journal::MirrorPeerClientMeta* mirror_peer_client_meta, + std::string* local_image_id, Context* on_finish) { + return new MockCreateLocalImageRequest( + &mock_threads, m_local_io_ctx, m_mock_remote_image_ctx, + &mock_journaler, global_image_id, remote_mirror_uuid, + mirror_peer_client_meta, nullptr, local_image_id, on_finish); + } + + librbd::ImageCtx *m_remote_image_ctx; + librbd::MockTestImageCtx *m_mock_remote_image_ctx = nullptr; +}; + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, Success) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, 0); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + librbd::util::s_image_id = "local image id"; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data; + client_data.client_meta = mirror_peer_client_meta; + expect_journaler_register_client(mock_journaler, client_data, 0); + + // create the missing local image + MockCreateImageRequest mock_create_image_request; + expect_create_image(mock_create_image_request, "local image id", 0); + + C_SaferCond ctx; + MockThreads mock_threads; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); + + ASSERT_EQ("local image id", local_image_id); + ASSERT_EQ("local image id", mirror_peer_client_meta.image_id); + ASSERT_EQ(librbd::journal::MIRROR_PEER_STATE_SYNCING, + mirror_peer_client_meta.state); +} + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, UnregisterError) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, -EINVAL); + + C_SaferCond ctx; + MockThreads mock_threads; + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, RegisterError) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, 0); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + librbd::util::s_image_id = "local image id"; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data; + client_data.client_meta = mirror_peer_client_meta; + expect_journaler_register_client(mock_journaler, client_data, -EINVAL); + + C_SaferCond ctx; + MockThreads mock_threads; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, CreateImageError) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, 0); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + librbd::util::s_image_id = "local image id"; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data; + client_data.client_meta = mirror_peer_client_meta; + expect_journaler_register_client(mock_journaler, client_data, 0); + + // create the missing local image + MockCreateImageRequest mock_create_image_request; + expect_create_image(mock_create_image_request, "local image id", -EINVAL); + + C_SaferCond ctx; + MockThreads mock_threads; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, CreateImageDuplicate) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, 0); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + librbd::util::s_image_id = "local image id"; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data; + client_data.client_meta = mirror_peer_client_meta; + expect_journaler_register_client(mock_journaler, client_data, 0); + + // create the missing local image + MockCreateImageRequest mock_create_image_request; + expect_create_image(mock_create_image_request, "local image id", -EBADF); + + // update image id + expect_journaler_update_client(mock_journaler, client_data, 0); + + // re-create the local image + expect_create_image(mock_create_image_request, "local image id", 0); + + C_SaferCond ctx; + MockThreads mock_threads; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockImageReplayerJournalCreateLocalImageRequest, UpdateClientImageError) { + InSequence seq; + + // re-register the client + ::journal::MockJournaler mock_journaler; + expect_journaler_unregister_client(mock_journaler, 0); + + librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; + librbd::util::s_image_id = "local image id"; + mirror_peer_client_meta.image_id = "local image id"; + mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + librbd::journal::ClientData client_data; + client_data.client_meta = mirror_peer_client_meta; + expect_journaler_register_client(mock_journaler, client_data, 0); + + // create the missing local image + MockCreateImageRequest mock_create_image_request; + expect_create_image(mock_create_image_request, "local image id", -EBADF); + + // update image id + expect_journaler_update_client(mock_journaler, client_data, -EINVAL); + + C_SaferCond ctx; + MockThreads mock_threads; + std::string local_image_id; + auto request = create_request( + mock_threads, mock_journaler, "global image id", "remote mirror uuid", + &mirror_peer_client_meta, &local_image_id, &ctx); + request->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +} // namespace journal +} // namespace image_replayer +} // namespace mirror +} // namespace rbd diff --git a/src/tools/rbd_mirror/CMakeLists.txt b/src/tools/rbd_mirror/CMakeLists.txt index c642ae6afc4c..26e77eaa7a6a 100644 --- a/src/tools/rbd_mirror/CMakeLists.txt +++ b/src/tools/rbd_mirror/CMakeLists.txt @@ -41,6 +41,7 @@ set(rbd_mirror_internal image_replayer/PrepareLocalImageRequest.cc image_replayer/PrepareRemoteImageRequest.cc image_replayer/Utils.cc + image_replayer/journal/CreateLocalImageRequest.cc image_replayer/journal/EventPreprocessor.cc image_replayer/journal/Replayer.cc image_replayer/journal/ReplayStatusFormatter.cc diff --git a/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.cc b/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.cc new file mode 100644 index 000000000000..1f46c6331e28 --- /dev/null +++ b/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.cc @@ -0,0 +1,194 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "CreateLocalImageRequest.h" +#include "include/rados/librados.hpp" +#include "common/debug.h" +#include "common/dout.h" +#include "common/errno.h" +#include "journal/Journaler.h" +#include "librbd/ImageCtx.h" +#include "librbd/Utils.h" +#include "tools/rbd_mirror/ProgressContext.h" +#include "tools/rbd_mirror/image_replayer/CreateImageRequest.h" + +#define dout_context g_ceph_context +#define dout_subsys ceph_subsys_rbd_mirror +#undef dout_prefix +#define dout_prefix *_dout << "rbd::mirror::image_replayer::journal::" \ + << "CreateLocalImageRequest: " << this << " " \ + << __func__ << ": " + +namespace rbd { +namespace mirror { +namespace image_replayer { +namespace journal { + +using librbd::util::create_context_callback; + +template +void CreateLocalImageRequest::send() { + *m_local_image_id = ""; + unregister_client(); +} + +template +void CreateLocalImageRequest::unregister_client() { + dout(10) << dendl; + update_progress("UNREGISTER_CLIENT"); + + auto ctx = create_context_callback< + CreateLocalImageRequest, + &CreateLocalImageRequest::handle_unregister_client>(this); + m_remote_journaler->unregister_client(ctx); +} + +template +void CreateLocalImageRequest::handle_unregister_client(int r) { + dout(10) << "r=" << r << dendl; + if (r < 0 && r != -ENOENT) { + derr << "failed to unregister with remote journal: " << cpp_strerror(r) + << dendl; + finish(r); + return; + } + + *m_client_meta = librbd::journal::MirrorPeerClientMeta{""}; + register_client(); +} + +template +void CreateLocalImageRequest::register_client() { + ceph_assert(m_local_image_id->empty()); + *m_local_image_id = librbd::util::generate_image_id(m_local_io_ctx); + dout(10) << "local_image_id=" << *m_local_image_id << dendl; + update_progress("REGISTER_CLIENT"); + + librbd::journal::MirrorPeerClientMeta client_meta{*m_local_image_id}; + client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + + librbd::journal::ClientData client_data{client_meta}; + bufferlist client_data_bl; + encode(client_data, client_data_bl); + + auto ctx = create_context_callback< + CreateLocalImageRequest, + &CreateLocalImageRequest::handle_register_client>(this); + m_remote_journaler->register_client(client_data_bl, ctx); +} + +template +void CreateLocalImageRequest::handle_register_client(int r) { + dout(10) << "r=" << r << dendl; + + if (r < 0) { + derr << "failed to register with remote journal: " << cpp_strerror(r) + << dendl; + finish(r); + return; + } + + *m_client_meta = librbd::journal::MirrorPeerClientMeta{*m_local_image_id}; + m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + + create_local_image(); +} + +template +void CreateLocalImageRequest::create_local_image() { + dout(10) << "local_image_id=" << *m_local_image_id << dendl; + update_progress("CREATE_LOCAL_IMAGE"); + + m_remote_image_ctx->image_lock.lock_shared(); + std::string image_name = m_remote_image_ctx->name; + m_remote_image_ctx->image_lock.unlock_shared(); + + auto ctx = create_context_callback< + CreateLocalImageRequest, + &CreateLocalImageRequest::handle_create_local_image>(this); + auto request = CreateImageRequest::create( + m_threads, m_local_io_ctx, m_global_image_id, m_remote_mirror_uuid, + image_name, *m_local_image_id, m_remote_image_ctx, ctx); + request->send(); +} +template +void CreateLocalImageRequest::handle_create_local_image(int r) { + dout(10) << "r=" << r << dendl; + + if (r == -EBADF) { + dout(5) << "image id " << *m_local_image_id << " already in-use" << dendl; + *m_local_image_id = ""; + update_client_image(); + return; + } else if (r < 0) { + if (r == -ENOENT) { + dout(10) << "parent image does not exist" << dendl; + } else { + derr << "failed to create local image: " << cpp_strerror(r) << dendl; + } + finish(r); + return; + } + + finish(0); +} + +template +void CreateLocalImageRequest::update_client_image() { + ceph_assert(m_local_image_id->empty()); + *m_local_image_id = librbd::util::generate_image_id(m_local_io_ctx); + + dout(10) << "local_image_id=" << *m_local_image_id << dendl; + update_progress("UPDATE_CLIENT_IMAGE"); + + librbd::journal::MirrorPeerClientMeta client_meta{*m_local_image_id}; + client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + + librbd::journal::ClientData client_data(client_meta); + bufferlist data_bl; + encode(client_data, data_bl); + + auto ctx = create_context_callback< + CreateLocalImageRequest, + &CreateLocalImageRequest::handle_update_client_image>(this); + m_remote_journaler->update_client(data_bl, ctx); +} + +template +void CreateLocalImageRequest::handle_update_client_image(int r) { + dout(10) << "r=" << r << dendl; + + if (r < 0) { + derr << "failed to update client: " << cpp_strerror(r) << dendl; + finish(r); + return; + } + + *m_client_meta = librbd::journal::MirrorPeerClientMeta{*m_local_image_id}; + m_client_meta->state = librbd::journal::MIRROR_PEER_STATE_SYNCING; + create_local_image(); +} + +template +void CreateLocalImageRequest::finish(int r) { + dout(10) << "r=" << r << dendl; + + m_on_finish->complete(r); + delete this; +} + +template +void CreateLocalImageRequest::update_progress( + const std::string& description) { + dout(15) << description << dendl; + if (m_progress_ctx != nullptr) { + m_progress_ctx->update_progress(description); + } +} + +} // namespace journal +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +template class rbd::mirror::image_replayer::journal::CreateLocalImageRequest; diff --git a/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h b/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h new file mode 100644 index 000000000000..cd2c3abca106 --- /dev/null +++ b/src/tools/rbd_mirror/image_replayer/journal/CreateLocalImageRequest.h @@ -0,0 +1,122 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef RBD_MIRROR_IMAGE_REPLAYER_JOURNAL_CREATE_LOCAL_IMAGE_REQUEST_H +#define RBD_MIRROR_IMAGE_REPLAYER_JOURNAL_CREATE_LOCAL_IMAGE_REQUEST_H + +#include "include/rados/librados_fwd.hpp" +#include "librbd/journal/Types.h" +#include "librbd/journal/TypeTraits.h" +#include + +struct Context; +namespace librbd { class ImageCtx; } + +namespace rbd { +namespace mirror { + +class ProgressContext; +template struct Threads; + +namespace image_replayer { +namespace journal { + +template +class CreateLocalImageRequest { +public: + typedef librbd::journal::MirrorPeerClientMeta MirrorPeerClientMeta; + typedef librbd::journal::TypeTraits TypeTraits; + typedef typename TypeTraits::Journaler Journaler; + typedef rbd::mirror::ProgressContext ProgressContext; + + static CreateLocalImageRequest* create( + Threads* threads, librados::IoCtx& local_io_ctx, + ImageCtxT* remote_image_ctx, Journaler* remote_journaler, + const std::string& global_image_id, + const std::string& remote_mirror_uuid, + MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx, + std::string* local_image_id, Context* on_finish) { + return new CreateLocalImageRequest(threads, local_io_ctx, remote_image_ctx, + remote_journaler, global_image_id, + remote_mirror_uuid, client_meta, + progress_ctx, local_image_id, on_finish); + } + + CreateLocalImageRequest( + Threads* threads, librados::IoCtx& local_io_ctx, + ImageCtxT* remote_image_ctx, Journaler* remote_journaler, + const std::string& global_image_id, + const std::string& remote_mirror_uuid, + MirrorPeerClientMeta* client_meta, ProgressContext* progress_ctx, + std::string* local_image_id, Context* on_finish) + : m_threads(threads), m_local_io_ctx(local_io_ctx), + m_remote_image_ctx(remote_image_ctx), + m_remote_journaler(remote_journaler), + m_global_image_id(global_image_id), + m_remote_mirror_uuid(remote_mirror_uuid), m_client_meta(client_meta), + m_progress_ctx(progress_ctx), m_local_image_id(local_image_id), + m_on_finish(on_finish) { + } + + void send(); + +private: + /** + * @verbatim + * + * + * | + * v + * UNREGISTER_CLIENT + * | + * v + * REGISTER_CLIENT + * | + * | . . . . . . . . . UPDATE_CLIENT_IMAGE + * | . ^ + * v v (id exists) * + * CREATE_LOCAL_IMAGE * * * * * * * * * + * | + * v + * + * + * @endverbatim + */ + + Threads* m_threads; + librados::IoCtx& m_local_io_ctx; + ImageCtxT* m_remote_image_ctx; + Journaler* m_remote_journaler; + std::string m_global_image_id; + std::string m_remote_mirror_uuid; + MirrorPeerClientMeta* m_client_meta; + ProgressContext* m_progress_ctx; + std::string* m_local_image_id; + Context* m_on_finish; + + void unregister_client(); + void handle_unregister_client(int r); + + void register_client(); + void handle_register_client(int r); + + void create_local_image(); + void handle_create_local_image(int r); + + void update_client_image(); + void handle_update_client_image(int r); + + void finish(int r); + + void update_progress(const std::string& description); + +}; + +} // namespace journal +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +extern template class rbd::mirror::image_replayer::journal::CreateLocalImageRequest; + +#endif // RBD_MIRROR_IMAGE_REPLAYER_JOURNAL_CREATE_LOCAL_IMAGE_REQUEST_H