From 7411477153219d66625a74c5886530029c516036 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Tue, 6 May 2014 11:50:14 -0700 Subject: [PATCH] ReplicatedPG: block scrub on blocked object contexts Fixes: #8011 Backport: firefly Signed-off-by: Samuel Just --- src/osd/PG.cc | 20 +++++++++++++++----- src/osd/PG.h | 7 +++++++ src/osd/ReplicatedPG.cc | 23 +++++++++++++++++++++++ src/osd/ReplicatedPG.h | 2 ++ src/osd/osd_types.h | 3 ++- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 8eb3c34d4572..cda09e79a919 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -3881,6 +3881,7 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) scrubber.received_maps.clear(); { + hobject_t candidate_end; // get the start and end of our scrub chunk // @@ -3899,11 +3900,11 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) cct->_conf->osd_scrub_chunk_max, 0, &objects, - &scrubber.end); + &candidate_end); assert(ret >= 0); // in case we don't find a boundary: start again at the end - start = scrubber.end; + start = candidate_end; // special case: reached end of file store, implicitly a boundary if (objects.empty()) { @@ -3911,19 +3912,28 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle) } // search backward from the end looking for a boundary - objects.push_back(scrubber.end); + objects.push_back(candidate_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; + candidate_end = end; boundary_found = true; } } } - } + if (!_range_available_for_scrub(scrubber.start, candidate_end)) { + // we'll be requeued by whatever made us unavailable for scrub + dout(10) << __func__ << ": scrub blocked somewhere in range " + << "[" << scrubber.start << ", " << candidate_end << ")" + << dendl; + done = true; + break; + } + scrubber.end = candidate_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 64ab8856ac15..8967a56fd2d7 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 2635d58501c8..976855423f56 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -7433,6 +7433,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) @@ -11510,6 +11513,26 @@ 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; + dout(10) << __func__ << ": scrub delayed, " + << next.first << " is blocked" + << dendl; + return false; + } + more = object_contexts.get_next(next.first, &next); + } + return true; +} + void ReplicatedPG::_scrub(ScrubMap& scrubmap) { dout(10) << "_scrub" << dendl; diff --git a/src/osd/ReplicatedPG.h b/src/osd/ReplicatedPG.h index b69a16316138..abee8bf57b67 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 092d6ccbf6fa..328962001cca 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.47.3