]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osd: EC Optimizations proc_master_log boundary case bug fixes
authorBill Scales <bill_scales@uk.ibm.com>
Thu, 17 Jul 2025 18:17:27 +0000 (19:17 +0100)
committerJon <jonathan.bailey1@ibm.com>
Fri, 3 Oct 2025 13:31:25 +0000 (14:31 +0100)
Fix a couple of bugs in proc_master_log for optimized EC
pools dealing with boundary conditions such as an empty
log and merging two logs that diverge from the very first
entry.

Refactor the code to handle the boundary conditions and
neaten up the code.

Predicate the code block with if (pool.info.allows_ecoptimizations())
to make it clear this code path is only for optimized EC pools.

Signed-off-by: Bill Scales <bill_scales@uk.ibm.com>
(cherry picked from commit 1b44fd9991f5f46b969911440363563ddfad94ad)

src/osd/PeeringState.cc

index c74c7cdb09fa74f66ce62f4689e29dd6d405cec2..170d94703c964cec504b6fff3f3ba7551c2e5ed1 100644 (file)
@@ -3337,24 +3337,18 @@ void PeeringState::proc_master_log(
   bool invalidate_stats = false;
 
   // For partial writes we may be able to keep some of the divergent entries
-  if (olog.head < pg_log.get_head()) {
+  if (pool.info.allows_ecoptimizations() && (olog.head < pg_log.get_head())) {
     // Iterate backwards to divergence
     auto p = pg_log.get_log().log.end();
-    while (true) {
-      if (p == pg_log.get_log().log.begin()) {
-       break;
-      }
+    while (p != pg_log.get_log().log.begin()) {
       --p;
-      if (p->version.version <= olog.head.version) {
+      if (p->version <= olog.head) {
        break;
       }
     }
-    // See if we can wind forward partially written entries
-    map<pg_shard_t, pg_info_t> all_info(peer_info.begin(), peer_info.end());
-    all_info[pg_whoami] = info;
-    // Normal case is that both logs have entry olog.head
-    bool can_check_next_entry = (p->version == olog.head);
-    if ((p->version < olog.head) || (p == pg_log.get_log().log.begin())) {
+    if (p == pg_log.get_log().log.end()) {
+      // Empty log - probably due to a PG split - nothing to do
+    } else {
       // After a PG split there may be gaps in the log where entries were
       // split to the other PG. This can result in olog.head being ahead
       // of p->version. So long as there are no entries in olog between
@@ -3362,20 +3356,30 @@ void PeeringState::proc_master_log(
       // partially written entries
       auto op = olog.log.end();
       if (op == olog.log.begin()) {
-       can_check_next_entry = true;
-      } else if (op->version.version < p->version.version) {
-       can_check_next_entry = true;
+       // Other log is emtpy
+       if (p->version <= olog.head) {
+         consider_adjusting_pwlc(p->version);
+         ++p;
+       } else {
+         consider_adjusting_pwlc(pg_log.get_tail());
+       }
+      } else if (op->version == p->version) {
+       // Normal case - both logs have this entry
+       consider_adjusting_pwlc(p->version);
+       ++p;
+      } else if (op->version < p->version) {
+       // Last entry in other log is before this entry
+       consider_adjusting_pwlc(pg_log.get_tail());
+      } else {
+       // Other log is ahead of the primary log - give up
+       p = pg_log.get_log().log.end();
       }
     }
-    if (can_check_next_entry) {
-      consider_adjusting_pwlc(p->version);
-    }
+    // See if we can wind forward partially written entries
+    map<pg_shard_t, pg_info_t> all_info(peer_info.begin(), peer_info.end());
+    all_info[pg_whoami] = info;
     PGLog::LogEntryHandlerRef rollbacker{pl->get_log_handler(t)};
-    while (can_check_next_entry) {
-      ++p;
-      if (p == pg_log.get_log().log.end()) {
-       break;
-      }
+    while (p != pg_log.get_log().log.end()) {
       if (p->is_written_shard(from.shard)) {
         psdout(10) << "entry " << p->version << " has written shards "
                   << p->written_shards << " so is divergent" << dendl;
@@ -3415,15 +3419,16 @@ void PeeringState::proc_master_log(
       psdout(20) << "keeping entry " << p->version << dendl;
       invalidate_stats = true;
       eversion_t previous_version;
-       if (p == pg_log.get_log().log.begin()) {
-         previous_version = pg_log.get_tail();
-       } else {
-         previous_version = std::prev(p)->version;
-       }
-       rollbacker.get()->partial_write(&info, previous_version, *p);
-       olog.head = p->version;
+      if (p == pg_log.get_log().log.begin()) {
+       previous_version = pg_log.get_tail();
+      } else {
+       previous_version = std::prev(p)->version;
+      }
+      rollbacker.get()->partial_write(&info, previous_version, *p);
+      olog.head = p->version;
 
-      // We need to continue processing the log, so don't break.
+      // Process the next entry
+      ++p;
     }
   }
   // merge log into our own log to build master log.  no need to