github-actions[bot] commented on code in PR #69631:
URL: https://github.com/apache/doris/pull/69631#discussion_r4376412528


##########
fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlChannel.java:
##########
@@ -156,6 +156,12 @@ public void invalidate(String handle) {
         resultCache.invalidate(handle);
     }
 
+    public boolean hasPendingResults() {
+        // Expired local tickets no longer need to hold up shutdown.
+        resultCache.cleanUp();

Review Comment:
   [P2] Pin Flight results before expiring them during shutdown
   
   This new shutdown-thread cleanup can close a result already borrowed by an 
admitted `DoGet`. For a ticket fetched just before its 10-minute expiry, 
`getStreamStatementResult()` can obtain the cached `VectorSchemaRoot`, then 
this poll expires the entry and its removal listener closes the root before 
`listener.start()/putNext()` finishes reading it. The active-request count 
keeps shutdown waiting but does not protect those buffers, so a previously 
valid retrieval can fail during serialization. In [Arrow 19, the listener keeps 
the root and unloads its buffers 
later](https://github.com/apache/arrow-java/blob/v19.0.0/flight/flight-core/src/main/java/org/apache/arrow/flight/OutboundStreamListenerImpl.java#L49-L95).
 Pin/reference-count in-use entries or serialize removal against borrowing and 
batch unloading; the drain poll must not free an active reader's vectors.



##########
be/src/runtime/exec_env.cpp:
##########
@@ -170,20 +174,44 @@ std::map<TNetworkAddress, FrontendInfo> 
ExecEnv::get_running_frontends() {
     return res;
 }
 
+void ExecEnv::wait_for_shutdown_heartbeat() {
+    int32_t elapsed = 0;
+    while (!k_shutdown_heartbeat_sent && elapsed < 
config::grace_shutdown_heartbeat_wait_seconds) {
+        sleep(1);
+        ++elapsed;
+    }
+    LOG(INFO) << "shutdown heartbeat prepared: " << 
k_shutdown_heartbeat_sent.load() << ", waited "
+              << elapsed << " seconds";
+    // The response may still be in transit. This buffer also gives followers 
time
+    // to replay shutdown state. It does not prove that every FE has applied 
it.
+    sleep(std::max(0, config::grace_shutdown_heartbeat_propagation_seconds));
+}
+
 void ExecEnv::wait_for_all_tasks_done() {
-    // For graceful shutdown, need to wait for all running queries to stop
+    // Both receiver implementations and the load coordinator must finish. For 
example,
+    // an HTTP upload or transaction commit can outlive all of its pipeline 
fragments.
     int32_t wait_seconds_passed = 0;
     while (true) {
         int num_queries = _fragment_mgr->running_query_num();
-        if (num_queries < 1) {
+        size_t num_channels = _load_channel_mgr->num_active_channels();

Review Comment:
   [P2] Reserve queued opens for the legacy receiver too
   
   The new census can still report zero with an accepted `tablet_writer_open` 
waiting in `_heavy_work_pool`: that RPC has no `PendingOpen` reservation, and 
`LoadChannelMgr::open()` inserts its channel only after the worker starts. A 
remote load receiver can have neither a local fragment nor a 
`StreamLoadContext` (the `LoadChannel` constructor explicitly supports that 
case). If the worker starts after this census, the load runs only during the 
fixed post-delay and can be killed while `grace_shutdown_wait_seconds` remains 
unused. The new reservation in `open_load_stream` covers the other receiver 
implementation only. Reserve legacy opens before queuing, releasing the 
reservation on rejection/failure or after registered-channel ownership takes 
over.



##########
fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java:
##########
@@ -445,14 +445,26 @@ public void processOnce() throws IOException {
             return;
         }
 
-        // dispatch
-        dispatch();
-        // finalize
-        finalizeCommand();
-
-        ctx.setCommand(MysqlCommand.COM_SLEEP);
-        ctx.clear();
-        executor = null;
+        if (!ctx.startMysqlCommand()) {
+            return;
+        }
+        // Account for planning and FE-local statements too: they may have no 
Coordinator.
+        // Refuse new packets by closing the socket so a connection pool can 
reconnect.
+        if (!QueryAdmissionController.INSTANCE.tryAcquire()) {
+            ctx.setKilled();
+            ctx.finishMysqlCommand();
+            channel.close();

Review Comment:
   [P2] Keep connection teardown in the drain count
   
   If an existing transaction receives a packet just after admission closes, 
this branch sets the session killed and closes its channel without a 
request/continuation reservation. The close listener runs 
`unregisterConnection() -> closeTxn()` and can still be waiting for rollback. 
Meanwhile `closeIdleMysqlConnection()` skips killed sessions, so the idle scan 
can finish and `waitForGracefulShutdown()` can see zero work and stop FE 
services before the rollback finishes, even with budget remaining. Admitted 
`COM_QUIT` has the same gap because its count is released before `ReadListener` 
calls cleanup. Track the complete close/rollback/temporary-table cleanup 
lifetime, including refused packets, before publishing it as drained.



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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to