]>
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) 2013 Inktank Storage, Inc. | |
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 | #ifndef SNAPMAPPER_H | |
16 | #define SNAPMAPPER_H | |
17 | ||
1e59de90 | 18 | #include <cstring> |
7c673cae | 19 | #include <set> |
1e59de90 | 20 | #include <string> |
7c673cae | 21 | #include <utility> |
7c673cae | 22 | |
7c673cae | 23 | #include "common/hobject.h" |
1e59de90 TL |
24 | #include "common/map_cacher.hpp" |
25 | #ifdef WITH_SEASTAR | |
26 | # include "crimson/os/futurized_store.h" | |
27 | # include "crimson/os/futurized_collection.h" | |
28 | #endif | |
7c673cae FG |
29 | #include "include/buffer.h" |
30 | #include "include/encoding.h" | |
31 | #include "include/object.h" | |
32 | #include "os/ObjectStore.h" | |
9f95a23c | 33 | #include "osd/OSDMap.h" |
1e59de90 | 34 | #include "osd/SnapMapReaderI.h" |
7c673cae | 35 | |
f67539c2 | 36 | class OSDriver : public MapCacher::StoreDriver<std::string, ceph::buffer::list> { |
1e59de90 TL |
37 | #ifdef WITH_SEASTAR |
38 | using ObjectStoreT = crimson::os::FuturizedStore::Shard; | |
39 | using CollectionHandleT = ObjectStoreT::CollectionRef; | |
40 | #else | |
41 | using ObjectStoreT = ObjectStore; | |
42 | using CollectionHandleT = ObjectStoreT::CollectionHandle; | |
43 | #endif | |
44 | ||
45 | ObjectStoreT *os; | |
46 | CollectionHandleT ch; | |
7c673cae FG |
47 | ghobject_t hoid; |
48 | ||
49 | public: | |
f67539c2 | 50 | class OSTransaction : public MapCacher::Transaction<std::string, ceph::buffer::list> { |
7c673cae FG |
51 | friend class OSDriver; |
52 | coll_t cid; | |
53 | ghobject_t hoid; | |
1e59de90 | 54 | ceph::os::Transaction *t; |
7c673cae | 55 | OSTransaction( |
11fdf7f2 | 56 | const coll_t &cid, |
7c673cae | 57 | const ghobject_t &hoid, |
1e59de90 | 58 | ceph::os::Transaction *t) |
7c673cae FG |
59 | : cid(cid), hoid(hoid), t(t) {} |
60 | public: | |
61 | void set_keys( | |
f67539c2 | 62 | const std::map<std::string, ceph::buffer::list> &to_set) override { |
7c673cae FG |
63 | t->omap_setkeys(cid, hoid, to_set); |
64 | } | |
65 | void remove_keys( | |
66 | const std::set<std::string> &to_remove) override { | |
67 | t->omap_rmkeys(cid, hoid, to_remove); | |
68 | } | |
69 | void add_callback( | |
70 | Context *c) override { | |
71 | t->register_on_applied(c); | |
72 | } | |
73 | }; | |
74 | ||
75 | OSTransaction get_transaction( | |
1e59de90 TL |
76 | ceph::os::Transaction *t) const { |
77 | return OSTransaction(ch->get_cid(), hoid, t); | |
7c673cae FG |
78 | } |
79 | ||
1e59de90 TL |
80 | #ifndef WITH_SEASTAR |
81 | OSDriver(ObjectStoreT *os, const coll_t& cid, const ghobject_t &hoid) : | |
82 | OSDriver(os, os->open_collection(cid), hoid) {} | |
83 | #endif | |
84 | OSDriver(ObjectStoreT *os, CollectionHandleT ch, const ghobject_t &hoid) : | |
11fdf7f2 | 85 | os(os), |
1e59de90 TL |
86 | ch(ch), |
87 | hoid(hoid) {} | |
88 | ||
7c673cae FG |
89 | int get_keys( |
90 | const std::set<std::string> &keys, | |
f67539c2 | 91 | std::map<std::string, ceph::buffer::list> *out) override; |
7c673cae FG |
92 | int get_next( |
93 | const std::string &key, | |
f67539c2 | 94 | std::pair<std::string, ceph::buffer::list> *next) override; |
1e59de90 TL |
95 | int get_next_or_current( |
96 | const std::string &key, | |
97 | std::pair<std::string, ceph::buffer::list> *next_or_current) override; | |
7c673cae FG |
98 | }; |
99 | ||
100 | /** | |
101 | * SnapMapper | |
102 | * | |
103 | * Manages two mappings: | |
104 | * 1) hobject_t -> {snapid} | |
105 | * 2) snapid -> {hobject_t} | |
106 | * | |
107 | * We accomplish this using two sets of keys: | |
108 | * 1) OBJECT_PREFIX + obj.str() -> encoding of object_snaps | |
f67539c2 | 109 | * 2) MAPPING_PREFIX + poolid + snapid_t + obj.str() -> encoding of std::pair<snapid_t, obj> |
7c673cae FG |
110 | * |
111 | * The on disk strings and encodings are implemented in to_raw, to_raw_key, | |
112 | * from_raw, to_object_key. | |
113 | * | |
114 | * The object -> {snapid} mapping is primarily included so that the | |
115 | * SnapMapper state can be verified against the external PG state during | |
116 | * scrub etc. | |
117 | * | |
118 | * The 2) mapping is arranged such that all objects in a particular | |
119 | * snap will sort together, and so that all objects in a pg for a | |
120 | * particular snap will group under up to 8 prefixes. | |
121 | */ | |
1e59de90 TL |
122 | class SnapMapper : public Scrub::SnapMapReaderI { |
123 | friend class MapperVerifier; // unit-test support | |
124 | friend class DirectMapper; // unit-test support | |
7c673cae FG |
125 | public: |
126 | CephContext* cct; | |
127 | struct object_snaps { | |
128 | hobject_t oid; | |
129 | std::set<snapid_t> snaps; | |
130 | object_snaps(hobject_t oid, const std::set<snapid_t> &snaps) | |
131 | : oid(oid), snaps(snaps) {} | |
132 | object_snaps() {} | |
f67539c2 TL |
133 | void encode(ceph::buffer::list &bl) const; |
134 | void decode(ceph::buffer::list::const_iterator &bp); | |
7c673cae FG |
135 | }; |
136 | ||
9f95a23c TL |
137 | struct Mapping { |
138 | snapid_t snap; | |
139 | hobject_t hoid; | |
f67539c2 | 140 | explicit Mapping(const std::pair<snapid_t, hobject_t> &in) |
9f95a23c TL |
141 | : snap(in.first), hoid(in.second) {} |
142 | Mapping() : snap(0) {} | |
f67539c2 | 143 | void encode(ceph::buffer::list &bl) const { |
9f95a23c TL |
144 | ENCODE_START(1, 1, bl); |
145 | encode(snap, bl); | |
146 | encode(hoid, bl); | |
147 | ENCODE_FINISH(bl); | |
148 | } | |
f67539c2 | 149 | void decode(ceph::buffer::list::const_iterator &bl) { |
9f95a23c TL |
150 | DECODE_START(1, bl); |
151 | decode(snap, bl); | |
152 | decode(hoid, bl); | |
153 | DECODE_FINISH(bl); | |
154 | } | |
155 | }; | |
7c673cae | 156 | |
9f95a23c | 157 | static const std::string LEGACY_MAPPING_PREFIX; |
7c673cae FG |
158 | static const std::string MAPPING_PREFIX; |
159 | static const std::string OBJECT_PREFIX; | |
9f95a23c TL |
160 | static const char *PURGED_SNAP_EPOCH_PREFIX; |
161 | static const char *PURGED_SNAP_PREFIX; | |
162 | ||
1e59de90 | 163 | #ifndef WITH_SEASTAR |
9f95a23c TL |
164 | struct Scrubber { |
165 | CephContext *cct; | |
166 | ObjectStore *store; | |
167 | ObjectStore::CollectionHandle ch; | |
168 | ghobject_t mapping_hoid; | |
169 | ghobject_t purged_snaps_hoid; | |
170 | ||
171 | ObjectMap::ObjectMapIterator psit; | |
172 | int64_t pool; | |
173 | snapid_t begin, end; | |
174 | ||
175 | bool _parse_p(); ///< advance the purged_snaps pointer | |
176 | ||
177 | ObjectMap::ObjectMapIterator mapit; | |
178 | Mapping mapping; | |
179 | shard_id_t shard; | |
180 | ||
181 | bool _parse_m(); ///< advance the (object) mapper pointer | |
182 | ||
f67539c2 | 183 | std::vector<std::tuple<int64_t, snapid_t, uint32_t, shard_id_t>> stray; |
7c673cae | 184 | |
9f95a23c TL |
185 | Scrubber( |
186 | CephContext *cct, | |
187 | ObjectStore *store, | |
188 | ObjectStore::CollectionHandle& ch, | |
189 | ghobject_t mapping_hoid, | |
190 | ghobject_t purged_snaps_hoid) | |
191 | : cct(cct), | |
192 | store(store), | |
193 | ch(ch), | |
194 | mapping_hoid(mapping_hoid), | |
195 | purged_snaps_hoid(purged_snaps_hoid) {} | |
196 | ||
197 | void run(); | |
198 | }; | |
199 | ||
2a845540 TL |
200 | static std::string convert_legacy_key( |
201 | const std::string& old_key, | |
202 | const bufferlist& value); | |
203 | ||
9f95a23c TL |
204 | static int convert_legacy( |
205 | CephContext *cct, | |
206 | ObjectStore *store, | |
207 | ObjectStore::CollectionHandle& ch, | |
208 | ghobject_t hoid, | |
209 | unsigned max); | |
1e59de90 | 210 | #endif |
9f95a23c TL |
211 | |
212 | static void record_purged_snaps( | |
213 | CephContext *cct, | |
1e59de90 TL |
214 | OSDriver& backend, |
215 | OSDriver::OSTransaction&& txn, | |
f67539c2 | 216 | std::map<epoch_t,mempool::osdmap::map<int64_t,snap_interval_set_t>> purged_snaps); |
9f95a23c TL |
217 | |
218 | private: | |
219 | static int _lookup_purged_snap( | |
220 | CephContext *cct, | |
1e59de90 | 221 | OSDriver& backend, |
9f95a23c TL |
222 | int64_t pool, snapid_t snap, |
223 | snapid_t *begin, snapid_t *end); | |
224 | static void make_purged_snap_key_value( | |
225 | int64_t pool, snapid_t begin, | |
f67539c2 TL |
226 | snapid_t end, std::map<std::string,ceph::buffer::list> *m); |
227 | static std::string make_purged_snap_key(int64_t pool, snapid_t last); | |
9f95a23c | 228 | |
1e59de90 TL |
229 | // note: marked 'mutable', as functions as a cache and used in some 'const' |
230 | // functions. | |
231 | mutable MapCacher::MapCacher<std::string, ceph::buffer::list> backend; | |
9f95a23c TL |
232 | |
233 | static std::string get_legacy_prefix(snapid_t snap); | |
234 | std::string to_legacy_raw_key( | |
235 | const std::pair<snapid_t, hobject_t> &to_map); | |
236 | static bool is_legacy_mapping(const std::string &to_test); | |
7c673cae | 237 | |
9f95a23c | 238 | static std::string get_prefix(int64_t pool, snapid_t snap); |
7c673cae | 239 | std::string to_raw_key( |
1e59de90 TL |
240 | const std::pair<snapid_t, hobject_t> &to_map) const; |
241 | ||
242 | std::string to_raw_key(snapid_t snap, const hobject_t& clone) const; | |
7c673cae | 243 | |
f67539c2 | 244 | std::pair<std::string, ceph::buffer::list> to_raw( |
1e59de90 | 245 | const std::pair<snapid_t, hobject_t> &to_map) const; |
7c673cae FG |
246 | |
247 | static bool is_mapping(const std::string &to_test); | |
248 | ||
9f95a23c | 249 | static std::pair<snapid_t, hobject_t> from_raw( |
f67539c2 | 250 | const std::pair<std::string, ceph::buffer::list> &image); |
7c673cae | 251 | |
1e59de90 TL |
252 | static std::pair<snapid_t, hobject_t> from_raw( |
253 | const ceph::buffer::list& image); | |
254 | ||
255 | std::string to_object_key(const hobject_t &hoid) const; | |
7c673cae | 256 | |
1e59de90 TL |
257 | int get_snaps(const hobject_t &oid, object_snaps *out) const; |
258 | ||
259 | std::set<std::string> to_raw_keys( | |
260 | const hobject_t &clone, | |
261 | const std::set<snapid_t> &snaps) const; | |
7c673cae FG |
262 | |
263 | void set_snaps( | |
264 | const hobject_t &oid, | |
265 | const object_snaps &out, | |
f67539c2 | 266 | MapCacher::Transaction<std::string, ceph::buffer::list> *t); |
7c673cae FG |
267 | |
268 | void clear_snaps( | |
269 | const hobject_t &oid, | |
f67539c2 | 270 | MapCacher::Transaction<std::string, ceph::buffer::list> *t); |
7c673cae FG |
271 | |
272 | // True if hoid belongs in this mapping based on mask_bits and match | |
11fdf7f2 | 273 | bool check(const hobject_t &hoid) const; |
7c673cae FG |
274 | |
275 | int _remove_oid( | |
276 | const hobject_t &oid, ///< [in] oid to remove | |
f67539c2 | 277 | MapCacher::Transaction<std::string, ceph::buffer::list> *t ///< [out] transaction |
7c673cae FG |
278 | ); |
279 | ||
1e59de90 TL |
280 | /// Get snaps (as an 'object_snaps' object) for oid |
281 | tl::expected<object_snaps, SnapMapReaderI::result_t> get_snaps_common( | |
282 | const hobject_t &hoid) const; | |
283 | ||
284 | public: | |
f67539c2 | 285 | static std::string make_shard_prefix(shard_id_t shard) { |
7c673cae | 286 | if (shard == shard_id_t::NO_SHARD) |
f67539c2 | 287 | return std::string(); |
7c673cae FG |
288 | char buf[20]; |
289 | int r = snprintf(buf, sizeof(buf), ".%x", (int)shard); | |
11fdf7f2 | 290 | ceph_assert(r < (int)sizeof(buf)); |
f67539c2 | 291 | return std::string(buf, r) + '_'; |
7c673cae FG |
292 | } |
293 | uint32_t mask_bits; | |
294 | const uint32_t match; | |
f67539c2 | 295 | std::string last_key_checked; |
7c673cae FG |
296 | const int64_t pool; |
297 | const shard_id_t shard; | |
f67539c2 | 298 | const std::string shard_prefix; |
7c673cae FG |
299 | SnapMapper( |
300 | CephContext* cct, | |
f67539c2 | 301 | MapCacher::StoreDriver<std::string, ceph::buffer::list> *driver, |
7c673cae FG |
302 | uint32_t match, ///< [in] pgid |
303 | uint32_t bits, ///< [in] current split bits | |
304 | int64_t pool, ///< [in] pool | |
305 | shard_id_t shard ///< [in] shard | |
306 | ) | |
307 | : cct(cct), backend(driver), mask_bits(bits), match(match), pool(pool), | |
308 | shard(shard), shard_prefix(make_shard_prefix(shard)) { | |
309 | update_bits(mask_bits); | |
310 | } | |
311 | ||
f67539c2 | 312 | std::set<std::string> prefixes; |
11fdf7f2 | 313 | /// Update bits in case of pg split or merge |
7c673cae FG |
314 | void update_bits( |
315 | uint32_t new_bits ///< [in] new split bits | |
316 | ) { | |
7c673cae | 317 | mask_bits = new_bits; |
f67539c2 | 318 | std::set<std::string> _prefixes = hobject_t::get_prefixes( |
7c673cae FG |
319 | mask_bits, |
320 | match, | |
321 | pool); | |
322 | prefixes.clear(); | |
f67539c2 | 323 | for (auto i = _prefixes.begin(); i != _prefixes.end(); ++i) { |
7c673cae FG |
324 | prefixes.insert(shard_prefix + *i); |
325 | } | |
326 | } | |
327 | ||
328 | /// Update snaps for oid, empty new_snaps removes the mapping | |
329 | int update_snaps( | |
330 | const hobject_t &oid, ///< [in] oid to update | |
f67539c2 | 331 | const std::set<snapid_t> &new_snaps, ///< [in] new snap std::set |
7c673cae | 332 | const std::set<snapid_t> *old_snaps, ///< [in] old snaps (for debugging) |
f67539c2 | 333 | MapCacher::Transaction<std::string, ceph::buffer::list> *t ///< [out] transaction |
7c673cae FG |
334 | ); ///@ return error, 0 on success |
335 | ||
336 | /// Add mapping for oid, must not already be mapped | |
337 | void add_oid( | |
338 | const hobject_t &oid, ///< [in] oid to add | |
339 | const std::set<snapid_t>& new_snaps, ///< [in] snaps | |
f67539c2 | 340 | MapCacher::Transaction<std::string, ceph::buffer::list> *t ///< [out] transaction |
7c673cae FG |
341 | ); |
342 | ||
343 | /// Returns first object with snap as a snap | |
344 | int get_next_objects_to_trim( | |
345 | snapid_t snap, ///< [in] snap to check | |
346 | unsigned max, ///< [in] max to get | |
f67539c2 | 347 | std::vector<hobject_t> *out ///< [out] next objects to trim (must be empty) |
7c673cae FG |
348 | ); ///< @return error, -ENOENT if no more objects |
349 | ||
350 | /// Remove mapping for oid | |
351 | int remove_oid( | |
352 | const hobject_t &oid, ///< [in] oid to remove | |
f67539c2 | 353 | MapCacher::Transaction<std::string, ceph::buffer::list> *t ///< [out] transaction |
7c673cae FG |
354 | ); ///< @return error, -ENOENT if the object is not mapped |
355 | ||
356 | /// Get snaps for oid | |
357 | int get_snaps( | |
358 | const hobject_t &oid, ///< [in] oid to get snaps for | |
359 | std::set<snapid_t> *snaps ///< [out] snaps | |
1e59de90 TL |
360 | ) const; ///< @return error, -ENOENT if oid is not recorded |
361 | ||
362 | /// Get snaps for oid - alternative interface | |
363 | tl::expected<std::set<snapid_t>, SnapMapReaderI::result_t> get_snaps( | |
364 | const hobject_t &hoid) const final; | |
365 | ||
366 | /** | |
367 | * get_snaps_check_consistency | |
368 | * | |
369 | * Returns snaps for hoid as in get_snaps(), but additionally validates the | |
370 | * snap->hobject_t mappings ('SNA_' entries). | |
371 | */ | |
372 | tl::expected<std::set<snapid_t>, SnapMapReaderI::result_t> | |
373 | get_snaps_check_consistency(const hobject_t &hoid) const final; | |
7c673cae FG |
374 | }; |
375 | WRITE_CLASS_ENCODER(SnapMapper::object_snaps) | |
9f95a23c | 376 | WRITE_CLASS_ENCODER(SnapMapper::Mapping) |
7c673cae FG |
377 | |
378 | #endif |