<< local_pool_name << ", remote_pool_name=" << remote_pool_name
<< ", image_name=" << image_name << dendl;
- rbd::mirror::ImageReplayer<>::BootstrapParams bootstap_params(local_pool_name,
- image_name);
+ rbd::mirror::ImageReplayer<>::BootstrapParams bootstap_params(image_name);
int64_t local_pool_id;
int64_t remote_pool_id;
std::string remote_image_id;
create_replayer<>();
rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params(m_local_pool_name, m_image_name);
+ bootstap_params(m_image_name);
start(&bootstap_params);
wait_for_replay_complete();
stop();
bootstrap();
}
-TEST_F(TestImageReplayer, BootstrapErrorInvalidPool)
-{
- create_replayer<>();
-
- rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params("INVALID_LOCAL_POOL_NAME", m_image_name);
- C_SaferCond cond;
- m_replayer->start(&cond, &bootstap_params);
- ASSERT_EQ(-ENOENT, cond.wait());
-}
-
TEST_F(TestImageReplayer, BootstrapErrorLocalImageExists)
{
int order = 0;
create_replayer<>();
rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params(m_local_pool_name, m_image_name);
+ bootstap_params(m_image_name);
C_SaferCond cond;
m_replayer->start(&cond, &bootstap_params);
ASSERT_EQ(-EEXIST, cond.wait());
create_replayer<>();
rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params(m_local_pool_name, m_image_name);
+ bootstap_params(m_image_name);
C_SaferCond cond;
m_replayer->start(&cond, &bootstap_params);
ASSERT_EQ(-ENOENT, cond.wait());
{
create_replayer<>();
rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params(m_local_pool_name, m_image_name);
+ bootstap_params(m_image_name);
C_SaferCond start_cond, stop_cond;
m_replayer->start(&start_cond, &bootstap_params);
m_replayer->stop(&stop_cond);
close_image(ictx);
rbd::mirror::ImageReplayer<>::BootstrapParams
- bootstap_params(m_local_pool_name, m_image_name);
+ bootstap_params(m_image_name);
C_SaferCond cond;
m_replayer->start(&cond, &bootstap_params);
ASSERT_EQ(-ENOENT, cond.wait());
}
protected:
- virtual void on_start_get_registered_client_status_finish(int r,
- const std::set<cls::journal::Client> ®istered_clients,
- const BootstrapParams &bootstrap_params) {
- rbd::mirror::ImageReplayer<>::on_start_get_registered_client_status_finish(
- get_error("on_start_get_registered_client_status"), registered_clients,
- bootstrap_params);
- }
-
- virtual void on_start_remote_journaler_init_finish(int r) {
- ASSERT_EQ(0, r);
- rbd::mirror::ImageReplayer<>::on_start_remote_journaler_init_finish(
- get_error("on_start_remote_journaler_init"));
- }
-
- virtual void on_start_local_image_open_finish(int r) {
- int test_r = get_error("on_start_local_image_open");
- if (!test_r) {
- rbd::mirror::ImageReplayer<>::on_start_local_image_open_finish(r);
- return;
- }
-
- // The image open error was imitated, so we need to close the image back
- // before propagating the error.
- ASSERT_EQ(0, r);
- set_error("on_start_local_image_open", 0);
- FunctionContext *ctx = new FunctionContext(
- [this, test_r](int r) {
- on_start_local_image_open_finish(test_r);
- });
- close_local_image(ctx);
- }
-
- virtual void on_start_wait_for_local_journal_ready_finish(int r) {
- ASSERT_EQ(0, r);
- rbd::mirror::ImageReplayer<>::on_start_wait_for_local_journal_ready_finish(
- get_error("on_start_wait_for_local_journal_ready"));
- }
-
virtual void on_stop_journal_replay_shut_down_finish(int r) {
ASSERT_EQ(0, r);
rbd::mirror::ImageReplayer<>::on_stop_journal_replay_shut_down_finish(
reinterpret_cast<ImageReplayer *>(m_replayer)-> \
set_error("on_start_" #state, -1); \
rbd::mirror::ImageReplayer<>::BootstrapParams \
- bootstap_params(m_local_pool_name, m_image_name); \
+ bootstap_params(m_image_name); \
C_SaferCond cond; \
m_replayer->start(&cond, &bootstap_params); \
ASSERT_EQ(-1, cond.wait()); \
reinterpret_cast<ImageReplayer *>(m_replayer)-> \
set_error("on_stop_" #state, -1); \
rbd::mirror::ImageReplayer<>::BootstrapParams \
- bootstap_params(m_local_pool_name, m_image_name); \
+ bootstap_params(m_image_name); \
start(&bootstap_params); \
/* TODO: investigate: without wait below I observe: */ \
/* librbd/journal/Replay.cc: 70: FAILED assert(m_op_events.empty()) */\
ASSERT_EQ(0, cond.wait()); \
}
-TEST_ON_START_ERROR(get_registered_client_status);
-TEST_ON_START_ERROR(remote_journaler_init);
-TEST_ON_START_ERROR(wait_for_local_journal_ready);
-
TEST_ON_STOP_ERROR(journal_replay_shut_down);
TEST_ON_STOP_ERROR(no_error);
template <typename I>
ImageReplayer<I>::ImageReplayer(Threads *threads, RadosRef local, RadosRef remote,
- const std::string &client_id,
+ const std::string &mirror_uuid,
int64_t local_pool_id,
int64_t remote_pool_id,
const std::string &remote_image_id) :
m_threads(threads),
m_local(local),
m_remote(remote),
- m_client_id(client_id),
+ m_mirror_uuid(mirror_uuid),
m_remote_pool_id(remote_pool_id),
m_local_pool_id(local_pool_id),
m_remote_image_id(remote_image_id),
template <typename I>
void ImageReplayer<I>::start(Context *on_finish,
- const BootstrapParams *bootstrap_params)
+ const BootstrapParams *bootstrap_params)
{
dout(20) << "on_finish=" << on_finish << ", m_on_finish=" << m_on_finish
<< dendl;
}
if (bootstrap_params != nullptr && !bootstrap_params->empty()) {
- r = m_local->pool_lookup(bootstrap_params->local_pool_name.c_str());
- if (r < 0) {
- derr << "error finding local pool " << bootstrap_params->local_pool_name
- << ": " << cpp_strerror(r) << dendl;
- on_start_fail_start(r);
- return;
- }
- m_local_pool_id = r;
+ m_local_image_name = bootstrap_params->local_image_name;
}
r = m_local->ioctx_create2(m_local_pool_id, m_local_ioctx);
}
CephContext *cct = static_cast<CephContext *>(m_local->cct());
-
double commit_interval = cct->_conf->rbd_journal_commit_age;
m_remote_journaler = new Journaler(m_threads->work_queue,
m_threads->timer,
&m_threads->timer_lock, m_remote_ioctx,
- m_remote_image_id, m_client_id,
+ m_remote_image_id, m_mirror_uuid,
commit_interval);
- on_start_get_registered_client_status_start(bootstrap_params);
-}
-
-template <typename I>
-void ImageReplayer<I>::on_start_get_registered_client_status_start(
- const BootstrapParams *bootstrap_params)
-{
- dout(20) << "enter" << dendl;
-
- struct Metadata {
- uint64_t minimum_set;
- uint64_t active_set;
- std::set<cls::journal::Client> registered_clients;
- BootstrapParams bootstrap_params;
- } *m = new Metadata();
-
- if (bootstrap_params) {
- m->bootstrap_params = *bootstrap_params;
- }
-
- FunctionContext *ctx = new FunctionContext(
- [this, m, bootstrap_params](int r) {
- on_start_get_registered_client_status_finish(r, m->registered_clients,
- m->bootstrap_params);
- delete m;
- });
-
- m_remote_journaler->get_mutable_metadata(&m->minimum_set, &m->active_set,
- &m->registered_clients, ctx);
-}
-
-template <typename I>
-void ImageReplayer<I>::on_start_get_registered_client_status_finish(int r,
- const std::set<cls::journal::Client> ®istered_clients,
- const BootstrapParams &bootstrap_params)
-{
- dout(20) << "r=" << r << dendl;
-
- if (r < 0) {
- derr << "error obtaining registered client status: "
- << cpp_strerror(r) << dendl;
- on_start_fail_start(r);
- return;
- }
- if (on_start_interrupted()) {
- return;
- }
-
- for (auto c : registered_clients) {
- if (c.id == m_client_id) {
- librbd::journal::ClientData client_data;
- bufferlist::iterator bl = c.data.begin();
- try {
- ::decode(client_data, bl);
- } catch (const buffer::error &err) {
- derr << "failed to decode client meta data: " << err.what() << dendl;
- on_start_fail_start(-EINVAL);
- return;
- }
-
- // TODO: unsafe cast
- m_client_meta =
- boost::get<librbd::journal::MirrorPeerClientMeta>(client_data.client_meta);
- m_local_image_id = m_client_meta.image_id;
-
- dout(20) << "client found, pool_id=" << m_local_pool_id << ", image_id="
- << m_local_image_id << dendl;
-
- if (!bootstrap_params.empty()) {
- dout(0) << "ignoring bootsrap params: client already registered" << dendl;
- }
-
- on_start_remote_journaler_init_start();
- return;
- }
- }
-
- dout(20) << "client not found" << dendl;
- bootstrap(bootstrap_params);
+ bootstrap();
}
template <typename I>
-void ImageReplayer<I>::bootstrap(const BootstrapParams &bootstrap_params) {
- int r;
- BootstrapParams params;
-
- if (!bootstrap_params.empty()) {
- dout(20) << "using external bootstrap params" << dendl;
- params = bootstrap_params;
- } else {
- r = get_bootstrap_params(¶ms);
- if (r < 0) {
- derr << "error obtaining bootstrap parameters: "
- << cpp_strerror(r) << dendl;
- on_start_fail_start(r);
- return;
- }
- }
-
+void ImageReplayer<I>::bootstrap() {
dout(20) << "bootstrap params: "
- << "local_pool_name=" << params.local_pool_name << ", "
- << "local_image_name=" << params.local_image_name << dendl;
+ << "local_image_name=" << m_local_image_name << dendl;
// TODO: add a new bootstrap state and support canceling
Context *ctx = create_context_callback<
ImageReplayer, &ImageReplayer<I>::handle_bootstrap>(this);
BootstrapRequest<I> *request = BootstrapRequest<I>::create(
m_local_ioctx, m_remote_ioctx, &m_local_image_ctx,
- params.local_image_name, m_remote_image_id, m_threads->work_queue,
- m_threads->timer, &m_threads->timer_lock, m_client_id, m_remote_journaler,
+ m_local_image_name, m_remote_image_id, m_threads->work_queue,
+ m_threads->timer, &m_threads->timer_lock, m_mirror_uuid, m_remote_journaler,
&m_client_meta, ctx);
request->send();
}
if (r < 0) {
on_start_fail_start(r);
return;
- }
- if (on_start_interrupted()) {
+ } else if (on_start_interrupted()) {
return;
}
- on_start_remote_journaler_init_start();
-}
-
-template <typename I>
-void ImageReplayer<I>::on_start_remote_journaler_init_start()
-{
- if (on_start_interrupted()) {
- return;
- }
-
- dout(20) << "enter" << dendl;
-
- FunctionContext *ctx = new FunctionContext(
- [this](int r) {
- on_start_remote_journaler_init_finish(r);
- });
-
- m_remote_journaler->init(ctx);
-}
-
-template <typename I>
-void ImageReplayer<I>::on_start_remote_journaler_init_finish(int r)
-{
- dout(20) << "r=" << r << dendl;
+ {
+ Mutex::Locker locker(m_lock);
+ m_name = m_local_ioctx.get_pool_name() + "/" + m_local_image_ctx->name;
- if (r < 0) {
- derr << "error initializing journal: " << cpp_strerror(r) << dendl;
- on_start_fail_start(r);
- return;
- }
- if (on_start_interrupted()) {
- return;
+ CephContext *cct = static_cast<CephContext *>(m_local->cct());
+ delete m_asok_hook;
+ m_asok_hook = new ImageReplayerAdminSocketHook<I>(cct, m_name, this);
}
-
- on_start_local_image_open_start();
+ init_remote_journaler();
}
template <typename I>
-void ImageReplayer<I>::on_start_local_image_open_start()
-{
- dout(20) << "enter" << dendl;
- if (m_local_image_ctx != nullptr) {
- // already opened during bootstrap
- on_start_wait_for_local_journal_ready_start();
- return;
- }
+void ImageReplayer<I>::init_remote_journaler() {
+ dout(20) << dendl;
- // open and lock the local image
Context *ctx = create_context_callback<
- ImageReplayer, &ImageReplayer<I>::on_start_local_image_open_finish>(this);
- OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
- m_local_ioctx, &m_local_image_ctx, "", m_local_image_id,
- m_threads->work_queue, ctx);
- request->send();
+ ImageReplayer, &ImageReplayer<I>::handle_init_remote_journaler>(this);
+ m_remote_journaler->init(ctx);
}
template <typename I>
-void ImageReplayer<I>::on_start_local_image_open_finish(int r)
-{
+void ImageReplayer<I>::handle_init_remote_journaler(int r) {
dout(20) << "r=" << r << dendl;
if (r < 0) {
- derr << "error opening local image " << m_local_image_id
- << ": " << cpp_strerror(r) << dendl;
+ derr << "failed to initialize remote journal: " << cpp_strerror(r) << dendl;
on_start_fail_start(r);
return;
- }
- if (on_start_interrupted()) {
+ } else if (on_start_interrupted()) {
return;
}
- on_start_wait_for_local_journal_ready_start();
-}
-
-template <typename I>
-void ImageReplayer<I>::on_start_wait_for_local_journal_ready_start()
-{
- dout(20) << "enter" << dendl;
-
- if (!m_asok_hook) {
- Mutex::Locker locker(m_lock);
-
- m_name = m_local_ioctx.get_pool_name() + "/" + m_local_image_ctx->name;
-
- CephContext *cct = static_cast<CephContext *>(m_local->cct());
-
- m_asok_hook = new ImageReplayerAdminSocketHook<I>(cct, m_name, this);
- }
-
- FunctionContext *ctx = new FunctionContext(
- [this](int r) {
- on_start_wait_for_local_journal_ready_finish(r);
- });
- m_local_image_ctx->journal->wait_for_journal_ready(ctx);
+ start_replay();
}
template <typename I>
-void ImageReplayer<I>::on_start_wait_for_local_journal_ready_finish(int r)
-{
- dout(20) << "r=" << r << dendl;
-
- if (r < 0) {
- derr << "error when waiting for local journal ready: " << cpp_strerror(r)
- << dendl;
- on_start_fail_start(r);
- return;
- }
- if (on_start_interrupted()) {
- return;
- }
+void ImageReplayer<I>::start_replay() {
+ dout(20) << dendl;
- r = m_local_image_ctx->journal->start_external_replay(&m_local_replay);
+ int r = m_local_image_ctx->journal->start_external_replay(&m_local_replay);
if (r < 0) {
derr << "error starting external replay on local image "
<< m_local_image_id << ": " << cpp_strerror(r) << dendl;
}
m_replay_handler = new ReplayHandler<I>(this);
-
m_remote_journaler->start_live_replay(m_replay_handler,
1 /* TODO: configurable */);
assert(r == 0);
Context *on_finish(nullptr);
-
{
Mutex::Locker locker(m_lock);
-
if (m_state == STATE_STOPPING) {
on_start_fail_start(-EINTR);
return;
assert(m_state == STATE_STARTING);
m_state = STATE_REPLAYING;
-
std::swap(m_on_finish, on_finish);
}
dout(20) << "start succeeded" << dendl;
-
if (on_finish) {
dout(20) << "on finish complete, r=" << r << dendl;
on_finish->complete(r);
Context *ctx = create_context_callback<
ImageReplayer, &ImageReplayer<I>::on_stop_local_image_close_finish>(this);
CloseImageRequest<I> *request = CloseImageRequest<I>::create(
- &m_local_image_ctx, m_threads->work_queue, ctx);
+ &m_local_image_ctx, m_threads->work_queue, false, ctx);
request->send();
}
m_remote_journaler->committed(*replay_entry);
}
-template <typename I>
-int ImageReplayer<I>::get_bootstrap_params(BootstrapParams *params)
-{
- int r = librbd::cls_client::dir_get_name(&m_remote_ioctx, RBD_DIRECTORY,
- m_remote_image_id,
- ¶ms->local_image_name);
- if (r < 0) {
- derr << "error looking up name for remote image id " << m_remote_image_id
- << ": " << cpp_strerror(r) << dendl;
- return r;
- }
-
- params->local_pool_name = m_remote_ioctx.get_pool_name();
-
- return 0;
-}
-
template <typename I>
void ImageReplayer<I>::shut_down_journal_replay(bool cancel_ops)
{
};
struct BootstrapParams {
- std::string local_pool_name;
std::string local_image_name;
BootstrapParams() {}
- BootstrapParams(const std::string &local_pool_name,
- const std::string local_image_name) :
- local_pool_name(local_pool_name),
+ BootstrapParams(const std::string local_image_name) :
local_image_name(local_image_name) {}
bool empty() const {
- return local_pool_name.empty() && local_image_name.empty();
+ return local_image_name.empty();
}
};
ImageReplayer(Threads *threads, RadosRef local, RadosRef remote,
- const std::string &client_id, int64_t local_pool_id,
+ const std::string &mirror_uuid, int64_t local_pool_id,
int64_t remote_pool_id, const std::string &remote_image_id);
virtual ~ImageReplayer();
ImageReplayer(const ImageReplayer&) = delete;
* <starting> *
* | *
* v (error) *
- * GET_REGISTERED_CLIENT_STATUS * * * * * * * *
- * | *
- * | (sync required) *
- * |\-----\ *
- * | | *
- * | v (error) *
- * | BOOTSTRAP_IMAGE * * * * * * * * * * *
- * | | *
- * | v *
- * |/-----/ *
- * | *
- * v (no sync required) (error) *
- * REMOTE_JOURNALER_INIT * * * * * * * * * * *
+ * BOOTSTRAP_IMAGE * * * * * * * * * * * * * *
* | *
* v (error) *
- * LOCAL_IMAGE_OPEN (skip if not * * * * * * *
- * | needed *
+ * INIT_REMOTE_JOURNALER * * * * * * * * * * *
+ * | *
* v (error) *
- * WAIT_FOR_LOCAL_JOURNAL_READY * * * * * * * *
+ * START_REPLAY * * * * * * * * * * * * * * * *
* |
- * v-----------------------------------------------\
+ * | /-------------------------------------------\
+ * | | |
+ * v v |
* <replaying> --------------> <flushing_replay> |
* | | |
* v v |
* @endverbatim
*/
- virtual void on_start_get_registered_client_status_start(
- const BootstrapParams *bootstrap_params);
- virtual void on_start_get_registered_client_status_finish(int r,
- const std::set<cls::journal::Client> ®istered_clients,
- const BootstrapParams &bootstrap_params);
-
- void bootstrap(const BootstrapParams ¶ms);
- void handle_bootstrap(int r);
-
- virtual void on_start_remote_journaler_init_start();
- virtual void on_start_remote_journaler_init_finish(int r);
- virtual void on_start_local_image_open_start();
- virtual void on_start_local_image_open_finish(int r);
- virtual void on_start_wait_for_local_journal_ready_start();
- virtual void on_start_wait_for_local_journal_ready_finish(int r);
virtual void on_start_fail_start(int r);
virtual void on_start_fail_finish(int r);
virtual bool on_start_interrupted();
private:
typedef typename librbd::journal::TypeTraits<ImageCtxT>::Journaler Journaler;
- State get_state_() const { return m_state; }
- bool is_stopped_() const { return m_state == STATE_UNINITIALIZED ||
- m_state == STATE_STOPPED; }
- bool is_running_() const { return !is_stopped_() && m_state != STATE_STOPPING; }
-
- int get_bootstrap_params(BootstrapParams *params);
-
- void shut_down_journal_replay(bool cancel_ops);
-
Threads *m_threads;
RadosRef m_local, m_remote;
- std::string m_client_id;
+ std::string m_mirror_uuid;
int64_t m_remote_pool_id, m_local_pool_id;
std::string m_remote_image_id, m_local_image_id;
+ std::string m_local_image_name;
std::string m_name;
Mutex m_lock;
State m_state;
- std::string m_local_pool_name, m_remote_pool_name;
librados::IoCtx m_local_ioctx, m_remote_ioctx;
ImageCtxT *m_local_image_ctx;
librbd::journal::Replay<ImageCtxT> *m_local_replay;
AdminSocketHook *m_asok_hook;
librbd::journal::MirrorPeerClientMeta m_client_meta;
+
+ State get_state_() const { return m_state; }
+ bool is_stopped_() const { return m_state == STATE_UNINITIALIZED ||
+ m_state == STATE_STOPPED; }
+ bool is_running_() const { return !is_stopped_() && m_state != STATE_STOPPING; }
+
+ void shut_down_journal_replay(bool cancel_ops);
+
+ void bootstrap();
+ void handle_bootstrap(int r);
+
+ void init_remote_journaler();
+ void handle_init_remote_journaler(int r);
+
+ void start_replay();
};
} // namespace mirror
template <typename I>
void BootstrapRequest<I>::send() {
+ get_client();
+}
+
+template <typename I>
+void BootstrapRequest<I>::get_client() {
+ dout(20) << dendl;
+
+ Context *ctx = create_context_callback<
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_get_client>(
+ this);
+ m_journaler->get_client(m_mirror_uuid, &m_client, ctx);
+}
+
+template <typename I>
+void BootstrapRequest<I>::handle_get_client(int r) {
+ dout(20) << ": r=" << r << dendl;
+
+ if (r == -ENOENT) {
+ dout(10) << ": client not registered" << dendl;
+ } else if (r < 0) {
+ derr << ": failed to retreive client: " << cpp_strerror(r) << dendl;
+ finish(r);
+ return;
+ } else if (decode_client_meta()) {
+ // skip registration if it already exists
+ open_remote_image();
+ return;
+ }
+
+ register_client();
+}
+
+template <typename I>
+void BootstrapRequest<I>::register_client() {
+ dout(20) << dendl;
+
+ // record an empty place-holder record
+ librbd::journal::ClientData client_data{
+ librbd::journal::MirrorPeerClientMeta{}};
+ bufferlist client_data_bl;
+ ::encode(client_data, client_data_bl);
+
+ Context *ctx = create_context_callback<
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_register_client>(
+ this);
+ m_journaler->register_client(client_data_bl, ctx);
+}
+
+template <typename I>
+void BootstrapRequest<I>::handle_register_client(int r) {
+ dout(20) << ": 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();
open_remote_image();
}
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- derr << "failed to open remote image: " << cpp_strerror(r) << dendl;
+ derr << ": failed to open remote image: " << cpp_strerror(r) << dendl;
m_ret_val = r;
close_remote_image();
return;
}
- create_local_image();
+ // default local image name to the remote image name if not provided
+ if (m_local_image_name.empty()) {
+ m_local_image_name = m_remote_image_ctx->name;
+ }
+
+ if (m_local_image_id.empty()) {
+ create_local_image();
+ return;
+ }
+
+ open_local_image();
}
template <typename I>
-void BootstrapRequest<I>::create_local_image() {
+void BootstrapRequest<I>::open_local_image() {
dout(20) << dendl;
- // TODO: local image might already exist (e.g. interrupted sync)
- // need to determine what type of bootstrap we are performing
-
- // TODO: librbd should provide an AIO image creation method -- this is
- // blocking so we execute in our worker thread
Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_create_local_image>(
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
this);
- m_work_queue->queue(new C_CreateImage<I>(m_local_io_ctx, m_local_image_name,
- m_remote_image_ctx, ctx), 0);
+ OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
+ m_local_io_ctx, m_local_image_ctx,
+ (!m_local_image_id.empty() ? std::string() : m_local_image_name),
+ m_local_image_id, m_work_queue, ctx);
+ request->send();
}
template <typename I>
-void BootstrapRequest<I>::handle_create_local_image(int r) {
+void BootstrapRequest<I>::handle_open_local_image(int r) {
dout(20) << ": r=" << r << dendl;
- if (r < 0) {
- derr << "failed to create local image: " << cpp_strerror(r) << dendl;
+ if (r == -ENOENT) {
+ assert(*m_local_image_ctx == nullptr);
+ dout(10) << ": local image missing" << dendl;
+ create_local_image();
+ return;
+ } else if (r < 0) {
+ assert(*m_local_image_ctx == nullptr);
+ derr << ": failed to open local image: " << cpp_strerror(r) << dendl;
m_ret_val = r;
close_remote_image();
return;
}
- open_local_image();
+ update_client();
}
template <typename I>
-void BootstrapRequest<I>::open_local_image() {
+void BootstrapRequest<I>::remove_local_image() {
+ dout(20) << dendl;
+
+ // TODO
+}
+
+template <typename I>
+void BootstrapRequest<I>::handle_remove_local_image(int r) {
+ dout(20) << ": r=" << r << dendl;
+
+ // TODO
+}
+
+template <typename I>
+void BootstrapRequest<I>::create_local_image() {
dout(20) << dendl;
+ // TODO: librbd should provide an AIO image creation method -- this is
+ // blocking so we execute in our worker thread
Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_open_local_image>(
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_create_local_image>(
this);
- OpenLocalImageRequest<I> *request = OpenLocalImageRequest<I>::create(
- m_local_io_ctx, m_local_image_ctx, m_local_image_name, "", m_work_queue,
- ctx);
- request->send();
+ m_work_queue->queue(new C_CreateImage<I>(m_local_io_ctx, m_local_image_name,
+ m_remote_image_ctx, ctx), 0);
}
template <typename I>
-void BootstrapRequest<I>::handle_open_local_image(int r) {
+void BootstrapRequest<I>::handle_create_local_image(int r) {
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- assert(*m_local_image_ctx == nullptr);
- derr << "failed to open local image: " << cpp_strerror(r) << dendl;
+ derr << ": failed to create local image: " << cpp_strerror(r) << dendl;
m_ret_val = r;
close_remote_image();
return;
}
- register_client();
+ open_local_image();
}
template <typename I>
-void BootstrapRequest<I>::register_client() {
- dout(20) << dendl;
+void BootstrapRequest<I>::update_client() {
+ if (m_local_image_id == (*m_local_image_ctx)->id) {
+ image_sync();
+ return;
+ }
+ m_local_image_id = (*m_local_image_ctx)->id;
- // TODO: if client fails to register newly created image to journal,
- // need to ensure we can recover (i.e. see if image of the same
- // name already exists)
+ dout(20) << dendl;
- librbd::journal::MirrorPeerClientMeta client_meta(*m_client_meta);
- client_meta.image_id = (*m_local_image_ctx)->id;
+ librbd::journal::MirrorPeerClientMeta client_meta;
+ client_meta.image_id = m_local_image_id;
librbd::journal::ClientData client_data(client_meta);
- bufferlist client_data_bl;
- ::encode(client_data, client_data_bl);
+ bufferlist data_bl;
+ ::encode(client_data, data_bl);
Context *ctx = create_context_callback<
- BootstrapRequest<I>, &BootstrapRequest<I>::handle_register_client>(
+ BootstrapRequest<I>, &BootstrapRequest<I>::handle_update_client>(
this);
- m_journaler->register_client(client_data_bl, ctx);
+ m_journaler->update_client(data_bl, ctx);
}
template <typename I>
-void BootstrapRequest<I>::handle_register_client(int r) {
+void BootstrapRequest<I>::handle_update_client(int r) {
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- derr << "failed to register with remote journal: " << cpp_strerror(r)
- << dendl;
+ derr << ": failed to update client: " << cpp_strerror(r) << dendl;
+ m_ret_val = r;
close_local_image();
return;
}
- m_client_meta->image_id = (*m_local_image_ctx)->id;
+ m_client_meta->image_id = m_local_image_id;
image_sync();
}
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- derr << "failed to sync remote image: " << cpp_strerror(r) << dendl;
+ derr << ": failed to sync remote image: " << cpp_strerror(r) << dendl;
m_ret_val = r;
close_local_image();
return;
BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_local_image>(
this);
CloseImageRequest<I> *request = CloseImageRequest<I>::create(
- m_local_image_ctx, m_work_queue, ctx);
+ m_local_image_ctx, m_work_queue, false, ctx);
request->send();
}
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- derr << "error encountered closing local image: " << cpp_strerror(r)
+ derr << ": error encountered closing local image: " << cpp_strerror(r)
<< dendl;
}
BootstrapRequest<I>, &BootstrapRequest<I>::handle_close_remote_image>(
this);
CloseImageRequest<I> *request = CloseImageRequest<I>::create(
- &m_remote_image_ctx, m_work_queue, ctx);
+ &m_remote_image_ctx, m_work_queue, false, ctx);
request->send();
}
dout(20) << ": r=" << r << dendl;
if (r < 0) {
- derr << "error encountered closing remote image: " << cpp_strerror(r)
+ derr << ": error encountered closing remote image: " << cpp_strerror(r)
<< dendl;
}
delete this;
}
+template <typename I>
+bool BootstrapRequest<I>::decode_client_meta() {
+ dout(20) << dendl;
+
+ librbd::journal::ClientData client_data;
+ bufferlist::iterator it = m_client.data.begin();
+ try {
+ ::decode(client_data, it);
+ } catch (const buffer::error &err) {
+ derr << ": failed to decode client meta data: " << err.what() << dendl;
+ return true;
+ }
+
+ librbd::journal::MirrorPeerClientMeta *client_meta =
+ boost::get<librbd::journal::MirrorPeerClientMeta>(&client_data.client_meta);
+ if (client_meta == nullptr) {
+ derr << ": unknown peer registration" << dendl;
+ return true;
+ } else if (!client_meta->image_id.empty()) {
+ // have an image id -- use that to open the image
+ m_local_image_id = client_meta->image_id;
+ }
+
+ *m_client_meta = *client_meta;
+
+ dout(20) << ": client found: image_id=" << m_local_image_id << dendl;
+ return true;
+}
+
} // namespace image_replayer
} // namespace mirror
} // namespace rbd
#include "include/int_types.h"
#include "include/rados/librados.hpp"
+#include "cls/journal/cls_journal_types.h"
#include "librbd/journal/TypeTraits.h"
#include <string>
* <start>
* |
* v
- * OPEN_REMOTE_IMAGE * * * * * * * * * * * *
+ * GET_CLIENT * * * * * * * * * * * * * * * *
+ * | *
+ * v (skip if not needed) * (error)
+ * REGISTER_CLIENT * * * * * * * * * * * * *
* | *
* v *
- * CREATE_LOCAL_IMAGE * * * * * * * * * * * * (error)
+ * OPEN_REMOTE_IMAGE * * * * * * * * * * * *
* | *
* v *
* OPEN_LOCAL_IMAGE * * * * * * * * * * * * *
+ * | . ^ *
+ * | . | *
+ * | . \-----------------------\ *
+ * | . | *
+ * | . (image sync requested) | *
+ * | . . > REMOVE_LOCAL_IMAGE * * * * *
+ * | . | | *
+ * | . (image doesn't | | *
+ * | . exist) v | *
+ * | . . > CREATE_LOCAL_IMAGE * * * * *
+ * | | | *
+ * | \-----------------/ *
* | *
- * v *
- * REGISTER_CLIENT * * * * *
- * | * *
- * v v *
+ * v (skip if not needed) *
+ * UPDATE_CLIENT *
+ * | *
+ * v (skip if not needed) *
* IMAGE_SYNC * * * > CLOSE_LOCAL_IMAGE *
- * | | *
- * | /-------------/ *
+ * | | *
+ * | /-------------------/ *
* | | *
* v v *
* CLOSE_REMOTE_IMAGE < * * * * * * * * * * *
librados::IoCtx &m_remote_io_ctx;
ImageCtxT **m_local_image_ctx;
std::string m_local_image_name;
+ std::string m_local_image_id;
std::string m_remote_image_id;
ContextWQ *m_work_queue;
SafeTimer *m_timer;
MirrorPeerClientMeta *m_client_meta;
Context *m_on_finish;
+ cls::journal::Client m_client;
ImageCtxT *m_remote_image_ctx = nullptr;
int m_ret_val = 0;
+ void get_client();
+ void handle_get_client(int r);
+
+ void register_client();
+ void handle_register_client(int r);
+
void open_remote_image();
void handle_open_remote_image(int r);
- void create_local_image();
- void handle_create_local_image(int r);
-
void open_local_image();
void handle_open_local_image(int r);
- void register_client();
- void handle_register_client(int r);
+ void remove_local_image();
+ void handle_remove_local_image(int r);
+
+ void create_local_image();
+ void handle_create_local_image(int r);
+
+ void update_client();
+ void handle_update_client(int r);
void image_sync();
void handle_image_sync(int r);
void finish(int r);
+ bool decode_client_meta();
};
} // namespace image_replayer