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


##########
core/server/src/dispatch/mod.rs:
##########
@@ -615,45 +457,34 @@ async fn handle_client_request<B, MJ, S, SB>(
     sessions.borrow_mut().record_heartbeat(transport_client_id);
 
     let header = *request.header();
-    if header.operation == Operation::NonReplicated {
-        // Auth bypass guard: `PING`, the liveness probe, is the only pre-auth
-        // code, on every roster shape. `GET_CLUSTER_METADATA` describes the
-        // private replica network and is not something an unauthenticated
-        // caller gets to read; a client that dialed a backup no longer needs
-        // it to find the leader, because the backup authenticates the login
-        // locally and forwards only the consensus proposal
-        // (`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.
-        let nr_code = 
u32::from_le_bytes(request.header().reserved[..4].try_into().unwrap());
-        // Legacy (pre-register) login codes. The server authenticates only via
-        // the Register handshake (LOGIN_REGISTER / LOGIN_REGISTER_WITH_PAT,
-        // Operation::Register); the vsr SDK funnels both logins there and 
never
-        // emits these. Reject them uniformly with a typed MalformedLogin (the
-        // SDK maps it to InvalidFormat) before the session gate, so a legacy 
or
-        // foreign client fails fast instead of getting the generic
-        // Unauthenticated deny the pre-auth guard would send unbound, or the
-        // silent empty-ok Reply the bound non-replicated path would send.
-        if matches!(
-            nr_code,
-            LOGIN_USER_CODE | LOGIN_WITH_PERSONAL_ACCESS_TOKEN_CODE
-        ) {
+    let bound = sessions.borrow().get_session(transport_client_id);

Review Comment:
   Both deferred items are in this PR after all, so the trade lands the other 
way: the funnel prologue now costs fewer lookups than before the refactor, not 
one more.
   
   `SessionManager::touch_connection` stamps the heartbeat and returns the 
bound session, the acting user and the peer address in ONE `connections` walk. 
That replaces `record_heartbeat`, `get_session`, the `Partition` arm's 
`get_user_id` and `reads.rs`'s `read_context`, and the `bus.client_meta` lookup 
now runs only on a transport's first frame, which is the only place the address 
has to come from the bus. `read_context` and the already-dead 
`connection_address` are gone.
   
   `header` is bound as a reference; only the `ReplicatedMetadata` arm takes 
the by-value copy, which it needs for the pre-`transmute_header` echo on a 
deny. `queues`, `active` and `SessionManager`'s two maps are on `ahash` now: 
ids are server-minted and neither map is order-sensitive.



##########
core/server/src/dispatch/mod.rs:
##########
@@ -299,8 +230,19 @@ fn enqueue_client_request<B, MJ, S, SB>(
         return;
     }
 
-    let bus = shard.bus.clone();
+    let shard_handle = Rc::clone(shard_handle);
+    let sessions = Rc::clone(sessions);
+    let system_config = Arc::clone(system_config);
+    let queues = Rc::clone(queues);
+    let active = Rc::clone(active);
     bus.spawn(async move {
+        // The handle is set once the shard is built. A frame that beats
+        // it stays queued and the client's next frame drains both, so the
+        // active slot must be released here or that next frame never spawns.
+        let Some(shard) = upgrade_shard_handle(&shard_handle) else {
+            active.borrow_mut().remove(&client_id);

Review Comment:
   The connection-lost hook now frees both `queues` and `active` for the 
client, which covers the stranded queue entry and the 
panic-leaves-the-slot-taken case in one place. `pop_next_client_request` keeps 
the map entry when the queue drains empty, so a lockstep client no longer pays 
a `HashMap` insert plus a `VecDeque` alloc/free per request, and the hook is 
what removes it. Both maps moved to `ahash`.
   
   The unbounded per-client `VecDeque` is deliberately NOT capped here. A cap 
needs an overflow policy, whether to shed the frame, deny typed, or evict the 
connection, plus an operator-facing knob to size it. Picking either silently 
inside a review round is worse than leaving the queue as it is. I can open a 
follow-up issue if you want it tracked.



##########
core/server/src/dispatch/session_ops.rs:
##########
@@ -552,35 +475,18 @@ async fn evict_stale_client<B, MJ, S, SB>(
     if let Some((vsr_client_id, session)) = bound {
         submit_disconnect_logout(Rc::clone(shard), vsr_client_id, session);
     }
-    let ctx = shard.plane.metadata().consensus.as_ref().map_or(
-        consensus::EvictionContext {
-            cluster: 0,
-            view: 0,
-            replica: 0,
-        },
-        consensus::EvictionContext::from_consensus,
-    );
-    let eviction = consensus::build_eviction_message(
-        ctx,
+    warn!(

Review Comment:
   Reworded rather than moved. `send_eviction` swallows the send result by 
design, since it is best-effort and logs its own failure, so there is no result 
left to branch on.
   
   The line now claims only what it observed: the session was dropped and the 
`Logout` submitted, and the notice is being sent. A delivery failure still 
comes from `send_host_frame`, and it now carries the reason through the channel 
label (see the `send_host_frame` thread).



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