1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include "ProgressContext.h"
6 #include "common/errno.h"
7 #include "journal/Journaler.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ObjectMap.h"
10 #include "librbd/Utils.h"
11 #include "librbd/journal/Types.h"
12 #include "tools/rbd_mirror/image_sync/ImageCopyRequest.h"
13 #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
14 #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
15 #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
17 #define dout_context g_ceph_context
18 #define dout_subsys ceph_subsys_rbd_mirror
20 #define dout_prefix *_dout << "rbd::mirror::ImageSync: " \
21 << this << " " << __func__
26 using namespace image_sync
;
27 using librbd::util::create_context_callback
;
28 using librbd::util::unique_lock_name
;
31 ImageSync
<I
>::ImageSync(I
*local_image_ctx
, I
*remote_image_ctx
,
32 SafeTimer
*timer
, Mutex
*timer_lock
,
33 const std::string
&mirror_uuid
, Journaler
*journaler
,
34 MirrorPeerClientMeta
*client_meta
,
35 ContextWQ
*work_queue
, Context
*on_finish
,
36 ProgressContext
*progress_ctx
)
37 : BaseRequest("rbd::mirror::ImageSync", local_image_ctx
->cct
, on_finish
),
38 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
39 m_timer(timer
), m_timer_lock(timer_lock
), m_mirror_uuid(mirror_uuid
),
40 m_journaler(journaler
), m_client_meta(client_meta
),
41 m_work_queue(work_queue
), m_progress_ctx(progress_ctx
),
42 m_lock(unique_lock_name("ImageSync::m_lock", this)) {
46 ImageSync
<I
>::~ImageSync() {
47 assert(m_snapshot_copy_request
== nullptr);
48 assert(m_image_copy_request
== nullptr);
52 void ImageSync
<I
>::send() {
53 send_prune_catch_up_sync_point();
57 void ImageSync
<I
>::cancel() {
58 Mutex::Locker
locker(m_lock
);
64 if (m_snapshot_copy_request
!= nullptr) {
65 m_snapshot_copy_request
->cancel();
68 if (m_image_copy_request
!= nullptr) {
69 m_image_copy_request
->cancel();
74 void ImageSync
<I
>::send_prune_catch_up_sync_point() {
75 update_progress("PRUNE_CATCH_UP_SYNC_POINT");
77 if (m_client_meta
->sync_points
.empty()) {
78 send_create_sync_point();
84 // prune will remove sync points with missing snapshots and
85 // ensure we have a maximum of one sync point (in case we
87 Context
*ctx
= create_context_callback
<
88 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_catch_up_sync_point
>(this);
89 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
90 m_remote_image_ctx
, false, m_journaler
, m_client_meta
, ctx
);
95 void ImageSync
<I
>::handle_prune_catch_up_sync_point(int r
) {
96 dout(20) << ": r=" << r
<< dendl
;
99 derr
<< ": failed to prune catch-up sync point: "
100 << cpp_strerror(r
) << dendl
;
105 send_create_sync_point();
108 template <typename I
>
109 void ImageSync
<I
>::send_create_sync_point() {
110 update_progress("CREATE_SYNC_POINT");
112 // TODO: when support for disconnecting laggy clients is added,
113 // re-connect and create catch-up sync point
114 if (m_client_meta
->sync_points
.size() > 0) {
115 send_copy_snapshots();
121 Context
*ctx
= create_context_callback
<
122 ImageSync
<I
>, &ImageSync
<I
>::handle_create_sync_point
>(this);
123 SyncPointCreateRequest
<I
> *request
= SyncPointCreateRequest
<I
>::create(
124 m_remote_image_ctx
, m_mirror_uuid
, m_journaler
, m_client_meta
, ctx
);
128 template <typename I
>
129 void ImageSync
<I
>::handle_create_sync_point(int r
) {
130 dout(20) << ": r=" << r
<< dendl
;
133 derr
<< ": failed to create sync point: " << cpp_strerror(r
)
139 send_copy_snapshots();
142 template <typename I
>
143 void ImageSync
<I
>::send_copy_snapshots() {
153 Context
*ctx
= create_context_callback
<
154 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_snapshots
>(this);
155 m_snapshot_copy_request
= SnapshotCopyRequest
<I
>::create(
156 m_local_image_ctx
, m_remote_image_ctx
, &m_snap_map
, m_journaler
,
157 m_client_meta
, m_work_queue
, ctx
);
158 m_snapshot_copy_request
->get();
161 update_progress("COPY_SNAPSHOTS");
163 m_snapshot_copy_request
->send();
166 template <typename I
>
167 void ImageSync
<I
>::handle_copy_snapshots(int r
) {
168 dout(20) << ": r=" << r
<< dendl
;
171 Mutex::Locker
locker(m_lock
);
172 m_snapshot_copy_request
->put();
173 m_snapshot_copy_request
= nullptr;
174 if (r
== 0 && m_canceled
) {
179 if (r
== -ECANCELED
) {
180 dout(10) << ": snapshot copy canceled" << dendl
;
184 derr
<< ": failed to copy snapshot metadata: " << cpp_strerror(r
) << dendl
;
192 template <typename I
>
193 void ImageSync
<I
>::send_copy_image() {
203 Context
*ctx
= create_context_callback
<
204 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_image
>(this);
205 m_image_copy_request
= ImageCopyRequest
<I
>::create(
206 m_local_image_ctx
, m_remote_image_ctx
, m_timer
, m_timer_lock
,
207 m_journaler
, m_client_meta
, &m_client_meta
->sync_points
.front(),
208 ctx
, m_progress_ctx
);
209 m_image_copy_request
->get();
212 update_progress("COPY_IMAGE");
214 m_image_copy_request
->send();
217 template <typename I
>
218 void ImageSync
<I
>::handle_copy_image(int r
) {
219 dout(20) << ": r=" << r
<< dendl
;
222 Mutex::Locker
locker(m_lock
);
223 m_image_copy_request
->put();
224 m_image_copy_request
= nullptr;
225 if (r
== 0 && m_canceled
) {
230 if (r
== -ECANCELED
) {
231 dout(10) << ": image copy canceled" << dendl
;
235 derr
<< ": failed to copy image: " << cpp_strerror(r
) << dendl
;
240 send_copy_object_map();
243 template <typename I
>
244 void ImageSync
<I
>::send_copy_object_map() {
245 update_progress("COPY_OBJECT_MAP");
247 m_local_image_ctx
->snap_lock
.get_read();
248 if (!m_local_image_ctx
->test_features(RBD_FEATURE_OBJECT_MAP
,
249 m_local_image_ctx
->snap_lock
)) {
250 m_local_image_ctx
->snap_lock
.put_read();
251 send_prune_sync_points();
255 assert(m_local_image_ctx
->object_map
!= nullptr);
257 assert(!m_client_meta
->sync_points
.empty());
258 librbd::journal::MirrorPeerSyncPoint
&sync_point
=
259 m_client_meta
->sync_points
.front();
260 auto snap_id_it
= m_local_image_ctx
->snap_ids
.find({cls::rbd::UserSnapshotNamespace(),
261 sync_point
.snap_name
});
262 assert(snap_id_it
!= m_local_image_ctx
->snap_ids
.end());
263 librados::snap_t snap_id
= snap_id_it
->second
;
265 dout(20) << ": snap_id=" << snap_id
<< ", "
266 << "snap_name=" << sync_point
.snap_name
<< dendl
;
268 // rollback the object map (copy snapshot object map to HEAD)
269 RWLock::WLocker
object_map_locker(m_local_image_ctx
->object_map_lock
);
270 Context
*ctx
= create_context_callback
<
271 ImageSync
<I
>, &ImageSync
<I
>::handle_copy_object_map
>(this);
272 m_local_image_ctx
->object_map
->rollback(snap_id
, ctx
);
273 m_local_image_ctx
->snap_lock
.put_read();
276 template <typename I
>
277 void ImageSync
<I
>::handle_copy_object_map(int r
) {
281 send_refresh_object_map();
284 template <typename I
>
285 void ImageSync
<I
>::send_refresh_object_map() {
288 update_progress("REFRESH_OBJECT_MAP");
290 Context
*ctx
= create_context_callback
<
291 ImageSync
<I
>, &ImageSync
<I
>::handle_refresh_object_map
>(this);
292 m_object_map
= m_local_image_ctx
->create_object_map(CEPH_NOSNAP
);
293 m_object_map
->open(ctx
);
296 template <typename I
>
297 void ImageSync
<I
>::handle_refresh_object_map(int r
) {
302 RWLock::WLocker
snap_locker(m_local_image_ctx
->snap_lock
);
303 std::swap(m_local_image_ctx
->object_map
, m_object_map
);
307 send_prune_sync_points();
310 template <typename I
>
311 void ImageSync
<I
>::send_prune_sync_points() {
314 update_progress("PRUNE_SYNC_POINTS");
316 Context
*ctx
= create_context_callback
<
317 ImageSync
<I
>, &ImageSync
<I
>::handle_prune_sync_points
>(this);
318 SyncPointPruneRequest
<I
> *request
= SyncPointPruneRequest
<I
>::create(
319 m_remote_image_ctx
, true, m_journaler
, m_client_meta
, ctx
);
323 template <typename I
>
324 void ImageSync
<I
>::handle_prune_sync_points(int r
) {
325 dout(20) << ": r=" << r
<< dendl
;
328 derr
<< ": failed to prune sync point: "
329 << cpp_strerror(r
) << dendl
;
334 if (!m_client_meta
->sync_points
.empty()) {
342 template <typename I
>
343 void ImageSync
<I
>::update_progress(const std::string
&description
) {
344 dout(20) << ": " << description
<< dendl
;
346 if (m_progress_ctx
) {
347 m_progress_ctx
->update_progress("IMAGE_SYNC/" + description
);
351 } // namespace mirror
354 template class rbd::mirror::ImageSync
<librbd::ImageCtx
>;