template <typename I>
ImageReplayer<I>::ImageReplayer(Threads<librbd::ImageCtx> *threads,
- shared_ptr<ImageDeleter> image_deleter,
+ ImageDeleter<I>* image_deleter,
InstanceWatcher<I> *instance_watcher,
RadosRef local,
const std::string &local_mirror_uuid,
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 ||
+ *m_mirror_image_status_state ==
+ cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN) {
+ 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,
dout(20) << dendl;
if (m_remote_images.empty()) {
- on_start_fail(0, "waiting for primary remote image");
+ on_start_fail(-EREMOTEIO, "waiting for primary remote image");
return;
}
if (r == -EREMOTEIO) {
m_local_image_tag_owner = "";
- dout(5) << "remote image is non-primary or local image is primary" << dendl;
- on_start_fail(0, "remote image is non-primary or local image is primary");
+ dout(5) << "remote image is non-primary" << dendl;
+ on_start_fail(-EREMOTEIO, "remote image is non-primary");
return;
} else if (r == -EEXIST) {
m_local_image_tag_owner = "";
Mutex::Locker locker(m_lock);
assert(m_state == STATE_STARTING);
m_state = STATE_STOPPING;
- if (r < 0 && r != -ECANCELED) {
+ if (r < 0 && r != -ECANCELED && r != -EREMOTEIO) {
derr << "start failed: " << cpp_strerror(r) << dendl;
} else {
dout(20) << "start canceled" << dendl;
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:
}
// FALLTHROUGH
case STATE_STOPPED:
- if (last_r < 0) {
+ if (last_r == -EREMOTEIO) {
+ status.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN;
+ status.description = state_desc;
+ mirror_image_status_state = status.state;
+ } else 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);
if (m_stopping_for_resync) {
m_image_deleter->schedule_image_delete(m_local,
m_local_pool_id,
- m_global_image_id);
+ m_global_image_id,
+ true);
m_stopping_for_resync = false;
}
}