]>
Commit | Line | Data |
---|---|---|
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 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "SnapMapper.h" | |
16 | ||
17 | #define dout_context cct | |
18 | #define dout_subsys ceph_subsys_osd | |
19 | #undef dout_prefix | |
20 | #define dout_prefix *_dout << "snap_mapper." | |
21 | ||
22 | using std::string; | |
23 | ||
24 | const string SnapMapper::MAPPING_PREFIX = "MAP_"; | |
25 | const string SnapMapper::OBJECT_PREFIX = "OBJ_"; | |
26 | ||
27 | int OSDriver::get_keys( | |
28 | const std::set<std::string> &keys, | |
29 | std::map<std::string, bufferlist> *out) | |
30 | { | |
31 | return os->omap_get_values(cid, hoid, keys, out); | |
32 | } | |
33 | ||
34 | int OSDriver::get_next( | |
35 | const std::string &key, | |
36 | pair<std::string, bufferlist> *next) | |
37 | { | |
38 | ObjectMap::ObjectMapIterator iter = | |
39 | os->get_omap_iterator(cid, hoid); | |
40 | if (!iter) { | |
41 | ceph_abort(); | |
42 | return -EINVAL; | |
43 | } | |
44 | iter->upper_bound(key); | |
45 | if (iter->valid()) { | |
46 | if (next) | |
47 | *next = make_pair(iter->key(), iter->value()); | |
48 | return 0; | |
49 | } else { | |
50 | return -ENOENT; | |
51 | } | |
52 | } | |
53 | ||
54 | struct Mapping { | |
55 | snapid_t snap; | |
56 | hobject_t hoid; | |
57 | explicit Mapping(const pair<snapid_t, hobject_t> &in) | |
58 | : snap(in.first), hoid(in.second) {} | |
59 | Mapping() : snap(0) {} | |
60 | void encode(bufferlist &bl) const { | |
61 | ENCODE_START(1, 1, bl); | |
62 | ::encode(snap, bl); | |
63 | ::encode(hoid, bl); | |
64 | ENCODE_FINISH(bl); | |
65 | } | |
66 | void decode(bufferlist::iterator &bl) { | |
67 | DECODE_START(1, bl); | |
68 | ::decode(snap, bl); | |
69 | ::decode(hoid, bl); | |
70 | DECODE_FINISH(bl); | |
71 | } | |
72 | }; | |
73 | WRITE_CLASS_ENCODER(Mapping) | |
74 | ||
75 | string SnapMapper::get_prefix(snapid_t snap) | |
76 | { | |
77 | char buf[100]; | |
78 | int len = snprintf( | |
79 | buf, sizeof(buf), | |
80 | "%.*X_", (int)(sizeof(snap)*2), | |
81 | static_cast<unsigned>(snap)); | |
82 | return MAPPING_PREFIX + string(buf, len); | |
83 | } | |
84 | ||
85 | string SnapMapper::to_raw_key( | |
86 | const pair<snapid_t, hobject_t> &in) | |
87 | { | |
88 | return get_prefix(in.first) + shard_prefix + in.second.to_str(); | |
89 | } | |
90 | ||
91 | pair<string, bufferlist> SnapMapper::to_raw( | |
92 | const pair<snapid_t, hobject_t> &in) | |
93 | { | |
94 | bufferlist bl; | |
95 | ::encode(Mapping(in), bl); | |
96 | return make_pair( | |
97 | to_raw_key(in), | |
98 | bl); | |
99 | } | |
100 | ||
101 | pair<snapid_t, hobject_t> SnapMapper::from_raw( | |
102 | const pair<std::string, bufferlist> &image) | |
103 | { | |
104 | Mapping map; | |
105 | bufferlist bl(image.second); | |
106 | bufferlist::iterator bp(bl.begin()); | |
107 | ::decode(map, bp); | |
108 | return make_pair(map.snap, map.hoid); | |
109 | } | |
110 | ||
111 | bool SnapMapper::is_mapping(const string &to_test) | |
112 | { | |
113 | return to_test.substr(0, MAPPING_PREFIX.size()) == MAPPING_PREFIX; | |
114 | } | |
115 | ||
116 | string SnapMapper::to_object_key(const hobject_t &hoid) | |
117 | { | |
118 | return OBJECT_PREFIX + shard_prefix + hoid.to_str(); | |
119 | } | |
120 | ||
121 | void SnapMapper::object_snaps::encode(bufferlist &bl) const | |
122 | { | |
123 | ENCODE_START(1, 1, bl); | |
124 | ::encode(oid, bl); | |
125 | ::encode(snaps, bl); | |
126 | ENCODE_FINISH(bl); | |
127 | } | |
128 | ||
129 | void SnapMapper::object_snaps::decode(bufferlist::iterator &bl) | |
130 | { | |
131 | DECODE_START(1, bl); | |
132 | ::decode(oid, bl); | |
133 | ::decode(snaps, bl); | |
134 | DECODE_FINISH(bl); | |
135 | } | |
136 | ||
137 | int SnapMapper::get_snaps( | |
138 | const hobject_t &oid, | |
139 | object_snaps *out) | |
140 | { | |
141 | assert(check(oid)); | |
142 | set<string> keys; | |
143 | map<string, bufferlist> got; | |
144 | keys.insert(to_object_key(oid)); | |
145 | int r = backend.get_keys(keys, &got); | |
146 | if (r < 0) | |
147 | return r; | |
148 | if (got.empty()) | |
149 | return -ENOENT; | |
150 | if (out) { | |
151 | bufferlist::iterator bp = got.begin()->second.begin(); | |
152 | ::decode(*out, bp); | |
153 | dout(20) << __func__ << " " << oid << " " << out->snaps << dendl; | |
28e407b8 AA |
154 | if (out->snaps.empty()) { |
155 | dout(1) << __func__ << " " << oid << " empty snapset" << dendl; | |
156 | assert(!cct->_conf->osd_debug_verify_snaps); | |
157 | } | |
7c673cae FG |
158 | } else { |
159 | dout(20) << __func__ << " " << oid << " (out == NULL)" << dendl; | |
160 | } | |
161 | return 0; | |
162 | } | |
163 | ||
164 | void SnapMapper::clear_snaps( | |
165 | const hobject_t &oid, | |
166 | MapCacher::Transaction<std::string, bufferlist> *t) | |
167 | { | |
168 | dout(20) << __func__ << " " << oid << dendl; | |
169 | assert(check(oid)); | |
170 | set<string> to_remove; | |
171 | to_remove.insert(to_object_key(oid)); | |
31f18b77 FG |
172 | if (g_conf->subsys.should_gather(ceph_subsys_osd, 20)) { |
173 | for (auto& i : to_remove) { | |
174 | dout(20) << __func__ << " rm " << i << dendl; | |
175 | } | |
176 | } | |
7c673cae FG |
177 | backend.remove_keys(to_remove, t); |
178 | } | |
179 | ||
180 | void SnapMapper::set_snaps( | |
181 | const hobject_t &oid, | |
182 | const object_snaps &in, | |
183 | MapCacher::Transaction<std::string, bufferlist> *t) | |
184 | { | |
185 | assert(check(oid)); | |
186 | map<string, bufferlist> to_set; | |
187 | bufferlist bl; | |
188 | ::encode(in, bl); | |
189 | to_set[to_object_key(oid)] = bl; | |
190 | dout(20) << __func__ << " " << oid << " " << in.snaps << dendl; | |
31f18b77 FG |
191 | if (g_conf->subsys.should_gather(ceph_subsys_osd, 20)) { |
192 | for (auto& i : to_set) { | |
193 | dout(20) << __func__ << " set " << i.first << dendl; | |
194 | } | |
195 | } | |
7c673cae FG |
196 | backend.set_keys(to_set, t); |
197 | } | |
198 | ||
199 | int SnapMapper::update_snaps( | |
200 | const hobject_t &oid, | |
201 | const set<snapid_t> &new_snaps, | |
202 | const set<snapid_t> *old_snaps_check, | |
203 | MapCacher::Transaction<std::string, bufferlist> *t) | |
204 | { | |
205 | dout(20) << __func__ << " " << oid << " " << new_snaps | |
206 | << " was " << (old_snaps_check ? *old_snaps_check : set<snapid_t>()) | |
207 | << dendl; | |
208 | assert(check(oid)); | |
209 | if (new_snaps.empty()) | |
210 | return remove_oid(oid, t); | |
211 | ||
212 | object_snaps out; | |
213 | int r = get_snaps(oid, &out); | |
214 | if (r < 0) | |
215 | return r; | |
216 | if (old_snaps_check) | |
217 | assert(out.snaps == *old_snaps_check); | |
218 | ||
219 | object_snaps in(oid, new_snaps); | |
220 | set_snaps(oid, in, t); | |
221 | ||
222 | set<string> to_remove; | |
223 | for (set<snapid_t>::iterator i = out.snaps.begin(); | |
224 | i != out.snaps.end(); | |
225 | ++i) { | |
226 | if (!new_snaps.count(*i)) { | |
227 | to_remove.insert(to_raw_key(make_pair(*i, oid))); | |
228 | } | |
229 | } | |
31f18b77 FG |
230 | if (g_conf->subsys.should_gather(ceph_subsys_osd, 20)) { |
231 | for (auto& i : to_remove) { | |
232 | dout(20) << __func__ << " rm " << i << dendl; | |
233 | } | |
234 | } | |
7c673cae FG |
235 | backend.remove_keys(to_remove, t); |
236 | return 0; | |
237 | } | |
238 | ||
239 | void SnapMapper::add_oid( | |
240 | const hobject_t &oid, | |
241 | const set<snapid_t>& snaps, | |
242 | MapCacher::Transaction<std::string, bufferlist> *t) | |
243 | { | |
244 | dout(20) << __func__ << " " << oid << " " << snaps << dendl; | |
94b18763 | 245 | assert(!snaps.empty()); |
7c673cae FG |
246 | assert(check(oid)); |
247 | { | |
248 | object_snaps out; | |
249 | int r = get_snaps(oid, &out); | |
94b18763 FG |
250 | if (r != -ENOENT) { |
251 | derr << __func__ << " found existing snaps mapped on " << oid | |
252 | << ", removing" << dendl; | |
253 | assert(!cct->_conf->osd_debug_verify_snaps); | |
254 | remove_oid(oid, t); | |
255 | } | |
7c673cae FG |
256 | } |
257 | ||
258 | object_snaps _snaps(oid, snaps); | |
259 | set_snaps(oid, _snaps, t); | |
260 | ||
261 | map<string, bufferlist> to_add; | |
262 | for (set<snapid_t>::iterator i = snaps.begin(); | |
263 | i != snaps.end(); | |
264 | ++i) { | |
265 | to_add.insert(to_raw(make_pair(*i, oid))); | |
266 | } | |
31f18b77 FG |
267 | if (g_conf->subsys.should_gather(ceph_subsys_osd, 20)) { |
268 | for (auto& i : to_add) { | |
269 | dout(20) << __func__ << " set " << i.first << dendl; | |
270 | } | |
271 | } | |
7c673cae FG |
272 | backend.set_keys(to_add, t); |
273 | } | |
274 | ||
275 | int SnapMapper::get_next_objects_to_trim( | |
276 | snapid_t snap, | |
277 | unsigned max, | |
278 | vector<hobject_t> *out) | |
279 | { | |
280 | assert(out); | |
281 | assert(out->empty()); | |
282 | int r = 0; | |
283 | for (set<string>::iterator i = prefixes.begin(); | |
284 | i != prefixes.end() && out->size() < max && r == 0; | |
285 | ++i) { | |
286 | string prefix(get_prefix(snap) + *i); | |
287 | string pos = prefix; | |
288 | while (out->size() < max) { | |
289 | pair<string, bufferlist> next; | |
290 | r = backend.get_next(pos, &next); | |
31f18b77 FG |
291 | dout(20) << __func__ << " get_next(" << pos << ") returns " << r |
292 | << " " << next << dendl; | |
7c673cae FG |
293 | if (r != 0) { |
294 | break; // Done | |
295 | } | |
296 | ||
297 | if (next.first.substr(0, prefix.size()) != | |
298 | prefix) { | |
299 | break; // Done with this prefix | |
300 | } | |
301 | ||
302 | assert(is_mapping(next.first)); | |
303 | ||
31f18b77 | 304 | dout(20) << __func__ << " " << next.first << dendl; |
7c673cae FG |
305 | pair<snapid_t, hobject_t> next_decoded(from_raw(next)); |
306 | assert(next_decoded.first == snap); | |
307 | assert(check(next_decoded.second)); | |
308 | ||
309 | out->push_back(next_decoded.second); | |
310 | pos = next.first; | |
311 | } | |
312 | } | |
313 | if (out->size() == 0) { | |
314 | return -ENOENT; | |
315 | } else { | |
316 | return 0; | |
317 | } | |
318 | } | |
319 | ||
320 | ||
321 | int SnapMapper::remove_oid( | |
322 | const hobject_t &oid, | |
323 | MapCacher::Transaction<std::string, bufferlist> *t) | |
324 | { | |
325 | dout(20) << __func__ << " " << oid << dendl; | |
326 | assert(check(oid)); | |
327 | return _remove_oid(oid, t); | |
328 | } | |
329 | ||
330 | int SnapMapper::_remove_oid( | |
331 | const hobject_t &oid, | |
332 | MapCacher::Transaction<std::string, bufferlist> *t) | |
333 | { | |
334 | dout(20) << __func__ << " " << oid << dendl; | |
335 | object_snaps out; | |
336 | int r = get_snaps(oid, &out); | |
337 | if (r < 0) | |
338 | return r; | |
339 | ||
340 | clear_snaps(oid, t); | |
341 | ||
342 | set<string> to_remove; | |
343 | for (set<snapid_t>::iterator i = out.snaps.begin(); | |
344 | i != out.snaps.end(); | |
345 | ++i) { | |
346 | to_remove.insert(to_raw_key(make_pair(*i, oid))); | |
347 | } | |
31f18b77 FG |
348 | if (g_conf->subsys.should_gather(ceph_subsys_osd, 20)) { |
349 | for (auto& i : to_remove) { | |
350 | dout(20) << __func__ << " rm " << i << dendl; | |
351 | } | |
352 | } | |
7c673cae FG |
353 | backend.remove_keys(to_remove, t); |
354 | return 0; | |
355 | } | |
356 | ||
357 | int SnapMapper::get_snaps( | |
358 | const hobject_t &oid, | |
359 | std::set<snapid_t> *snaps) | |
360 | { | |
361 | assert(check(oid)); | |
362 | object_snaps out; | |
363 | int r = get_snaps(oid, &out); | |
364 | if (r < 0) | |
365 | return r; | |
366 | if (snaps) | |
367 | snaps->swap(out.snaps); | |
368 | return 0; | |
369 | } |