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,
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);
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:
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,
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;
*/
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
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)
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'
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;
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)