]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/object_map/DiffRequest.cc
import ceph 16.2.7
[ceph.git] / ceph / src / librbd / object_map / DiffRequest.cc
CommitLineData
9f95a23c
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "librbd/object_map/DiffRequest.h"
5#include "common/debug.h"
6#include "common/errno.h"
7#include "librbd/ImageCtx.h"
8#include "librbd/ObjectMap.h"
9#include "librbd/Utils.h"
10#include "osdc/Striper.h"
11#include <string>
12
13#define dout_subsys ceph_subsys_rbd
14#undef dout_prefix
15#define dout_prefix *_dout << "librbd::object_map::DiffRequest: " \
16 << this << " " << __func__ << ": "
17
18namespace librbd {
19namespace object_map {
20
21using util::create_rados_callback;
22
23template <typename I>
24void DiffRequest<I>::send() {
adb31ebb 25 auto cct = m_image_ctx->cct;
9f95a23c 26
adb31ebb
TL
27 if (m_snap_id_start == CEPH_NOSNAP || m_snap_id_start > m_snap_id_end) {
28 lderr(cct) << "invalid start/end snap ids: "
29 << "snap_id_start=" << m_snap_id_start << ", "
30 << "snap_id_end=" << m_snap_id_end << dendl;
31 finish(-EINVAL);
32 return;
33 } else if (m_snap_id_start == m_snap_id_end) {
34 // no delta between the same snapshot
35 finish(0);
36 return;
9f95a23c
TL
37 }
38
39 m_object_diff_state->clear();
adb31ebb
TL
40
41 // collect all the snap ids in the provided range (inclusive)
42 if (m_snap_id_start != 0) {
43 m_snap_ids.insert(m_snap_id_start);
44 }
45
46 std::shared_lock image_locker{m_image_ctx->image_lock};
47 auto snap_info_it = m_image_ctx->snap_info.upper_bound(m_snap_id_start);
48 auto snap_info_it_end = m_image_ctx->snap_info.lower_bound(m_snap_id_end);
49 for (; snap_info_it != snap_info_it_end; ++snap_info_it) {
50 m_snap_ids.insert(snap_info_it->first);
51 }
52 m_snap_ids.insert(m_snap_id_end);
9f95a23c
TL
53
54 load_object_map(&image_locker);
55}
56
57template <typename I>
58void DiffRequest<I>::load_object_map(
59 std::shared_lock<ceph::shared_mutex>* image_locker) {
60 ceph_assert(ceph_mutex_is_locked(m_image_ctx->image_lock));
61
adb31ebb
TL
62 if (m_snap_ids.empty()) {
63 image_locker->unlock();
9f95a23c 64
adb31ebb
TL
65 finish(0);
66 return;
9f95a23c
TL
67 }
68
adb31ebb
TL
69 m_current_snap_id = *m_snap_ids.begin();
70 m_snap_ids.erase(m_current_snap_id);
71
72 auto cct = m_image_ctx->cct;
73 ldout(cct, 10) << "snap_id=" << m_current_snap_id << dendl;
74
75 if ((m_image_ctx->features & RBD_FEATURE_FAST_DIFF) == 0) {
9f95a23c
TL
76 image_locker->unlock();
77
78 ldout(cct, 10) << "fast-diff feature not enabled" << dendl;
79 finish(-EINVAL);
80 return;
81 }
82
adb31ebb
TL
83 // ignore ENOENT with intermediate snapshots since deleted
84 // snaps will get merged with later snapshots
85 m_ignore_enoent = (m_current_snap_id != m_snap_id_start &&
86 m_current_snap_id != m_snap_id_end);
87
88 if (m_current_snap_id == CEPH_NOSNAP) {
89 m_current_size = m_image_ctx->size;
90 } else {
91 auto snap_it = m_image_ctx->snap_info.find(m_current_snap_id);
92 if (snap_it == m_image_ctx->snap_info.end()) {
93 ldout(cct, 10) << "snapshot " << m_current_snap_id << " does not exist"
94 << dendl;
95 if (!m_ignore_enoent) {
96 image_locker->unlock();
97
98 finish(-ENOENT);
99 return;
100 }
101
102 load_object_map(image_locker);
103 return;
104 }
105
106 m_current_size = snap_it->second.size;
107 }
108
9f95a23c
TL
109 uint64_t flags = 0;
110 int r = m_image_ctx->get_flags(m_current_snap_id, &flags);
111 if (r < 0) {
112 image_locker->unlock();
113
114 lderr(cct) << "failed to retrieve image flags: " << cpp_strerror(r)
115 << dendl;
116 finish(r);
117 return;
118 }
adb31ebb 119 image_locker->unlock();
9f95a23c 120
adb31ebb 121 if ((flags & RBD_FLAG_FAST_DIFF_INVALID) != 0) {
9f95a23c
TL
122 ldout(cct, 1) << "cannot perform fast diff on invalid object map"
123 << dendl;
124 finish(-EINVAL);
125 return;
126 }
127
128 std::string oid(ObjectMap<>::object_map_name(m_image_ctx->id,
129 m_current_snap_id));
130
131 librados::ObjectReadOperation op;
132 cls_client::object_map_load_start(&op);
133
134 m_out_bl.clear();
135 auto aio_comp = create_rados_callback<
136 DiffRequest<I>, &DiffRequest<I>::handle_load_object_map>(this);
137 r = m_image_ctx->md_ctx.aio_operate(oid, aio_comp, &op, &m_out_bl);
138 ceph_assert(r == 0);
139 aio_comp->release();
140}
141
142template <typename I>
143void DiffRequest<I>::handle_load_object_map(int r) {
144 auto cct = m_image_ctx->cct;
145 ldout(cct, 10) << "r=" << r << dendl;
146
147 if (r == 0) {
148 auto bl_it = m_out_bl.cbegin();
149 r = cls_client::object_map_load_finish(&bl_it, &m_object_map);
150 }
151
152 std::string oid(ObjectMap<>::object_map_name(m_image_ctx->id,
153 m_current_snap_id));
adb31ebb
TL
154 if (r == -ENOENT && m_ignore_enoent) {
155 ldout(cct, 10) << "object map " << oid << " does not exist" << dendl;
156
157 std::shared_lock image_locker{m_image_ctx->image_lock};
158 load_object_map(&image_locker);
159 return;
160 } else if (r < 0) {
9f95a23c
TL
161 lderr(cct) << "failed to load object map: " << oid << dendl;
162 finish(r);
163 return;
164 }
165 ldout(cct, 20) << "loaded object map " << oid << dendl;
166
167 uint64_t num_objs = Striper::get_num_objects(m_image_ctx->layout,
168 m_current_size);
169 if (m_object_map.size() < num_objs) {
170 ldout(cct, 1) << "object map too small: "
171 << m_object_map.size() << " < " << num_objs << dendl;
172 finish(-EINVAL);
173 return;
174 } else {
175 m_object_map.resize(num_objs);
176 }
177
cd265ab1
TL
178 size_t prev_object_diff_state_size = m_object_diff_state->size();
179 if (prev_object_diff_state_size < num_objs) {
9f95a23c
TL
180 // the diff state should be the largest of all snapshots in the set
181 m_object_diff_state->resize(num_objs);
182 }
183 if (m_object_map.size() < m_object_diff_state->size()) {
184 // the image was shrunk so expanding the object map will flag end objects
185 // as non-existent and they will be compared against the previous object
cd265ab1 186 // diff state
9f95a23c
TL
187 m_object_map.resize(m_object_diff_state->size());
188 }
189
cd265ab1 190 uint64_t overlap = std::min(m_object_map.size(), prev_object_diff_state_size);
9f95a23c
TL
191 auto it = m_object_map.begin();
192 auto overlap_end_it = it + overlap;
9f95a23c
TL
193 auto diff_it = m_object_diff_state->begin();
194 uint64_t i = 0;
cd265ab1
TL
195 for (; it != overlap_end_it; ++it, ++diff_it, ++i) {
196 uint8_t object_map_state = *it;
197 uint8_t prev_object_diff_state = *diff_it;
198 if (object_map_state == OBJECT_EXISTS ||
199 object_map_state == OBJECT_PENDING ||
200 (object_map_state == OBJECT_EXISTS_CLEAN &&
201 prev_object_diff_state != DIFF_STATE_DATA &&
202 prev_object_diff_state != DIFF_STATE_DATA_UPDATED)) {
203 *diff_it = DIFF_STATE_DATA_UPDATED;
204 } else if (object_map_state == OBJECT_NONEXISTENT &&
205 prev_object_diff_state != DIFF_STATE_HOLE &&
206 prev_object_diff_state != DIFF_STATE_HOLE_UPDATED) {
207 *diff_it = DIFF_STATE_HOLE_UPDATED;
9f95a23c 208 }
cd265ab1
TL
209
210 ldout(cct, 20) << "object state: " << i << " "
211 << static_cast<uint32_t>(prev_object_diff_state)
212 << "->" << static_cast<uint32_t>(*diff_it) << " ("
213 << static_cast<uint32_t>(object_map_state) << ")"
214 << dendl;
9f95a23c
TL
215 }
216 ldout(cct, 20) << "computed overlap diffs" << dendl;
217
adb31ebb 218 bool diff_from_start = (m_snap_id_start == 0);
9f95a23c 219 auto end_it = m_object_map.end();
cd265ab1 220 if (m_object_map.size() > prev_object_diff_state_size) {
9f95a23c 221 for (; it != end_it; ++it,++diff_it, ++i) {
cd265ab1
TL
222 uint8_t object_map_state = *it;
223 if (object_map_state == OBJECT_NONEXISTENT) {
224 *diff_it = DIFF_STATE_HOLE;
a4b75251
TL
225 } else if (diff_from_start ||
226 (m_object_diff_state_valid &&
227 object_map_state != OBJECT_EXISTS_CLEAN)) {
cd265ab1 228 *diff_it = DIFF_STATE_DATA_UPDATED;
9f95a23c 229 } else {
cd265ab1 230 *diff_it = DIFF_STATE_DATA;
9f95a23c 231 }
cd265ab1
TL
232
233 ldout(cct, 20) << "object state: " << i << " "
234 << "->" << static_cast<uint32_t>(*diff_it) << " ("
235 << static_cast<uint32_t>(*it) << ")" << dendl;
9f95a23c
TL
236 }
237 }
238 ldout(cct, 20) << "computed resize diffs" << dendl;
239
cd265ab1 240 m_object_diff_state_valid = true;
9f95a23c
TL
241
242 std::shared_lock image_locker{m_image_ctx->image_lock};
243 load_object_map(&image_locker);
244}
245
246template <typename I>
247void DiffRequest<I>::finish(int r) {
248 auto cct = m_image_ctx->cct;
249 ldout(cct, 10) << "r=" << r << dendl;
250
251 m_on_finish->complete(r);
252 delete this;
253}
254
255} // namespace object_map
256} // namespace librbd
257
258template class librbd::object_map::DiffRequest<librbd::ImageCtx>;