]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osd/: extract MissingLoc into its own file
authorSamuel Just <sjust@redhat.com>
Fri, 12 Apr 2019 18:08:54 +0000 (11:08 -0700)
committersjust@redhat.com <sjust@redhat.com>
Wed, 1 May 2019 18:22:13 +0000 (11:22 -0700)
Signed-off-by: Samuel Just <sjust@redhat.com>
src/osd/CMakeLists.txt
src/osd/MissingLoc.cc [new file with mode: 0644]
src/osd/MissingLoc.h [new file with mode: 0644]
src/osd/PG.cc
src/osd/PG.h
src/osd/PeeringState.h

index 0ab2876ad5ab7af3be4bb024cb4e0b7aee74f77f..d7f7efa07d33a9c031af01adcde7936addb3bd32 100644 (file)
@@ -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 (file)
index 0000000..984beed
--- /dev/null
@@ -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<pg_shard_t> &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<pg_shard_t> &locs = missing_loc_entry->second;
+  ldout(cct, 10) << __func__ << ": locs:" << locs << dendl;
+  set<pg_shard_t> have_acting;
+  for (set<pg_shard_t>::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<pg_shard_t> &sources,
+  ThreadPool::TPHandle* handle)
+{
+  ldout(cct, 10) << __func__ << ": adding sources in batch "
+                    << sources.size() << dendl;
+  unsigned loop = 0;
+  bool sources_updated = false;
+  for (map<hobject_t, pg_missing_item>::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<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;
+    }
+  }
+}
+
+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<hobject_t,pg_missing_item>::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<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;
+    }
+    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<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(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<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;
+      }
+    }
+  }
+}
diff --git a/src/osd/MissingLoc.h b/src/osd/MissingLoc.h
new file mode 100644 (file)
index 0000000..19aef81
--- /dev/null
@@ -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 <map>
+#include <set>
+
+#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<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 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<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;
+  }
+
+  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 < shard_id_t, map<loc_count_t,int> > missing_by_count;
+
+  void pgs_by_shard_id(
+    const set<pg_shard_t>& s,
+    map< shard_id_t, 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 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 set<pg_shard_t>& s) {
+    map< shard_id_t, 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 set<pg_shard_t>& s) {
+    map< shard_id_t, 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;
+  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);
+  }
+  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<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 set<pg_shard_t> &acting) const;
+  uint64_t num_unfound() const {
+    uint64_t ret = 0;
+    for (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 (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, 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 (map<hobject_t, pg_missing_item>::const_iterator i =
+          missing.get_items().begin();
+        i != missing.get_items().end();
+        ++i) {
+      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
+    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<pg_shard_t> &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<pg_shard_t> to_recover,
+    const pg_info_t &info,
+    const pg_missing_t &missing,
+    const map<pg_shard_t, pg_missing_t> &pmissing,
+    const map<pg_shard_t, pg_info_t> &pinfo) {
+    recovered(hoid);
+    boost::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, 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 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 map<hobject_t, set<pg_shard_t>> &get_missing_locs() const {
+    return missing_loc;
+  }
+  const map<hobject_t, pg_missing_item> &get_needs_recovery() const {
+    return needs_recovery_map;
+  }
+  const map < shard_id_t, map<loc_count_t,int> > &get_missing_by_count() const {
+    return missing_by_count;
+  }
+};
index 95fd9b9f719a8a31a86aa01021fcbd5a98d82e98..728e9fbda02f938f6a0028ac9326912f048c2a7a 100644 (file)
@@ -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<pg_shard_t> &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<pg_shard_t> &locs = missing_loc_entry->second;
-  ldout(pg->cct, 10) << __func__ << ": locs:" << locs << dendl;
-  set<pg_shard_t> have_acting;
-  for (set<pg_shard_t>::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<pg_shard_t> &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<hobject_t, pg_missing_item>::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<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;
-    }
-  }
-}
-
-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<hobject_t,pg_missing_item>::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<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;
-    }
-    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<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();
index 9060a8db6388dfa02a00ae5176a5c26cbb1cbc7c..069cf1689360e7d038fe760585ef404eb32c3f7f 100644 (file)
@@ -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<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 < shard_id_t, map<loc_count_t,int> > missing_by_count;
-
-   void pgs_by_shard_id(const set<pg_shard_t>& s, map< shard_id_t, set<pg_shard_t> >& 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<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 set<pg_shard_t>& s) {
-      map< shard_id_t, 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 set<pg_shard_t>& s) {
-      map< shard_id_t, 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);
-        }
-      }
-    }
-
-    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) { }
-    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<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 set<pg_shard_t> &acting) const;
-    uint64_t num_unfound() const {
-      uint64_t ret = 0;
-      for (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 (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, 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 (map<hobject_t, pg_missing_item>::const_iterator i =
-            missing.get_items().begin();
-          i != missing.get_items().end();
-          ++i) {
-       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(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<pg_shard_t> &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<pg_shard_t> to_recover,
-      const pg_info_t &info,
-      const pg_missing_t &missing,
-      const map<pg_shard_t, pg_missing_t> &pmissing,
-      const map<pg_shard_t, pg_info_t> &pinfo) {
-      recovered(hoid);
-      boost::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, 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 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 map<hobject_t, set<pg_shard_t>> &get_missing_locs() const {
-      return missing_loc;
-    }
-    const map<hobject_t, pg_missing_item> &get_needs_recovery() const {
-      return needs_recovery_map;
-    }
-    const map < shard_id_t, map<loc_count_t,int> > &get_missing_by_count() const {
-      return missing_by_count;
-    }
-  } missing_loc;
+  MissingLoc missing_loc;
   
   interval_set<snapid_t> snap_trimq;
 
index 27d6ebb85601e3ab6e4da639a41872c00c6fb90d..1b202dbef33b0525fb75e17946fae9ddfe947f56 100644 (file)
@@ -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<pg_shard_t> &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;
   }