1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
5 #include "BootstrapRequest.h"
6 #include "CreateImageRequest.h"
7 #include "OpenImageRequest.h"
8 #include "OpenLocalImageRequest.h"
9 #include "common/debug.h"
10 #include "common/dout.h"
11 #include "common/errno.h"
12 #include "cls/rbd/cls_rbd_client.h"
13 #include "journal/Journaler.h"
14 #include "journal/Settings.h"
15 #include "librbd/ImageCtx.h"
16 #include "librbd/ImageState.h"
17 #include "librbd/internal.h"
18 #include "librbd/Journal.h"
19 #include "librbd/Utils.h"
20 #include "librbd/asio/ContextWQ.h"
21 #include "librbd/journal/Types.h"
22 #include "tools/rbd_mirror/BaseRequest.h"
23 #include "tools/rbd_mirror/ImageSync.h"
24 #include "tools/rbd_mirror/ProgressContext.h"
25 #include "tools/rbd_mirror/Threads.h"
26 #include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
27 #include "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
28 #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
29 #include "tools/rbd_mirror/image_replayer/journal/SyncPointHandler.h"
31 #define dout_context g_ceph_context
32 #define dout_subsys ceph_subsys_rbd_mirror
34 #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
35 << "BootstrapRequest: " << this << " " \
40 namespace image_replayer
{
42 using librbd::util::create_context_callback
;
43 using librbd::util::unique_lock_name
;
46 BootstrapRequest
<I
>::BootstrapRequest(
48 librados::IoCtx
& local_io_ctx
,
49 librados::IoCtx
& remote_io_ctx
,
50 InstanceWatcher
<I
>* instance_watcher
,
51 const std::string
& global_image_id
,
52 const std::string
& local_mirror_uuid
,
53 const RemotePoolMeta
& remote_pool_meta
,
54 ::journal::CacheManagerHandler
* cache_manager_handler
,
55 PoolMetaCache
* pool_meta_cache
,
56 ProgressContext
* progress_ctx
,
57 StateBuilder
<I
>** state_builder
,
60 : CancelableRequest("rbd::mirror::image_replayer::BootstrapRequest",
61 reinterpret_cast<CephContext
*>(local_io_ctx
.cct()),
64 m_local_io_ctx(local_io_ctx
),
65 m_remote_io_ctx(remote_io_ctx
),
66 m_instance_watcher(instance_watcher
),
67 m_global_image_id(global_image_id
),
68 m_local_mirror_uuid(local_mirror_uuid
),
69 m_remote_pool_meta(remote_pool_meta
),
70 m_cache_manager_handler(cache_manager_handler
),
71 m_pool_meta_cache(pool_meta_cache
),
72 m_progress_ctx(progress_ctx
),
73 m_state_builder(state_builder
),
74 m_do_resync(do_resync
),
75 m_lock(ceph::make_mutex(unique_lock_name("BootstrapRequest::m_lock",
81 bool BootstrapRequest
<I
>::is_syncing() const {
82 std::lock_guard locker
{m_lock
};
83 return (m_image_sync
!= nullptr);
87 void BootstrapRequest
<I
>::send() {
90 prepare_local_image();
94 void BootstrapRequest
<I
>::cancel() {
97 std::lock_guard locker
{m_lock
};
100 if (m_image_sync
!= nullptr) {
101 m_image_sync
->cancel();
105 template <typename I
>
106 std::string BootstrapRequest
<I
>::get_local_image_name() const {
107 std::unique_lock locker
{m_lock
};
108 return m_local_image_name
;
111 template <typename I
>
112 void BootstrapRequest
<I
>::prepare_local_image() {
114 update_progress("PREPARE_LOCAL_IMAGE");
117 std::unique_lock locker
{m_lock
};
118 m_local_image_name
= m_global_image_id
;
121 ceph_assert(*m_state_builder
== nullptr);
122 auto ctx
= create_context_callback
<
123 BootstrapRequest
, &BootstrapRequest
<I
>::handle_prepare_local_image
>(this);
124 auto req
= image_replayer::PrepareLocalImageRequest
<I
>::create(
125 m_local_io_ctx
, m_global_image_id
, &m_prepare_local_image_name
,
126 m_state_builder
, m_threads
->work_queue
, ctx
);
130 template <typename I
>
131 void BootstrapRequest
<I
>::handle_prepare_local_image(int r
) {
132 dout(10) << "r=" << r
<< dendl
;
134 ceph_assert(r
< 0 || *m_state_builder
!= nullptr);
136 dout(10) << "local image does not exist" << dendl
;
138 derr
<< "error preparing local image for replay" << cpp_strerror(r
)
144 // image replayer will detect the name change (if any) at next
146 if (r
>= 0 && !m_prepare_local_image_name
.empty()) {
147 std::unique_lock locker
{m_lock
};
148 m_local_image_name
= m_prepare_local_image_name
;
151 prepare_remote_image();
154 template <typename I
>
155 void BootstrapRequest
<I
>::prepare_remote_image() {
157 update_progress("PREPARE_REMOTE_IMAGE");
159 Context
*ctx
= create_context_callback
<
160 BootstrapRequest
, &BootstrapRequest
<I
>::handle_prepare_remote_image
>(this);
161 auto req
= image_replayer::PrepareRemoteImageRequest
<I
>::create(
162 m_threads
, m_local_io_ctx
, m_remote_io_ctx
, m_global_image_id
,
163 m_local_mirror_uuid
, m_remote_pool_meta
, m_cache_manager_handler
,
164 m_state_builder
, ctx
);
168 template <typename I
>
169 void BootstrapRequest
<I
>::handle_prepare_remote_image(int r
) {
170 dout(10) << "r=" << r
<< dendl
;
172 auto state_builder
= *m_state_builder
;
173 ceph_assert(state_builder
== nullptr ||
174 !state_builder
->remote_mirror_uuid
.empty());
176 if (state_builder
!= nullptr && state_builder
->is_local_primary()) {
177 dout(5) << "local image is primary" << dendl
;
180 } else if (r
== -EREMOTEIO
) {
181 dout(10) << "remote-image is non-primary" << cpp_strerror(r
) << dendl
;
184 } else if (r
== -ENOENT
|| state_builder
== nullptr) {
185 dout(10) << "remote image does not exist";
186 if (state_builder
!= nullptr) {
188 << "local_image_id=" << state_builder
->local_image_id
<< ", "
189 << "remote_image_id=" << state_builder
->remote_image_id
<< ", "
190 << "is_linked=" << state_builder
->is_linked();
194 // TODO need to support multiple remote images
195 if (state_builder
!= nullptr &&
196 state_builder
->remote_image_id
.empty() &&
197 (state_builder
->local_image_id
.empty() ||
198 state_builder
->is_linked())) {
199 // both images doesn't exist or local image exists and is non-primary
200 // and linked to the missing remote image
207 derr
<< "error retrieving remote image id" << cpp_strerror(r
) << dendl
;
215 template <typename I
>
216 void BootstrapRequest
<I
>::open_remote_image() {
217 ceph_assert(*m_state_builder
!= nullptr);
218 auto remote_image_id
= (*m_state_builder
)->remote_image_id
;
219 dout(15) << "remote_image_id=" << remote_image_id
<< dendl
;
221 update_progress("OPEN_REMOTE_IMAGE");
223 auto ctx
= create_context_callback
<
225 &BootstrapRequest
<I
>::handle_open_remote_image
>(this);
226 ceph_assert(*m_state_builder
!= nullptr);
227 OpenImageRequest
<I
> *request
= OpenImageRequest
<I
>::create(
228 m_remote_io_ctx
, &(*m_state_builder
)->remote_image_ctx
, remote_image_id
,
233 template <typename I
>
234 void BootstrapRequest
<I
>::handle_open_remote_image(int r
) {
235 dout(15) << "r=" << r
<< dendl
;
237 ceph_assert(*m_state_builder
!= nullptr);
239 derr
<< "failed to open remote image: " << cpp_strerror(r
) << dendl
;
240 ceph_assert((*m_state_builder
)->remote_image_ctx
== nullptr);
245 if ((*m_state_builder
)->local_image_id
.empty()) {
246 create_local_image();
253 template <typename I
>
254 void BootstrapRequest
<I
>::open_local_image() {
255 ceph_assert(*m_state_builder
!= nullptr);
256 auto local_image_id
= (*m_state_builder
)->local_image_id
;
258 dout(15) << "local_image_id=" << local_image_id
<< dendl
;
260 update_progress("OPEN_LOCAL_IMAGE");
262 Context
*ctx
= create_context_callback
<
263 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_open_local_image
>(
265 OpenLocalImageRequest
<I
> *request
= OpenLocalImageRequest
<I
>::create(
266 m_local_io_ctx
, &(*m_state_builder
)->local_image_ctx
, local_image_id
,
267 m_threads
->work_queue
, ctx
);
271 template <typename I
>
272 void BootstrapRequest
<I
>::handle_open_local_image(int r
) {
273 dout(15) << "r=" << r
<< dendl
;
275 ceph_assert(*m_state_builder
!= nullptr);
276 auto local_image_ctx
= (*m_state_builder
)->local_image_ctx
;
277 ceph_assert((r
>= 0 && local_image_ctx
!= nullptr) ||
278 (r
< 0 && local_image_ctx
== nullptr));
281 dout(10) << "local image missing" << dendl
;
282 create_local_image();
284 } else if (r
== -EREMOTEIO
) {
285 dout(10) << "local image is primary -- skipping image replay" << dendl
;
287 close_remote_image();
290 derr
<< "failed to open local image: " << cpp_strerror(r
) << dendl
;
292 close_remote_image();
299 template <typename I
>
300 void BootstrapRequest
<I
>::prepare_replay() {
302 update_progress("PREPARE_REPLAY");
304 ceph_assert(*m_state_builder
!= nullptr);
305 auto ctx
= create_context_callback
<
306 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_prepare_replay
>(this);
307 auto request
= (*m_state_builder
)->create_prepare_replay_request(
308 m_local_mirror_uuid
, m_progress_ctx
, m_do_resync
, &m_syncing
, ctx
);
312 template <typename I
>
313 void BootstrapRequest
<I
>::handle_prepare_replay(int r
) {
314 dout(10) << "r=" << r
<< dendl
;
317 if (r
!= -EREMOTEIO
) {
318 derr
<< "failed to prepare local replay: " << cpp_strerror(r
) << dendl
;
321 close_remote_image();
323 } else if (*m_do_resync
) {
324 dout(10) << "local image resync requested" << dendl
;
325 close_remote_image();
327 } else if ((*m_state_builder
)->is_disconnected()) {
328 dout(10) << "client flagged disconnected -- skipping bootstrap" << dendl
;
329 // The caller is expected to detect disconnect initializing remote journal.
331 close_remote_image();
333 } else if (m_syncing
) {
334 dout(10) << "local image still syncing to remote image" << dendl
;
339 close_remote_image();
342 template <typename I
>
343 void BootstrapRequest
<I
>::create_local_image() {
345 update_progress("CREATE_LOCAL_IMAGE");
347 ceph_assert(*m_state_builder
!= nullptr);
348 auto ctx
= create_context_callback
<
350 &BootstrapRequest
<I
>::handle_create_local_image
>(this);
351 auto request
= (*m_state_builder
)->create_local_image_request(
352 m_threads
, m_local_io_ctx
, m_global_image_id
, m_pool_meta_cache
,
353 m_progress_ctx
, ctx
);
357 template <typename I
>
358 void BootstrapRequest
<I
>::handle_create_local_image(int r
) {
359 dout(15) << "r=" << r
<< dendl
;
363 dout(10) << "parent image does not exist" << dendl
;
365 derr
<< "failed to create local image: " << cpp_strerror(r
) << dendl
;
368 close_remote_image();
375 template <typename I
>
376 void BootstrapRequest
<I
>::image_sync() {
377 std::unique_lock locker
{m_lock
};
381 m_ret_val
= -ECANCELED
;
382 dout(10) << "request canceled" << dendl
;
383 close_remote_image();
388 ceph_assert(m_image_sync
== nullptr);
390 auto state_builder
= *m_state_builder
;
391 auto sync_point_handler
= state_builder
->create_sync_point_handler();
393 Context
*ctx
= create_context_callback
<
394 BootstrapRequest
<I
>, &BootstrapRequest
<I
>::handle_image_sync
>(this);
395 m_image_sync
= ImageSync
<I
>::create(
396 m_threads
, state_builder
->local_image_ctx
, state_builder
->remote_image_ctx
,
397 m_local_mirror_uuid
, sync_point_handler
, m_instance_watcher
,
398 m_progress_ctx
, ctx
);
402 update_progress("IMAGE_SYNC");
403 m_image_sync
->send();
406 template <typename I
>
407 void BootstrapRequest
<I
>::handle_image_sync(int r
) {
408 dout(15) << "r=" << r
<< dendl
;
411 std::lock_guard locker
{m_lock
};
413 m_image_sync
= nullptr;
415 (*m_state_builder
)->destroy_sync_point_handler();
419 if (r
== -ECANCELED
) {
420 dout(10) << "request canceled" << dendl
;
422 derr
<< "failed to sync remote image: " << cpp_strerror(r
) << dendl
;
427 close_remote_image();
430 template <typename I
>
431 void BootstrapRequest
<I
>::close_remote_image() {
432 if ((*m_state_builder
)->replay_requires_remote_image()) {
439 update_progress("CLOSE_REMOTE_IMAGE");
441 auto ctx
= create_context_callback
<
443 &BootstrapRequest
<I
>::handle_close_remote_image
>(this);
444 ceph_assert(*m_state_builder
!= nullptr);
445 (*m_state_builder
)->close_remote_image(ctx
);
448 template <typename I
>
449 void BootstrapRequest
<I
>::handle_close_remote_image(int r
) {
450 dout(15) << "r=" << r
<< dendl
;
453 derr
<< "error encountered closing remote image: " << cpp_strerror(r
)
460 template <typename I
>
461 void BootstrapRequest
<I
>::update_progress(const std::string
&description
) {
462 dout(15) << description
<< dendl
;
464 if (m_progress_ctx
) {
465 m_progress_ctx
->update_progress(description
);
469 } // namespace image_replayer
470 } // namespace mirror
473 template class rbd::mirror::image_replayer::BootstrapRequest
<librbd::ImageCtx
>;