1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
5 #include "include/rados/librados.hpp"
6 #include "cls/rbd/cls_rbd_client.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "journal/Journaler.h"
10 #include "journal/Settings.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/Journal.h"
13 #include "librbd/Utils.h"
14 #include "librbd/asio/ContextWQ.h"
15 #include "librbd/mirror/GetInfoRequest.h"
16 #include "tools/rbd_mirror/Threads.h"
17 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
18 #include "tools/rbd_mirror/image_replayer/Utils.h"
19 #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
20 #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h"
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_rbd_mirror
25 #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
26 << "PrepareRemoteImageRequest: " << this << " " \
31 namespace image_replayer
{
33 using librbd::util::create_async_context_callback
;
34 using librbd::util::create_context_callback
;
35 using librbd::util::create_rados_callback
;
38 void PrepareRemoteImageRequest
<I
>::send() {
39 if (*m_state_builder
!= nullptr) {
40 (*m_state_builder
)->remote_mirror_uuid
= m_remote_pool_meta
.mirror_uuid
;
43 get_remote_image_id();
47 void PrepareRemoteImageRequest
<I
>::get_remote_image_id() {
50 Context
*ctx
= create_context_callback
<
51 PrepareRemoteImageRequest
<I
>,
52 &PrepareRemoteImageRequest
<I
>::handle_get_remote_image_id
>(this);
53 auto req
= GetMirrorImageIdRequest
<I
>::create(m_remote_io_ctx
,
55 &m_remote_image_id
, ctx
);
60 void PrepareRemoteImageRequest
<I
>::handle_get_remote_image_id(int r
) {
61 dout(10) << "r=" << r
<< ", "
62 << "remote_image_id=" << m_remote_image_id
<< dendl
;
65 finalize_snapshot_state_builder(r
);
77 void PrepareRemoteImageRequest
<I
>::get_mirror_info() {
80 auto ctx
= create_context_callback
<
81 PrepareRemoteImageRequest
<I
>,
82 &PrepareRemoteImageRequest
<I
>::handle_get_mirror_info
>(this);
83 auto req
= librbd::mirror::GetInfoRequest
<I
>::create(
84 m_remote_io_ctx
, m_threads
->work_queue
, m_remote_image_id
,
85 &m_mirror_image
, &m_promotion_state
, &m_primary_mirror_uuid
,
91 void PrepareRemoteImageRequest
<I
>::handle_get_mirror_info(int r
) {
92 dout(10) << "r=" << r
<< dendl
;
95 dout(10) << "image " << m_global_image_id
<< " not mirrored" << dendl
;
96 finalize_snapshot_state_builder(r
);
100 derr
<< "failed to retrieve mirror image details for image "
101 << m_global_image_id
<< ": " << cpp_strerror(r
) << dendl
;
106 auto state_builder
= *m_state_builder
;
107 if (state_builder
!= nullptr &&
108 state_builder
->get_mirror_image_mode() != m_mirror_image
.mode
) {
109 derr
<< "local and remote mirror image using different mirroring modes "
110 << "for image " << m_global_image_id
<< ": split-brain" << dendl
;
113 } else if (m_mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
114 dout(5) << "remote image mirroring is being disabled" << dendl
;
117 } else if (m_promotion_state
!= librbd::mirror::PROMOTION_STATE_PRIMARY
&&
118 (state_builder
== nullptr ||
119 state_builder
->local_image_id
.empty() ||
120 state_builder
->local_promotion_state
==
121 librbd::mirror::PROMOTION_STATE_UNKNOWN
)) {
122 // no local image and remote isn't primary -- don't sync it
123 dout(5) << "remote image is not primary -- not syncing" << dendl
;
128 switch (m_mirror_image
.mode
) {
129 case cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
:
132 case cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
:
133 finalize_snapshot_state_builder(0);
137 derr
<< "unsupported mirror image mode " << m_mirror_image
.mode
<< " "
138 << "for image " << m_global_image_id
<< dendl
;
144 template <typename I
>
145 void PrepareRemoteImageRequest
<I
>::get_client() {
148 auto cct
= static_cast<CephContext
*>(m_local_io_ctx
.cct());
149 ::journal::Settings journal_settings
;
150 journal_settings
.commit_interval
= cct
->_conf
.get_val
<double>(
151 "rbd_mirror_journal_commit_age");
153 // TODO use Journal thread pool for journal ops until converted to ASIO
154 ContextWQ
* context_wq
;
155 librbd::Journal
<>::get_work_queue(cct
, &context_wq
);
157 ceph_assert(m_remote_journaler
== nullptr);
158 m_remote_journaler
= new Journaler(context_wq
, m_threads
->timer
,
159 &m_threads
->timer_lock
, m_remote_io_ctx
,
160 m_remote_image_id
, m_local_mirror_uuid
,
161 journal_settings
, m_cache_manager_handler
);
163 Context
*ctx
= create_async_context_callback(
164 m_threads
->work_queue
, create_context_callback
<
165 PrepareRemoteImageRequest
<I
>,
166 &PrepareRemoteImageRequest
<I
>::handle_get_client
>(this));
167 m_remote_journaler
->get_client(m_local_mirror_uuid
, &m_client
, ctx
);
170 template <typename I
>
171 void PrepareRemoteImageRequest
<I
>::handle_get_client(int r
) {
172 dout(10) << "r=" << r
<< dendl
;
174 MirrorPeerClientMeta client_meta
;
176 dout(10) << "client not registered" << dendl
;
179 derr
<< "failed to retrieve client: " << cpp_strerror(r
) << dendl
;
181 } else if (!util::decode_client_meta(m_client
, &client_meta
)) {
182 // require operator intervention since the data is corrupt
185 // skip registration if it already exists
186 finalize_journal_state_builder(m_client
.state
, client_meta
);
191 template <typename I
>
192 void PrepareRemoteImageRequest
<I
>::register_client() {
195 auto state_builder
= *m_state_builder
;
196 librbd::journal::MirrorPeerClientMeta client_meta
{
197 (state_builder
== nullptr ? "" : state_builder
->local_image_id
)};
198 client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
200 librbd::journal::ClientData client_data
{client_meta
};
201 bufferlist client_data_bl
;
202 encode(client_data
, client_data_bl
);
204 Context
*ctx
= create_async_context_callback(
205 m_threads
->work_queue
, create_context_callback
<
206 PrepareRemoteImageRequest
<I
>,
207 &PrepareRemoteImageRequest
<I
>::handle_register_client
>(this));
208 m_remote_journaler
->register_client(client_data_bl
, ctx
);
211 template <typename I
>
212 void PrepareRemoteImageRequest
<I
>::handle_register_client(int r
) {
213 dout(10) << "r=" << r
<< dendl
;
216 derr
<< "failed to register with remote journal: " << cpp_strerror(r
)
222 auto state_builder
= *m_state_builder
;
223 librbd::journal::MirrorPeerClientMeta client_meta
{
224 (state_builder
== nullptr ? "" : state_builder
->local_image_id
)};
225 client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
226 finalize_journal_state_builder(cls::journal::CLIENT_STATE_CONNECTED
,
231 template <typename I
>
232 void PrepareRemoteImageRequest
<I
>::finalize_journal_state_builder(
233 cls::journal::ClientState client_state
,
234 const MirrorPeerClientMeta
& client_meta
) {
235 journal::StateBuilder
<I
>* state_builder
= nullptr;
236 if (*m_state_builder
!= nullptr) {
237 // already verified that it's a matching builder in
238 // 'handle_get_mirror_info'
239 state_builder
= dynamic_cast<journal::StateBuilder
<I
>*>(*m_state_builder
);
240 ceph_assert(state_builder
!= nullptr);
242 state_builder
= journal::StateBuilder
<I
>::create(m_global_image_id
);
243 *m_state_builder
= state_builder
;
246 state_builder
->remote_mirror_uuid
= m_remote_pool_meta
.mirror_uuid
;
247 state_builder
->remote_image_id
= m_remote_image_id
;
248 state_builder
->remote_promotion_state
= m_promotion_state
;
249 state_builder
->remote_journaler
= m_remote_journaler
;
250 state_builder
->remote_client_state
= client_state
;
251 state_builder
->remote_client_meta
= client_meta
;
254 template <typename I
>
255 void PrepareRemoteImageRequest
<I
>::finalize_snapshot_state_builder(int r
) {
256 snapshot::StateBuilder
<I
>* state_builder
= nullptr;
257 if (*m_state_builder
!= nullptr) {
258 state_builder
= dynamic_cast<snapshot::StateBuilder
<I
>*>(*m_state_builder
);
260 state_builder
= snapshot::StateBuilder
<I
>::create(m_global_image_id
);
261 *m_state_builder
= state_builder
;
264 if (state_builder
== nullptr) {
265 // local image prepare failed or is using journal-based mirroring
269 dout(10) << "remote_mirror_uuid=" << m_remote_pool_meta
.mirror_uuid
<< ", "
270 << "remote_mirror_peer_uuid="
271 << m_remote_pool_meta
.mirror_peer_uuid
<< ", "
272 << "remote_image_id=" << m_remote_image_id
<< ", "
273 << "remote_promotion_state=" << m_promotion_state
<< dendl
;
274 ceph_assert(state_builder
!= nullptr);
275 state_builder
->remote_mirror_uuid
= m_remote_pool_meta
.mirror_uuid
;
276 state_builder
->remote_mirror_peer_uuid
= m_remote_pool_meta
.mirror_peer_uuid
;
277 state_builder
->remote_image_id
= m_remote_image_id
;
278 state_builder
->remote_promotion_state
= m_promotion_state
;
281 template <typename I
>
282 void PrepareRemoteImageRequest
<I
>::finish(int r
) {
283 dout(10) << "r=" << r
<< dendl
;
286 delete m_remote_journaler
;
287 m_remote_journaler
= nullptr;
290 m_on_finish
->complete(r
);
294 } // namespace image_replayer
295 } // namespace mirror
298 template class rbd::mirror::image_replayer::PrepareRemoteImageRequest
<librbd::ImageCtx
>;