]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osd/PG: fix lost unfound + delete when there are no missing objects
authorJosh Durgin <jdurgin@redhat.com>
Fri, 4 Aug 2017 00:45:26 +0000 (20:45 -0400)
committerJosh Durgin <jdurgin@redhat.com>
Fri, 4 Aug 2017 03:02:43 +0000 (23:02 -0400)
The default constructed pg_missing_t for a peer with no missing
objects resets may_include_deletes to false, so when missing items for
lost deletes should be added later, they are not, and the old
version of the lost object is left on the replica.

Fix this by always setting may_include_deletes upon entering the
GetMissing state, and using clear() rather than the default
constructor to create an empty missing set.

This only affects lost_unfound delete since it is the only way for a
peer to gain missing delete entries. If the peer starts out missing
some objects, its missing set sent over the wire is used instead, with
the correct setting for may_include_deletes.

Fixes: http://tracker.ceph.com/issues/20904
Signed-off-by: Josh Durgin <jdurgin@redhat.com>
src/osd/PG.cc

index 56866b6e383c5d07b5ce1bd90b1b28f0b39fd37c..440cd2e6f87ce7fd58a1fe3536ae6377c5f5f232 100644 (file)
@@ -1644,6 +1644,7 @@ void PG::activate(ObjectStore::Transaction& t,
       dout(10) << "activate peer osd." << peer << " " << pi << dendl;
 
       MOSDPGLog *m = 0;
+      assert(peer_missing.count(peer));
       pg_missing_t& pm = peer_missing[peer];
 
       bool needs_past_intervals = pi.dne();
@@ -5069,6 +5070,7 @@ void PG::merge_new_log_entries(
     assert(peer_missing.count(peer));
     assert(peer_info.count(peer));
     pg_missing_t& pmissing(peer_missing[peer]);
+    dout(20) << __func__ << " peer_missing for " << peer << " = " << pmissing << dendl;
     pg_info_t& pinfo(peer_info[peer]);
     bool invalidate_stats = PGLog::append_log_entries_update_missing(
       pinfo.last_backfill,
@@ -8003,18 +8005,23 @@ PG::RecoveryState::GetMissing::GetMissing(my_context ctx)
        ++i) {
     if (*i == pg->get_primary()) continue;
     const pg_info_t& pi = pg->peer_info[*i];
+    // reset this so to make sure the pg_missing_t is initialized and
+    // has the correct semantics even if we don't need to get a
+    // missing set from a shard. This way later additions due to
+    // lost+unfound delete work properly.
+    pg->peer_missing[*i].may_include_deletes = !pg->perform_deletes_during_peering();
 
     if (pi.is_empty())
       continue;                                // no pg data, nothing divergent
 
     if (pi.last_update < pg->pg_log.get_tail()) {
       ldout(pg->cct, 10) << " osd." << *i << " is not contiguous, will restart backfill" << dendl;
-      pg->peer_missing[*i];
+      pg->peer_missing[*i].clear();
       continue;
     }
     if (pi.last_backfill == hobject_t()) {
       ldout(pg->cct, 10) << " osd." << *i << " will fully backfill; can infer empty missing set" << dendl;
-      pg->peer_missing[*i];
+      pg->peer_missing[*i].clear();
       continue;
     }
 
@@ -8025,7 +8032,7 @@ PG::RecoveryState::GetMissing::GetMissing(my_context ctx)
       // FIXME: we can do better here.  if last_update==last_complete we
       //        can infer the rest!
       ldout(pg->cct, 10) << " osd." << *i << " has no missing, identical log" << dendl;
-      pg->peer_missing[*i];
+      pg->peer_missing[*i].clear();
       continue;
     }