github-actions[bot] commented on code in PR #4429:
URL: https://github.com/apache/iggy/pull/4429#discussion_r4272746070


##########
core/shard/src/lib.rs:
##########
@@ -1489,10 +1489,10 @@ where
     /// metadata group per node (precedent: 
[`Self::metadata_transfer_attempts`]).
     metadata_gap_ticks: Cell<u32>,
 
-    /// Op the tick's commit walk last stopped on without moving, or `0`. The
-    /// journal names it but cannot produce its body, so the gap probe counts 
it
-    /// as absent and lets repair fetch it. Cleared implicitly: any advance of
-    /// `commit_min` makes it stop matching `commit_min + 1`.
+    /// Op last truncated after a `BodyMissing` walk stop, or `0`. The gap 
probe

Review Comment:
   nit: The field doc says this op was truncated, but the code records it 
before the `truncate_from` attempt and keeps it after a failure. Say instead 
that the record names the op the drop targeted.



##########
core/shard/src/lib.rs:
##########
@@ -10571,13 +10572,20 @@ where
                     commit_max = probe.commit_max,
                     "metadata commit walk parked over resident committed ops; 
resuming"
                 );
-                metadata.commit_journal().await;
-                // Promotion above can give the pipeline ownership after the
-                // stranded-commit driver ran. Verify an absent body before
-                // removing any header from a walk that made no progress.
-                let walked = consensus.commit_min();
-                if walked == probe.commit_min {
-                    let stuck_op = walked.saturating_add(1);
+                // Truncate on `BodyMissing` alone. A walk that moved nothing 
is
+                // not proof: `PipelineHead` moves nothing either, and dropping

Review Comment:
   nit: `drop_unwalkable_metadata_entry` already returns early when any 
pipeline head is resident, so a `PipelineHead` stop never reaches 
`truncate_from`. State what this change adds instead, for example the explicit 
stop reason or the same-tick truncation after a partial walk. Also at 
`core/simulator/src/lib.rs:11161`.



##########
core/simulator/src/lib.rs:
##########
@@ -11150,3 +11150,117 @@ mod probe_answer_divergence_tests {
         );
     }
 }
+
+#[cfg(test)]
+mod metadata_walk_stuck_detector_tests {
+    //! The metadata walk-stall detector in `tick_metadata` must not mistake 
the
+    //! pipeline head for a header without a body.
+    //!
+    //! `commit_journal` stops, without moving `commit_min`, at the op the
+    //! pipeline holds, because committing it is `on_ack`'s job. A detector 
that
+    //! read "the walk moved nothing" as "the body is unreadable" would 
truncate
+    //! the WAL from that op, leaving the primary's pipeline with a committed
+    //! header whose prepare is gone, and the next commit driver would panic
+    //! with `committed prepare ... must be in journal`.
+
+    use consensus::Consensus;
+
+    use super::*;
+
+    /// Swarm seed whose network elects replica 1 primary of view 1 with a
+    /// committed pipeline head it has not yet walked.
+    const SEED: u64 = 1716;
+    const REPLICAS: u8 = 3;
+    const CLIENTS: [u128; 3] = [1, 2, 3];
+
+    const VIEW_0_PRIMARY: u8 = 0;
+    /// The replica the faults leave to win view 1.
+    const PRIMARY_ELECT: usize = 1;
+
+    /// Replica faults as `(step, replica, crash)`. The view-0 primary goes
+    /// down, which puts the view-1 change on the primary-elect, and comes back
+    /// before the primary-elect holds the inherited head (step ~722).
+    const FAULTS: [(usize, u8, bool); 2] =
+        [(91, VIEW_0_PRIMARY, true), (631, VIEW_0_PRIMARY, false)];
+
+    /// Past the inherited-head window, then the drain heals the cluster.
+    const FAULT_STEPS: usize = 800;
+    const DRAIN_STEPS: usize = 4_000;
+
+    /// Only the three `Register`s go through the metadata plane: no client
+    /// traffic, no metadata workload. Op 3 is the last of them.
+    const REGISTERED_OPS: u64 = 3;
+
+    #[test]
+    fn 
given_primary_elect_inheriting_a_committed_head_when_the_tick_probes_the_walk_should_keep_its_prepare()
+     {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
+            enabled: false,
+            size: iggy_common::IggyByteSize::from(0u64),
+            bucket_capacity: 1,
+        });
+        let mut network = packet::PacketSimulatorOptions::swarm(SEED);
+        network.node_count = REPLICAS;
+        network.client_count = u8::try_from(CLIENTS.len()).expect("few 
clients");
+        let mut sim = Simulator::new(usize::from(REPLICAS), 
CLIENTS.iter().copied(), network);
+        sim.init_partition(IggyNamespace::new(1, 1, 0));
+        for id in CLIENTS {
+            sim.register_client_with_primary(&SimClient::new(id));
+        }
+
+        let mut inherited_head_seen = false;
+        for step in 0..FAULT_STEPS {
+            for &(at, replica, crash) in &FAULTS {
+                if at == step {
+                    if crash {
+                        sim.replica_crash(replica);
+                    } else {
+                        sim.replica_restart(replica);
+                    }
+                }
+            }
+            sim.step();
+            inherited_head_seen |= primary_elect_holds_inherited_head(&sim);
+        }
+        // Without this a drifted seed that never builds the shape passes the
+        // drain assertion below without testing anything.
+        assert!(
+            inherited_head_seen,
+            "replica {PRIMARY_ELECT} never led view 1 with a committed 
pipeline head at \
+             commit_min + 1; the seed no longer reaches the shape under test"
+        );
+        for _ in 0..DRAIN_STEPS {
+            sim.step();
+        }
+
+        // Every replica applies every registration: a dropped pipeline prepare
+        // must neither panic the primary nor leave any replica short of it.
+        for replica in 0..usize::from(REPLICAS) {
+            let consensus = sim
+                .metadata_consensus(replica)
+                .expect("shard 0 hosts the metadata plane");
+            assert!(
+                consensus.commit_min() >= REGISTERED_OPS,
+                "replica {replica} applied metadata only through op {}, short 
of the \
+                 {REGISTERED_OPS} registrations",
+                consensus.commit_min()
+            );
+        }
+    }
+
+    /// Whether the primary-elect is a normal view-2 primary whose pipeline 
head

Review Comment:
   nit: The helper doc says the check looks for a view-2 primary, but the code 
accepts any `view() >= 1`. Change the doc to match the code, `view() >= 1`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to