1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "common/debug.h"
6 #include "common/errno.h"
7 #include "include/stringify.h"
8 #include "common/Timer.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "json_spirit/json_spirit.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/Operations.h"
14 #include "librbd/Utils.h"
15 #include "librbd/asio/ContextWQ.h"
16 #include "librbd/deep_copy/Handler.h"
17 #include "librbd/deep_copy/ImageCopyRequest.h"
18 #include "librbd/deep_copy/SnapshotCopyRequest.h"
19 #include "librbd/mirror/ImageStateUpdateRequest.h"
20 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
21 #include "librbd/mirror/snapshot/GetImageStateRequest.h"
22 #include "librbd/mirror/snapshot/ImageMeta.h"
23 #include "librbd/mirror/snapshot/UnlinkPeerRequest.h"
24 #include "tools/rbd_mirror/InstanceWatcher.h"
25 #include "tools/rbd_mirror/PoolMetaCache.h"
26 #include "tools/rbd_mirror/Threads.h"
27 #include "tools/rbd_mirror/Types.h"
28 #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
29 #include "tools/rbd_mirror/image_replayer/ReplayerListener.h"
30 #include "tools/rbd_mirror/image_replayer/Utils.h"
31 #include "tools/rbd_mirror/image_replayer/snapshot/ApplyImageStateRequest.h"
32 #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h"
33 #include "tools/rbd_mirror/image_replayer/snapshot/Utils.h"
36 #define dout_context g_ceph_context
37 #define dout_subsys ceph_subsys_rbd_mirror
39 #define dout_prefix *_dout << "rbd::mirror::image_replayer::snapshot::" \
40 << "Replayer: " << this << " " << __func__ << ": "
42 extern PerfCounters
*g_perf_counters
;
46 namespace image_replayer
{
51 double round_to_two_places(double value
) {
52 return abs(round(value
* 100) / 100);
56 std::pair
<uint64_t, librbd::SnapInfo
*> get_newest_mirror_snapshot(
58 for (auto snap_info_it
= image_ctx
->snap_info
.rbegin();
59 snap_info_it
!= image_ctx
->snap_info
.rend(); ++snap_info_it
) {
60 const auto& snap_ns
= snap_info_it
->second
.snap_namespace
;
61 auto mirror_ns
= boost::get
<
62 cls::rbd::MirrorSnapshotNamespace
>(&snap_ns
);
63 if (mirror_ns
== nullptr || !mirror_ns
->complete
) {
67 return {snap_info_it
->first
, &snap_info_it
->second
};
70 return {CEPH_NOSNAP
, nullptr};
73 } // anonymous namespace
75 using librbd::util::create_async_context_callback
;
76 using librbd::util::create_context_callback
;
77 using librbd::util::create_rados_callback
;
80 struct Replayer
<I
>::C_UpdateWatchCtx
: public librbd::UpdateWatchCtx
{
81 Replayer
<I
>* replayer
;
83 C_UpdateWatchCtx(Replayer
<I
>* replayer
) : replayer(replayer
) {
86 void handle_notify() override
{
87 replayer
->handle_image_update_notify();
92 struct Replayer
<I
>::DeepCopyHandler
: public librbd::deep_copy::Handler
{
95 DeepCopyHandler(Replayer
* replayer
) : replayer(replayer
) {
98 void handle_read(uint64_t bytes_read
) override
{
99 replayer
->handle_copy_image_read(bytes_read
);
102 int update_progress(uint64_t object_number
, uint64_t object_count
) override
{
103 replayer
->handle_copy_image_progress(object_number
, object_count
);
108 template <typename I
>
109 Replayer
<I
>::Replayer(
111 InstanceWatcher
<I
>* instance_watcher
,
112 const std::string
& local_mirror_uuid
,
113 PoolMetaCache
* pool_meta_cache
,
114 StateBuilder
<I
>* state_builder
,
115 ReplayerListener
* replayer_listener
)
116 : m_threads(threads
),
117 m_instance_watcher(instance_watcher
),
118 m_local_mirror_uuid(local_mirror_uuid
),
119 m_pool_meta_cache(pool_meta_cache
),
120 m_state_builder(state_builder
),
121 m_replayer_listener(replayer_listener
),
122 m_lock(ceph::make_mutex(librbd::util::unique_lock_name(
123 "rbd::mirror::image_replayer::snapshot::Replayer", this))) {
127 template <typename I
>
128 Replayer
<I
>::~Replayer() {
130 ceph_assert(m_state
== STATE_COMPLETE
);
131 ceph_assert(m_update_watch_ctx
== nullptr);
132 ceph_assert(m_deep_copy_handler
== nullptr);
135 template <typename I
>
136 void Replayer
<I
>::init(Context
* on_finish
) {
139 ceph_assert(m_state
== STATE_INIT
);
141 RemotePoolMeta remote_pool_meta
;
142 int r
= m_pool_meta_cache
->get_remote_pool_meta(
143 m_state_builder
->remote_image_ctx
->md_ctx
.get_id(), &remote_pool_meta
);
144 if (r
< 0 || remote_pool_meta
.mirror_peer_uuid
.empty()) {
145 derr
<< "failed to retrieve mirror peer uuid from remote pool" << dendl
;
146 m_state
= STATE_COMPLETE
;
147 m_threads
->work_queue
->queue(on_finish
, r
);
151 m_remote_mirror_peer_uuid
= remote_pool_meta
.mirror_peer_uuid
;
152 dout(10) << "remote_mirror_peer_uuid=" << m_remote_mirror_peer_uuid
<< dendl
;
154 ceph_assert(m_on_init_shutdown
== nullptr);
155 m_on_init_shutdown
= on_finish
;
157 register_local_update_watcher();
160 template <typename I
>
161 void Replayer
<I
>::shut_down(Context
* on_finish
) {
164 std::unique_lock locker
{m_lock
};
165 ceph_assert(m_on_init_shutdown
== nullptr);
166 m_on_init_shutdown
= on_finish
;
168 m_error_description
= "";
170 ceph_assert(m_state
!= STATE_INIT
);
171 auto state
= STATE_COMPLETE
;
172 std::swap(m_state
, state
);
174 if (state
== STATE_REPLAYING
) {
175 // if a sync request was pending, request a cancelation
176 m_instance_watcher
->cancel_sync_request(
177 m_state_builder
->local_image_ctx
->id
);
179 // TODO interrupt snapshot copy and image copy state machines even if remote
180 // cluster is unreachable
181 dout(10) << "shut down pending on completion of snapshot replay" << dendl
;
186 unregister_remote_update_watcher();
189 template <typename I
>
190 void Replayer
<I
>::flush(Context
* on_finish
) {
194 m_threads
->work_queue
->queue(on_finish
, 0);
197 template <typename I
>
198 bool Replayer
<I
>::get_replay_status(std::string
* description
,
199 Context
* on_finish
) {
202 std::unique_lock locker
{m_lock
};
203 if (m_state
!= STATE_REPLAYING
&& m_state
!= STATE_IDLE
) {
206 derr
<< "replay not running" << dendl
;
207 on_finish
->complete(-EAGAIN
);
211 std::shared_lock local_image_locker
{
212 m_state_builder
->local_image_ctx
->image_lock
};
213 auto [local_snap_id
, local_snap_info
] = get_newest_mirror_snapshot(
214 m_state_builder
->local_image_ctx
);
216 std::shared_lock remote_image_locker
{
217 m_state_builder
->remote_image_ctx
->image_lock
};
218 auto [remote_snap_id
, remote_snap_info
] = get_newest_mirror_snapshot(
219 m_state_builder
->remote_image_ctx
);
221 if (remote_snap_info
== nullptr) {
222 remote_image_locker
.unlock();
223 local_image_locker
.unlock();
226 derr
<< "remote image does not contain mirror snapshots" << dendl
;
227 on_finish
->complete(-EAGAIN
);
231 std::string replay_state
= "idle";
232 if (m_remote_snap_id_end
!= CEPH_NOSNAP
) {
233 replay_state
= "syncing";
236 json_spirit::mObject root_obj
;
237 root_obj
["replay_state"] = replay_state
;
238 root_obj
["remote_snapshot_timestamp"] = remote_snap_info
->timestamp
.sec();
240 auto matching_remote_snap_id
= util::compute_remote_snap_id(
241 m_state_builder
->local_image_ctx
->image_lock
,
242 m_state_builder
->local_image_ctx
->snap_info
,
243 local_snap_id
, m_state_builder
->remote_mirror_uuid
);
244 auto matching_remote_snap_it
=
245 m_state_builder
->remote_image_ctx
->snap_info
.find(matching_remote_snap_id
);
246 if (matching_remote_snap_id
!= CEPH_NOSNAP
&&
247 matching_remote_snap_it
!=
248 m_state_builder
->remote_image_ctx
->snap_info
.end()) {
249 // use the timestamp from the matching remote image since
250 // the local snapshot would just be the time the snapshot was
251 // synced and not the consistency point in time.
252 root_obj
["local_snapshot_timestamp"] =
253 matching_remote_snap_it
->second
.timestamp
.sec();
256 matching_remote_snap_it
= m_state_builder
->remote_image_ctx
->snap_info
.find(
257 m_remote_snap_id_end
);
258 if (m_remote_snap_id_end
!= CEPH_NOSNAP
&&
259 matching_remote_snap_it
!=
260 m_state_builder
->remote_image_ctx
->snap_info
.end()) {
261 root_obj
["syncing_snapshot_timestamp"] = remote_snap_info
->timestamp
.sec();
262 root_obj
["syncing_percent"] = static_cast<uint64_t>(
263 100 * m_local_mirror_snap_ns
.last_copied_object_number
/
264 static_cast<float>(std::max
<uint64_t>(1U, m_local_object_count
)));
267 m_bytes_per_second(0);
268 auto bytes_per_second
= m_bytes_per_second
.get_average();
269 root_obj
["bytes_per_second"] = round_to_two_places(bytes_per_second
);
271 auto bytes_per_snapshot
= boost::accumulators::rolling_mean(
272 m_bytes_per_snapshot
);
273 root_obj
["bytes_per_snapshot"] = round_to_two_places(bytes_per_snapshot
);
275 auto pending_bytes
= bytes_per_snapshot
* m_pending_snapshots
;
276 if (bytes_per_second
> 0 && m_pending_snapshots
> 0) {
277 std::uint64_t seconds_until_synced
= round_to_two_places(
278 pending_bytes
/ bytes_per_second
);
279 if (seconds_until_synced
>= std::numeric_limits
<uint64_t>::max()) {
280 seconds_until_synced
= std::numeric_limits
<uint64_t>::max();
283 root_obj
["seconds_until_synced"] = seconds_until_synced
;
286 *description
= json_spirit::write(
287 root_obj
, json_spirit::remove_trailing_zeros
);
289 local_image_locker
.unlock();
290 remote_image_locker
.unlock();
292 on_finish
->complete(-EEXIST
);
296 template <typename I
>
297 void Replayer
<I
>::load_local_image_meta() {
301 // reset state in case new snapshot is added while we are scanning
302 std::unique_lock locker
{m_lock
};
303 m_image_updated
= false;
306 ceph_assert(m_state_builder
->local_image_meta
!= nullptr);
307 auto ctx
= create_context_callback
<
308 Replayer
<I
>, &Replayer
<I
>::handle_load_local_image_meta
>(this);
309 m_state_builder
->local_image_meta
->load(ctx
);
312 template <typename I
>
313 void Replayer
<I
>::handle_load_local_image_meta(int r
) {
314 dout(10) << "r=" << r
<< dendl
;
316 if (r
< 0 && r
!= -ENOENT
) {
317 derr
<< "failed to load local image-meta: " << cpp_strerror(r
) << dendl
;
318 handle_replay_complete(r
, "failed to load local image-meta");
322 if (r
>= 0 && m_state_builder
->local_image_meta
->resync_requested
) {
323 m_resync_requested
= true;
325 dout(10) << "local image resync requested" << dendl
;
326 handle_replay_complete(0, "resync requested");
330 refresh_local_image();
333 template <typename I
>
334 void Replayer
<I
>::refresh_local_image() {
335 if (!m_state_builder
->local_image_ctx
->state
->is_refresh_required()) {
336 refresh_remote_image();
341 auto ctx
= create_context_callback
<
342 Replayer
<I
>, &Replayer
<I
>::handle_refresh_local_image
>(this);
343 m_state_builder
->local_image_ctx
->state
->refresh(ctx
);
346 template <typename I
>
347 void Replayer
<I
>::handle_refresh_local_image(int r
) {
348 dout(10) << "r=" << r
<< dendl
;
351 derr
<< "failed to refresh local image: " << cpp_strerror(r
) << dendl
;
352 handle_replay_complete(r
, "failed to refresh local image");
356 refresh_remote_image();
359 template <typename I
>
360 void Replayer
<I
>::refresh_remote_image() {
361 if (!m_state_builder
->remote_image_ctx
->state
->is_refresh_required()) {
362 std::unique_lock locker
{m_lock
};
363 scan_local_mirror_snapshots(&locker
);
368 auto ctx
= create_context_callback
<
369 Replayer
<I
>, &Replayer
<I
>::handle_refresh_remote_image
>(this);
370 m_state_builder
->remote_image_ctx
->state
->refresh(ctx
);
373 template <typename I
>
374 void Replayer
<I
>::handle_refresh_remote_image(int r
) {
375 dout(10) << "r=" << r
<< dendl
;
378 derr
<< "failed to refresh remote image: " << cpp_strerror(r
) << dendl
;
379 handle_replay_complete(r
, "failed to refresh remote image");
383 std::unique_lock locker
{m_lock
};
384 scan_local_mirror_snapshots(&locker
);
387 template <typename I
>
388 void Replayer
<I
>::scan_local_mirror_snapshots(
389 std::unique_lock
<ceph::mutex
>* locker
) {
390 if (is_replay_interrupted(locker
)) {
396 m_local_snap_id_start
= 0;
397 m_local_snap_id_end
= CEPH_NOSNAP
;
398 m_local_mirror_snap_ns
= {};
399 m_local_object_count
= 0;
401 m_remote_snap_id_start
= 0;
402 m_remote_snap_id_end
= CEPH_NOSNAP
;
403 m_remote_mirror_snap_ns
= {};
405 std::set
<uint64_t> prune_snap_ids
;
407 bool completed_non_primary_snapshots_exist
= false;
408 auto local_image_ctx
= m_state_builder
->local_image_ctx
;
409 std::shared_lock image_locker
{local_image_ctx
->image_lock
};
410 for (auto snap_info_it
= local_image_ctx
->snap_info
.begin();
411 snap_info_it
!= local_image_ctx
->snap_info
.end(); ++snap_info_it
) {
412 const auto& snap_ns
= snap_info_it
->second
.snap_namespace
;
413 auto mirror_ns
= boost::get
<
414 cls::rbd::MirrorSnapshotNamespace
>(&snap_ns
);
415 if (mirror_ns
== nullptr) {
419 dout(15) << "local mirror snapshot: id=" << snap_info_it
->first
<< ", "
420 << "mirror_ns=" << *mirror_ns
<< dendl
;
421 m_local_mirror_snap_ns
= *mirror_ns
;
423 auto local_snap_id
= snap_info_it
->first
;
424 if (mirror_ns
->is_non_primary()) {
425 if (mirror_ns
->complete
) {
426 // if remote has new snapshots, we would sync from here
427 m_local_snap_id_start
= local_snap_id
;
428 m_local_snap_id_end
= CEPH_NOSNAP
;
429 completed_non_primary_snapshots_exist
= true;
431 if (mirror_ns
->mirror_peer_uuids
.empty()) {
432 // no other peer will attempt to sync to this snapshot so store as
433 // a candidate for removal
434 prune_snap_ids
.insert(local_snap_id
);
436 } else if (mirror_ns
->last_copied_object_number
== 0 &&
437 m_local_snap_id_start
> 0) {
438 // shouldn't be possible, but ensure that pruning this snapshot
439 // wouldn't leave this image w/o any non-primary snapshots
440 if (!completed_non_primary_snapshots_exist
) {
441 derr
<< "incomplete local non-primary snapshot" << dendl
;
442 handle_replay_complete(locker
, -EINVAL
,
443 "incomplete local non-primary snapshot");
447 // snapshot might be missing image state, object-map, etc, so just
448 // delete and re-create it if we haven't started copying data
449 // objects. Also only prune this snapshot since we will need the
450 // previous mirror snapshot for syncing. Special case exception for
451 // the first non-primary snapshot since we know its snapshot is
452 // well-formed because otherwise the mirror-image-state would have
453 // forced an image deletion.
454 prune_snap_ids
.clear();
455 prune_snap_ids
.insert(local_snap_id
);
458 // start snap will be last complete mirror snapshot or initial
460 m_local_snap_id_end
= local_snap_id
;
463 } else if (mirror_ns
->is_primary()) {
464 if (mirror_ns
->complete
) {
465 m_local_snap_id_start
= local_snap_id
;
466 m_local_snap_id_end
= CEPH_NOSNAP
;
468 derr
<< "incomplete local primary snapshot" << dendl
;
469 handle_replay_complete(locker
, -EINVAL
,
470 "incomplete local primary snapshot");
474 derr
<< "unknown local mirror snapshot state" << dendl
;
475 handle_replay_complete(locker
, -EINVAL
,
476 "invalid local mirror snapshot state");
480 image_locker
.unlock();
482 if (m_local_snap_id_start
> 0 && m_local_snap_id_end
== CEPH_NOSNAP
) {
483 // remove candidate that is required for delta snapshot sync
484 prune_snap_ids
.erase(m_local_snap_id_start
);
486 if (!prune_snap_ids
.empty()) {
489 auto prune_snap_id
= *prune_snap_ids
.begin();
490 dout(5) << "pruning unused non-primary snapshot " << prune_snap_id
<< dendl
;
491 prune_non_primary_snapshot(prune_snap_id
);
495 if (m_local_snap_id_start
> 0 || m_local_snap_id_end
!= CEPH_NOSNAP
) {
496 if (m_local_mirror_snap_ns
.is_non_primary() &&
497 m_local_mirror_snap_ns
.primary_mirror_uuid
!=
498 m_state_builder
->remote_mirror_uuid
) {
499 // TODO support multiple peers
500 derr
<< "local image linked to unknown peer: "
501 << m_local_mirror_snap_ns
.primary_mirror_uuid
<< dendl
;
502 handle_replay_complete(locker
, -EEXIST
,
503 "local image linked to unknown peer");
505 } else if (m_local_mirror_snap_ns
.state
==
506 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY
) {
507 dout(5) << "local image promoted" << dendl
;
508 handle_replay_complete(locker
, 0, "force promoted");
512 dout(10) << "found local mirror snapshot: "
513 << "local_snap_id_start=" << m_local_snap_id_start
<< ", "
514 << "local_snap_id_end=" << m_local_snap_id_end
<< ", "
515 << "local_snap_ns=" << m_local_mirror_snap_ns
<< dendl
;
516 if (!m_local_mirror_snap_ns
.is_primary() &&
517 m_local_mirror_snap_ns
.complete
) {
518 // our remote sync should start after this completed snapshot
519 m_remote_snap_id_start
= m_local_mirror_snap_ns
.primary_snap_id
;
523 // we don't have any mirror snapshots or only completed non-primary
525 scan_remote_mirror_snapshots(locker
);
528 template <typename I
>
529 void Replayer
<I
>::scan_remote_mirror_snapshots(
530 std::unique_lock
<ceph::mutex
>* locker
) {
533 m_pending_snapshots
= 0;
535 std::set
<uint64_t> unlink_snap_ids
;
536 bool split_brain
= false;
537 bool remote_demoted
= false;
538 auto remote_image_ctx
= m_state_builder
->remote_image_ctx
;
539 std::shared_lock image_locker
{remote_image_ctx
->image_lock
};
540 for (auto snap_info_it
= remote_image_ctx
->snap_info
.begin();
541 snap_info_it
!= remote_image_ctx
->snap_info
.end(); ++snap_info_it
) {
542 const auto& snap_ns
= snap_info_it
->second
.snap_namespace
;
543 auto mirror_ns
= boost::get
<
544 cls::rbd::MirrorSnapshotNamespace
>(&snap_ns
);
545 if (mirror_ns
== nullptr) {
549 dout(15) << "remote mirror snapshot: id=" << snap_info_it
->first
<< ", "
550 << "mirror_ns=" << *mirror_ns
<< dendl
;
551 remote_demoted
= mirror_ns
->is_demoted();
552 if (!mirror_ns
->is_primary() && !mirror_ns
->is_non_primary()) {
553 derr
<< "unknown remote mirror snapshot state" << dendl
;
554 handle_replay_complete(locker
, -EINVAL
,
555 "invalid remote mirror snapshot state");
557 } else if (mirror_ns
->mirror_peer_uuids
.count(m_remote_mirror_peer_uuid
) ==
559 dout(15) << "skipping remote snapshot due to missing mirror peer"
564 auto remote_snap_id
= snap_info_it
->first
;
565 if (m_local_snap_id_start
> 0 || m_local_snap_id_end
!= CEPH_NOSNAP
) {
566 // we have a local mirror snapshot
567 if (m_local_mirror_snap_ns
.is_non_primary()) {
568 // previously validated that it was linked to remote
569 ceph_assert(m_local_mirror_snap_ns
.primary_mirror_uuid
==
570 m_state_builder
->remote_mirror_uuid
);
572 if (m_remote_snap_id_end
== CEPH_NOSNAP
) {
573 // haven't found the end snap so treat this as a candidate for unlink
574 unlink_snap_ids
.insert(remote_snap_id
);
576 if (m_local_mirror_snap_ns
.complete
&&
577 m_local_mirror_snap_ns
.primary_snap_id
>= remote_snap_id
) {
578 // skip past completed remote snapshot
579 m_remote_snap_id_start
= remote_snap_id
;
580 m_remote_mirror_snap_ns
= *mirror_ns
;
581 dout(15) << "skipping synced remote snapshot " << remote_snap_id
584 } else if (!m_local_mirror_snap_ns
.complete
&&
585 m_local_mirror_snap_ns
.primary_snap_id
> remote_snap_id
) {
586 // skip until we get to the in-progress remote snapshot
587 dout(15) << "skipping synced remote snapshot " << remote_snap_id
588 << " while search for in-progress sync" << dendl
;
589 m_remote_snap_id_start
= remote_snap_id
;
590 m_remote_mirror_snap_ns
= *mirror_ns
;
593 } else if (m_local_mirror_snap_ns
.state
==
594 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED
) {
595 // find the matching demotion snapshot in remote image
596 ceph_assert(m_local_snap_id_start
> 0);
597 if (mirror_ns
->state
==
598 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED
&&
599 mirror_ns
->primary_mirror_uuid
== m_local_mirror_uuid
&&
600 mirror_ns
->primary_snap_id
== m_local_snap_id_start
) {
601 dout(10) << "located matching demotion snapshot: "
602 << "remote_snap_id=" << remote_snap_id
<< ", "
603 << "local_snap_id=" << m_local_snap_id_start
<< dendl
;
604 m_remote_snap_id_start
= remote_snap_id
;
607 } else if (m_remote_snap_id_start
== 0) {
608 // still looking for our matching demotion snapshot
609 dout(15) << "skipping remote snapshot " << remote_snap_id
<< " "
610 << "while searching for demotion" << dendl
;
615 // should not have been able to reach this
618 } else if (!mirror_ns
->is_primary()) {
619 dout(15) << "skipping non-primary remote snapshot" << dendl
;
623 // found candidate snapshot to sync
624 ++m_pending_snapshots
;
625 if (m_remote_snap_id_end
!= CEPH_NOSNAP
) {
629 // first primary snapshot where were are listed as a peer
630 m_remote_snap_id_end
= remote_snap_id
;
631 m_remote_mirror_snap_ns
= *mirror_ns
;
634 if (m_remote_snap_id_start
!= 0 &&
635 remote_image_ctx
->snap_info
.count(m_remote_snap_id_start
) == 0) {
636 // the remote start snapshot was deleted out from under us
637 derr
<< "failed to locate remote start snapshot: "
638 << "snap_id=" << m_remote_snap_id_start
<< dendl
;
642 image_locker
.unlock();
645 unlink_snap_ids
.erase(m_remote_snap_id_start
);
646 unlink_snap_ids
.erase(m_remote_snap_id_end
);
647 if (!unlink_snap_ids
.empty()) {
650 // retry the unlinking process for a remote snapshot that we do not
652 auto remote_snap_id
= *unlink_snap_ids
.begin();
653 dout(10) << "unlinking from remote snapshot " << remote_snap_id
<< dendl
;
654 unlink_peer(remote_snap_id
);
658 if (m_remote_snap_id_end
!= CEPH_NOSNAP
) {
659 dout(10) << "found remote mirror snapshot: "
660 << "remote_snap_id_start=" << m_remote_snap_id_start
<< ", "
661 << "remote_snap_id_end=" << m_remote_snap_id_end
<< ", "
662 << "remote_snap_ns=" << m_remote_mirror_snap_ns
<< dendl
;
663 if (m_remote_mirror_snap_ns
.complete
) {
666 if (m_local_snap_id_end
!= CEPH_NOSNAP
&&
667 !m_local_mirror_snap_ns
.complete
) {
668 // attempt to resume image-sync
669 dout(10) << "local image contains in-progress mirror snapshot"
671 get_local_image_state();
677 // might have raced with the creation of a remote mirror snapshot
678 // so we will need to refresh and rescan once it completes
679 dout(15) << "remote mirror snapshot not complete" << dendl
;
684 if (m_image_updated
) {
685 // received update notification while scanning image, restart ...
686 m_image_updated
= false;
689 dout(10) << "restarting snapshot scan due to remote update notification"
691 load_local_image_meta();
695 if (is_replay_interrupted(locker
)) {
697 } else if (split_brain
) {
698 derr
<< "split-brain detected: failed to find matching non-primary "
699 << "snapshot in remote image: "
700 << "local_snap_id_start=" << m_local_snap_id_start
<< ", "
701 << "local_snap_ns=" << m_local_mirror_snap_ns
<< dendl
;
702 handle_replay_complete(locker
, -EEXIST
, "split-brain");
704 } else if (remote_demoted
) {
705 dout(10) << "remote image demoted" << dendl
;
706 handle_replay_complete(locker
, -EREMOTEIO
, "remote image demoted");
710 dout(10) << "all remote snapshots synced: idling waiting for new snapshot"
712 ceph_assert(m_state
== STATE_REPLAYING
);
713 m_state
= STATE_IDLE
;
715 notify_status_updated();
718 template <typename I
>
719 void Replayer
<I
>::prune_non_primary_snapshot(uint64_t snap_id
) {
720 dout(10) << "snap_id=" << snap_id
<< dendl
;
722 auto local_image_ctx
= m_state_builder
->local_image_ctx
;
723 bool snap_valid
= false;
724 cls::rbd::SnapshotNamespace snap_namespace
;
725 std::string snap_name
;
728 std::shared_lock image_locker
{local_image_ctx
->image_lock
};
729 auto snap_info
= local_image_ctx
->get_snap_info(snap_id
);
730 if (snap_info
!= nullptr) {
732 snap_namespace
= snap_info
->snap_namespace
;
733 snap_name
= snap_info
->name
;
735 ceph_assert(boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
736 &snap_namespace
) != nullptr);
741 load_local_image_meta();
745 auto ctx
= create_context_callback
<
746 Replayer
<I
>, &Replayer
<I
>::handle_prune_non_primary_snapshot
>(this);
747 local_image_ctx
->operations
->snap_remove(snap_namespace
, snap_name
, ctx
);
750 template <typename I
>
751 void Replayer
<I
>::handle_prune_non_primary_snapshot(int r
) {
752 dout(10) << "r=" << r
<< dendl
;
754 if (r
< 0 && r
!= -ENOENT
) {
755 derr
<< "failed to prune non-primary snapshot: " << cpp_strerror(r
)
757 handle_replay_complete(r
, "failed to prune non-primary snapshot");
761 if (is_replay_interrupted()) {
765 load_local_image_meta();
768 template <typename I
>
769 void Replayer
<I
>::copy_snapshots() {
770 dout(10) << "remote_snap_id_start=" << m_remote_snap_id_start
<< ", "
771 << "remote_snap_id_end=" << m_remote_snap_id_end
<< ", "
772 << "local_snap_id_start=" << m_local_snap_id_start
<< dendl
;
774 ceph_assert(m_remote_snap_id_start
!= CEPH_NOSNAP
);
775 ceph_assert(m_remote_snap_id_end
> 0 &&
776 m_remote_snap_id_end
!= CEPH_NOSNAP
);
777 ceph_assert(m_local_snap_id_start
!= CEPH_NOSNAP
);
779 m_local_mirror_snap_ns
= {};
780 auto ctx
= create_context_callback
<
781 Replayer
<I
>, &Replayer
<I
>::handle_copy_snapshots
>(this);
782 auto req
= librbd::deep_copy::SnapshotCopyRequest
<I
>::create(
783 m_state_builder
->remote_image_ctx
, m_state_builder
->local_image_ctx
,
784 m_remote_snap_id_start
, m_remote_snap_id_end
, m_local_snap_id_start
,
785 false, m_threads
->work_queue
, &m_local_mirror_snap_ns
.snap_seqs
,
790 template <typename I
>
791 void Replayer
<I
>::handle_copy_snapshots(int r
) {
792 dout(10) << "r=" << r
<< dendl
;
795 derr
<< "failed to copy snapshots from remote to local image: "
796 << cpp_strerror(r
) << dendl
;
797 handle_replay_complete(
798 r
, "failed to copy snapshots from remote to local image");
802 dout(10) << "remote_snap_id_start=" << m_remote_snap_id_start
<< ", "
803 << "remote_snap_id_end=" << m_remote_snap_id_end
<< ", "
804 << "local_snap_id_start=" << m_local_snap_id_start
<< ", "
805 << "snap_seqs=" << m_local_mirror_snap_ns
.snap_seqs
<< dendl
;
806 get_remote_image_state();
809 template <typename I
>
810 void Replayer
<I
>::get_remote_image_state() {
813 auto ctx
= create_context_callback
<
814 Replayer
<I
>, &Replayer
<I
>::handle_get_remote_image_state
>(this);
815 auto req
= librbd::mirror::snapshot::GetImageStateRequest
<I
>::create(
816 m_state_builder
->remote_image_ctx
, m_remote_snap_id_end
,
817 &m_image_state
, ctx
);
821 template <typename I
>
822 void Replayer
<I
>::handle_get_remote_image_state(int r
) {
823 dout(10) << "r=" << r
<< dendl
;
826 derr
<< "failed to retrieve remote snapshot image state: "
827 << cpp_strerror(r
) << dendl
;
828 handle_replay_complete(r
, "failed to retrieve remote snapshot image state");
832 create_non_primary_snapshot();
835 template <typename I
>
836 void Replayer
<I
>::get_local_image_state() {
839 ceph_assert(m_local_snap_id_end
!= CEPH_NOSNAP
);
840 auto ctx
= create_context_callback
<
841 Replayer
<I
>, &Replayer
<I
>::handle_get_local_image_state
>(this);
842 auto req
= librbd::mirror::snapshot::GetImageStateRequest
<I
>::create(
843 m_state_builder
->local_image_ctx
, m_local_snap_id_end
,
844 &m_image_state
, ctx
);
848 template <typename I
>
849 void Replayer
<I
>::handle_get_local_image_state(int r
) {
850 dout(10) << "r=" << r
<< dendl
;
853 derr
<< "failed to retrieve local snapshot image state: "
854 << cpp_strerror(r
) << dendl
;
855 handle_replay_complete(r
, "failed to retrieve local snapshot image state");
862 template <typename I
>
863 void Replayer
<I
>::create_non_primary_snapshot() {
864 auto local_image_ctx
= m_state_builder
->local_image_ctx
;
866 if (m_local_snap_id_start
> 0) {
867 std::shared_lock local_image_locker
{local_image_ctx
->image_lock
};
869 auto local_snap_info_it
= local_image_ctx
->snap_info
.find(
870 m_local_snap_id_start
);
871 if (local_snap_info_it
== local_image_ctx
->snap_info
.end()) {
872 local_image_locker
.unlock();
874 derr
<< "failed to locate local snapshot " << m_local_snap_id_start
876 handle_replay_complete(-ENOENT
, "failed to locate local start snapshot");
880 auto mirror_ns
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
881 &local_snap_info_it
->second
.snap_namespace
);
882 ceph_assert(mirror_ns
!= nullptr);
884 auto remote_image_ctx
= m_state_builder
->remote_image_ctx
;
885 std::shared_lock remote_image_locker
{remote_image_ctx
->image_lock
};
887 // (re)build a full mapping from remote to local snap ids for all user
888 // snapshots to support applying image state in the future
889 for (auto& [remote_snap_id
, remote_snap_info
] :
890 remote_image_ctx
->snap_info
) {
891 if (remote_snap_id
>= m_remote_snap_id_end
) {
895 // we can ignore all non-user snapshots since image state only includes
897 if (boost::get
<cls::rbd::UserSnapshotNamespace
>(
898 &remote_snap_info
.snap_namespace
) == nullptr) {
902 uint64_t local_snap_id
= CEPH_NOSNAP
;
903 if (mirror_ns
->is_demoted() && !m_remote_mirror_snap_ns
.is_demoted()) {
904 // if we are creating a non-primary snapshot following a demotion,
905 // re-build the full snapshot sequence since we don't have a valid
907 auto local_snap_id_it
= local_image_ctx
->snap_ids
.find(
908 {remote_snap_info
.snap_namespace
, remote_snap_info
.name
});
909 if (local_snap_id_it
!= local_image_ctx
->snap_ids
.end()) {
910 local_snap_id
= local_snap_id_it
->second
;
913 auto snap_seq_it
= mirror_ns
->snap_seqs
.find(remote_snap_id
);
914 if (snap_seq_it
!= mirror_ns
->snap_seqs
.end()) {
915 local_snap_id
= snap_seq_it
->second
;
919 if (m_local_mirror_snap_ns
.snap_seqs
.count(remote_snap_id
) == 0 &&
920 local_snap_id
!= CEPH_NOSNAP
) {
921 dout(15) << "mapping remote snapshot " << remote_snap_id
<< " to "
922 << "local snapshot " << local_snap_id
<< dendl
;
923 m_local_mirror_snap_ns
.snap_seqs
[remote_snap_id
] = local_snap_id
;
928 dout(10) << "demoted=" << m_remote_mirror_snap_ns
.is_demoted() << ", "
929 << "primary_mirror_uuid="
930 << m_state_builder
->remote_mirror_uuid
<< ", "
931 << "primary_snap_id=" << m_remote_snap_id_end
<< ", "
932 << "snap_seqs=" << m_local_mirror_snap_ns
.snap_seqs
<< dendl
;
934 auto ctx
= create_context_callback
<
935 Replayer
<I
>, &Replayer
<I
>::handle_create_non_primary_snapshot
>(this);
936 auto req
= librbd::mirror::snapshot::CreateNonPrimaryRequest
<I
>::create(
937 local_image_ctx
, m_remote_mirror_snap_ns
.is_demoted(),
938 m_state_builder
->remote_mirror_uuid
, m_remote_snap_id_end
,
939 m_local_mirror_snap_ns
.snap_seqs
, m_image_state
, &m_local_snap_id_end
, ctx
);
943 template <typename I
>
944 void Replayer
<I
>::handle_create_non_primary_snapshot(int r
) {
945 dout(10) << "r=" << r
<< dendl
;
948 derr
<< "failed to create local mirror snapshot: " << cpp_strerror(r
)
950 handle_replay_complete(r
, "failed to create local mirror snapshot");
954 dout(15) << "local_snap_id_end=" << m_local_snap_id_end
<< dendl
;
956 update_mirror_image_state();
959 template <typename I
>
960 void Replayer
<I
>::update_mirror_image_state() {
961 if (m_local_snap_id_start
> 0) {
966 // a newly created non-primary image has a local mirror state of CREATING
967 // until this point so that we could avoid preserving the image until
968 // the first non-primary snapshot linked the two images together.
970 auto ctx
= create_context_callback
<
971 Replayer
<I
>, &Replayer
<I
>::handle_update_mirror_image_state
>(this);
972 auto req
= librbd::mirror::ImageStateUpdateRequest
<I
>::create(
973 m_state_builder
->local_image_ctx
->md_ctx
,
974 m_state_builder
->local_image_ctx
->id
,
975 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
, {}, ctx
);
979 template <typename I
>
980 void Replayer
<I
>::handle_update_mirror_image_state(int r
) {
981 dout(10) << "r=" << r
<< dendl
;
984 derr
<< "failed to update local mirror image state: " << cpp_strerror(r
)
986 handle_replay_complete(r
, "failed to update local mirror image state");
993 template <typename I
>
994 void Replayer
<I
>::request_sync() {
995 if (m_remote_mirror_snap_ns
.clean_since_snap_id
== m_remote_snap_id_start
) {
996 dout(10) << "skipping unnecessary image copy: "
997 << "remote_snap_id_start=" << m_remote_snap_id_start
<< ", "
998 << "remote_mirror_snap_ns=" << m_remote_mirror_snap_ns
<< dendl
;
1004 std::unique_lock locker
{m_lock
};
1005 if (is_replay_interrupted(&locker
)) {
1009 auto ctx
= create_async_context_callback(
1010 m_threads
->work_queue
, create_context_callback
<
1011 Replayer
<I
>, &Replayer
<I
>::handle_request_sync
>(this));
1012 m_instance_watcher
->notify_sync_request(m_state_builder
->local_image_ctx
->id
,
1016 template <typename I
>
1017 void Replayer
<I
>::handle_request_sync(int r
) {
1018 dout(10) << "r=" << r
<< dendl
;
1020 std::unique_lock locker
{m_lock
};
1021 if (is_replay_interrupted(&locker
)) {
1023 } else if (r
== -ECANCELED
) {
1024 dout(5) << "image-sync canceled" << dendl
;
1025 handle_replay_complete(&locker
, r
, "image-sync canceled");
1028 derr
<< "failed to request image-sync: " << cpp_strerror(r
) << dendl
;
1029 handle_replay_complete(&locker
, r
, "failed to request image-sync");
1033 m_sync_in_progress
= true;
1039 template <typename I
>
1040 void Replayer
<I
>::copy_image() {
1041 dout(10) << "remote_snap_id_start=" << m_remote_snap_id_start
<< ", "
1042 << "remote_snap_id_end=" << m_remote_snap_id_end
<< ", "
1043 << "local_snap_id_start=" << m_local_snap_id_start
<< ", "
1044 << "last_copied_object_number="
1045 << m_local_mirror_snap_ns
.last_copied_object_number
<< ", "
1046 << "snap_seqs=" << m_local_mirror_snap_ns
.snap_seqs
<< dendl
;
1048 m_snapshot_bytes
= 0;
1049 m_deep_copy_handler
= new DeepCopyHandler(this);
1050 auto ctx
= create_context_callback
<
1051 Replayer
<I
>, &Replayer
<I
>::handle_copy_image
>(this);
1052 auto req
= librbd::deep_copy::ImageCopyRequest
<I
>::create(
1053 m_state_builder
->remote_image_ctx
, m_state_builder
->local_image_ctx
,
1054 m_remote_snap_id_start
, m_remote_snap_id_end
, m_local_snap_id_start
, false,
1055 (m_local_mirror_snap_ns
.last_copied_object_number
> 0 ?
1056 librbd::deep_copy::ObjectNumber
{
1057 m_local_mirror_snap_ns
.last_copied_object_number
} :
1058 librbd::deep_copy::ObjectNumber
{}),
1059 m_local_mirror_snap_ns
.snap_seqs
, m_deep_copy_handler
, ctx
);
1063 template <typename I
>
1064 void Replayer
<I
>::handle_copy_image(int r
) {
1065 dout(10) << "r=" << r
<< dendl
;
1067 delete m_deep_copy_handler
;
1068 m_deep_copy_handler
= nullptr;
1071 derr
<< "failed to copy remote image to local image: " << cpp_strerror(r
)
1073 handle_replay_complete(r
, "failed to copy remote image");
1078 std::unique_lock locker
{m_lock
};
1079 m_bytes_per_snapshot(m_snapshot_bytes
);
1080 m_snapshot_bytes
= 0;
1083 apply_image_state();
1086 template <typename I
>
1087 void Replayer
<I
>::handle_copy_image_progress(uint64_t object_number
,
1088 uint64_t object_count
) {
1089 dout(10) << "object_number=" << object_number
<< ", "
1090 << "object_count=" << object_count
<< dendl
;
1092 std::unique_lock locker
{m_lock
};
1093 m_local_mirror_snap_ns
.last_copied_object_number
= std::min(
1094 object_number
, object_count
);
1095 m_local_object_count
= object_count
;
1097 update_non_primary_snapshot(false);
1100 template <typename I
>
1101 void Replayer
<I
>::handle_copy_image_read(uint64_t bytes_read
) {
1102 dout(20) << "bytes_read=" << bytes_read
<< dendl
;
1104 std::unique_lock locker
{m_lock
};
1105 m_bytes_per_second(bytes_read
);
1106 m_snapshot_bytes
+= bytes_read
;
1109 template <typename I
>
1110 void Replayer
<I
>::apply_image_state() {
1113 auto ctx
= create_context_callback
<
1114 Replayer
<I
>, &Replayer
<I
>::handle_apply_image_state
>(this);
1115 auto req
= ApplyImageStateRequest
<I
>::create(
1116 m_local_mirror_uuid
,
1117 m_state_builder
->remote_mirror_uuid
,
1118 m_state_builder
->local_image_ctx
,
1119 m_state_builder
->remote_image_ctx
,
1120 m_image_state
, ctx
);
1124 template <typename I
>
1125 void Replayer
<I
>::handle_apply_image_state(int r
) {
1126 dout(10) << "r=" << r
<< dendl
;
1128 if (r
< 0 && r
!= -ENOENT
) {
1129 derr
<< "failed to apply remote image state to local image: "
1130 << cpp_strerror(r
) << dendl
;
1131 handle_replay_complete(r
, "failed to apply remote image state");
1135 std::unique_lock locker
{m_lock
};
1136 update_non_primary_snapshot(true);
1139 template <typename I
>
1140 void Replayer
<I
>::update_non_primary_snapshot(bool complete
) {
1141 ceph_assert(ceph_mutex_is_locked_by_me(m_lock
));
1143 // disallow two in-flight updates if this isn't the completion of the sync
1144 if (m_updating_sync_point
) {
1147 m_updating_sync_point
= true;
1149 m_local_mirror_snap_ns
.complete
= true;
1154 librados::ObjectWriteOperation op
;
1155 librbd::cls_client::mirror_image_snapshot_set_copy_progress(
1156 &op
, m_local_snap_id_end
, m_local_mirror_snap_ns
.complete
,
1157 m_local_mirror_snap_ns
.last_copied_object_number
);
1159 auto ctx
= new C_TrackedOp(
1160 m_in_flight_op_tracker
, new LambdaContext([this, complete
](int r
) {
1161 handle_update_non_primary_snapshot(complete
, r
);
1163 auto aio_comp
= create_rados_callback(ctx
);
1164 int r
= m_state_builder
->local_image_ctx
->md_ctx
.aio_operate(
1165 m_state_builder
->local_image_ctx
->header_oid
, aio_comp
, &op
);
1166 ceph_assert(r
== 0);
1167 aio_comp
->release();
1170 template <typename I
>
1171 void Replayer
<I
>::handle_update_non_primary_snapshot(bool complete
, int r
) {
1172 dout(10) << "r=" << r
<< dendl
;
1175 derr
<< "failed to update local snapshot progress: " << cpp_strerror(r
)
1178 // only fail if this was the final update
1179 handle_replay_complete(r
, "failed to update local snapshot progress");
1185 // periodic sync-point update -- do not advance state machine
1186 std::unique_lock locker
{m_lock
};
1188 ceph_assert(m_updating_sync_point
);
1189 m_updating_sync_point
= false;
1193 notify_image_update();
1196 template <typename I
>
1197 void Replayer
<I
>::notify_image_update() {
1200 auto ctx
= create_context_callback
<
1201 Replayer
<I
>, &Replayer
<I
>::handle_notify_image_update
>(this);
1202 m_state_builder
->local_image_ctx
->notify_update(ctx
);
1205 template <typename I
>
1206 void Replayer
<I
>::handle_notify_image_update(int r
) {
1207 dout(10) << "r=" << r
<< dendl
;
1210 derr
<< "failed to notify local image update: " << cpp_strerror(r
) << dendl
;
1213 unlink_peer(m_remote_snap_id_start
);
1216 template <typename I
>
1217 void Replayer
<I
>::unlink_peer(uint64_t remote_snap_id
) {
1218 if (remote_snap_id
== 0) {
1223 // local snapshot fully synced -- we no longer depend on the sync
1224 // start snapshot in the remote image
1225 dout(10) << "remote_snap_id=" << remote_snap_id
<< dendl
;
1227 auto ctx
= create_context_callback
<
1228 Replayer
<I
>, &Replayer
<I
>::handle_unlink_peer
>(this);
1229 auto req
= librbd::mirror::snapshot::UnlinkPeerRequest
<I
>::create(
1230 m_state_builder
->remote_image_ctx
, remote_snap_id
,
1231 m_remote_mirror_peer_uuid
, ctx
);
1235 template <typename I
>
1236 void Replayer
<I
>::handle_unlink_peer(int r
) {
1237 dout(10) << "r=" << r
<< dendl
;
1239 if (r
< 0 && r
!= -ENOENT
) {
1240 derr
<< "failed to unlink local peer from remote image: " << cpp_strerror(r
)
1242 handle_replay_complete(r
, "failed to unlink local peer from remote image");
1249 template <typename I
>
1250 void Replayer
<I
>::finish_sync() {
1254 std::unique_lock locker
{m_lock
};
1255 notify_status_updated();
1257 if (m_sync_in_progress
) {
1258 m_sync_in_progress
= false;
1259 m_instance_watcher
->notify_sync_complete(
1260 m_state_builder
->local_image_ctx
->id
);
1264 if (is_replay_interrupted()) {
1268 load_local_image_meta();
1271 template <typename I
>
1272 void Replayer
<I
>::register_local_update_watcher() {
1275 m_update_watch_ctx
= new C_UpdateWatchCtx(this);
1277 int r
= m_state_builder
->local_image_ctx
->state
->register_update_watcher(
1278 m_update_watch_ctx
, &m_local_update_watcher_handle
);
1279 auto ctx
= create_context_callback
<
1280 Replayer
<I
>, &Replayer
<I
>::handle_register_local_update_watcher
>(this);
1281 m_threads
->work_queue
->queue(ctx
, r
);
1284 template <typename I
>
1285 void Replayer
<I
>::handle_register_local_update_watcher(int r
) {
1286 dout(10) << "r=" << r
<< dendl
;
1289 derr
<< "failed to register local update watcher: " << cpp_strerror(r
)
1291 handle_replay_complete(r
, "failed to register local image update watcher");
1292 m_state
= STATE_COMPLETE
;
1294 delete m_update_watch_ctx
;
1295 m_update_watch_ctx
= nullptr;
1297 Context
* on_init
= nullptr;
1298 std::swap(on_init
, m_on_init_shutdown
);
1299 on_init
->complete(r
);
1303 register_remote_update_watcher();
1306 template <typename I
>
1307 void Replayer
<I
>::register_remote_update_watcher() {
1310 int r
= m_state_builder
->remote_image_ctx
->state
->register_update_watcher(
1311 m_update_watch_ctx
, &m_remote_update_watcher_handle
);
1312 auto ctx
= create_context_callback
<
1313 Replayer
<I
>, &Replayer
<I
>::handle_register_remote_update_watcher
>(this);
1314 m_threads
->work_queue
->queue(ctx
, r
);
1317 template <typename I
>
1318 void Replayer
<I
>::handle_register_remote_update_watcher(int r
) {
1319 dout(10) << "r=" << r
<< dendl
;
1322 derr
<< "failed to register remote update watcher: " << cpp_strerror(r
)
1324 handle_replay_complete(r
, "failed to register remote image update watcher");
1325 m_state
= STATE_COMPLETE
;
1327 unregister_local_update_watcher();
1331 m_state
= STATE_REPLAYING
;
1333 Context
* on_init
= nullptr;
1334 std::swap(on_init
, m_on_init_shutdown
);
1335 on_init
->complete(0);
1337 // delay initial snapshot scan until after we have alerted
1338 // image replayer that we have initialized in case an error
1341 std::unique_lock locker
{m_lock
};
1342 notify_status_updated();
1345 load_local_image_meta();
1348 template <typename I
>
1349 void Replayer
<I
>::unregister_remote_update_watcher() {
1352 auto ctx
= create_context_callback
<
1354 &Replayer
<I
>::handle_unregister_remote_update_watcher
>(this);
1355 m_state_builder
->remote_image_ctx
->state
->unregister_update_watcher(
1356 m_remote_update_watcher_handle
, ctx
);
1359 template <typename I
>
1360 void Replayer
<I
>::handle_unregister_remote_update_watcher(int r
) {
1361 dout(10) << "r=" << r
<< dendl
;
1364 derr
<< "failed to unregister remote update watcher: " << cpp_strerror(r
)
1366 handle_replay_complete(
1367 r
, "failed to unregister remote image update watcher");
1370 unregister_local_update_watcher();
1373 template <typename I
>
1374 void Replayer
<I
>::unregister_local_update_watcher() {
1377 auto ctx
= create_context_callback
<
1379 &Replayer
<I
>::handle_unregister_local_update_watcher
>(this);
1380 m_state_builder
->local_image_ctx
->state
->unregister_update_watcher(
1381 m_local_update_watcher_handle
, ctx
);
1384 template <typename I
>
1385 void Replayer
<I
>::handle_unregister_local_update_watcher(int r
) {
1386 dout(10) << "r=" << r
<< dendl
;
1389 derr
<< "failed to unregister local update watcher: " << cpp_strerror(r
)
1391 handle_replay_complete(
1392 r
, "failed to unregister local image update watcher");
1395 delete m_update_watch_ctx
;
1396 m_update_watch_ctx
= nullptr;
1398 wait_for_in_flight_ops();
1401 template <typename I
>
1402 void Replayer
<I
>::wait_for_in_flight_ops() {
1405 auto ctx
= create_async_context_callback(
1406 m_threads
->work_queue
, create_context_callback
<
1407 Replayer
<I
>, &Replayer
<I
>::handle_wait_for_in_flight_ops
>(this));
1408 m_in_flight_op_tracker
.wait_for_ops(ctx
);
1411 template <typename I
>
1412 void Replayer
<I
>::handle_wait_for_in_flight_ops(int r
) {
1413 dout(10) << "r=" << r
<< dendl
;
1415 Context
* on_shutdown
= nullptr;
1417 std::unique_lock locker
{m_lock
};
1418 ceph_assert(m_on_init_shutdown
!= nullptr);
1419 std::swap(on_shutdown
, m_on_init_shutdown
);
1421 on_shutdown
->complete(m_error_code
);
1424 template <typename I
>
1425 void Replayer
<I
>::handle_image_update_notify() {
1428 std::unique_lock locker
{m_lock
};
1429 if (m_state
== STATE_REPLAYING
) {
1430 dout(15) << "flagging snapshot rescan required" << dendl
;
1431 m_image_updated
= true;
1432 } else if (m_state
== STATE_IDLE
) {
1433 m_state
= STATE_REPLAYING
;
1436 dout(15) << "restarting idle replayer" << dendl
;
1437 load_local_image_meta();
1441 template <typename I
>
1442 void Replayer
<I
>::handle_replay_complete(int r
,
1443 const std::string
& description
) {
1444 std::unique_lock locker
{m_lock
};
1445 handle_replay_complete(&locker
, r
, description
);
1448 template <typename I
>
1449 void Replayer
<I
>::handle_replay_complete(std::unique_lock
<ceph::mutex
>* locker
,
1451 const std::string
& description
) {
1452 ceph_assert(ceph_mutex_is_locked_by_me(m_lock
));
1454 if (m_error_code
== 0) {
1456 m_error_description
= description
;
1459 if (m_sync_in_progress
) {
1460 m_sync_in_progress
= false;
1461 m_instance_watcher
->notify_sync_complete(
1462 m_state_builder
->local_image_ctx
->id
);
1465 if (m_state
!= STATE_REPLAYING
&& m_state
!= STATE_IDLE
) {
1469 m_state
= STATE_COMPLETE
;
1470 notify_status_updated();
1473 template <typename I
>
1474 void Replayer
<I
>::notify_status_updated() {
1475 ceph_assert(ceph_mutex_is_locked_by_me(m_lock
));
1478 auto ctx
= new C_TrackedOp(m_in_flight_op_tracker
, new LambdaContext(
1480 m_replayer_listener
->handle_notification();
1482 m_threads
->work_queue
->queue(ctx
, 0);
1485 template <typename I
>
1486 bool Replayer
<I
>::is_replay_interrupted() {
1487 std::unique_lock locker
{m_lock
};
1488 return is_replay_interrupted(&locker
);
1491 template <typename I
>
1492 bool Replayer
<I
>::is_replay_interrupted(std::unique_lock
<ceph::mutex
>* locker
) {
1493 if (m_state
== STATE_COMPLETE
) {
1496 dout(10) << "resuming pending shut down" << dendl
;
1497 unregister_remote_update_watcher();
1503 } // namespace snapshot
1504 } // namespace image_replayer
1505 } // namespace mirror
1508 template class rbd::mirror::image_replayer::snapshot::Replayer
<librbd::ImageCtx
>;