From: Samuel Just Date: Tue, 6 May 2014 18:50:14 +0000 (-0700) Subject: ReplicatedPG: block scrub on blocked object contexts X-Git-Tag: v0.80.2~52 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=29ee6faecb9e16c63acae8318a7c8f6b14367af7;p=ceph.git ReplicatedPG: block scrub on blocked object contexts Fixes: #8011 Backport: firefly Signed-off-by: Samuel Just (cherry picked from commit 7411477153219d66625a74c5886530029c516036) --- diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 69813a413066..9b0f17bf607a 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 candidate_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); + &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()) { @@ -3910,19 +3911,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 1fce2979c4ea..e9f3981f412d 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 4c1d7b66df3d..4d9d59e04faf 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -7440,6 +7440,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) @@ -11581,6 +11584,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 3ea47218aada..562cb0692706 100644 --- a/src/osd/ReplicatedPG.h +++ b/src/osd/ReplicatedPG.h @@ -1243,6 +1243,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 60fa89d644e9..6d9ce37f2f48 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -2693,6 +2693,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; @@ -2865,7 +2866,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());