1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Inktank Storage, Inc.
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.
23 #include "common/hobject.h"
24 #include "common/map_cacher.hpp"
26 # include "crimson/os/futurized_store.h"
27 # include "crimson/os/futurized_collection.h"
29 #include "include/buffer.h"
30 #include "include/encoding.h"
31 #include "include/object.h"
32 #include "os/ObjectStore.h"
33 #include "osd/OSDMap.h"
34 #include "osd/SnapMapReaderI.h"
36 class OSDriver
: public MapCacher::StoreDriver
<std::string
, ceph::buffer::list
> {
38 using ObjectStoreT
= crimson::os::FuturizedStore::Shard
;
39 using CollectionHandleT
= ObjectStoreT::CollectionRef
;
41 using ObjectStoreT
= ObjectStore
;
42 using CollectionHandleT
= ObjectStoreT::CollectionHandle
;
50 class OSTransaction
: public MapCacher::Transaction
<std::string
, ceph::buffer::list
> {
51 friend class OSDriver
;
54 ceph::os::Transaction
*t
;
57 const ghobject_t
&hoid
,
58 ceph::os::Transaction
*t
)
59 : cid(cid
), hoid(hoid
), t(t
) {}
62 const std::map
<std::string
, ceph::buffer::list
> &to_set
) override
{
63 t
->omap_setkeys(cid
, hoid
, to_set
);
66 const std::set
<std::string
> &to_remove
) override
{
67 t
->omap_rmkeys(cid
, hoid
, to_remove
);
70 Context
*c
) override
{
71 t
->register_on_applied(c
);
75 OSTransaction
get_transaction(
76 ceph::os::Transaction
*t
) const {
77 return OSTransaction(ch
->get_cid(), hoid
, t
);
81 OSDriver(ObjectStoreT
*os
, const coll_t
& cid
, const ghobject_t
&hoid
) :
82 OSDriver(os
, os
->open_collection(cid
), hoid
) {}
84 OSDriver(ObjectStoreT
*os
, CollectionHandleT ch
, const ghobject_t
&hoid
) :
90 const std::set
<std::string
> &keys
,
91 std::map
<std::string
, ceph::buffer::list
> *out
) override
;
93 const std::string
&key
,
94 std::pair
<std::string
, ceph::buffer::list
> *next
) override
;
95 int get_next_or_current(
96 const std::string
&key
,
97 std::pair
<std::string
, ceph::buffer::list
> *next_or_current
) override
;
103 * Manages two mappings:
104 * 1) hobject_t -> {snapid}
105 * 2) snapid -> {hobject_t}
107 * We accomplish this using two sets of keys:
108 * 1) OBJECT_PREFIX + obj.str() -> encoding of object_snaps
109 * 2) MAPPING_PREFIX + poolid + snapid_t + obj.str() -> encoding of std::pair<snapid_t, obj>
111 * The on disk strings and encodings are implemented in to_raw, to_raw_key,
112 * from_raw, to_object_key.
114 * The object -> {snapid} mapping is primarily included so that the
115 * SnapMapper state can be verified against the external PG state during
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.
122 class SnapMapper
: public Scrub::SnapMapReaderI
{
123 friend class MapperVerifier
; // unit-test support
124 friend class DirectMapper
; // unit-test support
127 struct object_snaps
{
129 std::set
<snapid_t
> snaps
;
130 object_snaps(hobject_t oid
, const std::set
<snapid_t
> &snaps
)
131 : oid(oid
), snaps(snaps
) {}
133 void encode(ceph::buffer::list
&bl
) const;
134 void decode(ceph::buffer::list::const_iterator
&bp
);
140 explicit Mapping(const std::pair
<snapid_t
, hobject_t
> &in
)
141 : snap(in
.first
), hoid(in
.second
) {}
142 Mapping() : snap(0) {}
143 void encode(ceph::buffer::list
&bl
) const {
144 ENCODE_START(1, 1, bl
);
149 void decode(ceph::buffer::list::const_iterator
&bl
) {
157 static const std::string LEGACY_MAPPING_PREFIX
;
158 static const std::string MAPPING_PREFIX
;
159 static const std::string OBJECT_PREFIX
;
160 static const char *PURGED_SNAP_EPOCH_PREFIX
;
161 static const char *PURGED_SNAP_PREFIX
;
167 ObjectStore::CollectionHandle ch
;
168 ghobject_t mapping_hoid
;
169 ghobject_t purged_snaps_hoid
;
171 ObjectMap::ObjectMapIterator psit
;
175 bool _parse_p(); ///< advance the purged_snaps pointer
177 ObjectMap::ObjectMapIterator mapit
;
181 bool _parse_m(); ///< advance the (object) mapper pointer
183 std::vector
<std::tuple
<int64_t, snapid_t
, uint32_t, shard_id_t
>> stray
;
188 ObjectStore::CollectionHandle
& ch
,
189 ghobject_t mapping_hoid
,
190 ghobject_t purged_snaps_hoid
)
194 mapping_hoid(mapping_hoid
),
195 purged_snaps_hoid(purged_snaps_hoid
) {}
200 static std::string
convert_legacy_key(
201 const std::string
& old_key
,
202 const bufferlist
& value
);
204 static int convert_legacy(
207 ObjectStore::CollectionHandle
& ch
,
212 static void record_purged_snaps(
215 OSDriver::OSTransaction
&& txn
,
216 std::map
<epoch_t
,mempool::osdmap::map
<int64_t,snap_interval_set_t
>> purged_snaps
);
219 static int _lookup_purged_snap(
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
,
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
);
229 // note: marked 'mutable', as functions as a cache and used in some 'const'
231 mutable MapCacher::MapCacher
<std::string
, ceph::buffer::list
> backend
;
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
);
238 static std::string
get_prefix(int64_t pool
, snapid_t snap
);
239 std::string
to_raw_key(
240 const std::pair
<snapid_t
, hobject_t
> &to_map
) const;
242 std::string
to_raw_key(snapid_t snap
, const hobject_t
& clone
) const;
244 std::pair
<std::string
, ceph::buffer::list
> to_raw(
245 const std::pair
<snapid_t
, hobject_t
> &to_map
) const;
247 static bool is_mapping(const std::string
&to_test
);
249 static std::pair
<snapid_t
, hobject_t
> from_raw(
250 const std::pair
<std::string
, ceph::buffer::list
> &image
);
252 static std::pair
<snapid_t
, hobject_t
> from_raw(
253 const ceph::buffer::list
& image
);
255 std::string
to_object_key(const hobject_t
&hoid
) const;
257 int get_snaps(const hobject_t
&oid
, object_snaps
*out
) const;
259 std::set
<std::string
> to_raw_keys(
260 const hobject_t
&clone
,
261 const std::set
<snapid_t
> &snaps
) const;
264 const hobject_t
&oid
,
265 const object_snaps
&out
,
266 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
);
269 const hobject_t
&oid
,
270 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
);
272 // True if hoid belongs in this mapping based on mask_bits and match
273 bool check(const hobject_t
&hoid
) const;
276 const hobject_t
&oid
, ///< [in] oid to remove
277 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
///< [out] transaction
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;
285 static std::string
make_shard_prefix(shard_id_t shard
) {
286 if (shard
== shard_id_t::NO_SHARD
)
287 return std::string();
289 int r
= snprintf(buf
, sizeof(buf
), ".%x", (int)shard
);
290 ceph_assert(r
< (int)sizeof(buf
));
291 return std::string(buf
, r
) + '_';
294 const uint32_t match
;
295 std::string last_key_checked
;
297 const shard_id_t shard
;
298 const std::string shard_prefix
;
301 MapCacher::StoreDriver
<std::string
, ceph::buffer::list
> *driver
,
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
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
);
312 std::set
<std::string
> prefixes
;
313 /// Update bits in case of pg split or merge
315 uint32_t new_bits
///< [in] new split bits
317 mask_bits
= new_bits
;
318 std::set
<std::string
> _prefixes
= hobject_t::get_prefixes(
323 for (auto i
= _prefixes
.begin(); i
!= _prefixes
.end(); ++i
) {
324 prefixes
.insert(shard_prefix
+ *i
);
328 /// Update snaps for oid, empty new_snaps removes the mapping
330 const hobject_t
&oid
, ///< [in] oid to update
331 const std::set
<snapid_t
> &new_snaps
, ///< [in] new snap std::set
332 const std::set
<snapid_t
> *old_snaps
, ///< [in] old snaps (for debugging)
333 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
///< [out] transaction
334 ); ///@ return error, 0 on success
336 /// Add mapping for oid, must not already be mapped
338 const hobject_t
&oid
, ///< [in] oid to add
339 const std::set
<snapid_t
>& new_snaps
, ///< [in] snaps
340 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
///< [out] transaction
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
347 std::vector
<hobject_t
> *out
///< [out] next objects to trim (must be empty)
348 ); ///< @return error, -ENOENT if no more objects
350 /// Remove mapping for oid
352 const hobject_t
&oid
, ///< [in] oid to remove
353 MapCacher::Transaction
<std::string
, ceph::buffer::list
> *t
///< [out] transaction
354 ); ///< @return error, -ENOENT if the object is not mapped
356 /// Get snaps for oid
358 const hobject_t
&oid
, ///< [in] oid to get snaps for
359 std::set
<snapid_t
> *snaps
///< [out] snaps
360 ) const; ///< @return error, -ENOENT if oid is not recorded
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
;
367 * get_snaps_check_consistency
369 * Returns snaps for hoid as in get_snaps(), but additionally validates the
370 * snap->hobject_t mappings ('SNA_' entries).
372 tl::expected
<std::set
<snapid_t
>, SnapMapReaderI::result_t
>
373 get_snaps_check_consistency(const hobject_t
&hoid
) const final
;
375 WRITE_CLASS_ENCODER(SnapMapper::object_snaps
)
376 WRITE_CLASS_ENCODER(SnapMapper::Mapping
)