]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
ReplicatedPG: block scrub on blocked object contexts 1791/head
authorSamuel Just <sam.just@inktank.com>
Tue, 6 May 2014 18:50:14 +0000 (11:50 -0700)
committerSamuel Just <sam.just@inktank.com>
Thu, 8 May 2014 19:41:28 +0000 (12:41 -0700)
Fixes: #8011
Backport: firefly
Signed-off-by: Samuel Just <sam.just@inktank.com>
src/osd/PG.cc
src/osd/PG.h
src/osd/ReplicatedPG.cc
src/osd/ReplicatedPG.h
src/osd/osd_types.h

index 8eb3c34d457299a15f122f24cb5fde5b60d0c21d..cda09e79a91997b46d7178ab46e9eb3bf9abc6ec 100644 (file)
@@ -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
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 2635d58501c872dce41897171adc05237ffb9ec9..976855423f56b44ed5808f681f795082beaf16c5 100644 (file)
@@ -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<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;
+      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;
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());