1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "ImageCopyRequest.h"
5 #include "ObjectCopyRequest.h"
6 #include "include/stringify.h"
7 #include "common/errno.h"
8 #include "common/Timer.h"
9 #include "journal/Journaler.h"
10 #include "librbd/Utils.h"
11 #include "tools/rbd_mirror/ProgressContext.h"
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rbd_mirror
16 #define dout_prefix *_dout << "rbd::mirror::image_sync::ImageCopyRequest: " \
17 << this << " " << __func__
21 namespace image_sync
{
23 using librbd::util::create_context_callback
;
24 using librbd::util::unique_lock_name
;
27 ImageCopyRequest
<I
>::ImageCopyRequest(I
*local_image_ctx
, I
*remote_image_ctx
,
28 SafeTimer
*timer
, Mutex
*timer_lock
,
30 MirrorPeerClientMeta
*client_meta
,
31 MirrorPeerSyncPoint
*sync_point
,
33 ProgressContext
*progress_ctx
)
34 : BaseRequest("rbd::mirror::image_sync::ImageCopyRequest",
35 local_image_ctx
->cct
, on_finish
),
36 m_local_image_ctx(local_image_ctx
), m_remote_image_ctx(remote_image_ctx
),
37 m_timer(timer
), m_timer_lock(timer_lock
), m_journaler(journaler
),
38 m_client_meta(client_meta
), m_sync_point(sync_point
),
39 m_progress_ctx(progress_ctx
),
40 m_lock(unique_lock_name("ImageCopyRequest::m_lock", this)),
41 m_updating_sync_point(false), m_update_sync_ctx(nullptr),
42 m_update_sync_point_interval(m_local_image_ctx
->cct
->_conf
->rbd_mirror_sync_point_update_age
),
43 m_client_meta_copy(*client_meta
) {
44 assert(!m_client_meta_copy
.sync_points
.empty());
48 void ImageCopyRequest
<I
>::send() {
49 int r
= compute_snap_map();
55 send_update_max_object_count();
59 void ImageCopyRequest
<I
>::cancel() {
60 Mutex::Locker
locker(m_lock
);
67 void ImageCopyRequest
<I
>::send_update_max_object_count() {
68 uint64_t max_objects
= m_client_meta
->sync_object_count
;
70 RWLock::RLocker
snap_locker(m_remote_image_ctx
->snap_lock
);
71 max_objects
= std::max(max_objects
,
72 m_remote_image_ctx
->get_object_count(CEPH_NOSNAP
));
73 for (auto snap_id
: m_remote_image_ctx
->snaps
) {
74 max_objects
= std::max(max_objects
,
75 m_remote_image_ctx
->get_object_count(snap_id
));
79 if (max_objects
<= m_client_meta
->sync_object_count
) {
84 update_progress("UPDATE_MAX_OBJECT_COUNT");
86 dout(20) << ": sync_object_count=" << max_objects
<< dendl
;
88 m_client_meta_copy
= *m_client_meta
;
89 m_client_meta_copy
.sync_object_count
= max_objects
;
91 bufferlist client_data_bl
;
92 librbd::journal::ClientData
client_data(m_client_meta_copy
);
93 ::encode(client_data
, client_data_bl
);
95 Context
*ctx
= create_context_callback
<
96 ImageCopyRequest
<I
>, &ImageCopyRequest
<I
>::handle_update_max_object_count
>(
98 m_journaler
->update_client(client_data_bl
, ctx
);
101 template <typename I
>
102 void ImageCopyRequest
<I
>::handle_update_max_object_count(int r
) {
103 dout(20) << ": r=" << r
<< dendl
;
106 Mutex::Locker
locker(m_lock
);
108 dout(10) << ": image copy canceled" << dendl
;
114 if (r
!= -ECANCELED
) {
115 derr
<< ": failed to update client data: " << cpp_strerror(r
) << dendl
;
121 // update provided meta structure to reflect reality
122 m_client_meta
->sync_object_count
= m_client_meta_copy
.sync_object_count
;
124 send_object_copies();
127 template <typename I
>
128 void ImageCopyRequest
<I
>::send_object_copies() {
129 CephContext
*cct
= m_local_image_ctx
->cct
;
132 if (m_sync_point
->object_number
) {
133 m_object_no
= *m_sync_point
->object_number
+ 1;
135 m_end_object_no
= m_client_meta
->sync_object_count
;
137 dout(20) << ": start_object=" << m_object_no
<< ", "
138 << "end_object=" << m_end_object_no
<< dendl
;
140 update_progress("COPY_OBJECT");
144 Mutex::Locker
locker(m_lock
);
145 for (int i
= 0; i
< cct
->_conf
->rbd_concurrent_management_ops
; ++i
) {
146 send_next_object_copy();
147 if (m_ret_val
< 0 && m_current_ops
== 0) {
151 complete
= (m_current_ops
== 0);
154 m_update_sync_ctx
= new FunctionContext([this](int r
) {
155 this->send_update_sync_point();
161 Mutex::Locker
timer_locker(*m_timer_lock
);
162 if (m_update_sync_ctx
) {
163 m_timer
->add_event_after(m_update_sync_point_interval
,
169 send_flush_sync_point();
173 template <typename I
>
174 void ImageCopyRequest
<I
>::send_next_object_copy() {
175 assert(m_lock
.is_locked());
177 if (m_canceled
&& m_ret_val
== 0) {
178 dout(10) << ": image copy canceled" << dendl
;
179 m_ret_val
= -ECANCELED
;
182 if (m_ret_val
< 0 || m_object_no
>= m_end_object_no
) {
186 uint64_t ono
= m_object_no
++;
188 dout(20) << ": object_num=" << ono
<< dendl
;
192 Context
*ctx
= create_context_callback
<
193 ImageCopyRequest
<I
>, &ImageCopyRequest
<I
>::handle_object_copy
>(this);
194 ObjectCopyRequest
<I
> *req
= ObjectCopyRequest
<I
>::create(
195 m_local_image_ctx
, m_remote_image_ctx
, &m_snap_map
, ono
, ctx
);
199 template <typename I
>
200 void ImageCopyRequest
<I
>::handle_object_copy(int r
) {
201 dout(20) << ": r=" << r
<< dendl
;
206 Mutex::Locker
locker(m_lock
);
207 assert(m_current_ops
> 0);
210 percent
= 100 * m_object_no
/ m_end_object_no
;
213 derr
<< ": object copy failed: " << cpp_strerror(r
) << dendl
;
214 if (m_ret_val
== 0) {
219 send_next_object_copy();
220 complete
= (m_current_ops
== 0);
223 update_progress("COPY_OBJECT " + stringify(percent
) + "%", false);
226 bool do_flush
= true;
228 Mutex::Locker
timer_locker(*m_timer_lock
);
229 Mutex::Locker
locker(m_lock
);
230 if (!m_updating_sync_point
) {
231 if (m_update_sync_ctx
!= nullptr) {
232 m_timer
->cancel_event(m_update_sync_ctx
);
233 m_update_sync_ctx
= nullptr;
241 send_flush_sync_point();
246 template <typename I
>
247 void ImageCopyRequest
<I
>::send_update_sync_point() {
248 Mutex::Locker
l(m_lock
);
250 m_update_sync_ctx
= nullptr;
252 if (m_canceled
|| m_ret_val
< 0 || m_current_ops
== 0) {
256 if (m_sync_point
->object_number
&&
257 (m_object_no
-1) == m_sync_point
->object_number
.get()) {
258 // update sync point did not progress since last sync
262 m_updating_sync_point
= true;
264 m_client_meta_copy
= *m_client_meta
;
265 m_sync_point
->object_number
= m_object_no
- 1;
267 CephContext
*cct
= m_local_image_ctx
->cct
;
268 ldout(cct
, 20) << ": sync_point=" << *m_sync_point
<< dendl
;
270 bufferlist client_data_bl
;
271 librbd::journal::ClientData
client_data(*m_client_meta
);
272 ::encode(client_data
, client_data_bl
);
274 Context
*ctx
= create_context_callback
<
275 ImageCopyRequest
<I
>, &ImageCopyRequest
<I
>::handle_update_sync_point
>(
277 m_journaler
->update_client(client_data_bl
, ctx
);
280 template <typename I
>
281 void ImageCopyRequest
<I
>::handle_update_sync_point(int r
) {
282 CephContext
*cct
= m_local_image_ctx
->cct
;
283 ldout(cct
, 20) << ": r=" << r
<< dendl
;
286 *m_client_meta
= m_client_meta_copy
;
287 lderr(cct
) << ": failed to update client data: " << cpp_strerror(r
)
293 Mutex::Locker
l(m_lock
);
294 m_updating_sync_point
= false;
296 complete
= m_current_ops
== 0 || m_canceled
|| m_ret_val
< 0;
299 m_update_sync_ctx
= new FunctionContext([this](int r
) {
300 this->send_update_sync_point();
306 Mutex::Locker
timer_lock(*m_timer_lock
);
307 if (m_update_sync_ctx
) {
308 m_timer
->add_event_after(m_update_sync_point_interval
,
312 send_flush_sync_point();
316 template <typename I
>
317 void ImageCopyRequest
<I
>::send_flush_sync_point() {
323 update_progress("FLUSH_SYNC_POINT");
325 m_client_meta_copy
= *m_client_meta
;
326 if (m_object_no
> 0) {
327 m_sync_point
->object_number
= m_object_no
- 1;
329 m_sync_point
->object_number
= boost::none
;
332 dout(20) << ": sync_point=" << *m_sync_point
<< dendl
;
334 bufferlist client_data_bl
;
335 librbd::journal::ClientData
client_data(m_client_meta_copy
);
336 ::encode(client_data
, client_data_bl
);
338 Context
*ctx
= create_context_callback
<
339 ImageCopyRequest
<I
>, &ImageCopyRequest
<I
>::handle_flush_sync_point
>(
341 m_journaler
->update_client(client_data_bl
, ctx
);
344 template <typename I
>
345 void ImageCopyRequest
<I
>::handle_flush_sync_point(int r
) {
346 dout(20) << ": r=" << r
<< dendl
;
349 *m_client_meta
= m_client_meta_copy
;
351 derr
<< ": failed to update client data: " << cpp_strerror(r
)
360 template <typename I
>
361 int ImageCopyRequest
<I
>::compute_snap_map() {
363 librados::snap_t snap_id_start
= 0;
364 librados::snap_t snap_id_end
;
366 RWLock::RLocker
snap_locker(m_remote_image_ctx
->snap_lock
);
367 snap_id_end
= m_remote_image_ctx
->get_snap_id(
368 cls::rbd::UserSnapshotNamespace(), m_sync_point
->snap_name
);
369 if (snap_id_end
== CEPH_NOSNAP
) {
370 derr
<< ": failed to locate snapshot: "
371 << m_sync_point
->snap_name
<< dendl
;
375 if (!m_sync_point
->from_snap_name
.empty()) {
376 snap_id_start
= m_remote_image_ctx
->get_snap_id(
377 cls::rbd::UserSnapshotNamespace(), m_sync_point
->from_snap_name
);
378 if (snap_id_start
== CEPH_NOSNAP
) {
379 derr
<< ": failed to locate from snapshot: "
380 << m_sync_point
->from_snap_name
<< dendl
;
387 for (auto it
= m_client_meta
->snap_seqs
.begin();
388 it
!= m_client_meta
->snap_seqs
.end(); ++it
) {
389 snap_ids
.insert(snap_ids
.begin(), it
->second
);
390 if (it
->first
< snap_id_start
) {
392 } else if (it
->first
> snap_id_end
) {
396 m_snap_map
[it
->first
] = snap_ids
;
399 if (m_snap_map
.empty()) {
400 derr
<< ": failed to map snapshots within boundary" << dendl
;
407 template <typename I
>
408 void ImageCopyRequest
<I
>::update_progress(const std::string
&description
,
410 dout(20) << ": " << description
<< dendl
;
412 if (m_progress_ctx
) {
413 m_progress_ctx
->update_progress("IMAGE_COPY/" + description
, flush
);
417 } // namespace image_sync
418 } // namespace mirror
421 template class rbd::mirror::image_sync::ImageCopyRequest
<librbd::ImageCtx
>;