From b9439b59b42f1d32573da461a557ad41a37ce799 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 3 Aug 2017 20:45:26 -0400 Subject: [PATCH] osd/PG: fix lost unfound + delete when there are no missing objects 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 --- src/osd/PG.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/osd/PG.cc b/src/osd/PG.cc index 56866b6e383..440cd2e6f87 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -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; } -- 2.39.5