From 3a5b491ec61134dc2e18cbe4e27a54e64b17f7d2 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 20 Jun 2016 11:41:31 -0400 Subject: [PATCH] rbd-mirror: keep events from different epochs independent Fixes: http://tracker.ceph.com/issues/16362 Signed-off-by: Jason Dillaman --- src/tools/rbd_mirror/ImageReplayer.cc | 35 +++++++++++++++++++++++++-- src/tools/rbd_mirror/ImageReplayer.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/tools/rbd_mirror/ImageReplayer.cc b/src/tools/rbd_mirror/ImageReplayer.cc index 07790597358..89aef4748ce 100644 --- a/src/tools/rbd_mirror/ImageReplayer.cc +++ b/src/tools/rbd_mirror/ImageReplayer.cc @@ -692,7 +692,7 @@ void ImageReplayer::flush(Context *on_finish) { Mutex::Locker locker(m_lock); - if (m_state == STATE_REPLAYING || m_state == STATE_REPLAYING) { + if (m_state == STATE_REPLAYING) { Context *ctx = new FunctionContext( [on_finish](int r) { if (on_finish != nullptr) { @@ -816,19 +816,47 @@ template void ImageReplayer::replay_flush() { dout(20) << dendl; + { + Mutex::Locker locker(m_lock); + m_state = STATE_REPLAY_FLUSHING; + } + + // shut down the replay to flush all IO and ops and create a new + // replayer to handle the new tag epoch Context *ctx = create_context_callback< ImageReplayer, &ImageReplayer::handle_replay_flush>(this); - flush(ctx); + ctx = new FunctionContext([this, ctx](int r) { + m_local_image_ctx->journal->stop_external_replay(); + m_local_replay = nullptr; + + if (r < 0) { + ctx->complete(r); + return; + } + + Context *stop_ctx = create_context_callback< + ImageReplayer, &ImageReplayer::handle_stop_replay_request>(this); + m_local_journal->start_external_replay(&m_local_replay, ctx, stop_ctx); + }); + m_local_replay->shut_down(true, ctx); } template void ImageReplayer::handle_replay_flush(int r) { dout(20) << "r=" << r << dendl; + { + Mutex::Locker locker(m_lock); + assert(m_state == STATE_REPLAY_FLUSHING); + m_state = STATE_REPLAYING; + } + if (r < 0) { derr << "replay flush encountered an error: " << cpp_strerror(r) << dendl; handle_replay_complete(r, "replay flush encountered an error"); return; + } else if (on_replay_interrupted()) { + return; } get_remote_tag(); @@ -1054,6 +1082,7 @@ void ImageReplayer::send_mirror_status_update(const OptionalState &opt_state) } break; case STATE_REPLAYING: + case STATE_REPLAY_FLUSHING: status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING; { Context *on_req_finish = new FunctionContext( @@ -1295,6 +1324,8 @@ std::string ImageReplayer::to_string(const State state) { return "Starting"; case ImageReplayer::STATE_REPLAYING: return "Replaying"; + case ImageReplayer::STATE_REPLAY_FLUSHING: + return "ReplayFlushing"; case ImageReplayer::STATE_STOPPING: return "Stopping"; case ImageReplayer::STATE_STOPPED: diff --git a/src/tools/rbd_mirror/ImageReplayer.h b/src/tools/rbd_mirror/ImageReplayer.h index a434e5e54e8..df848884544 100644 --- a/src/tools/rbd_mirror/ImageReplayer.h +++ b/src/tools/rbd_mirror/ImageReplayer.h @@ -58,6 +58,7 @@ public: STATE_UNKNOWN, STATE_STARTING, STATE_REPLAYING, + STATE_REPLAY_FLUSHING, STATE_STOPPING, STATE_STOPPED, }; -- 2.39.5