]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ReplicatedPG: block scrub on blocked object contexts
authorSamuel Just <sam.just@inktank.com>
Fri, 18 Apr 2014 00:26:17 +0000 (17:26 -0700)
committerSage Weil <sage@inktank.com>
Wed, 30 Apr 2014 22:13:10 +0000 (15:13 -0700)
Fixes: #8011
Signed-off-by: Samuel Just <sam.just@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>
(cherry picked from commit e66f2e36c06ca00c1147f922d3513f56b122a5c0)

src/osd/PG.cc
src/osd/PG.h
src/osd/ReplicatedPG.cc
src/osd/ReplicatedPG.h
src/osd/osd_types.h

index 6deb0998b296658762ce7eedfdace7829c5a5d0a..2c86f3ba2d2511875be56256b2f2dedbe98f2da2 100644 (file)
@@ -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
index 64ab8856ac15276f8f242a272e77c1628ab29d0c..8967a56fd2d7d9b8cea8b415700f8944c84834e4 100644 (file)
@@ -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() { }
index b6beae665e9e6efafff45b854b6fa149608d7246..2521b966d030289d5c7696ed172b2765a6b46fe9 100644 (file)
@@ -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<hobject_t, ObjectContextRef> 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;
index b69a16316138e29d59c3245293b7aecced7054b7..abee8bf57b67acddb30b8a0561e2eca627d8c77a 100644 (file)
@@ -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();
index 092d6ccbf6fadb62272a68c682509fe155849973..328962001ccaca6f65f5fad459ce30ed5fd29a66 100644 (file)
@@ -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<ObjectContextRef> 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<pair<uint64_t, entity_name_t>, 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());