]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/deep_copy/ImageCopyRequest.cc
17aaa533efa4b4f73730c3c04db411f2a7b45bec
[ceph.git] / ceph / src / librbd / deep_copy / ImageCopyRequest.cc
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 "common/errno.h"
7 #include "librbd/Utils.h"
8 #include "librbd/deep_copy/Handler.h"
9 #include "librbd/deep_copy/Utils.h"
10 #include "librbd/image/CloseRequest.h"
11 #include "librbd/image/OpenRequest.h"
12 #include "librbd/object_map/DiffRequest.h"
13 #include "osdc/Striper.h"
14
15 #define dout_subsys ceph_subsys_rbd
16 #undef dout_prefix
17 #define dout_prefix *_dout << "librbd::deep_copy::ImageCopyRequest: " \
18 << this << " " << __func__ << ": "
19
20 namespace librbd {
21 namespace deep_copy {
22
23 using librbd::util::create_context_callback;
24 using librbd::util::unique_lock_name;
25
26 template <typename I>
27 ImageCopyRequest<I>::ImageCopyRequest(I *src_image_ctx, I *dst_image_ctx,
28 librados::snap_t src_snap_id_start,
29 librados::snap_t src_snap_id_end,
30 librados::snap_t dst_snap_id_start,
31 bool flatten,
32 const ObjectNumber &object_number,
33 const SnapSeqs &snap_seqs,
34 Handler *handler,
35 Context *on_finish)
36 : RefCountedObject(dst_image_ctx->cct), m_src_image_ctx(src_image_ctx),
37 m_dst_image_ctx(dst_image_ctx), m_src_snap_id_start(src_snap_id_start),
38 m_src_snap_id_end(src_snap_id_end), m_dst_snap_id_start(dst_snap_id_start),
39 m_flatten(flatten), m_object_number(object_number), m_snap_seqs(snap_seqs),
40 m_handler(handler), m_on_finish(on_finish), m_cct(dst_image_ctx->cct),
41 m_lock(ceph::make_mutex(unique_lock_name("ImageCopyRequest::m_lock", this))) {
42 }
43
44 template <typename I>
45 void ImageCopyRequest<I>::send() {
46 m_dst_image_ctx->image_lock.lock_shared();
47 util::compute_snap_map(m_dst_image_ctx->cct, m_src_snap_id_start,
48 m_src_snap_id_end, m_dst_image_ctx->snaps, m_snap_seqs,
49 &m_snap_map);
50 m_dst_image_ctx->image_lock.unlock_shared();
51
52 if (m_snap_map.empty()) {
53 lderr(m_cct) << "failed to map snapshots within boundary" << dendl;
54 finish(-EINVAL);
55 return;
56 }
57
58 compute_diff();
59 }
60
61 template <typename I>
62 void ImageCopyRequest<I>::cancel() {
63 std::lock_guard locker{m_lock};
64
65 ldout(m_cct, 20) << dendl;
66 m_canceled = true;
67 }
68
69 template <typename I>
70 void ImageCopyRequest<I>::map_src_objects(uint64_t dst_object,
71 std::set<uint64_t> *src_objects) {
72 std::vector<std::pair<uint64_t, uint64_t>> image_extents;
73 Striper::extent_to_file(m_cct, &m_dst_image_ctx->layout, dst_object, 0,
74 m_dst_image_ctx->layout.object_size, image_extents);
75
76 for (auto &e : image_extents) {
77 std::map<object_t, std::vector<ObjectExtent>> src_object_extents;
78 Striper::file_to_extents(m_cct, m_src_image_ctx->format_string,
79 &m_src_image_ctx->layout, e.first, e.second, 0,
80 src_object_extents);
81 for (auto &p : src_object_extents) {
82 for (auto &s : p.second) {
83 src_objects->insert(s.objectno);
84 }
85 }
86 }
87
88 ceph_assert(!src_objects->empty());
89
90 ldout(m_cct, 20) << dst_object << " -> " << *src_objects << dendl;
91 }
92
93 template <typename I>
94 void ImageCopyRequest<I>::compute_diff() {
95 if (m_flatten) {
96 send_object_copies();
97 return;
98 }
99
100 ldout(m_cct, 10) << dendl;
101
102 auto ctx = create_context_callback<
103 ImageCopyRequest<I>, &ImageCopyRequest<I>::handle_compute_diff>(this);
104 auto req = object_map::DiffRequest<I>::create(m_src_image_ctx, m_src_snap_id_start,
105 m_src_snap_id_end, &m_object_diff_state,
106 ctx);
107 req->send();
108 }
109
110 template <typename I>
111 void ImageCopyRequest<I>::handle_compute_diff(int r) {
112 ldout(m_cct, 10) << "r=" << r << dendl;
113
114 if (r < 0) {
115 ldout(m_cct, 10) << "fast-diff optimization disabled" << dendl;
116 m_object_diff_state.resize(0);
117 }
118
119 send_object_copies();
120 }
121
122 template <typename I>
123 void ImageCopyRequest<I>::send_object_copies() {
124 m_object_no = 0;
125 if (m_object_number) {
126 m_object_no = *m_object_number + 1;
127 }
128
129 uint64_t size;
130 {
131 std::shared_lock image_locker{m_src_image_ctx->image_lock};
132 size = m_src_image_ctx->get_image_size(CEPH_NOSNAP);
133 for (auto snap_id : m_src_image_ctx->snaps) {
134 size = std::max(size, m_src_image_ctx->get_image_size(snap_id));
135 }
136 }
137 m_end_object_no = Striper::get_num_objects(m_dst_image_ctx->layout, size);
138
139 ldout(m_cct, 20) << "start_object=" << m_object_no << ", "
140 << "end_object=" << m_end_object_no << dendl;
141
142 bool complete;
143 {
144 std::lock_guard locker{m_lock};
145 auto max_ops = m_src_image_ctx->config.template get_val<uint64_t>(
146 "rbd_concurrent_management_ops");
147
148 // attempt to schedule at least 'max_ops' initial requests where
149 // some objects might be skipped if fast-diff notes no change
150 while (m_current_ops < max_ops) {
151 int r = send_next_object_copy();
152 if (r < 0) {
153 break;
154 }
155 }
156
157 complete = (m_current_ops == 0) && !m_updating_progress;
158 }
159
160 if (complete) {
161 finish(m_ret_val);
162 }
163 }
164
165 template <typename I>
166 int ImageCopyRequest<I>::send_next_object_copy() {
167 ceph_assert(ceph_mutex_is_locked(m_lock));
168
169 if (m_canceled && m_ret_val == 0) {
170 ldout(m_cct, 10) << "image copy canceled" << dendl;
171 m_ret_val = -ECANCELED;
172 }
173
174 if (m_ret_val < 0) {
175 return m_ret_val;
176 } else if (m_object_no >= m_end_object_no) {
177 return -ENODATA;
178 }
179
180 uint64_t ono = m_object_no++;
181
182 if (m_object_diff_state.size() > 0) {
183 std::set<uint64_t> src_objects;
184 map_src_objects(ono, &src_objects);
185
186 bool skip = true;
187 for (auto src_ono : src_objects) {
188 if (src_ono >= m_object_diff_state.size() ||
189 m_object_diff_state[src_ono] != object_map::DIFF_STATE_NONE) {
190 skip = false;
191 break;
192 }
193 }
194
195 if (skip) {
196 ldout(m_cct, 20) << "skipping clean object " << ono << dendl;
197 return 1;
198 }
199 }
200
201 ldout(m_cct, 20) << "object_num=" << ono << dendl;
202 ++m_current_ops;
203
204 Context *ctx = new LambdaContext(
205 [this, ono](int r) {
206 handle_object_copy(ono, r);
207 });
208 auto req = ObjectCopyRequest<I>::create(
209 m_src_image_ctx, m_dst_image_ctx, m_src_snap_id_start, m_dst_snap_id_start,
210 m_snap_map, ono, m_flatten, m_handler, ctx);
211 req->send();
212 return 0;
213 }
214
215 template <typename I>
216 void ImageCopyRequest<I>::handle_object_copy(uint64_t object_no, int r) {
217 ldout(m_cct, 20) << "object_no=" << object_no << ", r=" << r << dendl;
218
219 bool complete;
220 {
221 std::lock_guard locker{m_lock};
222 ceph_assert(m_current_ops > 0);
223 --m_current_ops;
224
225 if (r < 0 && r != -ENOENT) {
226 lderr(m_cct) << "object copy failed: " << cpp_strerror(r) << dendl;
227 if (m_ret_val == 0) {
228 m_ret_val = r;
229 }
230 } else {
231 m_copied_objects.push(object_no);
232 while (!m_updating_progress && !m_copied_objects.empty() &&
233 m_copied_objects.top() ==
234 (m_object_number ? *m_object_number + 1 : 0)) {
235 m_object_number = m_copied_objects.top();
236 m_copied_objects.pop();
237 uint64_t progress_object_no = *m_object_number + 1;
238 m_updating_progress = true;
239 m_lock.unlock();
240 m_handler->update_progress(progress_object_no, m_end_object_no);
241 m_lock.lock();
242 ceph_assert(m_updating_progress);
243 m_updating_progress = false;
244 }
245 }
246
247 while (true) {
248 r = send_next_object_copy();
249 if (r != 1) {
250 break;
251 }
252 }
253
254 complete = (m_current_ops == 0) && !m_updating_progress;
255 }
256
257 if (complete) {
258 finish(m_ret_val);
259 }
260 }
261
262 template <typename I>
263 void ImageCopyRequest<I>::finish(int r) {
264 ldout(m_cct, 20) << "r=" << r << dendl;
265
266 m_on_finish->complete(r);
267 put();
268 }
269
270 } // namespace deep_copy
271 } // namespace librbd
272
273 template class librbd::deep_copy::ImageCopyRequest<librbd::ImageCtx>;