1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
10 #include "common/HBHandle.h"
11 #include "common/ceph_context.h"
12 #include "common/dout.h"
13 #include "osd_types.h"
20 virtual const std::set
<pg_shard_t
> &get_upset() const = 0;
21 virtual bool is_ec_pg() const = 0;
22 virtual int get_pg_size() const = 0;
23 virtual ~MappingInfo() {}
26 // a loc_count indicates how many locations we know in each of
27 // these distinct sets
30 int other
= 0; //< other
32 friend bool operator<(const loc_count_t
& l
,
33 const loc_count_t
& r
) {
34 return (l
.up
< r
.up
||
36 (l
.other
< r
.other
)));
38 friend std::ostream
& operator<<(std::ostream
& out
, const loc_count_t
& l
) {
39 ceph_assert(l
.up
>= 0);
40 ceph_assert(l
.other
>= 0);
41 return out
<< "(" << l
.up
<< "+" << l
.other
<< ")";
46 using missing_by_count_t
= std::map
<shard_id_t
, std::map
<loc_count_t
,int>>;
48 loc_count_t
_get_count(const std::set
<pg_shard_t
> &shards
) {
50 for (auto s
: shards
) {
51 if (mapping_info
->get_upset().count(s
)) {
60 std::map
<hobject_t
, pg_missing_item
> needs_recovery_map
;
61 std::map
<hobject_t
, std::set
<pg_shard_t
> > missing_loc
;
62 std::set
<pg_shard_t
> missing_loc_sources
;
64 // for every entry in missing_loc, we count how many of each type of shard we have,
65 // and maintain totals here. The sum of the values for this std::map will always equal
66 // missing_loc.size().
67 missing_by_count_t missing_by_count
;
70 const std::set
<pg_shard_t
>& s
,
71 std::map
<shard_id_t
, std::set
<pg_shard_t
> >& pgsbs
) {
72 if (mapping_info
->is_ec_pg()) {
73 int num_shards
= mapping_info
->get_pg_size();
74 // For completely missing shards initialize with empty std::set<pg_shard_t>
75 for (int i
= 0 ; i
< num_shards
; ++i
) {
80 pgsbs
[pgs
.shard
].insert(pgs
);
82 pgsbs
[shard_id_t::NO_SHARD
] = s
;
86 void _inc_count(const std::set
<pg_shard_t
>& s
) {
87 std::map
< shard_id_t
, std::set
<pg_shard_t
> > pgsbs
;
88 pgs_by_shard_id(s
, pgsbs
);
89 for (auto shard
: pgsbs
)
90 ++missing_by_count
[shard
.first
][_get_count(shard
.second
)];
92 void _dec_count(const std::set
<pg_shard_t
>& s
) {
93 std::map
< shard_id_t
, std::set
<pg_shard_t
> > pgsbs
;
94 pgs_by_shard_id(s
, pgsbs
);
95 for (auto shard
: pgsbs
) {
96 auto p
= missing_by_count
[shard
.first
].find(_get_count(shard
.second
));
97 ceph_assert(p
!= missing_by_count
[shard
.first
].end());
98 if (--p
->second
== 0) {
99 missing_by_count
[shard
.first
].erase(p
);
105 MappingInfo
*mapping_info
;
106 DoutPrefixProvider
*dpp
;
108 std::set
<pg_shard_t
> empty_set
;
110 boost::scoped_ptr
<IsPGReadablePredicate
> is_readable
;
111 boost::scoped_ptr
<IsPGRecoverablePredicate
> is_recoverable
;
114 MappingInfo
*mapping_info
,
115 DoutPrefixProvider
*dpp
,
117 : pgid(pgid
), mapping_info(mapping_info
), dpp(dpp
), cct(cct
) { }
118 void set_backend_predicates(
119 IsPGReadablePredicate
*_is_readable
,
120 IsPGRecoverablePredicate
*_is_recoverable
) {
121 is_readable
.reset(_is_readable
);
122 is_recoverable
.reset(_is_recoverable
);
124 const IsPGRecoverablePredicate
&get_recoverable_predicate() const {
125 return *is_recoverable
;
127 std::ostream
& gen_prefix(std::ostream
& out
) const {
128 return dpp
->gen_prefix(out
);
131 const hobject_t
&hoid
,
132 eversion_t
*v
= 0) const {
133 std::map
<hobject_t
, pg_missing_item
>::const_iterator i
=
134 needs_recovery_map
.find(hoid
);
135 if (i
== needs_recovery_map
.end())
141 bool is_deleted(const hobject_t
&hoid
) const {
142 auto i
= needs_recovery_map
.find(hoid
);
143 if (i
== needs_recovery_map
.end())
145 return i
->second
.is_delete();
147 bool is_unfound(const hobject_t
&hoid
) const {
148 auto it
= needs_recovery_map
.find(hoid
);
149 if (it
== needs_recovery_map
.end()) {
152 if (it
->second
.is_delete()) {
155 auto mit
= missing_loc
.find(hoid
);
156 return mit
== missing_loc
.end() || !(*is_recoverable
)(mit
->second
);
158 bool readable_with_acting(
159 const hobject_t
&hoid
,
160 const std::set
<pg_shard_t
> &acting
,
161 eversion_t
* v
= 0) const;
162 uint64_t num_unfound() const {
164 for (std::map
<hobject_t
, pg_missing_item
>::const_iterator i
=
165 needs_recovery_map
.begin();
166 i
!= needs_recovery_map
.end();
168 if (i
->second
.is_delete())
170 auto mi
= missing_loc
.find(i
->first
);
171 if (mi
== missing_loc
.end() || !(*is_recoverable
)(mi
->second
))
177 bool have_unfound() const {
178 for (std::map
<hobject_t
, pg_missing_item
>::const_iterator i
=
179 needs_recovery_map
.begin();
180 i
!= needs_recovery_map
.end();
182 if (i
->second
.is_delete())
184 auto mi
= missing_loc
.find(i
->first
);
185 if (mi
== missing_loc
.end() || !(*is_recoverable
)(mi
->second
))
191 needs_recovery_map
.clear();
193 missing_loc_sources
.clear();
194 missing_by_count
.clear();
197 void add_location(const hobject_t
&hoid
, pg_shard_t location
) {
198 auto p
= missing_loc
.find(hoid
);
199 if (p
== missing_loc
.end()) {
200 p
= missing_loc
.emplace(hoid
, std::set
<pg_shard_t
>()).first
;
202 _dec_count(p
->second
);
204 p
->second
.insert(location
);
205 _inc_count(p
->second
);
207 void remove_location(const hobject_t
&hoid
, pg_shard_t location
) {
208 auto p
= missing_loc
.find(hoid
);
209 if (p
!= missing_loc
.end()) {
210 _dec_count(p
->second
);
211 p
->second
.erase(location
);
212 if (p
->second
.empty()) {
213 missing_loc
.erase(p
);
215 _inc_count(p
->second
);
220 void clear_location(const hobject_t
&hoid
) {
221 auto p
= missing_loc
.find(hoid
);
222 if (p
!= missing_loc
.end()) {
223 _dec_count(p
->second
);
224 missing_loc
.erase(p
);
228 void add_active_missing(const pg_missing_t
&missing
) {
229 for (std::map
<hobject_t
, pg_missing_item
>::const_iterator i
=
230 missing
.get_items().begin();
231 i
!= missing
.get_items().end();
233 std::map
<hobject_t
, pg_missing_item
>::const_iterator j
=
234 needs_recovery_map
.find(i
->first
);
235 if (j
== needs_recovery_map
.end()) {
236 needs_recovery_map
.insert(*i
);
238 if (i
->second
.need
!= j
->second
.need
) {
239 lgeneric_dout(cct
, 0) << this << " " << pgid
<< " unexpected need for "
240 << i
->first
<< " have " << j
->second
241 << " tried to add " << i
->second
<< dendl
;
242 ceph_assert(0 == "unexpected need for missing item");
248 void add_missing(const hobject_t
&hoid
, eversion_t need
, eversion_t have
, bool is_delete
=false) {
249 needs_recovery_map
[hoid
] = pg_missing_item(need
, have
, is_delete
);
251 void revise_need(const hobject_t
&hoid
, eversion_t need
) {
252 auto it
= needs_recovery_map
.find(hoid
);
253 ceph_assert(it
!= needs_recovery_map
.end());
254 it
->second
.need
= need
;
257 /// Adds info about a possible recovery source
258 bool add_source_info(
259 pg_shard_t source
, ///< [in] source
260 const pg_info_t
&oinfo
, ///< [in] info
261 const pg_missing_t
&omissing
, ///< [in] (optional) missing
262 HBHandle
*handle
///< [in] ThreadPool handle
263 ); ///< @return whether a new object location was discovered
265 /// Adds recovery sources in batch
266 void add_batch_sources_info(
267 const std::set
<pg_shard_t
> &sources
, ///< [in] a std::set of resources which can be used for all objects
268 HBHandle
*handle
///< [in] ThreadPool handle
271 /// Uses osdmap to update structures for now down sources
272 void check_recovery_sources(const OSDMapRef
& osdmap
);
274 /// Remove stray from recovery sources
275 void remove_stray_recovery_sources(pg_shard_t stray
);
277 /// Call when hoid is no longer missing in acting std::set
278 void recovered(const hobject_t
&hoid
) {
279 needs_recovery_map
.erase(hoid
);
280 auto p
= missing_loc
.find(hoid
);
281 if (p
!= missing_loc
.end()) {
282 _dec_count(p
->second
);
283 missing_loc
.erase(p
);
287 /// Call to update structures for hoid after a change
289 const hobject_t
&hoid
,
291 const std::set
<pg_shard_t
> &to_recover
,
292 const pg_info_t
&info
,
293 const pg_missing_t
&missing
,
294 const std::map
<pg_shard_t
, pg_missing_t
> &pmissing
,
295 const std::map
<pg_shard_t
, pg_info_t
> &pinfo
) {
297 std::optional
<pg_missing_item
> item
;
298 auto miter
= missing
.get_items().find(hoid
);
299 if (miter
!= missing
.get_items().end()) {
300 item
= miter
->second
;
302 for (auto &&i
: to_recover
) {
305 auto pmiter
= pmissing
.find(i
);
306 ceph_assert(pmiter
!= pmissing
.end());
307 miter
= pmiter
->second
.get_items().find(hoid
);
308 if (miter
!= pmiter
->second
.get_items().end()) {
309 item
= miter
->second
;
315 return; // recovered!
317 needs_recovery_map
[hoid
] = *item
;
318 if (item
->is_delete())
321 missing_loc
.emplace(hoid
, std::set
<pg_shard_t
>()).first
;
322 ceph_assert(info
.last_backfill
.is_max());
323 ceph_assert(info
.last_update
>= item
->need
);
324 if (!missing
.is_missing(hoid
))
325 mliter
->second
.insert(self
);
326 for (auto &&i
: pmissing
) {
329 auto pinfoiter
= pinfo
.find(i
.first
);
330 ceph_assert(pinfoiter
!= pinfo
.end());
331 if (item
->need
<= pinfoiter
->second
.last_update
&&
332 hoid
<= pinfoiter
->second
.last_backfill
&&
333 !i
.second
.is_missing(hoid
))
334 mliter
->second
.insert(i
.first
);
336 _inc_count(mliter
->second
);
339 const std::set
<pg_shard_t
> &get_locations(const hobject_t
&hoid
) const {
340 auto it
= missing_loc
.find(hoid
);
341 return it
== missing_loc
.end() ? empty_set
: it
->second
;
343 const std::map
<hobject_t
, std::set
<pg_shard_t
>> &get_missing_locs() const {
346 const std::map
<hobject_t
, pg_missing_item
> &get_needs_recovery() const {
347 return needs_recovery_map
;
350 const missing_by_count_t
&get_missing_by_count() const {
351 return missing_by_count
;