From 0f3235d46c8fd6c537bd4aa8a3faec6c00f311a8 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Thu, 17 Apr 2014 17:26:17 -0700 Subject: [PATCH] ReplicatedPG: block scrub on blocked object contexts Fixes: #8011 Signed-off-by: Samuel Just Reviewed-by: Sage Weil (cherry picked from commit e66f2e36c06ca00c1147f922d3513f56b122a5c0) --- src/osd/PG.cc | 17 ++++++++++++----- src/osd/PG.h | 7 +++++++ src/osd/ReplicatedPG.cc | 20 ++++++++++++++++++++ src/osd/ReplicatedPG.h | 2 ++ src/osd/osd_types.h | 3 ++- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 6deb0998b2966..2c86f3ba2d251 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -3880,6 +3880,7 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) scrubber.received_maps.clear(); { + hobject_t end; // get the start and end of our scrub chunk // @@ -3898,11 +3899,11 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) cct->_conf->osd_scrub_chunk_max, 0, &objects, - &scrubber.end); + &end); assert(ret >= 0); // in case we don't find a boundary: start again at the end - start = scrubber.end; + start = end; // special case: reached end of file store, implicitly a boundary if (objects.empty()) { @@ -3910,19 +3911,25 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) } // search backward from the end looking for a boundary - objects.push_back(scrubber.end); + objects.push_back(end); while (!boundary_found && objects.size() > 1) { hobject_t end = objects.back().get_boundary(); objects.pop_back(); if (objects.back().get_filestore_key() != end.get_filestore_key()) { - scrubber.end = end; + end = end; boundary_found = true; } } } - } + if (!_range_available_for_scrub(scrubber.start, end)) { + // we'll be requeued by whatever made us unavailable for scrub + done = true; + break; + } + scrubber.end = end; + } scrubber.block_writes = true; // walk the log to find the latest update that affects our chunk diff --git a/src/osd/PG.h b/src/osd/PG.h index 64ab8856ac152..8967a56fd2d7d 100644 --- a/src/osd/PG.h +++ b/src/osd/PG.h @@ -1118,6 +1118,13 @@ public: void build_scrub_map(ScrubMap &map, ThreadPool::TPHandle &handle); void build_inc_scrub_map( ScrubMap &map, eversion_t v, ThreadPool::TPHandle &handle); + /** + * returns true if [begin, end) is good to scrub at this time + * a false return value obliges the implementer to requeue scrub when the + * condition preventing scrub clears + */ + virtual bool _range_available_for_scrub( + const hobject_t &begin, const hobject_t &end) = 0; virtual void _scrub(ScrubMap &map) { } virtual void _scrub_clear_state() { } virtual void _scrub_finish() { } diff --git a/src/osd/ReplicatedPG.cc b/src/osd/ReplicatedPG.cc index b6beae665e9e6..2521b966d0302 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -7425,6 +7425,9 @@ void ReplicatedPG::kick_object_context_blocked(ObjectContextRef obc) dout(10) << __func__ << " " << soid << " requeuing " << ls.size() << " requests" << dendl; requeue_ops(ls); waiting_for_blocked_object.erase(p); + + if (obc->requeue_scrub_on_unblock) + osd->queue_for_scrub(this); } SnapSetContext *ReplicatedPG::create_snapset_context(const hobject_t& oid) @@ -11502,6 +11505,23 @@ void ReplicatedPG::agent_estimate_atime_temp(const hobject_t& oid, // SCRUB +bool ReplicatedPG::_range_available_for_scrub( + const hobject_t &begin, const hobject_t &end) +{ + pair next; + next.second = object_contexts.lookup(begin); + next.first = begin; + bool more = true; + while (more && next.first < end) { + if (next.second && next.second->is_blocked()) { + next.second->requeue_scrub_on_unblock = true; + return true; + } + more = object_contexts.get_next(next.first, &next); + } + return false; +} + void ReplicatedPG::_scrub(ScrubMap& scrubmap) { dout(10) << "_scrub" << dendl; diff --git a/src/osd/ReplicatedPG.h b/src/osd/ReplicatedPG.h index b69a16316138e..abee8bf57b67a 100644 --- a/src/osd/ReplicatedPG.h +++ b/src/osd/ReplicatedPG.h @@ -1241,6 +1241,8 @@ protected: friend struct C_Flush; // -- scrub -- + virtual bool _range_available_for_scrub( + const hobject_t &begin, const hobject_t &end); virtual void _scrub(ScrubMap& map); virtual void _scrub_clear_state(); virtual void _scrub_finish(); diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 092d6ccbf6fad..328962001ccac 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -2690,6 +2690,7 @@ public: // set if writes for this object are blocked on another objects recovery ObjectContextRef blocked_by; // object blocking our writes set blocking; // objects whose writes we block + bool requeue_scrub_on_unblock; // true if we need to requeue scrub on unblock // any entity in obs.oi.watchers MUST be in either watchers or unconnected_watchers. map, WatchRef> watchers; @@ -2862,7 +2863,7 @@ public: destructor_callback(0), lock("ReplicatedPG::ObjectContext::lock"), unstable_writes(0), readers(0), writers_waiting(0), readers_waiting(0), - blocked(false) {} + blocked(false), requeue_scrub_on_unblock(false) {} ~ObjectContext() { assert(rwstate.empty()); -- 2.39.5