Skip to content

Commit 8c7ed7b

Browse files
committed
[BugFix] Record audit stats for async materialized view refresh
1 parent c7e3815 commit 8c7ed7b

3 files changed

Lines changed: 53 additions & 1 deletion

File tree

fe/fe-core/src/main/java/com/starrocks/qe/StmtExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ public void execute() throws Exception {
13561356
* some statements may execute multiple statement which will also create multiple StmtExecutor, so here
13571357
* we accumulate them into the ConnectContext instead of using the last one
13581358
*/
1359-
private void recordExecStatsIntoContext() {
1359+
public void recordExecStatsIntoContext() {
13601360
PQueryStatistics execStats = getQueryStatisticsForAuditLog();
13611361
context.getAuditEventBuilder().addCpuCostNs(execStats.getCpuCostNs() != null ? execStats.getCpuCostNs() : 0);
13621362
context.getAuditEventBuilder()

fe/fe-core/src/main/java/com/starrocks/scheduler/MVTaskRunProcessor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ public void executePlan(ExecPlan execPlan, InsertStmt insertStmt) throws Excepti
371371
throw e;
372372
} finally {
373373
logger.info("[QueryId:{}] finished to refresh mv in DML", ctx.getQueryId());
374+
// the MV refresh uses its own fresh ConnectContext whose audit builder starts at the default value.
375+
executor.recordExecStatsIntoContext();
374376
auditAfterExec(mvTaskRunContext, executor.getParsedStmt(), executor.getQueryStatisticsForAuditLog());
375377
executor.addFinishedQueryDetail();
376378
}

fe/fe-core/src/test/java/com/starrocks/scheduler/MVTaskRunProcessorTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.starrocks.catalog.MaterializedView;
1919
import com.starrocks.common.util.RuntimeProfile;
2020
import com.starrocks.common.util.UUIDUtil;
21+
import com.starrocks.plugin.AuditEvent;
2122
import com.starrocks.qe.ConnectContext;
2223
import com.starrocks.scheduler.mv.pct.MVPCTRefreshProcessor;
2324
import com.starrocks.scheduler.persist.MVTaskRunExtraMessage;
@@ -153,6 +154,55 @@ public void testPlanBuilderMessageTracing() throws Exception {
153154
starRocksAssert.dropMaterializedView("test_mv_plan_builder");
154155
}
155156

157+
/**
158+
* Regression test: async MV refresh runs the INSERT OVERWRITE through
159+
* StmtExecutor.handleDMLStmtWithProfile() directly and bypasses StmtExecutor.execute(), where
160+
* recordExecStatsIntoContext() is invoked. Before the fix the execution statistics were never
161+
* flushed into the audit event builder, so the audit log lost CpuCostNs/MemCostBytes/ScanRows
162+
* for every MV refresh (regression of #56257). This verifies they are recorded again.
163+
*/
164+
@Test
165+
public void testMVRefreshRecordsAuditStats() throws Exception {
166+
// Insert data so the refresh issues a real INSERT OVERWRITE that produces exec statistics.
167+
executeInsertSql(connectContext, "insert into test.tbl1 partition(p1) values('2022-01-02', 1, 10)");
168+
169+
starRocksAssert.useDatabase("test")
170+
.withMaterializedView("CREATE MATERIALIZED VIEW `test_mv_audit_stats` " +
171+
"REFRESH DEFERRED MANUAL\n" +
172+
"PROPERTIES (\n" +
173+
"\"replication_num\" = \"1\"" +
174+
")\n" +
175+
"AS SELECT k1, k2, v1 FROM test.tbl1;");
176+
177+
Database testDb = GlobalStateMgr.getCurrentState().getLocalMetastore().getDb("test");
178+
MaterializedView mv = ((MaterializedView) GlobalStateMgr.getCurrentState().getLocalMetastore()
179+
.getTable(testDb.getFullName(), "test_mv_audit_stats"));
180+
Assertions.assertNotNull(mv);
181+
182+
Task task = TaskBuilder.buildMvTask(mv, testDb.getFullName());
183+
task.getProperties().put(TaskRun.IS_TEST, "true");
184+
185+
TaskRun taskRun = TaskRunBuilder.newBuilder(task).build();
186+
taskRun.initStatus(UUIDUtil.genUUID().toString(), System.currentTimeMillis());
187+
taskRun.executeTaskRun();
188+
189+
// The refresh uses its own ConnectContext; read the audit event built on that context.
190+
ConnectContext runCtx = taskRun.getRunCtx();
191+
Assertions.assertNotNull(runCtx, "MV refresh ConnectContext should be available");
192+
AuditEvent auditEvent = runCtx.getAuditEventBuilder().build();
193+
194+
// Default value is -1 (dropped from the audit line by AuditLogBuilder). A non-default value
195+
// proves the stats were flushed into the builder on the MV refresh path.
196+
Assertions.assertNotEquals(-1L, auditEvent.cpuCostNs,
197+
"MV refresh audit log should record CpuCostNs");
198+
Assertions.assertNotEquals(-1L, auditEvent.memCostBytes,
199+
"MV refresh audit log should record MemCostBytes");
200+
Assertions.assertNotEquals(-1L, auditEvent.scanRows,
201+
"MV refresh audit log should record ScanRows");
202+
203+
starRocksAssert.dropMaterializedView("test_mv_audit_stats");
204+
}
205+
156206
/**
157207
* Test that MVPCTBasedRefreshProcessor correctly updates task run status definition.
158208
*/

0 commit comments

Comments
 (0)