From: Jason Dillaman Date: Wed, 19 Jul 2017 14:14:14 +0000 (-0400) Subject: rbd-mirror: helper state machine for retrieving image id from global id X-Git-Tag: v13.0.0~218^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=697c1d7a4a22a600e538a5b68f4de594240b2a08;p=ceph.git rbd-mirror: helper state machine for retrieving image id from global id Signed-off-by: Jason Dillaman --- diff --git a/src/test/rbd_mirror/CMakeLists.txt b/src/test/rbd_mirror/CMakeLists.txt index ba5e13f3e1f7..eb7b7674d60f 100644 --- a/src/test/rbd_mirror/CMakeLists.txt +++ b/src/test/rbd_mirror/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(unittest_rbd_mirror image_replayer/test_mock_BootstrapRequest.cc image_replayer/test_mock_CreateImageRequest.cc image_replayer/test_mock_EventPreprocessor.cc + image_replayer/test_mock_GetMirrorImageIdRequest.cc image_replayer/test_mock_PrepareLocalImageRequest.cc image_sync/test_mock_ImageCopyRequest.cc image_sync/test_mock_ObjectCopyRequest.cc diff --git a/src/test/rbd_mirror/image_replayer/test_mock_GetMirrorImageIdRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_GetMirrorImageIdRequest.cc new file mode 100644 index 000000000000..eaa9882de843 --- /dev/null +++ b/src/test/rbd_mirror/image_replayer/test_mock_GetMirrorImageIdRequest.cc @@ -0,0 +1,106 @@ +// -*- 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 "cls/rbd/cls_rbd_types.h" +#include "librbd/journal/TypeTraits.h" +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" +#include "test/journal/mock/MockJournaler.h" +#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "test/librbd/mock/MockJournal.h" + +namespace librbd { + +namespace { + +struct MockTestImageCtx : public librbd::MockImageCtx { + MockTestImageCtx(librbd::ImageCtx &image_ctx) + : librbd::MockImageCtx(image_ctx) { + } +}; + +} // anonymous namespace +} // namespace librbd + +// template definitions +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.cc" + +namespace rbd { +namespace mirror { +namespace image_replayer { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::WithArg; +using ::testing::WithArgs; + +class TestMockImageReplayerGetMirrorImageIdRequest : public TestMockFixture { +public: + typedef GetMirrorImageIdRequest MockGetMirrorImageIdRequest; + + void expect_mirror_image_get_image_id(librados::IoCtx &io_ctx, + const std::string &image_id, int r) { + bufferlist bl; + ::encode(image_id, bl); + + EXPECT_CALL(get_mock_io_ctx(io_ctx), + exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get_image_id"), _, _, _)) + .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) { + *out_bl = bl; + })), + Return(r))); + } + +}; + +TEST_F(TestMockImageReplayerGetMirrorImageIdRequest, Success) { + InSequence seq; + expect_mirror_image_get_image_id(m_local_io_ctx, "image id", 0); + + std::string image_id; + C_SaferCond ctx; + auto req = MockGetMirrorImageIdRequest::create(m_local_io_ctx, + "global image id", + &image_id, &ctx); + req->send(); + + ASSERT_EQ(0, ctx.wait()); + ASSERT_EQ(std::string("image id"), image_id); +} + +TEST_F(TestMockImageReplayerGetMirrorImageIdRequest, MirrorImageIdDNE) { + InSequence seq; + expect_mirror_image_get_image_id(m_local_io_ctx, "", -ENOENT); + + std::string image_id; + C_SaferCond ctx; + auto req = MockGetMirrorImageIdRequest::create(m_local_io_ctx, + "global image id", + &image_id, &ctx); + req->send(); + + ASSERT_EQ(-ENOENT, ctx.wait()); +} + +TEST_F(TestMockImageReplayerGetMirrorImageIdRequest, MirrorImageIdError) { + InSequence seq; + expect_mirror_image_get_image_id(m_local_io_ctx, "", -EINVAL); + + std::string image_id; + C_SaferCond ctx; + auto req = MockGetMirrorImageIdRequest::create(m_local_io_ctx, + "global image id", + &image_id, &ctx); + req->send(); + + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd diff --git a/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc b/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc index b79d4de9e18d..279debead9bf 100644 --- a/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc +++ b/src/test/rbd_mirror/image_replayer/test_mock_PrepareLocalImageRequest.cc @@ -4,6 +4,7 @@ #include "test/rbd_mirror/test_mock_fixture.h" #include "cls/rbd/cls_rbd_types.h" #include "librbd/journal/TypeTraits.h" +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h" #include "test/journal/mock/MockJournaler.h" #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" @@ -23,6 +24,39 @@ struct MockTestImageCtx : public librbd::MockImageCtx { } // anonymous namespace } // namespace librbd +namespace rbd { +namespace mirror { +namespace image_replayer { + +template <> +struct GetMirrorImageIdRequest { + static GetMirrorImageIdRequest* s_instance; + std::string* image_id = nullptr; + Context* on_finish = nullptr; + + static GetMirrorImageIdRequest* create(librados::IoCtx& io_ctx, + const std::string& global_image_id, + std::string* image_id, + Context* on_finish) { + assert(s_instance != nullptr); + s_instance->image_id = image_id; + s_instance->on_finish = on_finish; + return s_instance; + } + + GetMirrorImageIdRequest() { + s_instance = this; + } + + MOCK_METHOD0(send, void()); +}; + +GetMirrorImageIdRequest* GetMirrorImageIdRequest::s_instance = nullptr; + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + // template definitions #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc" @@ -42,18 +76,15 @@ using ::testing::WithArgs; class TestMockImageReplayerPrepareLocalImageRequest : public TestMockFixture { public: typedef PrepareLocalImageRequest MockPrepareLocalImageRequest; - - void expect_mirror_image_get_image_id(librados::IoCtx &io_ctx, - const std::string &image_id, int r) { - bufferlist bl; - ::encode(image_id, bl); - - EXPECT_CALL(get_mock_io_ctx(io_ctx), - exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get_image_id"), _, _, _)) - .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) { - *out_bl = bl; - })), - Return(r))); + typedef GetMirrorImageIdRequest MockGetMirrorImageIdRequest; + + void expect_get_mirror_image_id(MockGetMirrorImageIdRequest& mock_get_mirror_image_id_request, + const std::string& image_id, int r) { + EXPECT_CALL(mock_get_mirror_image_id_request, send()) + .WillOnce(Invoke([&mock_get_mirror_image_id_request, image_id, r]() { + *mock_get_mirror_image_id_request.image_id = image_id; + mock_get_mirror_image_id_request.on_finish->complete(r); + })); } void expect_mirror_image_get(librados::IoCtx &io_ctx, @@ -88,7 +119,9 @@ public: TEST_F(TestMockImageReplayerPrepareLocalImageRequest, Success) { InSequence seq; - expect_mirror_image_get_image_id(m_local_io_ctx, "local image id", 0); + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "local image id", + 0); expect_mirror_image_get(m_local_io_ctx, cls::rbd::MIRROR_IMAGE_STATE_ENABLED, "global image id", 0); @@ -111,27 +144,10 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, Success) { ASSERT_EQ(std::string("remote mirror uuid"), tag_owner); } -TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageIdDNE) { - InSequence seq; - expect_mirror_image_get_image_id(m_local_io_ctx, "", -ENOENT); - - std::string local_image_id; - std::string tag_owner; - C_SaferCond ctx; - auto req = MockPrepareLocalImageRequest::create(m_local_io_ctx, - "global image id", - &local_image_id, - &tag_owner, - m_threads->work_queue, - &ctx); - req->send(); - - ASSERT_EQ(-ENOENT, ctx.wait()); -} - TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageIdError) { InSequence seq; - expect_mirror_image_get_image_id(m_local_io_ctx, "", -EINVAL); + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "", -EINVAL); std::string local_image_id; std::string tag_owner; @@ -149,7 +165,9 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageIdError) { TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageError) { InSequence seq; - expect_mirror_image_get_image_id(m_local_io_ctx, "local image id", 0); + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "local image id", + 0); expect_mirror_image_get(m_local_io_ctx, cls::rbd::MIRROR_IMAGE_STATE_DISABLED, "", -EINVAL); @@ -169,7 +187,9 @@ TEST_F(TestMockImageReplayerPrepareLocalImageRequest, MirrorImageError) { TEST_F(TestMockImageReplayerPrepareLocalImageRequest, TagOwnerError) { InSequence seq; - expect_mirror_image_get_image_id(m_local_io_ctx, "local image id", 0); + MockGetMirrorImageIdRequest mock_get_mirror_image_id_request; + expect_get_mirror_image_id(mock_get_mirror_image_id_request, "local image id", + 0); expect_mirror_image_get(m_local_io_ctx, cls::rbd::MIRROR_IMAGE_STATE_ENABLED, "global image id", 0); diff --git a/src/tools/rbd_mirror/CMakeLists.txt b/src/tools/rbd_mirror/CMakeLists.txt index 88ff456419c6..27b7e26431c6 100644 --- a/src/tools/rbd_mirror/CMakeLists.txt +++ b/src/tools/rbd_mirror/CMakeLists.txt @@ -23,6 +23,7 @@ set(rbd_mirror_internal image_replayer/CloseImageRequest.cc image_replayer/CreateImageRequest.cc image_replayer/EventPreprocessor.cc + image_replayer/GetMirrorImageIdRequest.cc image_replayer/IsPrimaryRequest.cc image_replayer/OpenImageRequest.cc image_replayer/OpenLocalImageRequest.cc diff --git a/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.cc b/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.cc new file mode 100644 index 000000000000..a6a72b473f36 --- /dev/null +++ b/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.cc @@ -0,0 +1,84 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" +#include "include/rados/librados.hpp" +#include "cls/rbd/cls_rbd_client.h" +#include "common/errno.h" +#include "librbd/ImageCtx.h" +#include "librbd/Utils.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::" \ + << "GetMirrorImageIdRequest: " << this << " " \ + << __func__ << ": " + +namespace rbd { +namespace mirror { +namespace image_replayer { + +using librbd::util::create_rados_callback; + +template +void GetMirrorImageIdRequest::send() { + dout(20) << dendl; + get_image_id(); +} + +template +void GetMirrorImageIdRequest::get_image_id() { + dout(20) << dendl; + + // attempt to cross-reference a image id by the global image id + librados::ObjectReadOperation op; + librbd::cls_client::mirror_image_get_image_id_start(&op, m_global_image_id); + + librados::AioCompletion *aio_comp = create_rados_callback< + GetMirrorImageIdRequest, + &GetMirrorImageIdRequest::handle_get_image_id>( + this); + int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl); + assert(r == 0); + aio_comp->release(); +} + +template +void GetMirrorImageIdRequest::handle_get_image_id(int r) { + if (r == 0) { + bufferlist::iterator iter = m_out_bl.begin(); + r = librbd::cls_client::mirror_image_get_image_id_finish( + &iter, m_image_id); + } + + dout(20) << "r=" << r << ", " + << "image_id=" << *m_image_id << dendl; + + if (r < 0) { + if (r == -ENOENT) { + dout(10) << "global image " << m_global_image_id << " not registered" + << dendl; + } else { + derr << "failed to retrieve image id: " << cpp_strerror(r) << dendl; + } + finish(r); + return; + } + + finish(0); +} + +template +void GetMirrorImageIdRequest::finish(int r) { + dout(20) << "r=" << r << dendl; + + m_on_finish->complete(r); + delete this; +} + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +template class rbd::mirror::image_replayer::GetMirrorImageIdRequest; diff --git a/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h b/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h new file mode 100644 index 000000000000..9bdb7780ffba --- /dev/null +++ b/src/tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h @@ -0,0 +1,75 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef RBD_MIRROR_IMAGE_REPLAYER_GET_MIRROR_IMAGE_ID_REQUEST_H +#define RBD_MIRROR_IMAGE_REPLAYER_GET_MIRROR_IMAGE_ID_REQUEST_H + +#include "include/buffer.h" +#include + +namespace librados { struct IoCtx; } +namespace librbd { struct ImageCtx; } + +struct Context; + +namespace rbd { +namespace mirror { +namespace image_replayer { + +template +class GetMirrorImageIdRequest { +public: + static GetMirrorImageIdRequest *create(librados::IoCtx &io_ctx, + const std::string &global_image_id, + std::string *image_id, + Context *on_finish) { + return new GetMirrorImageIdRequest(io_ctx, global_image_id, image_id, + on_finish); + } + + GetMirrorImageIdRequest(librados::IoCtx &io_ctx, + const std::string &global_image_id, + std::string *image_id, + Context *on_finish) + : m_io_ctx(io_ctx), m_global_image_id(global_image_id), + m_image_id(image_id), m_on_finish(on_finish) { + } + + void send(); + +private: + /** + * @verbatim + * + * + * | + * v + * GET_IMAGE_ID + * | + * v + * + + * @endverbatim + */ + + librados::IoCtx &m_io_ctx; + std::string m_global_image_id; + std::string *m_image_id; + Context *m_on_finish; + + bufferlist m_out_bl; + + void get_image_id(); + void handle_get_image_id(int r); + + void finish(int r); + +}; + +} // namespace image_replayer +} // namespace mirror +} // namespace rbd + +extern template class rbd::mirror::image_replayer::GetMirrorImageIdRequest; + +#endif // RBD_MIRROR_IMAGE_REPLAYER_GET_MIRROR_IMAGE_ID_REQUEST_H diff --git a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc index b26ac05e9429..4009dc10d4af 100644 --- a/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc +++ b/src/tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.cc @@ -9,6 +9,7 @@ #include "librbd/Journal.h" #include "librbd/Utils.h" #include "tools/rbd_mirror/Threads.h" +#include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h" #include #define dout_context g_ceph_context @@ -35,38 +36,20 @@ template void PrepareLocalImageRequest::get_local_image_id() { dout(20) << dendl; - // attempt to cross-reference a local image by the global image id - librados::ObjectReadOperation op; - librbd::cls_client::mirror_image_get_image_id_start(&op, m_global_image_id); - - m_out_bl.clear(); - librados::AioCompletion *aio_comp = create_rados_callback< + Context *ctx = create_context_callback< PrepareLocalImageRequest, - &PrepareLocalImageRequest::handle_get_local_image_id>( - this); - int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl); - assert(r == 0); - aio_comp->release(); + &PrepareLocalImageRequest::handle_get_local_image_id>(this); + auto req = GetMirrorImageIdRequest::create(m_io_ctx, m_global_image_id, + m_local_image_id, ctx); + req->send(); } template void PrepareLocalImageRequest::handle_get_local_image_id(int r) { - if (r == 0) { - bufferlist::iterator iter = m_out_bl.begin(); - r = librbd::cls_client::mirror_image_get_image_id_finish( - &iter, m_local_image_id); - } - dout(20) << "r=" << r << ", " << "local_image_id=" << *m_local_image_id << dendl; if (r < 0) { - if (r == -ENOENT) { - dout(10) << "image not registered locally" << dendl; - } else { - derr << "failed to retrieve local image id: " << cpp_strerror(r) - << dendl; - } finish(r); return; }