diff options
Diffstat (limited to '')
-rw-r--r-- | src/osd/MissingLoc.h | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/src/osd/MissingLoc.h b/src/osd/MissingLoc.h new file mode 100644 index 000000000..9bce3ceda --- /dev/null +++ b/src/osd/MissingLoc.h @@ -0,0 +1,353 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include <map> +#include <set> + +#include "OSDMap.h" +#include "common/HBHandle.h" +#include "common/ceph_context.h" +#include "common/dout.h" +#include "osd_types.h" + +class MissingLoc { + public: + + class MappingInfo { + public: + virtual const std::set<pg_shard_t> &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 std::ostream& operator<<(std::ostream& out, const loc_count_t& l) { + ceph_assert(l.up >= 0); + ceph_assert(l.other >= 0); + return out << "(" << l.up << "+" << l.other << ")"; + } + }; + + + using missing_by_count_t = std::map<shard_id_t, std::map<loc_count_t,int>>; + private: + loc_count_t _get_count(const std::set<pg_shard_t> &shards) { + loc_count_t r; + for (auto s : shards) { + if (mapping_info->get_upset().count(s)) { + r.up++; + } else { + r.other++; + } + } + return r; + } + + std::map<hobject_t, pg_missing_item> needs_recovery_map; + std::map<hobject_t, std::set<pg_shard_t> > missing_loc; + std::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 std::map will always equal + // missing_loc.size(). + missing_by_count_t missing_by_count; + + void pgs_by_shard_id( + const std::set<pg_shard_t>& s, + std::map<shard_id_t, std::set<pg_shard_t> >& pgsbs) { + if (mapping_info->is_ec_pg()) { + int num_shards = mapping_info->get_pg_size(); + // For completely missing shards initialize with empty std::set<pg_shard_t> + 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 std::set<pg_shard_t>& s) { + std::map< shard_id_t, std::set<pg_shard_t> > pgsbs; + pgs_by_shard_id(s, pgsbs); + for (auto shard: pgsbs) + ++missing_by_count[shard.first][_get_count(shard.second)]; + } + void _dec_count(const std::set<pg_shard_t>& s) { + std::map< shard_id_t, std::set<pg_shard_t> > 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; + std::set<pg_shard_t> empty_set; + public: + boost::scoped_ptr<IsPGReadablePredicate> is_readable; + boost::scoped_ptr<IsPGRecoverablePredicate> 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); + } + const IsPGRecoverablePredicate &get_recoverable_predicate() const { + return *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 { + std::map<hobject_t, pg_missing_item>::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 std::set<pg_shard_t> &acting, + eversion_t* v = 0) const; + uint64_t num_unfound() const { + uint64_t ret = 0; + for (std::map<hobject_t, pg_missing_item>::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 (std::map<hobject_t, pg_missing_item>::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, std::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) { + 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 (std::map<hobject_t, pg_missing_item>::const_iterator i = + missing.get_items().begin(); + i != missing.get_items().end(); + ++i) { + std::map<hobject_t, pg_missing_item>::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 + HBHandle *handle ///< [in] ThreadPool handle + ); ///< @return whether a new object location was discovered + + /// Adds recovery sources in batch + void add_batch_sources_info( + const std::set<pg_shard_t> &sources, ///< [in] a std::set of resources which can be used for all objects + HBHandle *handle ///< [in] ThreadPool handle + ); + + /// Uses osdmap to update structures for now down sources + void check_recovery_sources(const OSDMapRef& osdmap); + + /// Remove stray from recovery sources + void remove_stray_recovery_sources(pg_shard_t stray); + + /// Call when hoid is no longer missing in acting std::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 std::set<pg_shard_t> &to_recover, + const pg_info_t &info, + const pg_missing_t &missing, + const std::map<pg_shard_t, pg_missing_t> &pmissing, + const std::map<pg_shard_t, pg_info_t> &pinfo) { + recovered(hoid); + std::optional<pg_missing_item> 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, std::set<pg_shard_t>()).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 std::set<pg_shard_t> &get_locations(const hobject_t &hoid) const { + auto it = missing_loc.find(hoid); + return it == missing_loc.end() ? empty_set : it->second; + } + const std::map<hobject_t, std::set<pg_shard_t>> &get_missing_locs() const { + return missing_loc; + } + const std::map<hobject_t, pg_missing_item> &get_needs_recovery() const { + return needs_recovery_map; + } + + const missing_by_count_t &get_missing_by_count() const { + return missing_by_count; + } +}; |