]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_sync/ImageCopyRequest.cc
update sources to v12.2.1
[ceph.git] / ceph / src / tools / rbd_mirror / image_sync / ImageCopyRequest.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
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"
12
13#define dout_context g_ceph_context
14#define dout_subsys ceph_subsys_rbd_mirror
15#undef dout_prefix
16#define dout_prefix *_dout << "rbd::mirror::image_sync::ImageCopyRequest: " \
17 << this << " " << __func__
18
19namespace rbd {
20namespace mirror {
21namespace image_sync {
22
23using librbd::util::create_context_callback;
24using librbd::util::unique_lock_name;
25
26template <typename I>
27ImageCopyRequest<I>::ImageCopyRequest(I *local_image_ctx, I *remote_image_ctx,
28 SafeTimer *timer, Mutex *timer_lock,
29 Journaler *journaler,
30 MirrorPeerClientMeta *client_meta,
31 MirrorPeerSyncPoint *sync_point,
32 Context *on_finish,
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),
181888fb
FG
42 m_update_sync_point_interval(m_local_image_ctx->cct->_conf->template get_val<double>(
43 "rbd_mirror_sync_point_update_age")),
7c673cae
FG
44 m_client_meta_copy(*client_meta) {
45 assert(!m_client_meta_copy.sync_points.empty());
46}
47
48template <typename I>
49void ImageCopyRequest<I>::send() {
50 int r = compute_snap_map();
51 if (r < 0) {
52 finish(r);
53 return;
54 }
55
56 send_update_max_object_count();
57}
58
59template <typename I>
60void ImageCopyRequest<I>::cancel() {
61 Mutex::Locker locker(m_lock);
62
63 dout(20) << dendl;
64 m_canceled = true;
65}
66
67template <typename I>
68void ImageCopyRequest<I>::send_update_max_object_count() {
69 uint64_t max_objects = m_client_meta->sync_object_count;
70 {
71 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
72 max_objects = std::max(max_objects,
73 m_remote_image_ctx->get_object_count(CEPH_NOSNAP));
74 for (auto snap_id : m_remote_image_ctx->snaps) {
75 max_objects = std::max(max_objects,
76 m_remote_image_ctx->get_object_count(snap_id));
77 }
78 }
79
80 if (max_objects <= m_client_meta->sync_object_count) {
81 send_object_copies();
82 return;
83 }
84
85 update_progress("UPDATE_MAX_OBJECT_COUNT");
86
87 dout(20) << ": sync_object_count=" << max_objects << dendl;
88
89 m_client_meta_copy = *m_client_meta;
90 m_client_meta_copy.sync_object_count = max_objects;
91
92 bufferlist client_data_bl;
93 librbd::journal::ClientData client_data(m_client_meta_copy);
94 ::encode(client_data, client_data_bl);
95
96 Context *ctx = create_context_callback<
97 ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_update_max_object_count>(
98 this);
99 m_journaler->update_client(client_data_bl, ctx);
100}
101
102template <typename I>
103void ImageCopyRequest<I>::handle_update_max_object_count(int r) {
104 dout(20) << ": r=" << r << dendl;
105
106 if (r == 0) {
107 Mutex::Locker locker(m_lock);
108 if (m_canceled) {
109 dout(10) << ": image copy canceled" << dendl;
110 r = -ECANCELED;
111 }
112 }
113
114 if (r < 0) {
115 if (r != -ECANCELED) {
116 derr << ": failed to update client data: " << cpp_strerror(r) << dendl;
117 }
118 finish(r);
119 return;
120 }
121
122 // update provided meta structure to reflect reality
123 m_client_meta->sync_object_count = m_client_meta_copy.sync_object_count;
124
125 send_object_copies();
126}
127
128template <typename I>
129void ImageCopyRequest<I>::send_object_copies() {
130 CephContext *cct = m_local_image_ctx->cct;
131
132 m_object_no = 0;
133 if (m_sync_point->object_number) {
134 m_object_no = *m_sync_point->object_number + 1;
135 }
136 m_end_object_no = m_client_meta->sync_object_count;
137
138 dout(20) << ": start_object=" << m_object_no << ", "
139 << "end_object=" << m_end_object_no << dendl;
140
141 update_progress("COPY_OBJECT");
142
143 bool complete;
144 {
145 Mutex::Locker locker(m_lock);
181888fb 146 for (int i = 0; i < cct->_conf->get_val<int64_t>("rbd_concurrent_management_ops"); ++i) {
7c673cae
FG
147 send_next_object_copy();
148 if (m_ret_val < 0 && m_current_ops == 0) {
149 break;
150 }
151 }
152 complete = (m_current_ops == 0);
153
154 if (!complete) {
155 m_update_sync_ctx = new FunctionContext([this](int r) {
156 this->send_update_sync_point();
157 });
158 }
159 }
160
161 {
162 Mutex::Locker timer_locker(*m_timer_lock);
163 if (m_update_sync_ctx) {
164 m_timer->add_event_after(m_update_sync_point_interval,
165 m_update_sync_ctx);
166 }
167 }
168
169 if (complete) {
170 send_flush_sync_point();
171 }
172}
173
174template <typename I>
175void ImageCopyRequest<I>::send_next_object_copy() {
176 assert(m_lock.is_locked());
177
178 if (m_canceled && m_ret_val == 0) {
179 dout(10) << ": image copy canceled" << dendl;
180 m_ret_val = -ECANCELED;
181 }
182
183 if (m_ret_val < 0 || m_object_no >= m_end_object_no) {
184 return;
185 }
186
187 uint64_t ono = m_object_no++;
188
189 dout(20) << ": object_num=" << ono << dendl;
190
191 ++m_current_ops;
192
193 Context *ctx = create_context_callback<
194 ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_object_copy>(this);
195 ObjectCopyRequest<I> *req = ObjectCopyRequest<I>::create(
196 m_local_image_ctx, m_remote_image_ctx, &m_snap_map, ono, ctx);
197 req->send();
198}
199
200template <typename I>
201void ImageCopyRequest<I>::handle_object_copy(int r) {
202 dout(20) << ": r=" << r << dendl;
203
204 int percent;
205 bool complete;
206 {
207 Mutex::Locker locker(m_lock);
208 assert(m_current_ops > 0);
209 --m_current_ops;
210
211 percent = 100 * m_object_no / m_end_object_no;
212
213 if (r < 0) {
214 derr << ": object copy failed: " << cpp_strerror(r) << dendl;
215 if (m_ret_val == 0) {
216 m_ret_val = r;
217 }
218 }
219
220 send_next_object_copy();
221 complete = (m_current_ops == 0);
222 }
223
224 update_progress("COPY_OBJECT " + stringify(percent) + "%", false);
225
226 if (complete) {
227 bool do_flush = true;
228 {
229 Mutex::Locker timer_locker(*m_timer_lock);
230 Mutex::Locker locker(m_lock);
231 if (!m_updating_sync_point) {
232 if (m_update_sync_ctx != nullptr) {
233 m_timer->cancel_event(m_update_sync_ctx);
234 m_update_sync_ctx = nullptr;
235 }
236 } else {
237 do_flush = false;
238 }
239 }
240
241 if (do_flush) {
242 send_flush_sync_point();
243 }
244 }
245}
246
247template <typename I>
248void ImageCopyRequest<I>::send_update_sync_point() {
249 Mutex::Locker l(m_lock);
250
251 m_update_sync_ctx = nullptr;
252
253 if (m_canceled || m_ret_val < 0 || m_current_ops == 0) {
254 return;
255 }
256
257 if (m_sync_point->object_number &&
258 (m_object_no-1) == m_sync_point->object_number.get()) {
259 // update sync point did not progress since last sync
260 return;
261 }
262
263 m_updating_sync_point = true;
264
265 m_client_meta_copy = *m_client_meta;
266 m_sync_point->object_number = m_object_no - 1;
267
268 CephContext *cct = m_local_image_ctx->cct;
269 ldout(cct, 20) << ": sync_point=" << *m_sync_point << dendl;
270
271 bufferlist client_data_bl;
272 librbd::journal::ClientData client_data(*m_client_meta);
273 ::encode(client_data, client_data_bl);
274
275 Context *ctx = create_context_callback<
276 ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_update_sync_point>(
277 this);
278 m_journaler->update_client(client_data_bl, ctx);
279}
280
281template <typename I>
282void ImageCopyRequest<I>::handle_update_sync_point(int r) {
283 CephContext *cct = m_local_image_ctx->cct;
284 ldout(cct, 20) << ": r=" << r << dendl;
285
286 if (r < 0) {
287 *m_client_meta = m_client_meta_copy;
288 lderr(cct) << ": failed to update client data: " << cpp_strerror(r)
289 << dendl;
290 }
291
292 bool complete;
293 {
294 Mutex::Locker l(m_lock);
295 m_updating_sync_point = false;
296
297 complete = m_current_ops == 0 || m_canceled || m_ret_val < 0;
298
299 if (!complete) {
300 m_update_sync_ctx = new FunctionContext([this](int r) {
301 this->send_update_sync_point();
302 });
303 }
304 }
305
306 if (!complete) {
307 Mutex::Locker timer_lock(*m_timer_lock);
308 if (m_update_sync_ctx) {
309 m_timer->add_event_after(m_update_sync_point_interval,
310 m_update_sync_ctx);
311 }
312 } else {
313 send_flush_sync_point();
314 }
315}
316
317template <typename I>
318void ImageCopyRequest<I>::send_flush_sync_point() {
319 if (m_ret_val < 0) {
320 finish(m_ret_val);
321 return;
322 }
323
324 update_progress("FLUSH_SYNC_POINT");
325
326 m_client_meta_copy = *m_client_meta;
327 if (m_object_no > 0) {
328 m_sync_point->object_number = m_object_no - 1;
329 } else {
330 m_sync_point->object_number = boost::none;
331 }
332
333 dout(20) << ": sync_point=" << *m_sync_point << dendl;
334
335 bufferlist client_data_bl;
336 librbd::journal::ClientData client_data(m_client_meta_copy);
337 ::encode(client_data, client_data_bl);
338
339 Context *ctx = create_context_callback<
340 ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_flush_sync_point>(
341 this);
342 m_journaler->update_client(client_data_bl, ctx);
343}
344
345template <typename I>
346void ImageCopyRequest<I>::handle_flush_sync_point(int r) {
347 dout(20) << ": r=" << r << dendl;
348
349 if (r < 0) {
350 *m_client_meta = m_client_meta_copy;
351
352 derr << ": failed to update client data: " << cpp_strerror(r)
353 << dendl;
354 finish(r);
355 return;
356 }
357
358 finish(0);
359}
360
361template <typename I>
362int ImageCopyRequest<I>::compute_snap_map() {
363
364 librados::snap_t snap_id_start = 0;
365 librados::snap_t snap_id_end;
366 {
367 RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock);
368 snap_id_end = m_remote_image_ctx->get_snap_id(
369 cls::rbd::UserSnapshotNamespace(), m_sync_point->snap_name);
370 if (snap_id_end == CEPH_NOSNAP) {
371 derr << ": failed to locate snapshot: "
372 << m_sync_point->snap_name << dendl;
373 return -ENOENT;
374 }
375
376 if (!m_sync_point->from_snap_name.empty()) {
377 snap_id_start = m_remote_image_ctx->get_snap_id(
378 cls::rbd::UserSnapshotNamespace(), m_sync_point->from_snap_name);
379 if (snap_id_start == CEPH_NOSNAP) {
380 derr << ": failed to locate from snapshot: "
381 << m_sync_point->from_snap_name << dendl;
382 return -ENOENT;
383 }
384 }
385 }
386
387 SnapIds snap_ids;
388 for (auto it = m_client_meta->snap_seqs.begin();
389 it != m_client_meta->snap_seqs.end(); ++it) {
390 snap_ids.insert(snap_ids.begin(), it->second);
391 if (it->first < snap_id_start) {
392 continue;
393 } else if (it->first > snap_id_end) {
394 break;
395 }
396
397 m_snap_map[it->first] = snap_ids;
398 }
399
400 if (m_snap_map.empty()) {
401 derr << ": failed to map snapshots within boundary" << dendl;
402 return -EINVAL;
403 }
404
405 return 0;
406}
407
408template <typename I>
409void ImageCopyRequest<I>::update_progress(const std::string &description,
410 bool flush) {
411 dout(20) << ": " << description << dendl;
412
413 if (m_progress_ctx) {
414 m_progress_ctx->update_progress("IMAGE_COPY/" + description, flush);
415 }
416}
417
418} // namespace image_sync
419} // namespace mirror
420} // namespace rbd
421
422template class rbd::mirror::image_sync::ImageCopyRequest<librbd::ImageCtx>;