// template definitions
#include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
-template class rbd::mirror::image_replayer::BootstrapRequest<librbd::MockTestImageCtx>;
namespace rbd {
namespace mirror {
void get() {
}
+ inline bool is_syncing() const {
+ return false;
+ }
+
MOCK_METHOD0(send, void());
MOCK_METHOD0(cancel, void());
};
C_SaferCond start_ctx;
m_image_replayer->start(&start_ctx);
ASSERT_EQ(0, start_ctx.wait());
+ ASSERT_EQ(image_replayer::HEALTH_STATE_OK,
+ m_image_replayer->get_health_state());
// STOP
C_SaferCond stop_ctx;
m_image_replayer->stop(&stop_ctx);
ASSERT_EQ(0, stop_ctx.wait());
+ ASSERT_EQ(image_replayer::HEALTH_STATE_OK,
+ m_image_replayer->get_health_state());
}
TEST_F(TestMockImageReplayer, LocalImagePrimary) {
C_SaferCond start_ctx;
m_image_replayer->start(&start_ctx);
ASSERT_EQ(-EINVAL, start_ctx.wait());
+ ASSERT_EQ(image_replayer::HEALTH_STATE_ERROR,
+ m_image_replayer->get_health_state());
}
TEST_F(TestMockImageReplayer, StopError) {
delete m_asok_hook;
}
+template <typename I>
+image_replayer::HealthState ImageReplayer<I>::get_health_state() const {
+ Mutex::Locker locker(m_lock);
+
+ if (!m_mirror_image_status_state) {
+ return image_replayer::HEALTH_STATE_OK;
+ } else if (*m_mirror_image_status_state ==
+ cls::rbd::MIRROR_IMAGE_STATUS_STATE_SYNCING) {
+ return image_replayer::HEALTH_STATE_WARNING;
+ }
+ return image_replayer::HEALTH_STATE_ERROR;
+}
+
template <typename I>
void ImageReplayer<I>::add_remote_image(const std::string &mirror_uuid,
const std::string &image_id,
State state;
std::string state_desc;
int last_r;
- bool bootstrapping;
bool stopping_replay;
+
+ OptionalMirrorImageStatusState mirror_image_status_state{
+ boost::make_optional(false, cls::rbd::MirrorImageStatusState{})};
+ image_replayer::BootstrapRequest<I>* bootstrap_request = nullptr;
{
Mutex::Locker locker(m_lock);
state = m_state;
state_desc = m_state_desc;
+ mirror_image_status_state = m_mirror_image_status_state;
last_r = m_last_r;
- bootstrapping = (m_bootstrap_request != nullptr);
stopping_replay = (m_local_image_ctx != nullptr);
+
+ if (m_bootstrap_request != nullptr) {
+ bootstrap_request = m_bootstrap_request;
+ bootstrap_request->get();
+ }
+ }
+
+ bool syncing = false;
+ if (bootstrap_request != nullptr) {
+ syncing = bootstrap_request->is_syncing();
+ bootstrap_request->put();
+ bootstrap_request = nullptr;
}
if (opt_state) {
status.up = true;
switch (state) {
case STATE_STARTING:
- if (bootstrapping) {
+ if (syncing) {
status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_SYNCING;
status.description = state_desc.empty() ? "syncing" : state_desc;
+ mirror_image_status_state = status.state;
} else {
status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_STARTING_REPLAY;
status.description = "starting replay";
return;
}
status.description = "replaying, " + desc;
+ mirror_image_status_state = boost::none;
}
break;
case STATE_STOPPING:
if (last_r < 0) {
status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR;
status.description = state_desc;
+ mirror_image_status_state = status.state;
} else {
status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_STOPPED;
status.description = state_desc.empty() ? "stopped" : state_desc;
+ mirror_image_status_state = boost::none;
}
break;
default:
assert(!"invalid state");
}
+ {
+ Mutex::Locker locker(m_lock);
+ m_mirror_image_status_state = mirror_image_status_state;
+ }
+
+ // prevent the status from ping-ponging when failed replays are restarted
+ if (mirror_image_status_state &&
+ *mirror_image_status_state == cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR) {
+ status.state = *mirror_image_status_state;
+ }
+
dout(20) << "status=" << status << dendl;
librados::ObjectWriteOperation op;
librbd::cls_client::mirror_image_status_set(&op, m_global_image_id, status);
#include "ImageDeleter.h"
#include "ProgressContext.h"
#include "types.h"
+#include "tools/rbd_mirror/image_replayer/Types.h"
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
template <typename ImageCtxT = librbd::ImageCtx>
class ImageReplayer {
public:
- typedef typename librbd::journal::TypeTraits<ImageCtxT>::ReplayEntry ReplayEntry;
-
- enum State {
- STATE_UNKNOWN,
- STATE_STARTING,
- STATE_REPLAYING,
- STATE_REPLAY_FLUSHING,
- STATE_STOPPING,
- STATE_STOPPED,
- };
-
static ImageReplayer *create(
Threads<librbd::ImageCtx> *threads, ImageDeleter<ImageCtxT>* image_deleter,
InstanceWatcher<ImageCtxT> *instance_watcher,
ImageReplayer(const ImageReplayer&) = delete;
ImageReplayer& operator=(const ImageReplayer&) = delete;
- State get_state() { Mutex::Locker l(m_lock); return get_state_(); }
bool is_stopped() { Mutex::Locker l(m_lock); return is_stopped_(); }
bool is_running() { Mutex::Locker l(m_lock); return is_running_(); }
bool is_replaying() { Mutex::Locker l(m_lock); return is_replaying_(); }
return (m_last_r == -EBLACKLISTED);
}
+ image_replayer::HealthState get_health_state() const;
+
void add_remote_image(const std::string &remote_mirror_uuid,
const std::string &remote_image_id,
librados::IoCtx &remote_io_ctx);
bool on_replay_interrupted();
private:
+ typedef typename librbd::journal::TypeTraits<ImageCtxT>::ReplayEntry ReplayEntry;
+
+ enum State {
+ STATE_UNKNOWN,
+ STATE_STARTING,
+ STATE_REPLAYING,
+ STATE_REPLAY_FLUSHING,
+ STATE_STOPPING,
+ STATE_STOPPED,
+ };
+
struct RemoteImage {
std::string mirror_uuid;
std::string image_id;
typedef typename librbd::journal::TypeTraits<ImageCtxT>::Journaler Journaler;
typedef boost::optional<State> OptionalState;
+ typedef boost::optional<cls::rbd::MirrorImageStatusState>
+ OptionalMirrorImageStatusState;
struct JournalListener : public librbd::journal::Listener {
ImageReplayer *img_replayer;
std::string m_name;
mutable Mutex m_lock;
State m_state = STATE_STOPPED;
- int m_last_r = 0;
std::string m_state_desc;
+
+ OptionalMirrorImageStatusState m_mirror_image_status_state = boost::none;
+ int m_last_r = 0;
+
BootstrapProgressContext m_progress_cxt;
bool m_do_resync{false};
image_replayer::EventPreprocessor<ImageCtxT> *m_event_preprocessor = nullptr;
static std::string to_string(const State state);
- State get_state_() const {
- return m_state;
- }
bool is_stopped_() const {
return m_state == STATE_STOPPED;
}
assert(m_remote_image_ctx == nullptr);
}
+template <typename I>
+bool BootstrapRequest<I>::is_syncing() const {
+ Mutex::Locker locker(m_lock);
+ return (m_image_sync != nullptr);
+}
+
template <typename I>
void BootstrapRequest<I>::send() {
*m_do_resync = false;
}
dout(20) << dendl;
- update_progress("IMAGE_SYNC");
-
- Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(
- this);
-
{
Mutex::Locker locker(m_lock);
if (m_canceled) {
m_ret_val = -ECANCELED;
} else {
assert(m_image_sync == nullptr);
+
+ Context *ctx = create_context_callback<
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_image_sync>(this);
m_image_sync = ImageSync<I>::create(
*m_local_image_ctx, m_remote_image_ctx, m_timer, m_timer_lock,
m_local_mirror_uuid, m_journaler, m_client_meta, m_work_queue,
m_instance_watcher, ctx, m_progress_ctx);
m_image_sync->get();
+
+ m_lock.Unlock();
+ update_progress("IMAGE_SYNC");
+ m_lock.Lock();
+
m_image_sync->send();
return;
}
{
Mutex::Locker locker(m_lock);
-
m_image_sync->put();
m_image_sync = nullptr;
bool *do_resync, ProgressContext *progress_ctx = nullptr);
~BootstrapRequest() override;
+ bool is_syncing() const;
+
void send() override;
void cancel() override;
ProgressContext *m_progress_ctx;
bool *m_do_resync;
- Mutex m_lock;
+ mutable Mutex m_lock;
bool m_canceled = false;
Tags m_remote_tags;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RBD_MIRROR_IMAGE_REPLAYER_TYPES_H
+#define CEPH_RBD_MIRROR_IMAGE_REPLAYER_TYPES_H
+
+namespace rbd {
+namespace mirror {
+namespace image_replayer {
+
+enum HealthState {
+ HEALTH_STATE_OK,
+ HEALTH_STATE_WARNING,
+ HEALTH_STATE_ERROR
+};
+
+} // namespace image_replayer
+} // namespace mirror
+} // namespace rbd
+
+#endif // CEPH_RBD_MIRROR_IMAGE_REPLAYER_TYPES_H