1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "InstanceWatcher.h"
6 #include "ProgressContext.h"
7 #include "common/errno.h"
8 #include "journal/Journaler.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ObjectMap.h"
12 #include "librbd/Utils.h"
13 #include "librbd/journal/Types.h"
14 #include "tools/rbd_mirror/image_sync/ImageCopyRequest.h"
15 #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
16 #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
17 #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
19 #define dout_context g_ceph_context
20 #define dout_subsys ceph_subsys_rbd_mirror
22 #define dout_prefix *_dout << "rbd::mirror::ImageSync: " \
23 << this << " " << __func__
28 using namespace image_sync
;
29 using librbd::util::create_context_callback
;
30 using librbd::util::unique_lock_name
;
33 ImageSync
<I
>::ImageSync(I
*local_image_ctx
, I
*remote_image_ctx
,
34 SafeTimer
*timer
, Mutex
*timer_lock
,
35 const std::string
&mirror_uuid
, Journaler
*journaler
,
36 MirrorPeerClientMeta
*client_meta
,
37 ContextWQ
*work_queue
,
38 InstanceWatcher
<I
> *instance_watcher
,
39 Context
*on_finish
, ProgressContext
*progress_ctx
)
40 : BaseRequest("rbd::mirror::ImageSync", local_image_ctx
->cct
, on_finish
),
41 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
42 m_timer(timer
), m_timer_lock(timer_lock
), m_mirror_uuid(mirror_uuid
),
43 m_journaler(journaler
), m_client_meta(client_meta
),
44 m_work_queue(work_queue
), m_instance_watcher(instance_watcher
),
45 m_progress_ctx(progress_ctx
),
46 m_lock(unique_lock_name("ImageSync::m_lock", this)) {
50 ImageSync
<I
>::~ImageSync() {
51 assert(m_snapshot_copy_request
== nullptr);
52 assert(m_image_copy_request
== nullptr);
56 void ImageSync
<I
>::send() {
57 send_notify_sync_request();
61 void ImageSync
<I
>::cancel() {
62 Mutex::Locker
locker(m_lock
);
68 if (m_instance_watcher
->cancel_sync_request(m_local_image_ctx
->id
)) {
72 if (m_snapshot_copy_request
!= nullptr) {
73 m_snapshot_copy_request
->cancel();
76 if (m_image_copy_request
!= nullptr) {
77 m_image_copy_request
->cancel();
82 void ImageSync
<I
>::send_notify_sync_request() {
83 update_progress("NOTIFY_SYNC_REQUEST");
87 Context
*ctx
= create_context_callback
<
88 ImageSync
<I
>, &ImageSync
<I
>::handle_notify_sync_request
>(this);
89 m_instance_watcher
->notify_sync_request(m_local_image_ctx
->id
, ctx
);
93 void ImageSync
<I
>::handle_notify_sync_request(int r
) {
94 dout(20) << ": r=" << r
<< dendl
;
97 BaseRequest::finish(r
);
101 send_prune_catch_up_sync_point();
104 template <typename I
>
105 void ImageSync
<I
>::send_prune_catch_up_sync_point() {
106 update_progress("PRUNE_CATCH_UP_SYNC_POINT");
108 if (m_client_meta
->sync_points
.empty()) {
109 send_create_sync_point();
115 // prune will remove sync points with missing snapshots and
116 // ensure we have a maximum of one sync point (in case we
118 Context
*ctx
= create_context_callback
<
119 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_catch_up_sync_point
>(this);
120 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
121 m_remote_image_ctx
, false, m_journaler
, m_client_meta
, ctx
);
125 template <typename I
>
126 void ImageSync
<I
>::handle_prune_catch_up_sync_point(int r
) {
127 dout(20) << ": r=" << r
<< dendl
;
130 derr
<< ": failed to prune catch-up sync point: "
131 << cpp_strerror(r
) << dendl
;
136 send_create_sync_point();
139 template <typename I
>
140 void ImageSync
<I
>::send_create_sync_point() {
141 update_progress("CREATE_SYNC_POINT");
143 // TODO: when support for disconnecting laggy clients is added,
144 // re-connect and create catch-up sync point
145 if (m_client_meta
->sync_points
.size() > 0) {
146 send_copy_snapshots();
152 Context
*ctx
= create_context_callback
<
153 ImageSync
<I
>, &ImageSync
<I
>::handle_create_sync_point
>(this);
154 SyncPointCreateRequest
<I
> *request
= SyncPointCreateRequest
<I
>::create(
155 m_remote_image_ctx
, m_mirror_uuid
, m_journaler
, m_client_meta
, ctx
);
159 template <typename I
>
160 void ImageSync
<I
>::handle_create_sync_point(int r
) {
161 dout(20) << ": r=" << r
<< dendl
;
164 derr
<< ": failed to create sync point: " << cpp_strerror(r
)
170 send_copy_snapshots();
173 template <typename I
>
174 void ImageSync
<I
>::send_copy_snapshots() {
184 Context
*ctx
= create_context_callback
<
185 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_snapshots
>(this);
186 m_snapshot_copy_request
= SnapshotCopyRequest
<I
>::create(
187 m_local_image_ctx
, m_remote_image_ctx
, &m_snap_map
, m_journaler
,
188 m_client_meta
, m_work_queue
, ctx
);
189 m_snapshot_copy_request
->get();
192 update_progress("COPY_SNAPSHOTS");
194 m_snapshot_copy_request
->send();
197 template <typename I
>
198 void ImageSync
<I
>::handle_copy_snapshots(int r
) {
199 dout(20) << ": r=" << r
<< dendl
;
202 Mutex::Locker
locker(m_lock
);
203 m_snapshot_copy_request
->put();
204 m_snapshot_copy_request
= nullptr;
205 if (r
== 0 && m_canceled
) {
210 if (r
== -ECANCELED
) {
211 dout(10) << ": snapshot copy canceled" << dendl
;
215 derr
<< ": failed to copy snapshot metadata: " << cpp_strerror(r
) << dendl
;
223 template <typename I
>
224 void ImageSync
<I
>::send_copy_image() {
234 Context
*ctx
= create_context_callback
<
235 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_image
>(this);
236 m_image_copy_request
= ImageCopyRequest
<I
>::create(
237 m_local_image_ctx
, m_remote_image_ctx
, m_timer
, m_timer_lock
,
238 m_journaler
, m_client_meta
, &m_client_meta
->sync_points
.front(),
239 ctx
, m_progress_ctx
);
240 m_image_copy_request
->get();
243 update_progress("COPY_IMAGE");
245 m_image_copy_request
->send();
248 template <typename I
>
249 void ImageSync
<I
>::handle_copy_image(int r
) {
250 dout(20) << ": r=" << r
<< dendl
;
253 Mutex::Locker
locker(m_lock
);
254 m_image_copy_request
->put();
255 m_image_copy_request
= nullptr;
256 if (r
== 0 && m_canceled
) {
261 if (r
== -ECANCELED
) {
262 dout(10) << ": image copy canceled" << dendl
;
266 derr
<< ": failed to copy image: " << cpp_strerror(r
) << dendl
;
271 send_copy_object_map();
274 template <typename I
>
275 void ImageSync
<I
>::send_copy_object_map() {
276 update_progress("COPY_OBJECT_MAP");
278 m_local_image_ctx
->owner_lock
.get_read();
279 m_local_image_ctx
->snap_lock
.get_read();
280 if (!m_local_image_ctx
->test_features(RBD_FEATURE_OBJECT_MAP
,
281 m_local_image_ctx
->snap_lock
)) {
282 m_local_image_ctx
->snap_lock
.put_read();
283 m_local_image_ctx
->owner_lock
.put_read();
284 send_prune_sync_points();
288 assert(m_local_image_ctx
->object_map
!= nullptr);
290 assert(!m_client_meta
->sync_points
.empty());
291 librbd::journal::MirrorPeerSyncPoint
&sync_point
=
292 m_client_meta
->sync_points
.front();
293 auto snap_id_it
= m_local_image_ctx
->snap_ids
.find(
294 {cls::rbd::UserSnapshotNamespace(), sync_point
.snap_name
});
295 assert(snap_id_it
!= m_local_image_ctx
->snap_ids
.end());
296 librados::snap_t snap_id
= snap_id_it
->second
;
298 dout(20) << ": snap_id=" << snap_id
<< ", "
299 << "snap_name=" << sync_point
.snap_name
<< dendl
;
301 Context
*finish_op_ctx
= nullptr;
302 if (m_local_image_ctx
->exclusive_lock
!= nullptr) {
303 finish_op_ctx
= m_local_image_ctx
->exclusive_lock
->start_op();
305 if (finish_op_ctx
== nullptr) {
306 derr
<< ": lost exclusive lock" << dendl
;
307 m_local_image_ctx
->snap_lock
.put_read();
308 m_local_image_ctx
->owner_lock
.put_read();
313 // rollback the object map (copy snapshot object map to HEAD)
314 RWLock::WLocker
object_map_locker(m_local_image_ctx
->object_map_lock
);
315 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
316 handle_copy_object_map(r
);
317 finish_op_ctx
->complete(0);
319 m_local_image_ctx
->object_map
->rollback(snap_id
, ctx
);
320 m_local_image_ctx
->snap_lock
.put_read();
321 m_local_image_ctx
->owner_lock
.put_read();
324 template <typename I
>
325 void ImageSync
<I
>::handle_copy_object_map(int r
) {
329 send_refresh_object_map();
332 template <typename I
>
333 void ImageSync
<I
>::send_refresh_object_map() {
336 update_progress("REFRESH_OBJECT_MAP");
338 Context
*ctx
= create_context_callback
<
339 ImageSync
<I
>, &ImageSync
<I
>::handle_refresh_object_map
>(this);
340 m_object_map
= m_local_image_ctx
->create_object_map(CEPH_NOSNAP
);
341 m_object_map
->open(ctx
);
344 template <typename I
>
345 void ImageSync
<I
>::handle_refresh_object_map(int r
) {
350 RWLock::WLocker
snap_locker(m_local_image_ctx
->snap_lock
);
351 std::swap(m_local_image_ctx
->object_map
, m_object_map
);
355 send_prune_sync_points();
358 template <typename I
>
359 void ImageSync
<I
>::send_prune_sync_points() {
362 update_progress("PRUNE_SYNC_POINTS");
364 Context
*ctx
= create_context_callback
<
365 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_sync_points
>(this);
366 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
367 m_remote_image_ctx
, true, m_journaler
, m_client_meta
, ctx
);
371 template <typename I
>
372 void ImageSync
<I
>::handle_prune_sync_points(int r
) {
373 dout(20) << ": r=" << r
<< dendl
;
376 derr
<< ": failed to prune sync point: "
377 << cpp_strerror(r
) << dendl
;
382 if (!m_client_meta
->sync_points
.empty()) {
390 template <typename I
>
391 void ImageSync
<I
>::update_progress(const std::string
&description
) {
392 dout(20) << ": " << description
<< dendl
;
394 if (m_progress_ctx
) {
395 m_progress_ctx
->update_progress("IMAGE_SYNC/" + description
);
399 template <typename I
>
400 void ImageSync
<I
>::finish(int r
) {
401 dout(20) << ": r=" << r
<< dendl
;
403 m_instance_watcher
->notify_sync_complete(m_local_image_ctx
->id
);
404 BaseRequest::finish(r
);
407 } // namespace mirror
410 template class rbd::mirror::ImageSync
<librbd::ImageCtx
>;