]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osd/PG: align past_intervals and last_epoch_clean for fabricated merge target
authorSage Weil <sage@redhat.com>
Thu, 20 Dec 2018 14:59:55 +0000 (08:59 -0600)
committerSage Weil <sage@redhat.com>
Thu, 20 Dec 2018 14:59:55 +0000 (08:59 -0600)
When we are fabricating a merge target, we have to construct a
meaningful pg_history_t and PastIntervals.  We do this with
pieces of the source PG and the last_epoch_clean and
last_epoch_started values from the pg_pool_t.  This usually
works, except when

 - source and target become clean, and we decrement pg_num
 - OSD mapping changes (for source and target)
 - source repeers, but target does not
 - OSD with source only tries to merge

In this case, the source will have a past_intervals start that is
later than the last_epoch_clean implied in the pg_pool_t.

This situation is harmless because we do not allow the actual
mappings of source and target to diverge during the merge window,
so if the source's past intervals was adjusted we can still use
it.  Avoid logging errors by adjusting the start epoch backwards.

Fixes: http://tracker.ceph.com/issues/37511
Signed-off-by: Sage Weil <sage@redhat.com>
src/osd/PG.cc
src/osd/osd_types.cc
src/osd/osd_types.h

index 49345cc2a61ccdc7e73beb93c3b8285475614fef..f42a8d04f1d6c6ad474312c94c5c7fb989b269e2 100644 (file)
@@ -2765,6 +2765,17 @@ void PG::merge_from(map<spg_t,PGRef>& sources, RecoveryCtx *rctx,
     // remapped in concert with each other...
     info.history = sources.begin()->second->info.history;
 
+    // if the past_intervals start is later than last_epoch_clean, it implies
+    // the source repeered again but the target didn't.  avoid the discrepancy
+    // but adjusting the interval start backwards to match.
+    auto pib = past_intervals.get_bounds();
+    if (info.history.last_epoch_clean < pib.first) {
+      dout(10) << __func__ << " last_epoch_clean "
+              << info.history.last_epoch_clean << " < past_interval start "
+              << pib.first << ", adjusting start backwards" << dendl;
+      past_intervals.adjust_start_backwards(info.history.last_epoch_clean);
+    }
+
     // we use the pg_num_dec_last_epoch_clean we got from the caller, which is
     // the epoch that was clean according to the target pg whe it requested
     // the mon decrement pg_num.
index 2b5485368008eca1a616b3ab405834d3e216126b..065fb5459e923d31a5c67d029639b0741a7b43a1 100644 (file)
@@ -3403,6 +3403,10 @@ public:
   pair<epoch_t, epoch_t> get_bounds() const override {
     return make_pair(first, last + 1);
   }
+  void adjust_start_backwards(epoch_t last_epoch_clean) {
+    first = last_epoch_clean;
+  }
+
   set<pg_shard_t> get_all_participants(
     bool ec_pool) const override {
     return all_participants;
index 3336db4e926baae4047272b77d7ae2745226c518..9ad9353aa1c9a94a6b6377891c0c223adb6583a7 100644 (file)
@@ -2935,6 +2935,7 @@ public:
       ceph_assert(!has_full_intervals());
       ceph_abort_msg("not valid for this implementation");
     }
+    virtual void adjust_start_backwards(epoch_t last_epoch_clean) = 0;
 
     virtual ~interval_rep() {}
   };
@@ -3101,6 +3102,11 @@ public:
     return past_intervals->get_bounds();
   }
 
+  void adjust_start_backwards(epoch_t last_epoch_clean) {
+    ceph_assert(past_intervals);
+    past_intervals->adjust_start_backwards(last_epoch_clean);
+  }
+
   enum osd_state_t {
     UP,
     DOWN,