return found_missing;
}
+
+// MissingLoc
+
bool PG::MissingLoc::readable_with_acting(
const hobject_t &hoid,
const set<pg_shard_t> &acting) const {
}
if (i->second.is_delete())
continue;
+
+ auto p = missing_loc.find(i->first);
+ if (p == missing_loc.end()) {
+ p = missing_loc.emplace(i->first, set<pg_shard_t>()).first;
+ } else {
+ _dec_count(p->second);
+ }
missing_loc[i->first].insert(sources.begin(), sources.end());
+ _inc_count(p->second);
+
if (!sources_updated) {
missing_loc_sources.insert(sources.begin(), sources.end());
sources_updated = true;
ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need
<< " is on osd." << fromosd << dendl;
- missing_loc[soid].insert(fromosd);
+ {
+ auto p = missing_loc.find(soid);
+ if (p == missing_loc.end()) {
+ p = missing_loc.emplace(soid, set<pg_shard_t>()).first;
+ } else {
+ _dec_count(p->second);
+ }
+ p->second.insert(fromosd);
+ _inc_count(p->second);
+ }
+
if (!sources_updated) {
missing_loc_sources.insert(fromosd);
sources_updated = true;
return found_missing;
}
+void PG::MissingLoc::check_recovery_sources(const OSDMapRef& osdmap)
+{
+ set<pg_shard_t> now_down;
+ for (set<pg_shard_t>::iterator p = missing_loc_sources.begin();
+ p != missing_loc_sources.end();
+ ) {
+ if (osdmap->is_up(p->osd)) {
+ ++p;
+ continue;
+ }
+ ldout(pg->cct, 10) << __func__ << " source osd." << *p << " now down" << dendl;
+ now_down.insert(*p);
+ missing_loc_sources.erase(p++);
+ }
+
+ if (now_down.empty()) {
+ ldout(pg->cct, 10) << __func__ << " no source osds (" << missing_loc_sources << ") went down" << dendl;
+ } else {
+ ldout(pg->cct, 10) << __func__ << " sources osds " << now_down << " now down, remaining sources are "
+ << missing_loc_sources << dendl;
+
+ // filter missing_loc
+ map<hobject_t, set<pg_shard_t>>::iterator p = missing_loc.begin();
+ while (p != missing_loc.end()) {
+ set<pg_shard_t>::iterator q = p->second.begin();
+ bool changed = false;
+ while (q != p->second.end()) {
+ if (now_down.count(*q)) {
+ if (!changed) {
+ changed = true;
+ _dec_count(p->second);
+ }
+ p->second.erase(q++);
+ } else {
+ ++q;
+ }
+ }
+ if (p->second.empty()) {
+ missing_loc.erase(p++);
+ } else {
+ if (changed) {
+ _inc_count(p->second);
+ }
+ ++p;
+ }
+ }
+ }
+}
+
void PG::discover_all_missing(map<int, map<spg_t,pg_query_t> > &query_map)
{
auto &missing = pg_log.get_missing();
complete_shards.insert(*i);
}
}
+
// If necessary, create might_have_unfound to help us find our unfound objects.
// NOTE: It's important that we build might_have_unfound before trimming the
// past intervals.
out << " u=" << unfound;
}
}
+ if (!pg.is_clean()) {
+ out << " mbc=" << pg.missing_loc.get_missing_by_count();
+ }
if (!pg.snap_trimq.empty()) {
out << " trimq=";
// only show a count if the set is large
#include <boost/statechart/event_base.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/circular_buffer.hpp>
+#include <boost/container/flat_set.hpp>
#include "include/memory.h"
#include "include/mempool.h"
}
ghobject_t pgmeta_oid;
+ // ------------------
+ // MissingLoc
+
class MissingLoc {
+ public:
+ // a loc_count indicates how many locations we know in each of
+ // these distinct sets
+ struct loc_count_t {
+ int up = 0; //< up
+ int other = 0; //< other
+
+ friend bool operator<(const loc_count_t& l,
+ const loc_count_t& r) {
+ return (l.up < r.up ||
+ (l.up == r.up &&
+ (l.other < r.other)));
+ }
+ friend ostream& operator<<(ostream& out, const loc_count_t& l) {
+ assert(l.up >= 0);
+ assert(l.other >= 0);
+ return out << "(" << l.up << "+" << l.other << ")";
+ }
+ };
+
+
+ private:
+
+ loc_count_t _get_count(const set<pg_shard_t>& shards) {
+ loc_count_t r;
+ for (auto s : shards) {
+ if (pg->upset.count(s)) {
+ r.up++;
+ } else {
+ r.other++;
+ }
+ }
+ return r;
+ }
+
map<hobject_t, pg_missing_item> needs_recovery_map;
map<hobject_t, set<pg_shard_t> > missing_loc;
set<pg_shard_t> missing_loc_sources;
+
+ // for every entry in missing_loc, we count how many of each type of shard we have,
+ // and maintain totals here. The sum of the values for this map will always equal
+ // missing_loc.size().
+ map<loc_count_t,int> missing_by_count;
+
+ void _inc_count(const set<pg_shard_t>& s) {
+ ++missing_by_count[_get_count(s)];
+ }
+ void _dec_count(const set<pg_shard_t>& s) {
+ auto p = missing_by_count.find(_get_count(s));
+ assert(p != missing_by_count.end());
+ if (--p->second == 0) {
+ missing_by_count.erase(p);
+ }
+ }
+
PG *pg;
set<pg_shard_t> empty_set;
public:
boost::scoped_ptr<IsPGReadablePredicate> is_readable;
boost::scoped_ptr<IsPGRecoverablePredicate> is_recoverable;
explicit MissingLoc(PG *pg)
- : pg(pg) {}
+ : pg(pg) { }
void set_backend_predicates(
IsPGReadablePredicate *_is_readable,
IsPGRecoverablePredicate *_is_recoverable) {
needs_recovery_map.clear();
missing_loc.clear();
missing_loc_sources.clear();
+ missing_by_count.clear();
}
void add_location(const hobject_t &hoid, pg_shard_t location) {
- missing_loc[hoid].insert(location);
+ auto p = missing_loc.find(hoid);
+ if (p == missing_loc.end()) {
+ p = missing_loc.emplace(hoid, set<pg_shard_t>()).first;
+ } else {
+ _dec_count(p->second);
+ }
+ p->second.insert(location);
+ _inc_count(p->second);
}
void remove_location(const hobject_t &hoid, pg_shard_t location) {
- missing_loc[hoid].erase(location);
+ auto p = missing_loc.find(hoid);
+ if (p != missing_loc.end()) {
+ _dec_count(p->second);
+ p->second.erase(location);
+ _inc_count(p->second);
+ }
}
void add_active_missing(const pg_missing_t &missing) {
for (map<hobject_t, pg_missing_item>::const_iterator i =
/// Call when hoid is no longer missing in acting set
void recovered(const hobject_t &hoid) {
needs_recovery_map.erase(hoid);
- missing_loc.erase(hoid);
+ auto p = missing_loc.find(hoid);
+ if (p != missing_loc.end()) {
+ _dec_count(p->second);
+ missing_loc.erase(p);
+ }
}
/// Call to update structures for hoid after a change
!i.second.is_missing(hoid))
mliter->second.insert(i.first);
}
+ _inc_count(mliter->second);
}
const set<pg_shard_t> &get_locations(const hobject_t &hoid) const {
const map<hobject_t, pg_missing_item> &get_needs_recovery() const {
return needs_recovery_map;
}
+ const map<loc_count_t,int> &get_missing_by_count() const {
+ return missing_by_count;
+ }
} missing_loc;
PastIntervals past_intervals;
}
}
-void PG::MissingLoc::check_recovery_sources(const OSDMapRef& osdmap)
-{
- set<pg_shard_t> now_down;
- for (set<pg_shard_t>::iterator p = missing_loc_sources.begin();
- p != missing_loc_sources.end();
- ) {
- if (osdmap->is_up(p->osd)) {
- ++p;
- continue;
- }
- ldout(pg->cct, 10) << __func__ << " source osd." << *p << " now down" << dendl;
- now_down.insert(*p);
- missing_loc_sources.erase(p++);
- }
-
- if (now_down.empty()) {
- ldout(pg->cct, 10) << __func__ << " no source osds (" << missing_loc_sources << ") went down" << dendl;
- } else {
- ldout(pg->cct, 10) << __func__ << " sources osds " << now_down << " now down, remaining sources are "
- << missing_loc_sources << dendl;
-
- // filter missing_loc
- map<hobject_t, set<pg_shard_t>>::iterator p = missing_loc.begin();
- while (p != missing_loc.end()) {
- set<pg_shard_t>::iterator q = p->second.begin();
- while (q != p->second.end())
- if (now_down.count(*q)) {
- p->second.erase(q++);
- } else {
- ++q;
- }
- if (p->second.empty())
- missing_loc.erase(p++);
- else
- ++p;
- }
- }
-}
-
-
bool PrimaryLogPG::start_recovery_ops(
uint64_t max,
ThreadPool::TPHandle &handle,