]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd/scrub: directly create or reinit the ScrubStore
authorRonen Friedman <rfriedma@redhat.com>
Mon, 23 Sep 2024 08:58:59 +0000 (03:58 -0500)
committerRonen Friedman <rfriedma@redhat.com>
Thu, 10 Oct 2024 16:29:20 +0000 (11:29 -0500)
The ScrubStore is now directly created or reinitialized by the
Scrubber. Note that the store object is not identical to the
errors DB: the errors DB is an entity in the OSD store (a
collection of OMap entries in a uniquely-named object(s)),
while the ScrubSTore object is a cacher and accessor for
that entity. That one can be recreated or disposed of at
will.

We now do not recreate the ScrubStore object for every scrub.

Signed-off-by: Ronen Friedman <rfriedma@redhat.com>
src/osd/scrubber/ScrubStore.cc
src/osd/scrubber/ScrubStore.h
src/osd/scrubber/pg_scrubber.cc
src/osd/scrubber/pg_scrubber.h

index af223cb5cdc097b15a610c9cf4da5bd57ba80abc..0c36be6b66b0278aa1a2ae406fc7da0116c9184f 100644 (file)
@@ -99,20 +99,6 @@ string last_snap_key(int64_t pool)
 
 namespace Scrub {
 
-Store*
-Store::create(ObjectStore* store,
-             ObjectStore::Transaction* t,
-             const spg_t& pgid,
-             const coll_t& coll)
-{
-  ceph_assert(store);
-  ceph_assert(t);
-  ghobject_t oid = make_scrub_object(pgid);
-  t->touch(coll, oid);
-  return new Store{*store, t, pgid, coll};
-}
-
-
 Store::Store(
     ObjectStore& osd_store,
     ObjectStore::Transaction* t,
@@ -174,6 +160,33 @@ void Store::flush(ObjectStore::Transaction* t)
   errors_db->results.clear();
 }
 
+
+void Store::clear_level_db(
+    ObjectStore::Transaction* t,
+    at_level_t& db)
+{
+  // easiest way to guarantee that the object representing the DB exists
+  t->touch(coll, db.errors_hoid);
+
+  // remove all the keys in the DB
+  t->omap_clear(coll, db.errors_hoid);
+
+  // restart the 'in progress' part of the MapCacher
+  db.backend.reset();
+}
+
+
+void Store::reinit(ObjectStore::Transaction* t, [[maybe_unused]] scrub_level_t level)
+{
+  // Note: only one caller, and it creates the transaction passed to reinit().
+  // No need to assert on 't'
+
+  if (errors_db) {
+    clear_level_db(t, *errors_db);
+  }
+}
+
+
 void Store::cleanup(ObjectStore::Transaction* t)
 {
   ceph_assert(t);
index 949a976051e67553966c48de0cfda8a46cf4e0ba..600905e85e8a286af309680db4c3daccd785213b 100644 (file)
@@ -20,11 +20,16 @@ namespace Scrub {
 class Store {
  public:
   ~Store();
-  static Store* create(ObjectStore* store,
-                      ObjectStore::Transaction* t,
-                      const spg_t& pgid,
-                      const coll_t& coll);
+
+  Store(ObjectStore& osd_store,
+    ObjectStore::Transaction* t,
+    const spg_t& pgid,
+    const coll_t& coll);
+
+
+  /// mark down detected errors, either shallow or deep
   void add_object_error(int64_t pool, const inconsistent_obj_wrapper& e);
+
   void add_snap_error(int64_t pool, const inconsistent_snapset_wrapper& e);
 
   // and a variant-friendly interface:
@@ -33,8 +38,22 @@ class Store {
 
   bool empty() const;
   void flush(ObjectStore::Transaction*);
+
+  /// remove both shallow and deep errors DBs. Called on interval.
   void cleanup(ObjectStore::Transaction*);
 
+  /**
+   * prepare the Store object for a new scrub session.
+   * This involves clearing one or both of the errors DBs, and resetting
+   * the cache.
+   *
+   * @param level: the scrub level to prepare for. Whenever a deep scrub
+   * is requested, both the shallow and deep errors DBs are cleared.
+   * If, on the other hand, a shallow scrub is requested, only the shallow
+   * errors DB is cleared.
+   */
+  void reinit(ObjectStore::Transaction* t, scrub_level_t level);
+
   std::vector<ceph::buffer::list> get_snap_errors(
     int64_t pool,
     const librados::object_id_t& start,
@@ -73,15 +92,9 @@ class Store {
     std::map<std::string, ceph::buffer::list> results;
   };
 
-  Store(ObjectStore& osd_store,
-    ObjectStore::Transaction* t,
-    const spg_t& pgid,
-    const coll_t& coll);
-
   std::vector<ceph::buffer::list> get_errors(const std::string& start,
                                             const std::string& end,
                                             uint64_t max_return) const;
- private:
   /// the OSD's storage backend
   ObjectStore& object_store;
 
@@ -96,6 +109,15 @@ class Store {
    */
   mutable std::optional<at_level_t> errors_db;
   // not yet: mutable std::optional<at_level_t> deep_db;
+
+  /**
+   * Clear the DB of errors at a specific scrub level by performing an
+   * omap_clear() on the DB object, and resetting the MapCacher.
+   */
+  void clear_level_db(
+      ObjectStore::Transaction* t,
+      at_level_t& db);
+
 };
 }  // namespace Scrub
 
index 555d13ba72b2b200ff15abf69871d8d2c3fc7a74..a085481f477acd525dbcffa006f3cf597f21e017 100644 (file)
@@ -1183,6 +1183,7 @@ void PgScrubber::_request_scrub_map(pg_shard_t replica,
   m_osds->send_message_osd_cluster(replica.osd, repscrubop, get_osdmap_epoch());
 }
 
+// only called on interval change. Both DBs are to be removed.
 void PgScrubber::cleanup_store(ObjectStore::Transaction* t)
 {
   if (!m_store)
@@ -1200,6 +1201,38 @@ void PgScrubber::cleanup_store(ObjectStore::Transaction* t)
   ceph_assert(!m_store);
 }
 
+
+void PgScrubber::reinit_scrub_store()
+{
+  // Entering, 0 to 3 of the following objects(*) may exist:
+  // ((*)'objects' here: both code objects (the ScrubStore object) and
+  // actual Object Store objects).
+  // 1. The ScrubStore object itself.
+  // 2,3. The two special hobjects in the coll (the PG data) holding the last
+  //      scrub's results. <<note: only one DB in this commit>>
+  //
+  // The Store object can be deleted and recreated, as a way to guarantee
+  // no junk is left. We won't do it here, but we will clear the at_level_t
+  // structures.
+  // The hobjects: possibly. The shallow DB object is always cleared. The
+  // deep one - only if running a deep scrub.
+  ObjectStore::Transaction t;
+  if (m_store) {
+    dout(10) << __func__ << " reusing existing store" << dendl;
+    m_store->flush(&t);
+  } else {
+    dout(10) << __func__ << " creating new store" << dendl;
+    m_store = std::make_unique<Scrub::Store>(
+       *m_pg->osd->store, &t, m_pg->info.pgid, m_pg->coll);
+  }
+
+  // regardless of whether the ScrubStore object was recreated or reused, we need to
+  // (possibly) clear the actual DB objects in the Object Store.
+  m_store->reinit(&t, m_active_target->level());
+  m_pg->osd->store->queue_transaction(m_pg->ch, std::move(t), nullptr);
+}
+
+
 void PgScrubber::on_init()
 {
   // going upwards from 'inactive'
@@ -1217,14 +1250,8 @@ void PgScrubber::on_init()
     m_is_deep ? scrub_level_t::deep : scrub_level_t::shallow,
     m_pg->get_actingset());
 
-  //  create a new store
-  {
-    ObjectStore::Transaction t;
-    cleanup_store(&t);
-    m_store.reset(
-      Scrub::Store::create(m_pg->osd->store, &t, m_pg->info.pgid, m_pg->coll));
-    m_pg->osd->store->queue_transaction(m_pg->ch, std::move(t), nullptr);
-  }
+  // create or reuse the 'known errors' store
+  reinit_scrub_store();
 
   m_start = m_pg->info.pgid.pgid.get_hobj_start();
   m_active = true;
index ff8c98d387ea2afb0e875901d158e0b7c28c638f..1a5813bd9235c1151d522989da833a83b4163cd4 100644 (file)
@@ -771,6 +771,16 @@ class PgScrubber : public ScrubPgIF,
 
   std::unique_ptr<Scrub::Store> m_store;
 
+  /**
+   * the ScrubStore sub-object caches and manages the database of known
+   * scrub errors. reinit_scrub_store() clears the database and re-initializes
+   * the ScrubStore object.
+   *
+   * in the next iteration - reinit_..() potentially deletes only the
+   * shallow errors part of the database.
+   */
+  void reinit_scrub_store();
+
   int num_digest_updates_pending{0};
   hobject_t m_start, m_end;  ///< note: half-closed: [start,end)