From: Samuel Just Date: Fri, 12 Apr 2019 18:08:54 +0000 (-0700) Subject: osd/: extract MissingLoc into its own file X-Git-Tag: v15.1.0~2774^2~74 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a22acd6032220f7ce9cfc3c3de58d073952114bd;p=ceph-ci.git osd/: extract MissingLoc into its own file Signed-off-by: Samuel Just --- diff --git a/src/osd/CMakeLists.txt b/src/osd/CMakeLists.txt index 0ab2876ad5a..d7f7efa07d3 100644 --- a/src/osd/CMakeLists.txt +++ b/src/osd/CMakeLists.txt @@ -35,6 +35,7 @@ set(osd_srcs OpQueueItem.cc PeeringState.cc PGStateUtils.cc + MissingLoc.cc ${CMAKE_SOURCE_DIR}/src/common/TrackedOp.cc ${CMAKE_SOURCE_DIR}/src/objclass/class_api.cc ${CMAKE_SOURCE_DIR}/src/mgr/OSDPerfMetricTypes.cc diff --git a/src/osd/MissingLoc.cc b/src/osd/MissingLoc.cc new file mode 100644 index 00000000000..984beedee4d --- /dev/null +++ b/src/osd/MissingLoc.cc @@ -0,0 +1,195 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "MissingLoc.h" + +#define dout_context cct +#undef dout_prefix +#define dout_prefix (gen_prefix(*_dout)) +#define dout_subsys ceph_subsys_osd + +bool MissingLoc::readable_with_acting( + const hobject_t &hoid, + const set &acting) const { + if (!needs_recovery(hoid)) + return true; + if (is_deleted(hoid)) + return false; + auto missing_loc_entry = missing_loc.find(hoid); + if (missing_loc_entry == missing_loc.end()) + return false; + const set &locs = missing_loc_entry->second; + ldout(cct, 10) << __func__ << ": locs:" << locs << dendl; + set have_acting; + for (set::const_iterator i = locs.begin(); + i != locs.end(); + ++i) { + if (acting.count(*i)) + have_acting.insert(*i); + } + return (*is_readable)(have_acting); +} + +void MissingLoc::add_batch_sources_info( + const set &sources, + ThreadPool::TPHandle* handle) +{ + ldout(cct, 10) << __func__ << ": adding sources in batch " + << sources.size() << dendl; + unsigned loop = 0; + bool sources_updated = false; + for (map::const_iterator i = needs_recovery_map.begin(); + i != needs_recovery_map.end(); + ++i) { + if (handle && ++loop >= cct->_conf->osd_loop_before_reset_tphandle) { + handle->reset_tp_timeout(); + loop = 0; + } + 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()).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; + } + } +} + +bool MissingLoc::add_source_info( + pg_shard_t fromosd, + const pg_info_t &oinfo, + const pg_missing_t &omissing, + ThreadPool::TPHandle* handle) +{ + bool found_missing = false; + unsigned loop = 0; + bool sources_updated = false; + // found items? + for (map::const_iterator p = needs_recovery_map.begin(); + p != needs_recovery_map.end(); + ++p) { + const hobject_t &soid(p->first); + eversion_t need = p->second.need; + if (handle && ++loop >= cct->_conf->osd_loop_before_reset_tphandle) { + handle->reset_tp_timeout(); + loop = 0; + } + if (p->second.is_delete()) { + ldout(cct, 10) << __func__ << " " << soid + << " delete, ignoring source" << dendl; + continue; + } + if (oinfo.last_update < need) { + ldout(cct, 10) << "search_for_missing " << soid << " " << need + << " also missing on osd." << fromosd + << " (last_update " << oinfo.last_update + << " < needed " << need << ")" << dendl; + continue; + } + if (!oinfo.last_backfill.is_max() && + !oinfo.last_backfill_bitwise) { + ldout(cct, 10) << "search_for_missing " << soid << " " << need + << " also missing on osd." << fromosd + << " (last_backfill " << oinfo.last_backfill + << " but with wrong sort order)" + << dendl; + continue; + } + if (p->first >= oinfo.last_backfill) { + // FIXME: this is _probably_ true, although it could conceivably + // be in the undefined region! Hmm! + ldout(cct, 10) << "search_for_missing " << soid << " " << need + << " also missing on osd." << fromosd + << " (past last_backfill " << oinfo.last_backfill + << ")" << dendl; + continue; + } + if (omissing.is_missing(soid)) { + ldout(cct, 10) << "search_for_missing " << soid << " " << need + << " also missing on osd." << fromosd << dendl; + continue; + } + + ldout(cct, 10) << "search_for_missing " << soid << " " << need + << " is on osd." << fromosd << dendl; + + { + auto p = missing_loc.find(soid); + if (p == missing_loc.end()) { + p = missing_loc.emplace(soid, set()).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; + } + found_missing = true; + } + + ldout(cct, 20) << "needs_recovery_map missing " << needs_recovery_map + << dendl; + return found_missing; +} + +void MissingLoc::check_recovery_sources(const OSDMapRef& osdmap) +{ + set now_down; + for (set::iterator p = missing_loc_sources.begin(); + p != missing_loc_sources.end(); + ) { + if (osdmap->is_up(p->osd)) { + ++p; + continue; + } + ldout(cct, 10) << __func__ << " source osd." << *p << " now down" << dendl; + now_down.insert(*p); + missing_loc_sources.erase(p++); + } + + if (now_down.empty()) { + ldout(cct, 10) << __func__ << " no source osds (" << missing_loc_sources << ") went down" << dendl; + } else { + ldout(cct, 10) << __func__ << " sources osds " << now_down << " now down, remaining sources are " + << missing_loc_sources << dendl; + + // filter missing_loc + map>::iterator p = missing_loc.begin(); + while (p != missing_loc.end()) { + set::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; + } + } + } +} diff --git a/src/osd/MissingLoc.h b/src/osd/MissingLoc.h new file mode 100644 index 00000000000..19aef8175cb --- /dev/null +++ b/src/osd/MissingLoc.h @@ -0,0 +1,344 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include +#include + +#include "OSDMap.h" +#include "common/WorkQueue.h" +#include "common/ceph_context.h" +#include "common/dout.h" +#include "osd_types.h" + +class MissingLoc { + public: + + class MappingInfo { + public: + virtual const set &get_upset() const = 0; + virtual bool is_ec_pg() const = 0; + virtual int get_pg_size() const = 0; + virtual ~MappingInfo() {} + }; + + // 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) { + ceph_assert(l.up >= 0); + ceph_assert(l.other >= 0); + return out << "(" << l.up << "+" << l.other << ")"; + } + }; + + + private: + loc_count_t _get_count(const set &shards) { + loc_count_t r; + for (auto s : shards) { + if (mapping_info->get_upset().count(s)) { + r.up++; + } else { + r.other++; + } + } + return r; + } + + map needs_recovery_map; + map > missing_loc; + set 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 < shard_id_t, map > missing_by_count; + + void pgs_by_shard_id( + const set& s, + map< shard_id_t, set >& pgsbs) { + if (mapping_info->is_ec_pg()) { + int num_shards = mapping_info->get_pg_size(); + // For completely missing shards initialize with empty set + for (int i = 0 ; i < num_shards ; ++i) { + shard_id_t shard(i); + pgsbs[shard]; + } + for (auto pgs: s) + pgsbs[pgs.shard].insert(pgs); + } else { + pgsbs[shard_id_t::NO_SHARD] = s; + } + } + + void _inc_count(const set& s) { + map< shard_id_t, set > pgsbs; + pgs_by_shard_id(s, pgsbs); + for (auto shard: pgsbs) + ++missing_by_count[shard.first][_get_count(shard.second)]; + } + void _dec_count(const set& s) { + map< shard_id_t, set > pgsbs; + pgs_by_shard_id(s, pgsbs); + for (auto shard: pgsbs) { + auto p = missing_by_count[shard.first].find(_get_count(shard.second)); + ceph_assert(p != missing_by_count[shard.first].end()); + if (--p->second == 0) { + missing_by_count[shard.first].erase(p); + } + } + } + + spg_t pgid; + MappingInfo *mapping_info; + DoutPrefixProvider *dpp; + CephContext *cct; + set empty_set; + public: + boost::scoped_ptr is_readable; + boost::scoped_ptr is_recoverable; + explicit MissingLoc( + spg_t pgid, + MappingInfo *mapping_info, + DoutPrefixProvider *dpp, + CephContext *cct) + : pgid(pgid), mapping_info(mapping_info), dpp(dpp), cct(cct) { } + void set_backend_predicates( + IsPGReadablePredicate *_is_readable, + IsPGRecoverablePredicate *_is_recoverable) { + is_readable.reset(_is_readable); + is_recoverable.reset(_is_recoverable); + } + std::ostream& gen_prefix(std::ostream& out) const { + return dpp->gen_prefix(out); + } + bool needs_recovery( + const hobject_t &hoid, + eversion_t *v = 0) const { + map::const_iterator i = + needs_recovery_map.find(hoid); + if (i == needs_recovery_map.end()) + return false; + if (v) + *v = i->second.need; + return true; + } + bool is_deleted(const hobject_t &hoid) const { + auto i = needs_recovery_map.find(hoid); + if (i == needs_recovery_map.end()) + return false; + return i->second.is_delete(); + } + bool is_unfound(const hobject_t &hoid) const { + auto it = needs_recovery_map.find(hoid); + if (it == needs_recovery_map.end()) { + return false; + } + if (it->second.is_delete()) { + return false; + } + auto mit = missing_loc.find(hoid); + return mit == missing_loc.end() || !(*is_recoverable)(mit->second); + } + bool readable_with_acting( + const hobject_t &hoid, + const set &acting) const; + uint64_t num_unfound() const { + uint64_t ret = 0; + for (map::const_iterator i = + needs_recovery_map.begin(); + i != needs_recovery_map.end(); + ++i) { + if (i->second.is_delete()) + continue; + auto mi = missing_loc.find(i->first); + if (mi == missing_loc.end() || !(*is_recoverable)(mi->second)) + ++ret; + } + return ret; + } + + bool have_unfound() const { + for (map::const_iterator i = + needs_recovery_map.begin(); + i != needs_recovery_map.end(); + ++i) { + if (i->second.is_delete()) + continue; + auto mi = missing_loc.find(i->first); + if (mi == missing_loc.end() || !(*is_recoverable)(mi->second)) + return true; + } + return false; + } + void clear() { + 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) { + auto p = missing_loc.find(hoid); + if (p == missing_loc.end()) { + p = missing_loc.emplace(hoid, set()).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) { + auto p = missing_loc.find(hoid); + if (p != missing_loc.end()) { + _dec_count(p->second); + p->second.erase(location); + if (p->second.empty()) { + missing_loc.erase(p); + } else { + _inc_count(p->second); + } + } + } + + void clear_location(const hobject_t &hoid) { + auto p = missing_loc.find(hoid); + if (p != missing_loc.end()) { + _dec_count(p->second); + missing_loc.erase(p); + } + } + + void add_active_missing(const pg_missing_t &missing) { + for (map::const_iterator i = + missing.get_items().begin(); + i != missing.get_items().end(); + ++i) { + map::const_iterator j = + needs_recovery_map.find(i->first); + if (j == needs_recovery_map.end()) { + needs_recovery_map.insert(*i); + } else { + if (i->second.need != j->second.need) { + lgeneric_dout(cct, 0) << this << " " << pgid << " unexpected need for " + << i->first << " have " << j->second + << " tried to add " << i->second << dendl; + ceph_assert(0 == "unexpected need for missing item"); + } + } + } + } + + void add_missing(const hobject_t &hoid, eversion_t need, eversion_t have, bool is_delete=false) { + needs_recovery_map[hoid] = pg_missing_item(need, have, is_delete); + } + void revise_need(const hobject_t &hoid, eversion_t need) { + auto it = needs_recovery_map.find(hoid); + ceph_assert(it != needs_recovery_map.end()); + it->second.need = need; + } + + /// Adds info about a possible recovery source + bool add_source_info( + pg_shard_t source, ///< [in] source + const pg_info_t &oinfo, ///< [in] info + const pg_missing_t &omissing, ///< [in] (optional) missing + ThreadPool::TPHandle* handle ///< [in] ThreadPool handle + ); ///< @return whether a new object location was discovered + + /// Adds recovery sources in batch + void add_batch_sources_info( + const set &sources, ///< [in] a set of resources which can be used for all objects + ThreadPool::TPHandle* handle ///< [in] ThreadPool handle + ); + + /// Uses osdmap to update structures for now down sources + void check_recovery_sources(const OSDMapRef& osdmap); + + /// Call when hoid is no longer missing in acting set + void recovered(const hobject_t &hoid) { + needs_recovery_map.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 + void rebuild( + const hobject_t &hoid, + pg_shard_t self, + const set to_recover, + const pg_info_t &info, + const pg_missing_t &missing, + const map &pmissing, + const map &pinfo) { + recovered(hoid); + boost::optional item; + auto miter = missing.get_items().find(hoid); + if (miter != missing.get_items().end()) { + item = miter->second; + } else { + for (auto &&i: to_recover) { + if (i == self) + continue; + auto pmiter = pmissing.find(i); + ceph_assert(pmiter != pmissing.end()); + miter = pmiter->second.get_items().find(hoid); + if (miter != pmiter->second.get_items().end()) { + item = miter->second; + break; + } + } + } + if (!item) + return; // recovered! + + needs_recovery_map[hoid] = *item; + if (item->is_delete()) + return; + auto mliter = + missing_loc.emplace(hoid, set()).first; + ceph_assert(info.last_backfill.is_max()); + ceph_assert(info.last_update >= item->need); + if (!missing.is_missing(hoid)) + mliter->second.insert(self); + for (auto &&i: pmissing) { + if (i.first == self) + continue; + auto pinfoiter = pinfo.find(i.first); + ceph_assert(pinfoiter != pinfo.end()); + if (item->need <= pinfoiter->second.last_update && + hoid <= pinfoiter->second.last_backfill && + !i.second.is_missing(hoid)) + mliter->second.insert(i.first); + } + _inc_count(mliter->second); + } + + const set &get_locations(const hobject_t &hoid) const { + auto it = missing_loc.find(hoid); + return it == missing_loc.end() ? empty_set : it->second; + } + const map> &get_missing_locs() const { + return missing_loc; + } + const map &get_needs_recovery() const { + return needs_recovery_map; + } + const map < shard_id_t, map > &get_missing_by_count() const { + return missing_by_count; + } +}; diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 95fd9b9f719..728e9fbda02 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -247,7 +247,7 @@ PG::PG(OSDService *o, OSDMapRef curmap, trace_endpoint("0.0.0.0", 0, "PG"), info_struct_v(0), pgmeta_oid(p.make_pgmeta_oid()), - missing_loc(this), + missing_loc(info.pgid, &recovery_state, this, cct), stat_queue_item(this), scrub_queued(false), recovery_queued(false), @@ -458,194 +458,6 @@ bool PG::search_for_missing( return found_missing; } - -// MissingLoc - -bool PG::MissingLoc::readable_with_acting( - const hobject_t &hoid, - const set &acting) const { - if (!needs_recovery(hoid)) - return true; - if (is_deleted(hoid)) - return false; - auto missing_loc_entry = missing_loc.find(hoid); - if (missing_loc_entry == missing_loc.end()) - return false; - const set &locs = missing_loc_entry->second; - ldout(pg->cct, 10) << __func__ << ": locs:" << locs << dendl; - set have_acting; - for (set::const_iterator i = locs.begin(); - i != locs.end(); - ++i) { - if (acting.count(*i)) - have_acting.insert(*i); - } - return (*is_readable)(have_acting); -} - -void PG::MissingLoc::add_batch_sources_info( - const set &sources, ThreadPool::TPHandle* handle) -{ - ldout(pg->cct, 10) << __func__ << ": adding sources in batch " - << sources.size() << dendl; - unsigned loop = 0; - bool sources_updated = false; - for (map::const_iterator i = needs_recovery_map.begin(); - i != needs_recovery_map.end(); - ++i) { - if (handle && ++loop >= pg->cct->_conf->osd_loop_before_reset_tphandle) { - handle->reset_tp_timeout(); - loop = 0; - } - 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()).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; - } - } -} - -bool PG::MissingLoc::add_source_info( - pg_shard_t fromosd, - const pg_info_t &oinfo, - const pg_missing_t &omissing, - ThreadPool::TPHandle* handle) -{ - bool found_missing = false; - unsigned loop = 0; - bool sources_updated = false; - // found items? - for (map::const_iterator p = needs_recovery_map.begin(); - p != needs_recovery_map.end(); - ++p) { - const hobject_t &soid(p->first); - eversion_t need = p->second.need; - if (handle && ++loop >= pg->cct->_conf->osd_loop_before_reset_tphandle) { - handle->reset_tp_timeout(); - loop = 0; - } - if (p->second.is_delete()) { - ldout(pg->cct, 10) << __func__ << " " << soid - << " delete, ignoring source" << dendl; - continue; - } - if (oinfo.last_update < need) { - ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need - << " also missing on osd." << fromosd - << " (last_update " << oinfo.last_update - << " < needed " << need << ")" << dendl; - continue; - } - if (!oinfo.last_backfill.is_max() && - !oinfo.last_backfill_bitwise) { - ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need - << " also missing on osd." << fromosd - << " (last_backfill " << oinfo.last_backfill - << " but with wrong sort order)" - << dendl; - continue; - } - if (p->first >= oinfo.last_backfill) { - // FIXME: this is _probably_ true, although it could conceivably - // be in the undefined region! Hmm! - ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need - << " also missing on osd." << fromosd - << " (past last_backfill " << oinfo.last_backfill - << ")" << dendl; - continue; - } - if (omissing.is_missing(soid)) { - ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need - << " also missing on osd." << fromosd << dendl; - continue; - } - - ldout(pg->cct, 10) << "search_for_missing " << soid << " " << need - << " is on osd." << fromosd << dendl; - - { - auto p = missing_loc.find(soid); - if (p == missing_loc.end()) { - p = missing_loc.emplace(soid, set()).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; - } - found_missing = true; - } - - ldout(pg->cct, 20) << "needs_recovery_map missing " << needs_recovery_map - << dendl; - return found_missing; -} - -void PG::MissingLoc::check_recovery_sources(const OSDMapRef& osdmap) -{ - set now_down; - for (set::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>::iterator p = missing_loc.begin(); - while (p != missing_loc.end()) { - set::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 > &query_map) { auto &missing = pg_log.get_missing(); diff --git a/src/osd/PG.h b/src/osd/PG.h index 9060a8db638..069cf168936 100644 --- a/src/osd/PG.h +++ b/src/osd/PG.h @@ -44,6 +44,7 @@ #include "PGBackend.h" #include "PGPeeringEvent.h" #include "PeeringState.h" +#include "MissingLoc.h" #include "mgr/OSDPerfMetricTypes.h" @@ -594,320 +595,8 @@ protected: // ------------------ // 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) { - ceph_assert(l.up >= 0); - ceph_assert(l.other >= 0); - return out << "(" << l.up << "+" << l.other << ")"; - } - }; - - - private: - loc_count_t _get_count(const set& shards) { - loc_count_t r; - for (auto s : shards) { - if (pg->upset.count(s)) { - r.up++; - } else { - r.other++; - } - } - return r; - } - - map needs_recovery_map; - map > missing_loc; - set 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 < shard_id_t, map > missing_by_count; - - void pgs_by_shard_id(const set& s, map< shard_id_t, set >& pgsbs) { - if (pg->get_osdmap()->pg_is_ec(pg->info.pgid.pgid)) { - int num_shards = pg->get_osdmap()->get_pg_size(pg->info.pgid.pgid); - // For completely missing shards initialize with empty set - for (int i = 0 ; i < num_shards ; ++i) { - shard_id_t shard(i); - pgsbs[shard]; - } - for (auto pgs: s) - pgsbs[pgs.shard].insert(pgs); - } else { - pgsbs[shard_id_t::NO_SHARD] = s; - } - } - - void _inc_count(const set& s) { - map< shard_id_t, set > pgsbs; - pgs_by_shard_id(s, pgsbs); - for (auto shard: pgsbs) - ++missing_by_count[shard.first][_get_count(shard.second)]; - } - void _dec_count(const set& s) { - map< shard_id_t, set > pgsbs; - pgs_by_shard_id(s, pgsbs); - for (auto shard: pgsbs) { - auto p = missing_by_count[shard.first].find(_get_count(shard.second)); - ceph_assert(p != missing_by_count[shard.first].end()); - if (--p->second == 0) { - missing_by_count[shard.first].erase(p); - } - } - } - - PG *pg; - set empty_set; - public: - boost::scoped_ptr is_readable; - boost::scoped_ptr is_recoverable; - explicit MissingLoc(PG *pg) - : pg(pg) { } - void set_backend_predicates( - IsPGReadablePredicate *_is_readable, - IsPGRecoverablePredicate *_is_recoverable) { - is_readable.reset(_is_readable); - is_recoverable.reset(_is_recoverable); - } - std::ostream& gen_prefix(std::ostream& out) const { - return pg->gen_prefix(out); - } - bool needs_recovery( - const hobject_t &hoid, - eversion_t *v = 0) const { - map::const_iterator i = - needs_recovery_map.find(hoid); - if (i == needs_recovery_map.end()) - return false; - if (v) - *v = i->second.need; - return true; - } - bool is_deleted(const hobject_t &hoid) const { - auto i = needs_recovery_map.find(hoid); - if (i == needs_recovery_map.end()) - return false; - return i->second.is_delete(); - } - bool is_unfound(const hobject_t &hoid) const { - auto it = needs_recovery_map.find(hoid); - if (it == needs_recovery_map.end()) { - return false; - } - if (it->second.is_delete()) { - return false; - } - auto mit = missing_loc.find(hoid); - return mit == missing_loc.end() || !(*is_recoverable)(mit->second); - } - bool readable_with_acting( - const hobject_t &hoid, - const set &acting) const; - uint64_t num_unfound() const { - uint64_t ret = 0; - for (map::const_iterator i = - needs_recovery_map.begin(); - i != needs_recovery_map.end(); - ++i) { - if (i->second.is_delete()) - continue; - auto mi = missing_loc.find(i->first); - if (mi == missing_loc.end() || !(*is_recoverable)(mi->second)) - ++ret; - } - return ret; - } - - bool have_unfound() const { - for (map::const_iterator i = - needs_recovery_map.begin(); - i != needs_recovery_map.end(); - ++i) { - if (i->second.is_delete()) - continue; - auto mi = missing_loc.find(i->first); - if (mi == missing_loc.end() || !(*is_recoverable)(mi->second)) - return true; - } - return false; - } - void clear() { - 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) { - auto p = missing_loc.find(hoid); - if (p == missing_loc.end()) { - p = missing_loc.emplace(hoid, set()).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) { - auto p = missing_loc.find(hoid); - if (p != missing_loc.end()) { - _dec_count(p->second); - p->second.erase(location); - if (p->second.empty()) { - missing_loc.erase(p); - } else { - _inc_count(p->second); - } - } - } - - void clear_location(const hobject_t &hoid) { - auto p = missing_loc.find(hoid); - if (p != missing_loc.end()) { - _dec_count(p->second); - missing_loc.erase(p); - } - } - - void add_active_missing(const pg_missing_t &missing) { - for (map::const_iterator i = - missing.get_items().begin(); - i != missing.get_items().end(); - ++i) { - map::const_iterator j = - needs_recovery_map.find(i->first); - if (j == needs_recovery_map.end()) { - needs_recovery_map.insert(*i); - } else { - if (i->second.need != j->second.need) { - lgeneric_dout(pg->cct, 0) << this << " " << pg->info.pgid << " unexpected need for " - << i->first << " have " << j->second - << " tried to add " << i->second << dendl; - ceph_assert(0 == "unexpected need for missing item"); - - } - } - } - } - - void add_missing(const hobject_t &hoid, eversion_t need, eversion_t have, bool is_delete=false) { - needs_recovery_map[hoid] = pg_missing_item(need, have, is_delete); - } - void revise_need(const hobject_t &hoid, eversion_t need) { - auto it = needs_recovery_map.find(hoid); - ceph_assert(it != needs_recovery_map.end()); - it->second.need = need; - } - /// Adds info about a possible recovery source - bool add_source_info( - pg_shard_t source, ///< [in] source - const pg_info_t &oinfo, ///< [in] info - const pg_missing_t &omissing, ///< [in] (optional) missing - ThreadPool::TPHandle* handle ///< [in] ThreadPool handle - ); ///< @return whether a new object location was discovered - - /// Adds recovery sources in batch - void add_batch_sources_info( - const set &sources, ///< [in] a set of resources which can be used for all objects - ThreadPool::TPHandle* handle ///< [in] ThreadPool handle - ); - - /// Uses osdmap to update structures for now down sources - void check_recovery_sources(const OSDMapRef& osdmap); - - /// Call when hoid is no longer missing in acting set - void recovered(const hobject_t &hoid) { - needs_recovery_map.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 - void rebuild( - const hobject_t &hoid, - pg_shard_t self, - const set to_recover, - const pg_info_t &info, - const pg_missing_t &missing, - const map &pmissing, - const map &pinfo) { - recovered(hoid); - boost::optional item; - auto miter = missing.get_items().find(hoid); - if (miter != missing.get_items().end()) { - item = miter->second; - } else { - for (auto &&i: to_recover) { - if (i == self) - continue; - auto pmiter = pmissing.find(i); - ceph_assert(pmiter != pmissing.end()); - miter = pmiter->second.get_items().find(hoid); - if (miter != pmiter->second.get_items().end()) { - item = miter->second; - break; - } - } - } - if (!item) - return; // recovered! - - needs_recovery_map[hoid] = *item; - if (item->is_delete()) - return; - auto mliter = - missing_loc.emplace(hoid, set()).first; - ceph_assert(info.last_backfill.is_max()); - ceph_assert(info.last_update >= item->need); - if (!missing.is_missing(hoid)) - mliter->second.insert(self); - for (auto &&i: pmissing) { - if (i.first == self) - continue; - auto pinfoiter = pinfo.find(i.first); - ceph_assert(pinfoiter != pinfo.end()); - if (item->need <= pinfoiter->second.last_update && - hoid <= pinfoiter->second.last_backfill && - !i.second.is_missing(hoid)) - mliter->second.insert(i.first); - } - _inc_count(mliter->second); - } - - const set &get_locations(const hobject_t &hoid) const { - auto it = missing_loc.find(hoid); - return it == missing_loc.end() ? empty_set : it->second; - } - const map> &get_missing_locs() const { - return missing_loc; - } - const map &get_needs_recovery() const { - return needs_recovery_map; - } - const map < shard_id_t, map > &get_missing_by_count() const { - return missing_by_count; - } - } missing_loc; + MissingLoc missing_loc; interval_set snap_trimq; diff --git a/src/osd/PeeringState.h b/src/osd/PeeringState.h index 27d6ebb8560..1b202dbef33 100644 --- a/src/osd/PeeringState.h +++ b/src/osd/PeeringState.h @@ -19,6 +19,7 @@ #include "osd_types.h" #include "os/ObjectStore.h" #include "OSDMap.h" +#include "MissingLoc.h" class PG; @@ -52,7 +53,7 @@ struct PGPool { }; /* Encapsulates PG recovery process */ -class PeeringState { +class PeeringState : public MissingLoc::MappingInfo { public: struct PeeringListener : public EpochSource { virtual void prepare_write( @@ -1158,6 +1159,19 @@ public: PeeringListener *pl, PG *pg); + // MissingLoc::MappingInfo + const set &get_upset() const override { + return upset; + } + + bool is_ec_pg() const override { + return pool.info.is_erasure(); + } + + int get_pg_size() const override { + return pool.info.size; + } + void handle_event(const boost::statechart::event_base &evt, PeeringCtx *rctx) { start_handle(rctx); @@ -1256,9 +1270,6 @@ public: return deleted || e < get_last_peering_reset(); } - bool is_ec_pg() const { - return pool.info.is_erasure(); - } int get_role() const { return role; }