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


##########
be/src/runtime/runtime_query_statistics_mgr.cpp:
##########
@@ -347,7 +370,8 @@ void 
RuntimeQueryStatisticsMgr::report_runtime_query_statistics() {
         for (auto iter = _resource_contexts_map.begin(); iter != 
_resource_contexts_map.end();) {
             std::string query_id = iter->first;
             auto resource_ctx = iter->second;
-            bool is_query_finished = 
resource_ctx->task_controller()->is_finished();
+            TQueryStatisticsResult stats_result = 
create_query_statistics_result(resource_ctx);

Review Comment:
   [P2] Skip snapshot construction for excluded EXTERNAL tasks. This now calls 
create_query_statistics_result() for every retained context while holding the 
registry lock, but the following branch never reports active 
TQueryType::EXTERNAL contexts and discards the serialized result. Previously 
to_thrift_query_statistics() ran only inside the non-EXTERNAL branch. With many 
long-lived Spark/Flink tasks this adds a full counter snapshot every three 
seconds and stalls registrations for work that cannot be sent. Read only the 
finished flag for the EXTERNAL erase decision and build the Thrift result after 
that filter.



##########
fe/fe-core/src/main/java/org/apache/doris/resource/workloadschedpolicy/WorkloadRuntimeStatusMgr.java:
##########
@@ -252,34 +352,61 @@ public Map<String, TQueryStatistics> 
getQueryStatisticsMap() {
     }
 
     // Build a merged map by traversing concurrent runtime structures.
-    private Map<String, TQueryStatistics> buildQueryStatisticsMapUnsafe() {
-        // 1 merge query stats in all be
-        Set<Long> beIdSet = beToQueryStatsMap.keySet();
-        Map<String, TQueryStatistics> resultQueryMap = Maps.newHashMap();
-        for (Long beId : beIdSet) {
-            BeReportInfo beReportInfo = beToQueryStatsMap.get(beId);
+    private RuntimeStatisticsSnapshot buildRuntimeStatisticsSnapshot() {
+        RuntimeStatisticsSnapshot snapshot = new RuntimeStatisticsSnapshot();
+        for (Map.Entry<Long, BeReportInfo> beEntry : 
beToQueryStatsMap.entrySet()) {
+            long beId = beEntry.getKey();
+            BeReportInfo beReportInfo = beEntry.getValue();
             if (beReportInfo == null) {
                 continue;
             }
-            Set<String> queryIdSet = beReportInfo.queryStatsMap.keySet();
-            for (String queryId : queryIdSet) {
-                Pair<Long, TQueryStatisticsResult> queryStatsPair =
-                        beReportInfo.queryStatsMap.get(queryId);
+            long currentBackendStartTime = getBackendStartTime(beId);
+            if (currentBackendStartTime > 0
+                    && currentBackendStartTime != 
beReportInfo.backendStartTime) {
+                // Heartbeat can expose a restart before the new process sends 
its first runtime
+                // report. Drop the old shell now so its final flag cannot 
release a new audit.
+                beToQueryStatsMap.remove(beId, beReportInfo);

Review Comment:
   [P1] Preserve old-incarnation snapshots for audits already queued. If 
process A's final q1 report is stored and q1 is enqueued, then the BE restarts 
before the five-second drain, this branch drops A's shell before merging it. 
Process B cannot reproduce q1, so that audit waits for fallback and logs 
without the accepted counters. Associate pending participants with the process 
incarnation and retain per-incarnation data until those audits drain, while 
preventing A from satisfying new B queries; add final-report -> enqueue -> 
restart -> drain coverage.



##########
fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java:
##########
@@ -408,7 +409,14 @@ private static void logAuditLogImpl(ConnectContext ctx, 
String origStmt, Stateme
             auditEventBuilder.setState(String.valueOf(MysqlStateType.OK));
         }
         AuditEvent event = auditEventBuilder.build();
-        
Env.getCurrentEnv().getWorkloadRuntimeStatusMgr().submitFinishQueryToAudit(event);
+        Set<Long> expectedBackendIds = ImmutableSet.of();
+        if (!event.isQuery && ctx.getExecutor() != null && 
ctx.getExecutor().getCoord() != null) {
+            // Audit completion is query-scoped: keep the event pending until 
every backend that
+            // received a fragment publishes its final cumulative statistics 
snapshot.
+            expectedBackendIds = 
ctx.getExecutor().getCoord().getInvolvedBackendIds();
+        }
+        Env.getCurrentEnv().getWorkloadRuntimeStatusMgr()

Review Comment:
   [P1] Update the existing audit mock expectations. 
AuditLogHelperBackendSelectionTest and StmtExecutorInternalQueryTest both 
verify submitFinishQueryToAudit(AuditEvent), but this path now invokes only the 
two-argument overload; a Mockito mock records no matching one-argument call. 
Update both tests to capture the backend-ID argument and assert it is empty in 
their no-coordinator cases, then add direct coordinator coverage.



##########
fe/fe-core/src/main/java/org/apache/doris/resource/workloadschedpolicy/WorkloadRuntimeStatusMgr.java:
##########
@@ -185,54 +211,128 @@ public void 
updateBeQueryStats(TReportWorkloadRuntimeStatusParams params) {
             LOG.warn("be report workload runtime status but without query 
stats map");
             return;
         }
+        if (!params.isSetBackendStartTime()) {
+            LOG.warn("be report workload runtime status without backend start 
time");
+            return;
+        }
         long beId = params.backend_id;
-        // NOTE(wb) one be sends update request one by one,
-        // so there is no need a global lock for beToQueryStatsMap here,
-        // just keep one be's put/remove/get is atomic operation is enough
+        long backendStartTime = params.backend_start_time;
+        long currentBackendStartTime = getBackendStartTime(beId);
+        if (currentBackendStartTime > 0 && currentBackendStartTime != 
backendStartTime) {

Review Comment:
   [P1] Do not acknowledge a report rejected before heartbeat catch-up. In a 
forwarded DML, coordinator FE B can schedule a restarted BE after B sees its 
new heartbeat while audit FE A still has the previous start time. The BE 
reports to A via current_connect_fe; this branch drops the payload, but the 
statistics-only RPC returns OK and BE erases the finished ResourceContext 
without inspecting acceptance. Propagate an explicit acceptance/retry signal, 
make BE inspect it before erasing, and cover the two-FE heartbeat-ordering case.



##########
fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java:
##########
@@ -408,7 +409,14 @@ private static void logAuditLogImpl(ConnectContext ctx, 
String origStmt, Stateme
             auditEventBuilder.setState(String.valueOf(MysqlStateType.OK));
         }
         AuditEvent event = auditEventBuilder.build();
-        
Env.getCurrentEnv().getWorkloadRuntimeStatusMgr().submitFinishQueryToAudit(event);
+        Set<Long> expectedBackendIds = ImmutableSet.of();
+        if (!event.isQuery && ctx.getExecutor() != null && 
ctx.getExecutor().getCoord() != null) {

Review Comment:
   [P1] Capture participants outside StmtExecutor.coord. This condition leaves 
the expected set empty for at least two distributed DML paths: a follower that 
forwards to the master has only a MasterOpExecutor, and the proxy result 
returns no backend IDs; InsertIntoTVFCommand owns a local Coordinator without 
assigning executor.coord. Empty is treated as all-final after five seconds, so 
a delayed periodic report still misses these audits. Publish the immutable 
participant set from every coordinator owner, including through TMasterOpResult 
for forwarding, and cover both paths.



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