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/MetadataCopyRequest.h"
16 #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
17 #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
18 #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
20 #define dout_context g_ceph_context
21 #define dout_subsys ceph_subsys_rbd_mirror
23 #define dout_prefix *_dout << "rbd::mirror::ImageSync: " \
24 << this << " " << __func__
29 using namespace image_sync
;
30 using librbd::util::create_async_context_callback
;
31 using librbd::util::create_context_callback
;
32 using librbd::util::unique_lock_name
;
35 ImageSync
<I
>::ImageSync(I
*local_image_ctx
, I
*remote_image_ctx
,
36 SafeTimer
*timer
, Mutex
*timer_lock
,
37 const std::string
&mirror_uuid
, Journaler
*journaler
,
38 MirrorPeerClientMeta
*client_meta
,
39 ContextWQ
*work_queue
,
40 InstanceWatcher
<I
> *instance_watcher
,
41 Context
*on_finish
, ProgressContext
*progress_ctx
)
42 : BaseRequest("rbd::mirror::ImageSync", local_image_ctx
->cct
, on_finish
),
43 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
44 m_timer(timer
), m_timer_lock(timer_lock
), m_mirror_uuid(mirror_uuid
),
45 m_journaler(journaler
), m_client_meta(client_meta
),
46 m_work_queue(work_queue
), m_instance_watcher(instance_watcher
),
47 m_progress_ctx(progress_ctx
),
48 m_lock(unique_lock_name("ImageSync::m_lock", this)) {
52 ImageSync
<I
>::~ImageSync() {
53 assert(m_snapshot_copy_request
== nullptr);
54 assert(m_image_copy_request
== nullptr);
58 void ImageSync
<I
>::send() {
59 send_notify_sync_request();
63 void ImageSync
<I
>::cancel() {
64 Mutex::Locker
locker(m_lock
);
70 if (m_instance_watcher
->cancel_sync_request(m_local_image_ctx
->id
)) {
74 if (m_snapshot_copy_request
!= nullptr) {
75 m_snapshot_copy_request
->cancel();
78 if (m_image_copy_request
!= nullptr) {
79 m_image_copy_request
->cancel();
84 void ImageSync
<I
>::send_notify_sync_request() {
85 update_progress("NOTIFY_SYNC_REQUEST");
92 BaseRequest::finish(-ECANCELED
);
96 Context
*ctx
= create_async_context_callback(
97 m_work_queue
, create_context_callback
<
98 ImageSync
<I
>, &ImageSync
<I
>::handle_notify_sync_request
>(this));
99 m_instance_watcher
->notify_sync_request(m_local_image_ctx
->id
, ctx
);
103 template <typename I
>
104 void ImageSync
<I
>::handle_notify_sync_request(int r
) {
105 dout(20) << ": r=" << r
<< dendl
;
108 if (r
== 0 && m_canceled
) {
114 BaseRequest::finish(r
);
118 send_prune_catch_up_sync_point();
121 template <typename I
>
122 void ImageSync
<I
>::send_prune_catch_up_sync_point() {
123 update_progress("PRUNE_CATCH_UP_SYNC_POINT");
125 if (m_client_meta
->sync_points
.empty()) {
126 send_create_sync_point();
132 // prune will remove sync points with missing snapshots and
133 // ensure we have a maximum of one sync point (in case we
135 Context
*ctx
= create_context_callback
<
136 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_catch_up_sync_point
>(this);
137 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
138 m_remote_image_ctx
, false, m_journaler
, m_client_meta
, ctx
);
142 template <typename I
>
143 void ImageSync
<I
>::handle_prune_catch_up_sync_point(int r
) {
144 dout(20) << ": r=" << r
<< dendl
;
147 derr
<< ": failed to prune catch-up sync point: "
148 << cpp_strerror(r
) << dendl
;
153 send_create_sync_point();
156 template <typename I
>
157 void ImageSync
<I
>::send_create_sync_point() {
158 update_progress("CREATE_SYNC_POINT");
160 // TODO: when support for disconnecting laggy clients is added,
161 // re-connect and create catch-up sync point
162 if (m_client_meta
->sync_points
.size() > 0) {
163 send_copy_snapshots();
169 Context
*ctx
= create_context_callback
<
170 ImageSync
<I
>, &ImageSync
<I
>::handle_create_sync_point
>(this);
171 SyncPointCreateRequest
<I
> *request
= SyncPointCreateRequest
<I
>::create(
172 m_remote_image_ctx
, m_mirror_uuid
, m_journaler
, m_client_meta
, ctx
);
176 template <typename I
>
177 void ImageSync
<I
>::handle_create_sync_point(int r
) {
178 dout(20) << ": r=" << r
<< dendl
;
181 derr
<< ": failed to create sync point: " << cpp_strerror(r
)
187 send_copy_snapshots();
190 template <typename I
>
191 void ImageSync
<I
>::send_copy_snapshots() {
201 Context
*ctx
= create_context_callback
<
202 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_snapshots
>(this);
203 m_snapshot_copy_request
= SnapshotCopyRequest
<I
>::create(
204 m_local_image_ctx
, m_remote_image_ctx
, &m_snap_map
, m_journaler
,
205 m_client_meta
, m_work_queue
, ctx
);
206 m_snapshot_copy_request
->get();
209 update_progress("COPY_SNAPSHOTS");
211 m_snapshot_copy_request
->send();
214 template <typename I
>
215 void ImageSync
<I
>::handle_copy_snapshots(int r
) {
216 dout(20) << ": r=" << r
<< dendl
;
219 Mutex::Locker
locker(m_lock
);
220 m_snapshot_copy_request
->put();
221 m_snapshot_copy_request
= nullptr;
222 if (r
== 0 && m_canceled
) {
227 if (r
== -ECANCELED
) {
228 dout(10) << ": snapshot copy canceled" << dendl
;
232 derr
<< ": failed to copy snapshot metadata: " << cpp_strerror(r
) << dendl
;
240 template <typename I
>
241 void ImageSync
<I
>::send_copy_image() {
251 Context
*ctx
= create_context_callback
<
252 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_image
>(this);
253 m_image_copy_request
= ImageCopyRequest
<I
>::create(
254 m_local_image_ctx
, m_remote_image_ctx
, m_timer
, m_timer_lock
,
255 m_journaler
, m_client_meta
, &m_client_meta
->sync_points
.front(),
256 ctx
, m_progress_ctx
);
257 m_image_copy_request
->get();
260 update_progress("COPY_IMAGE");
262 m_image_copy_request
->send();
265 template <typename I
>
266 void ImageSync
<I
>::handle_copy_image(int r
) {
267 dout(20) << ": r=" << r
<< dendl
;
270 Mutex::Locker
locker(m_lock
);
271 m_image_copy_request
->put();
272 m_image_copy_request
= nullptr;
273 if (r
== 0 && m_canceled
) {
278 if (r
== -ECANCELED
) {
279 dout(10) << ": image copy canceled" << dendl
;
283 derr
<< ": failed to copy image: " << cpp_strerror(r
) << dendl
;
288 send_copy_object_map();
291 template <typename I
>
292 void ImageSync
<I
>::send_copy_object_map() {
293 update_progress("COPY_OBJECT_MAP");
295 m_local_image_ctx
->owner_lock
.get_read();
296 m_local_image_ctx
->snap_lock
.get_read();
297 if (!m_local_image_ctx
->test_features(RBD_FEATURE_OBJECT_MAP
,
298 m_local_image_ctx
->snap_lock
)) {
299 m_local_image_ctx
->snap_lock
.put_read();
300 m_local_image_ctx
->owner_lock
.put_read();
301 send_prune_sync_points();
305 assert(m_local_image_ctx
->object_map
!= nullptr);
307 assert(!m_client_meta
->sync_points
.empty());
308 librbd::journal::MirrorPeerSyncPoint
&sync_point
=
309 m_client_meta
->sync_points
.front();
310 auto snap_id_it
= m_local_image_ctx
->snap_ids
.find(
311 {cls::rbd::UserSnapshotNamespace(), sync_point
.snap_name
});
312 assert(snap_id_it
!= m_local_image_ctx
->snap_ids
.end());
313 librados::snap_t snap_id
= snap_id_it
->second
;
315 dout(20) << ": snap_id=" << snap_id
<< ", "
316 << "snap_name=" << sync_point
.snap_name
<< dendl
;
318 Context
*finish_op_ctx
= nullptr;
319 if (m_local_image_ctx
->exclusive_lock
!= nullptr) {
320 finish_op_ctx
= m_local_image_ctx
->exclusive_lock
->start_op();
322 if (finish_op_ctx
== nullptr) {
323 derr
<< ": lost exclusive lock" << dendl
;
324 m_local_image_ctx
->snap_lock
.put_read();
325 m_local_image_ctx
->owner_lock
.put_read();
330 // rollback the object map (copy snapshot object map to HEAD)
331 RWLock::WLocker
object_map_locker(m_local_image_ctx
->object_map_lock
);
332 auto ctx
= new FunctionContext([this, finish_op_ctx
](int r
) {
333 handle_copy_object_map(r
);
334 finish_op_ctx
->complete(0);
336 m_local_image_ctx
->object_map
->rollback(snap_id
, ctx
);
337 m_local_image_ctx
->snap_lock
.put_read();
338 m_local_image_ctx
->owner_lock
.put_read();
341 template <typename I
>
342 void ImageSync
<I
>::handle_copy_object_map(int r
) {
346 send_refresh_object_map();
349 template <typename I
>
350 void ImageSync
<I
>::send_refresh_object_map() {
353 update_progress("REFRESH_OBJECT_MAP");
355 Context
*ctx
= create_context_callback
<
356 ImageSync
<I
>, &ImageSync
<I
>::handle_refresh_object_map
>(this);
357 m_object_map
= m_local_image_ctx
->create_object_map(CEPH_NOSNAP
);
358 m_object_map
->open(ctx
);
361 template <typename I
>
362 void ImageSync
<I
>::handle_refresh_object_map(int r
) {
367 RWLock::WLocker
snap_locker(m_local_image_ctx
->snap_lock
);
368 std::swap(m_local_image_ctx
->object_map
, m_object_map
);
372 send_prune_sync_points();
375 template <typename I
>
376 void ImageSync
<I
>::send_prune_sync_points() {
379 update_progress("PRUNE_SYNC_POINTS");
381 Context
*ctx
= create_context_callback
<
382 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_sync_points
>(this);
383 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
384 m_remote_image_ctx
, true, m_journaler
, m_client_meta
, ctx
);
388 template <typename I
>
389 void ImageSync
<I
>::handle_prune_sync_points(int r
) {
390 dout(20) << ": r=" << r
<< dendl
;
393 derr
<< ": failed to prune sync point: "
394 << cpp_strerror(r
) << dendl
;
399 if (!m_client_meta
->sync_points
.empty()) {
404 send_copy_metadata();
407 template <typename I
>
408 void ImageSync
<I
>::send_copy_metadata() {
410 update_progress("COPY_METADATA");
412 Context
*ctx
= create_context_callback
<
413 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_metadata
>(this);
414 auto request
= MetadataCopyRequest
<I
>::create(
415 m_local_image_ctx
, m_remote_image_ctx
, ctx
);
419 template <typename I
>
420 void ImageSync
<I
>::handle_copy_metadata(int r
) {
421 dout(20) << ": r=" << r
<< dendl
;
423 derr
<< ": failed to copy metadata: " << cpp_strerror(r
) << dendl
;
431 template <typename I
>
432 void ImageSync
<I
>::update_progress(const std::string
&description
) {
433 dout(20) << ": " << description
<< dendl
;
435 if (m_progress_ctx
) {
436 m_progress_ctx
->update_progress("IMAGE_SYNC/" + description
);
440 template <typename I
>
441 void ImageSync
<I
>::finish(int r
) {
442 dout(20) << ": r=" << r
<< dendl
;
444 m_instance_watcher
->notify_sync_complete(m_local_image_ctx
->id
);
445 BaseRequest::finish(r
);
448 } // namespace mirror
451 template class rbd::mirror::ImageSync
<librbd::ImageCtx
>;