hubcio commented on code in PR #4506:
URL: https://github.com/apache/iggy/pull/4506#discussion_r4270143419


##########
core/simulator/src/workload/oracle.rs:
##########
@@ -449,14 +500,15 @@ pub fn assert_converged(sim: &Simulator, workload: &mut 
Workload) -> Convergence
         "committed metadata prefixes agree across every live replica"
     );
 
-    let Some(leader) = metadata_leader(sim, &live) else {
+    let Some(leader) = sim.metadata_leader().map(usize::from) else {
         panic!("no metadata leader live at quiesce (seed={seed:#x})");
     };
 
     // Settlement treats "no live replica hosts this group" as settled, so 
losing
     // every instance of a LIVE partition reads as converged. The metadata read
     // separates that from a group whose stream the workload deleted.
     let namespaces_checked = assert_live_namespaces_have_a_primary(sim, 
workload, leader, seed);

Review Comment:
   Deferred to PR6 as recovery release blockers. B5 now retains the 
RebuildPipeline floor fix (`max(commit_min, merged.commit_max) + 1`), 
quorum-loss creation/delete wedge (#4476 family, including seed 24), and the 
baseline metadata fork campaigns. Closure requires separate baseline/candidate 
reproductions with full settings and acknowledged-history/recovery proof. The 
passing PR4 seed 7016 does not close these findings; the baseline attribution 
remains your evidence, not a campaign I reran.



##########
core/simulator/src/workload/oracle.rs:
##########
@@ -449,14 +500,15 @@ pub fn assert_converged(sim: &Simulator, workload: &mut 
Workload) -> Convergence
         "committed metadata prefixes agree across every live replica"
     );
 
-    let Some(leader) = metadata_leader(sim, &live) else {
+    let Some(leader) = sim.metadata_leader().map(usize::from) else {
         panic!("no metadata leader live at quiesce (seed={seed:#x})");
     };
 
     // Settlement treats "no live replica hosts this group" as settled, so 
losing
     // every instance of a LIVE partition reads as converged. The metadata read
     // separates that from a group whose stream the workload deleted.
     let namespaces_checked = assert_live_namespaces_have_a_primary(sim, 
workload, leader, seed);
+    assert_hosted_incarnations_named(sim, workload, &live, seed);
 
     // Safety direction: no live replica may have COMMITTED more of a group 
than

Review Comment:
   Deferred to PR6. The plan and consolidated simulator acceptance now require 
per-namespace applied-data/readback digests through apply, rebuild and transfer 
installation, plus a negative control where prepare identities agree but 
applied bytes differ. Simulator partition transfer must be implemented or its 
unsupported-directory runs explicitly classified, including seed 1078 with its 
full campaign settings. Such a classified run does not count as passing 
recovery evidence. The PR description limits PR4's convergence claim to prepare 
identities and offset tables.



##########
core/message_bus/src/transports/quic.rs:
##########
@@ -326,12 +316,205 @@ fn reply_route(frame: &BusMessage) -> ReplyRoute {
     if !is_reply {
         return ReplyRoute::Unkeyed;
     }
+    read_u64(bytes, offset_of!(ReplyHeader, 
request)).map_or(ReplyRoute::Unkeyed, ReplyRoute::Keyed)
+}
+
+/// The request id of a client frame, read as raw bytes like [`reply_route`],
+/// so a frame with an undeclared operation still has one.
+fn request_id(request: &Message<GenericHeader>) -> Option<u64> {
+    read_u64(request.as_slice(), offset_of!(RequestHeader, request))
+}
+
+fn read_u64(bytes: &[u8], offset: usize) -> Option<u64> {
     bytes
-        .get(..HEADER_SIZE)
-        .and_then(|header| 
bytemuck::checked::try_from_bytes::<ReplyHeader>(header).ok())
-        .map_or(ReplyRoute::Unkeyed, |header| {
-            ReplyRoute::Keyed(header.request)
-        })
+        .get(offset..offset + size_of::<u64>())
+        .and_then(|field| field.try_into().ok())
+        .map(u64::from_le_bytes)
+}
+
+/// Hands the outbound frames of one connection to the streams that wait
+/// for them.
+///
+/// A stream registers its waiter before it forwards its request, so a reply
+/// never comes before the stream it answers.
+struct ReplyRouter {
+    /// Waiting streams by request id, oldest first.
+    waiters: HashMap<u64, VecDeque<oneshot::Sender<BusMessage>>>,
+    /// Frames that came while no stream waited for them, oldest first.
+    unclaimed: VecDeque<BusMessage>,
+    /// When `unclaimed` holds this many frames, it drops its oldest one.
+    unclaimed_max: usize,
+}
+
+impl ReplyRouter {
+    fn new(unclaimed_max: usize) -> Self {
+        Self {
+            waiters: HashMap::new(),
+            unclaimed: VecDeque::new(),
+            unclaimed_max,
+        }
+    }
+
+    /// Register a stream that waits for the reply to `request_id`.
+    ///
+    /// The stream first takes the oldest unclaimed frame that has no request
+    /// id or has its own. The SDK replays an explicit transient with the same
+    /// request id on a new stream, so a late reply of the first attempt
+    /// answers the replay. The replies for other ids ahead of that frame are
+    /// dropped, because their streams already ended.
+    fn register(&mut self, request_id: u64) -> oneshot::Receiver<BusMessage> {
+        let (waiter, reply) = oneshot::channel();
+        while let Some(frame) = self.unclaimed.pop_front() {
+            if !matches!(reply_route(&frame), ReplyRoute::Keyed(id) if id != 
request_id) {

Review Comment:
   Deferred to PR6 with the QUIC reply-tracking work. An unclaimed Eviction 
that predates a new stream must not be assigned to that stream. Acceptance 
requires late-event isolation together with session-terminal Eviction behavior, 
bounded tracking, late acknowledgements and draining within close_grace. The B7 
and PR6 plan entries retain these conditions; PR4 does not change Eviction into 
a nonterminal event.



##########
core/server/src/dispatch/mod.rs:
##########
@@ -557,25 +814,51 @@ async fn handle_client_request<B, MJ, S, SB>(
             // (`submit_register_local_or_forward`). Every other non-replicated
             // code MUST go through Register first, which binds the acting user
             // the per-op authz gates resolve.
-            handle_non_replicated_request(
-                shard,
-                sessions,
-                server_config,
-                transport_client_id,
-                request,
-                ConnectionContext {
-                    bound,
-                    user_id,
-                    address: client_address,
-                    metadata_watermark,
-                },
-            )
-            .await;
+            let context = ConnectionContext {
+                bound,
+                user_id,
+                address: client_address,
+                metadata_watermark,
+            };
+            // `ClientDrain` says which frames stay on the drain.
+            if matches!(non_replicated_code(header), PING_CODE | 
BIND_SESSION_CODE) {
+                handle_non_replicated_request(
+                    shard,
+                    sessions,
+                    server_config,
+                    transport_client_id,
+                    request,
+                    context,
+                )
+                .await;
+                return;
+            }
+            let in_flight = match progress {
+                Some(progress) => progress,
+                None => drain.admit(Admission::Cap).await,
+            };
+            let task_shard = Rc::clone(shard);
+            let task_sessions = Rc::clone(sessions);
+            let task_config = Arc::clone(server_config);
+            shard.bus.spawn(async move {

Review Comment:
   Deferred to PR6. The recorded proposal is to poll inline, select against 
frame arrival, then promote the same pending future, InFlight permit and 
progress-lane guard when another frame arrives. The existing PING negative 
control rejects blanket inline serialization; it does not disprove this 
proposal. B7 requires lockstep and pipelined benchmarks plus preserved 
cancellation, bounded admission, unknown outcomes and Next/auto-commit 
ordering. The reported performance figures remain attributed measurements, not 
results I reproduced.



##########
core/server/src/dispatch/partition.rs:
##########
@@ -377,6 +381,74 @@ async fn relay_partition_reply<B, MJ, S, SB>(
     });
 }
 
+/// The offset key shared by stored-offset reads and progress writes on a 
connection.
+/// Failed resolution is left to the normal handler's authorization and error 
path.
+pub(super) fn progress_key<B, MJ, S, SB>(
+    shard: &Rc<ShellShard<B, MJ, S, SB>>,
+    message: &Message<GenericHeader>,
+) -> Option<ConsumerProgress>
+where
+    B: ShellBus,
+    MJ: JournalHandle + 'static,
+    MJ::Target: Journal<Entry = Message<PrepareHeader>, Header = 
PrepareHeader>,
+    S: 'static,
+    SB: SuperblockStore + 'static,
+{
+    let request = message.try_as_typed::<RequestHeader>().ok()?;
+    let wire = match request.header().operation {
+        Operation::NonReplicated
+            if request.header().reserved[..4] == 
GET_CONSUMER_OFFSET_CODE.to_le_bytes() =>
+        {
+            GetConsumerOffsetRequest::decode_from(request.body()).ok()?
+        }
+        Operation::NonReplicated
+            if request.header().reserved[..4] == 
POLL_MESSAGES_CODE.to_le_bytes()
+                || request.header().reserved[..4]
+                    == POLL_MESSAGES_ON_PRIMARY_CODE.to_le_bytes() =>
+        {
+            let poll = PollMessagesRequest::decode_from(request.body()).ok()?;

Review Comment:
   Deferred to PR6. B7 now explicitly requires removing the duplicate full 
PollMessages decode/allocation for non-Next, non-auto-commit polls, using the 
flag/strategy fields or passing the decoded request onward. Closure requires 
allocation/throughput measurements and unchanged Next/auto-commit progress 
ordering.



-- 
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