]>
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; | |
154 | assert(!out->snaps.empty()); | |
155 | } else { | |
156 | dout(20) << __func__ << " " << oid << " (out == NULL)" << dendl; | |
157 | } | |
158 | return 0; | |
159 | } | |
160 | ||
161 | void SnapMapper::clear_snaps( | |
162 | const hobject_t &oid, | |
163 | MapCacher::Transaction<std::string, bufferlist> *t) | |
164 | { | |
165 | dout(20) << __func__ << " " << oid << dendl; | |
166 | assert(check(oid)); | |
167 | set<string> to_remove; | |
168 | to_remove.insert(to_object_key(oid)); | |
169 | backend.remove_keys(to_remove, t); | |
170 | } | |
171 | ||
172 | void SnapMapper::set_snaps( | |
173 | const hobject_t &oid, | |
174 | const object_snaps &in, | |
175 | MapCacher::Transaction<std::string, bufferlist> *t) | |
176 | { | |
177 | assert(check(oid)); | |
178 | map<string, bufferlist> to_set; | |
179 | bufferlist bl; | |
180 | ::encode(in, bl); | |
181 | to_set[to_object_key(oid)] = bl; | |
182 | dout(20) << __func__ << " " << oid << " " << in.snaps << dendl; | |
183 | backend.set_keys(to_set, t); | |
184 | } | |
185 | ||
186 | int SnapMapper::update_snaps( | |
187 | const hobject_t &oid, | |
188 | const set<snapid_t> &new_snaps, | |
189 | const set<snapid_t> *old_snaps_check, | |
190 | MapCacher::Transaction<std::string, bufferlist> *t) | |
191 | { | |
192 | dout(20) << __func__ << " " << oid << " " << new_snaps | |
193 | << " was " << (old_snaps_check ? *old_snaps_check : set<snapid_t>()) | |
194 | << dendl; | |
195 | assert(check(oid)); | |
196 | if (new_snaps.empty()) | |
197 | return remove_oid(oid, t); | |
198 | ||
199 | object_snaps out; | |
200 | int r = get_snaps(oid, &out); | |
201 | if (r < 0) | |
202 | return r; | |
203 | if (old_snaps_check) | |
204 | assert(out.snaps == *old_snaps_check); | |
205 | ||
206 | object_snaps in(oid, new_snaps); | |
207 | set_snaps(oid, in, t); | |
208 | ||
209 | set<string> to_remove; | |
210 | for (set<snapid_t>::iterator i = out.snaps.begin(); | |
211 | i != out.snaps.end(); | |
212 | ++i) { | |
213 | if (!new_snaps.count(*i)) { | |
214 | to_remove.insert(to_raw_key(make_pair(*i, oid))); | |
215 | } | |
216 | } | |
217 | backend.remove_keys(to_remove, t); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | void SnapMapper::add_oid( | |
222 | const hobject_t &oid, | |
223 | const set<snapid_t>& snaps, | |
224 | MapCacher::Transaction<std::string, bufferlist> *t) | |
225 | { | |
226 | dout(20) << __func__ << " " << oid << " " << snaps << dendl; | |
227 | assert(check(oid)); | |
228 | { | |
229 | object_snaps out; | |
230 | int r = get_snaps(oid, &out); | |
231 | assert(r == -ENOENT); | |
232 | } | |
233 | ||
234 | object_snaps _snaps(oid, snaps); | |
235 | set_snaps(oid, _snaps, t); | |
236 | ||
237 | map<string, bufferlist> to_add; | |
238 | for (set<snapid_t>::iterator i = snaps.begin(); | |
239 | i != snaps.end(); | |
240 | ++i) { | |
241 | to_add.insert(to_raw(make_pair(*i, oid))); | |
242 | } | |
243 | backend.set_keys(to_add, t); | |
244 | } | |
245 | ||
246 | int SnapMapper::get_next_objects_to_trim( | |
247 | snapid_t snap, | |
248 | unsigned max, | |
249 | vector<hobject_t> *out) | |
250 | { | |
251 | assert(out); | |
252 | assert(out->empty()); | |
253 | int r = 0; | |
254 | for (set<string>::iterator i = prefixes.begin(); | |
255 | i != prefixes.end() && out->size() < max && r == 0; | |
256 | ++i) { | |
257 | string prefix(get_prefix(snap) + *i); | |
258 | string pos = prefix; | |
259 | while (out->size() < max) { | |
260 | pair<string, bufferlist> next; | |
261 | r = backend.get_next(pos, &next); | |
262 | if (r != 0) { | |
263 | break; // Done | |
264 | } | |
265 | ||
266 | if (next.first.substr(0, prefix.size()) != | |
267 | prefix) { | |
268 | break; // Done with this prefix | |
269 | } | |
270 | ||
271 | assert(is_mapping(next.first)); | |
272 | ||
273 | pair<snapid_t, hobject_t> next_decoded(from_raw(next)); | |
274 | assert(next_decoded.first == snap); | |
275 | assert(check(next_decoded.second)); | |
276 | ||
277 | out->push_back(next_decoded.second); | |
278 | pos = next.first; | |
279 | } | |
280 | } | |
281 | if (out->size() == 0) { | |
282 | return -ENOENT; | |
283 | } else { | |
284 | return 0; | |
285 | } | |
286 | } | |
287 | ||
288 | ||
289 | int SnapMapper::remove_oid( | |
290 | const hobject_t &oid, | |
291 | MapCacher::Transaction<std::string, bufferlist> *t) | |
292 | { | |
293 | dout(20) << __func__ << " " << oid << dendl; | |
294 | assert(check(oid)); | |
295 | return _remove_oid(oid, t); | |
296 | } | |
297 | ||
298 | int SnapMapper::_remove_oid( | |
299 | const hobject_t &oid, | |
300 | MapCacher::Transaction<std::string, bufferlist> *t) | |
301 | { | |
302 | dout(20) << __func__ << " " << oid << dendl; | |
303 | object_snaps out; | |
304 | int r = get_snaps(oid, &out); | |
305 | if (r < 0) | |
306 | return r; | |
307 | ||
308 | clear_snaps(oid, t); | |
309 | ||
310 | set<string> to_remove; | |
311 | for (set<snapid_t>::iterator i = out.snaps.begin(); | |
312 | i != out.snaps.end(); | |
313 | ++i) { | |
314 | to_remove.insert(to_raw_key(make_pair(*i, oid))); | |
315 | } | |
316 | backend.remove_keys(to_remove, t); | |
317 | return 0; | |
318 | } | |
319 | ||
320 | int SnapMapper::get_snaps( | |
321 | const hobject_t &oid, | |
322 | std::set<snapid_t> *snaps) | |
323 | { | |
324 | assert(check(oid)); | |
325 | object_snaps out; | |
326 | int r = get_snaps(oid, &out); | |
327 | if (r < 0) | |
328 | return r; | |
329 | if (snaps) | |
330 | snaps->swap(out.snaps); | |
331 | return 0; | |
332 | } |