]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/ImageSync.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / rbd_mirror / ImageSync.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 "ImageSync.h"
31f18b77 5#include "InstanceWatcher.h"
7c673cae 6#include "ProgressContext.h"
11fdf7f2
TL
7#include "common/debug.h"
8#include "common/Timer.h"
7c673cae 9#include "common/errno.h"
11fdf7f2 10#include "librbd/DeepCopyRequest.h"
7c673cae 11#include "librbd/ImageCtx.h"
11fdf7f2 12#include "librbd/ImageState.h"
7c673cae 13#include "librbd/Utils.h"
11fdf7f2 14#include "librbd/internal.h"
9f95a23c 15#include "tools/rbd_mirror/Threads.h"
7c673cae
FG
16#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
17#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
9f95a23c 18#include "tools/rbd_mirror/image_sync/Types.h"
7c673cae
FG
19
20#define dout_context g_ceph_context
21#define dout_subsys ceph_subsys_rbd_mirror
22#undef dout_prefix
23#define dout_prefix *_dout << "rbd::mirror::ImageSync: " \
24 << this << " " << __func__
25
26namespace rbd {
27namespace mirror {
28
29using namespace image_sync;
28e407b8 30using librbd::util::create_async_context_callback;
7c673cae
FG
31using librbd::util::create_context_callback;
32using librbd::util::unique_lock_name;
33
11fdf7f2
TL
34template <typename I>
35class ImageSync<I>::ImageCopyProgressContext : public librbd::ProgressContext {
36public:
37 ImageCopyProgressContext(ImageSync *image_sync) : image_sync(image_sync) {
38 }
39
40 int update_progress(uint64_t object_no, uint64_t object_count) override {
41 image_sync->handle_copy_image_update_progress(object_no, object_count);
42 return 0;
43 }
44
45 ImageSync *image_sync;
46};
47
7c673cae 48template <typename I>
9f95a23c
TL
49ImageSync<I>::ImageSync(
50 Threads<I>* threads,
51 I *local_image_ctx,
52 I *remote_image_ctx,
53 const std::string &local_mirror_uuid,
54 image_sync::SyncPointHandler* sync_point_handler,
55 InstanceWatcher<I> *instance_watcher,
56 ProgressContext *progress_ctx,
57 Context *on_finish)
58 : CancelableRequest("rbd::mirror::ImageSync", local_image_ctx->cct,
59 on_finish),
60 m_threads(threads),
61 m_local_image_ctx(local_image_ctx),
62 m_remote_image_ctx(remote_image_ctx),
63 m_local_mirror_uuid(local_mirror_uuid),
64 m_sync_point_handler(sync_point_handler),
65 m_instance_watcher(instance_watcher),
31f18b77 66 m_progress_ctx(progress_ctx),
9f95a23c
TL
67 m_lock(ceph::make_mutex(unique_lock_name("ImageSync::m_lock", this))),
68 m_update_sync_point_interval(
69 m_local_image_ctx->cct->_conf.template get_val<double>(
70 "rbd_mirror_sync_point_update_age")) {
7c673cae
FG
71}
72
73template <typename I>
74ImageSync<I>::~ImageSync() {
11fdf7f2
TL
75 ceph_assert(m_image_copy_request == nullptr);
76 ceph_assert(m_image_copy_prog_ctx == nullptr);
77 ceph_assert(m_update_sync_ctx == nullptr);
7c673cae
FG
78}
79
80template <typename I>
81void ImageSync<I>::send() {
31f18b77 82 send_notify_sync_request();
7c673cae
FG
83}
84
85template <typename I>
86void ImageSync<I>::cancel() {
9f95a23c 87 std::lock_guard locker{m_lock};
7c673cae 88
11fdf7f2 89 dout(10) << dendl;
7c673cae
FG
90
91 m_canceled = true;
92
31f18b77
FG
93 if (m_instance_watcher->cancel_sync_request(m_local_image_ctx->id)) {
94 return;
95 }
96
7c673cae
FG
97 if (m_image_copy_request != nullptr) {
98 m_image_copy_request->cancel();
99 }
100}
101
31f18b77
FG
102template <typename I>
103void ImageSync<I>::send_notify_sync_request() {
104 update_progress("NOTIFY_SYNC_REQUEST");
105
11fdf7f2 106 dout(10) << dendl;
31f18b77 107
9f95a23c 108 m_lock.lock();
28e407b8 109 if (m_canceled) {
9f95a23c
TL
110 m_lock.unlock();
111 CancelableRequest::finish(-ECANCELED);
28e407b8
AA
112 return;
113 }
114
115 Context *ctx = create_async_context_callback(
9f95a23c 116 m_threads->work_queue, create_context_callback<
28e407b8 117 ImageSync<I>, &ImageSync<I>::handle_notify_sync_request>(this));
31f18b77 118 m_instance_watcher->notify_sync_request(m_local_image_ctx->id, ctx);
9f95a23c 119 m_lock.unlock();
31f18b77
FG
120}
121
122template <typename I>
123void ImageSync<I>::handle_notify_sync_request(int r) {
11fdf7f2 124 dout(10) << ": r=" << r << dendl;
31f18b77 125
9f95a23c 126 m_lock.lock();
28e407b8
AA
127 if (r == 0 && m_canceled) {
128 r = -ECANCELED;
129 }
9f95a23c 130 m_lock.unlock();
28e407b8 131
31f18b77 132 if (r < 0) {
9f95a23c 133 CancelableRequest::finish(r);
31f18b77
FG
134 return;
135 }
136
137 send_prune_catch_up_sync_point();
138}
139
7c673cae
FG
140template <typename I>
141void ImageSync<I>::send_prune_catch_up_sync_point() {
142 update_progress("PRUNE_CATCH_UP_SYNC_POINT");
143
9f95a23c 144 if (m_sync_point_handler->get_sync_points().empty()) {
7c673cae
FG
145 send_create_sync_point();
146 return;
147 }
148
11fdf7f2 149 dout(10) << dendl;
7c673cae
FG
150
151 // prune will remove sync points with missing snapshots and
152 // ensure we have a maximum of one sync point (in case we
153 // restarted)
154 Context *ctx = create_context_callback<
155 ImageSync<I>, &ImageSync<I>::handle_prune_catch_up_sync_point>(this);
156 SyncPointPruneRequest<I> *request = SyncPointPruneRequest<I>::create(
9f95a23c 157 m_remote_image_ctx, false, m_sync_point_handler, ctx);
7c673cae
FG
158 request->send();
159}
160
161template <typename I>
162void ImageSync<I>::handle_prune_catch_up_sync_point(int r) {
11fdf7f2 163 dout(10) << ": r=" << r << dendl;
7c673cae
FG
164
165 if (r < 0) {
166 derr << ": failed to prune catch-up sync point: "
167 << cpp_strerror(r) << dendl;
168 finish(r);
169 return;
170 }
171
172 send_create_sync_point();
173}
174
175template <typename I>
176void ImageSync<I>::send_create_sync_point() {
177 update_progress("CREATE_SYNC_POINT");
178
179 // TODO: when support for disconnecting laggy clients is added,
180 // re-connect and create catch-up sync point
9f95a23c 181 if (!m_sync_point_handler->get_sync_points().empty()) {
11fdf7f2 182 send_copy_image();
7c673cae
FG
183 return;
184 }
185
11fdf7f2 186 dout(10) << dendl;
7c673cae
FG
187
188 Context *ctx = create_context_callback<
189 ImageSync<I>, &ImageSync<I>::handle_create_sync_point>(this);
190 SyncPointCreateRequest<I> *request = SyncPointCreateRequest<I>::create(
9f95a23c 191 m_remote_image_ctx, m_local_mirror_uuid, m_sync_point_handler, ctx);
7c673cae
FG
192 request->send();
193}
194
195template <typename I>
196void ImageSync<I>::handle_create_sync_point(int r) {
11fdf7f2 197 dout(10) << ": r=" << r << dendl;
7c673cae
FG
198
199 if (r < 0) {
200 derr << ": failed to create sync point: " << cpp_strerror(r)
201 << dendl;
202 finish(r);
203 return;
204 }
205
11fdf7f2 206 send_copy_image();
7c673cae
FG
207}
208
209template <typename I>
11fdf7f2
TL
210void ImageSync<I>::send_copy_image() {
211 librados::snap_t snap_id_start = 0;
212 librados::snap_t snap_id_end;
213 librbd::deep_copy::ObjectNumber object_number;
214 int r = 0;
9f95a23c
TL
215
216 m_snap_seqs_copy = m_sync_point_handler->get_snap_seqs();
217 m_sync_points_copy = m_sync_point_handler->get_sync_points();
218 ceph_assert(!m_sync_points_copy.empty());
219 auto &sync_point = m_sync_points_copy.front();
220
7c673cae 221 {
9f95a23c 222 std::shared_lock image_locker{m_remote_image_ctx->image_lock};
11fdf7f2
TL
223 snap_id_end = m_remote_image_ctx->get_snap_id(
224 cls::rbd::UserSnapshotNamespace(), sync_point.snap_name);
225 if (snap_id_end == CEPH_NOSNAP) {
226 derr << ": failed to locate snapshot: " << sync_point.snap_name << dendl;
227 r = -ENOENT;
228 } else if (!sync_point.from_snap_name.empty()) {
229 snap_id_start = m_remote_image_ctx->get_snap_id(
230 cls::rbd::UserSnapshotNamespace(), sync_point.from_snap_name);
231 if (snap_id_start == CEPH_NOSNAP) {
232 derr << ": failed to locate from snapshot: "
233 << sync_point.from_snap_name << dendl;
234 r = -ENOENT;
235 }
7c673cae 236 }
11fdf7f2 237 object_number = sync_point.object_number;
7c673cae 238 }
11fdf7f2 239 if (r < 0) {
7c673cae
FG
240 finish(r);
241 return;
242 }
243
9f95a23c 244 m_lock.lock();
7c673cae 245 if (m_canceled) {
9f95a23c 246 m_lock.unlock();
7c673cae
FG
247 finish(-ECANCELED);
248 return;
249 }
250
11fdf7f2 251 dout(10) << dendl;
7c673cae
FG
252
253 Context *ctx = create_context_callback<
254 ImageSync<I>, &ImageSync<I>::handle_copy_image>(this);
11fdf7f2
TL
255 m_image_copy_prog_ctx = new ImageCopyProgressContext(this);
256 m_image_copy_request = librbd::DeepCopyRequest<I>::create(
257 m_remote_image_ctx, m_local_image_ctx, snap_id_start, snap_id_end,
9f95a23c 258 0, false, object_number, m_threads->work_queue, &m_snap_seqs_copy,
11fdf7f2 259 m_image_copy_prog_ctx, ctx);
7c673cae 260 m_image_copy_request->get();
9f95a23c 261 m_lock.unlock();
7c673cae
FG
262
263 update_progress("COPY_IMAGE");
264
265 m_image_copy_request->send();
266}
267
268template <typename I>
269void ImageSync<I>::handle_copy_image(int r) {
11fdf7f2 270 dout(10) << ": r=" << r << dendl;
7c673cae
FG
271
272 {
9f95a23c 273 std::scoped_lock locker{m_threads->timer_lock, m_lock};
7c673cae
FG
274 m_image_copy_request->put();
275 m_image_copy_request = nullptr;
11fdf7f2
TL
276 delete m_image_copy_prog_ctx;
277 m_image_copy_prog_ctx = nullptr;
7c673cae
FG
278 if (r == 0 && m_canceled) {
279 r = -ECANCELED;
280 }
11fdf7f2
TL
281
282 if (m_update_sync_ctx != nullptr) {
9f95a23c 283 m_threads->timer->cancel_event(m_update_sync_ctx);
11fdf7f2
TL
284 m_update_sync_ctx = nullptr;
285 }
286
287 if (m_updating_sync_point) {
288 m_ret_val = r;
289 return;
290 }
7c673cae
FG
291 }
292
293 if (r == -ECANCELED) {
294 dout(10) << ": image copy canceled" << dendl;
295 finish(r);
296 return;
297 } else if (r < 0) {
298 derr << ": failed to copy image: " << cpp_strerror(r) << dendl;
299 finish(r);
300 return;
301 }
302
11fdf7f2 303 send_flush_sync_point();
7c673cae
FG
304}
305
306template <typename I>
11fdf7f2
TL
307void ImageSync<I>::handle_copy_image_update_progress(uint64_t object_no,
308 uint64_t object_count) {
309 int percent = 100 * object_no / object_count;
310 update_progress("COPY_IMAGE " + stringify(percent) + "%");
7c673cae 311
9f95a23c 312 std::lock_guard locker{m_lock};
11fdf7f2
TL
313 m_image_copy_object_no = object_no;
314 m_image_copy_object_count = object_count;
7c673cae 315
11fdf7f2
TL
316 if (m_update_sync_ctx == nullptr && !m_updating_sync_point) {
317 send_update_sync_point();
318 }
319}
7c673cae 320
11fdf7f2
TL
321template <typename I>
322void ImageSync<I>::send_update_sync_point() {
9f95a23c 323 ceph_assert(ceph_mutex_is_locked(m_lock));
7c673cae 324
11fdf7f2
TL
325 m_update_sync_ctx = nullptr;
326
327 if (m_canceled) {
328 return;
31f18b77 329 }
11fdf7f2 330
9f95a23c
TL
331 ceph_assert(!m_sync_points_copy.empty());
332 auto sync_point = &m_sync_points_copy.front();
11fdf7f2 333
9f95a23c 334 if (sync_point->object_number &&
11fdf7f2
TL
335 (m_image_copy_object_no - 1) == sync_point->object_number.get()) {
336 // update sync point did not progress since last sync
31f18b77
FG
337 return;
338 }
339
11fdf7f2
TL
340 m_updating_sync_point = true;
341
11fdf7f2
TL
342 if (m_image_copy_object_no > 0) {
343 sync_point->object_number = m_image_copy_object_no - 1;
344 }
345
9f95a23c
TL
346 auto ctx = create_context_callback<
347 ImageSync<I>, &ImageSync<I>::handle_update_sync_point>(this);
348 m_sync_point_handler->update_sync_points(m_snap_seqs_copy,
349 m_sync_points_copy, false, ctx);
7c673cae
FG
350}
351
352template <typename I>
11fdf7f2
TL
353void ImageSync<I>::handle_update_sync_point(int r) {
354 CephContext *cct = m_local_image_ctx->cct;
355 ldout(cct, 20) << ": r=" << r << dendl;
7c673cae 356
11fdf7f2 357 {
9f95a23c 358 std::scoped_lock locker{m_threads->timer_lock, m_lock};
11fdf7f2
TL
359 m_updating_sync_point = false;
360
361 if (m_image_copy_request != nullptr) {
9f95a23c 362 m_update_sync_ctx = new LambdaContext(
11fdf7f2 363 [this](int r) {
9f95a23c 364 std::lock_guard locker{m_lock};
11fdf7f2
TL
365 this->send_update_sync_point();
366 });
9f95a23c
TL
367 m_threads->timer->add_event_after(
368 m_update_sync_point_interval, m_update_sync_ctx);
11fdf7f2
TL
369 return;
370 }
371 }
372
373 send_flush_sync_point();
7c673cae
FG
374}
375
376template <typename I>
11fdf7f2
TL
377void ImageSync<I>::send_flush_sync_point() {
378 if (m_ret_val < 0) {
379 finish(m_ret_val);
380 return;
381 }
7c673cae 382
11fdf7f2
TL
383 update_progress("FLUSH_SYNC_POINT");
384
9f95a23c
TL
385 ceph_assert(!m_sync_points_copy.empty());
386 auto sync_point = &m_sync_points_copy.front();
387
11fdf7f2
TL
388 if (m_image_copy_object_no > 0) {
389 sync_point->object_number = m_image_copy_object_no - 1;
390 } else {
391 sync_point->object_number = boost::none;
392 }
393
9f95a23c
TL
394 auto ctx = create_context_callback<
395 ImageSync<I>, &ImageSync<I>::handle_flush_sync_point>(this);
396 m_sync_point_handler->update_sync_points(m_snap_seqs_copy,
397 m_sync_points_copy, false, ctx);
7c673cae
FG
398}
399
400template <typename I>
11fdf7f2
TL
401void ImageSync<I>::handle_flush_sync_point(int r) {
402 dout(10) << ": r=" << r << dendl;
7c673cae 403
11fdf7f2 404 if (r < 0) {
11fdf7f2
TL
405 derr << ": failed to update client data: " << cpp_strerror(r)
406 << dendl;
407 finish(r);
408 return;
7c673cae 409 }
7c673cae
FG
410
411 send_prune_sync_points();
412}
413
414template <typename I>
415void ImageSync<I>::send_prune_sync_points() {
11fdf7f2 416 dout(10) << dendl;
7c673cae
FG
417
418 update_progress("PRUNE_SYNC_POINTS");
419
420 Context *ctx = create_context_callback<
421 ImageSync<I>, &ImageSync<I>::handle_prune_sync_points>(this);
422 SyncPointPruneRequest<I> *request = SyncPointPruneRequest<I>::create(
9f95a23c 423 m_remote_image_ctx, true, m_sync_point_handler, ctx);
7c673cae
FG
424 request->send();
425}
426
427template <typename I>
428void ImageSync<I>::handle_prune_sync_points(int r) {
11fdf7f2 429 dout(10) << ": r=" << r << dendl;
7c673cae
FG
430
431 if (r < 0) {
432 derr << ": failed to prune sync point: "
433 << cpp_strerror(r) << dendl;
434 finish(r);
435 return;
436 }
437
9f95a23c 438 if (!m_sync_point_handler->get_sync_points().empty()) {
7c673cae
FG
439 send_copy_image();
440 return;
441 }
442
443 finish(0);
444}
445
446template <typename I>
447void ImageSync<I>::update_progress(const std::string &description) {
448 dout(20) << ": " << description << dendl;
449
450 if (m_progress_ctx) {
451 m_progress_ctx->update_progress("IMAGE_SYNC/" + description);
452 }
453}
454
31f18b77
FG
455template <typename I>
456void ImageSync<I>::finish(int r) {
457 dout(20) << ": r=" << r << dendl;
458
459 m_instance_watcher->notify_sync_complete(m_local_image_ctx->id);
9f95a23c 460 CancelableRequest::finish(r);
31f18b77
FG
461}
462
7c673cae
FG
463} // namespace mirror
464} // namespace rbd
465
466template class rbd::mirror::ImageSync<librbd::ImageCtx>;