This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch fix/server-ng-purge-partition-plane
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit 36a0012625eafac718db0ac788ee8a4d1bf72dd4
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Tue Jul 28 09:42:56 2026 +0200

    fix(server-ng): wake reconciler on purge and truncate commits
    
    Purge and truncate commit without changing the partition set, so
    they never fired a MetadataCommitTick. Their on-disk effect is
    enforced only by reconcile_partition_purges and
    reconcile_segment_truncations, which run when a pass runs, so the
    effect was deferred to the periodic safety tick, stretching a
    purge's client-visible tail to a full reconcile_periodic_interval.
    
    DeleteSegments stays out by design: the leader rewrites it into
    TruncatePartition before journaling, so no commit carries it.
---
 core/server-ng/src/bootstrap.rs | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/core/server-ng/src/bootstrap.rs b/core/server-ng/src/bootstrap.rs
index 9fe565c89..677e30eca 100644
--- a/core/server-ng/src/bootstrap.rs
+++ b/core/server-ng/src/bootstrap.rs
@@ -3116,6 +3116,15 @@ fn make_metadata_commit_notifier(
 /// before journaling, so a committed prepare only ever carries the
 /// assignment-bearing variant. Kept as defense-in-depth against a future
 /// commit path that emits a bare op.
+///
+/// "Partition-shape" is not only the partition SET: the purge and truncate
+/// ops leave the set intact but advance per-partition state (purge
+/// generation, delete watermark) that only the reconciler enforces on disk.
+/// Omitting them defers the on-disk effect to the periodic safety tick,
+/// stretching a purge's client-visible tail to a full
+/// `reconcile_periodic_interval`. `DeleteSegments` is absent by design: the
+/// leader rewrites it into `TruncatePartition` before journaling, so no
+/// commit ever carries it.
 const fn operation_triggers_partition_reconcile(op: Operation) -> bool {
     matches!(
         op,
@@ -3126,6 +3135,9 @@ const fn operation_triggers_partition_reconcile(op: 
Operation) -> bool {
             | Operation::DeleteTopic
             | Operation::DeleteStream
             | Operation::DeletePartitions
+            | Operation::PurgeStream
+            | Operation::PurgeTopic
+            | Operation::TruncatePartition
     )
 }
 
@@ -3151,6 +3163,29 @@ mod tests {
         );
     }
 
+    #[test]
+    fn reconciler_driven_ops_broadcast_a_commit_tick() {
+        // These commit without touching the partition set, so nothing else
+        // signals the reconciler: `reconcile_partition_purges` and
+        // `reconcile_segment_truncations` are the only code that turns them
+        // into on-disk effect, and they run only when a pass runs. Dropping
+        // one from the filter silently downgrades it to the periodic tick.
+        for op in [
+            Operation::PurgeStream,
+            Operation::PurgeTopic,
+            Operation::TruncatePartition,
+        ] {
+            assert!(
+                operation_triggers_partition_reconcile(op),
+                "{op:?} is enforced by the reconciler and must wake it on 
commit"
+            );
+        }
+        assert!(
+            !operation_triggers_partition_reconcile(Operation::CreateUser),
+            "ops with no partition-shape effect must stay off the broadcast"
+        );
+    }
+
     #[test]
     fn shutdown_on_drop_armed_flips_flag() {
         let flag = Arc::new(AtomicBool::new(false));

Reply via email to