From d2d6ea14ab34042c3d2a0b35ac18bfa8662085e6 Mon Sep 17 00:00:00 2001 From: zhaochangle Date: Fri, 13 Feb 2026 21:29:20 +0800 Subject: [PATCH] [fix](txn) Set transaction status to COMMITTED only after commit info is fully populated Move setTransactionStatus(COMMITTED) to after idToTableCommitInfos population in both commitTransaction methods. This prevents PublishVersionDaemon from seeing COMMITTED status with empty commit info, as it checks status without synchronized(transactionState) lock. --- .../doris/transaction/DatabaseTransactionMgr.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java index eb905f3eda155c..b0a17790170791 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java @@ -1589,7 +1589,6 @@ protected void unprotectedCommitTransaction(TransactionState transactionState, S if (MetricRepo.isInit) { MetricRepo.HISTO_TXN_EXEC_LATENCY.update(commitTime - transactionState.getPrepareTime()); } - transactionState.setTransactionStatus(TransactionStatus.COMMITTED); transactionState.setErrorReplicas(errorReplicaIds); for (long tableId : tableToPartition.keySet()) { OlapTable table = (OlapTable) db.getTableNullable(tableId); @@ -1601,6 +1600,10 @@ protected void unprotectedCommitTransaction(TransactionState transactionState, S } transactionState.putIdToTableCommitInfo(tableId, tableCommitInfo); } + // set COMMITTED only after idToTableCommitInfos is fully populated, so that + // PublishVersionDaemon (which checks status without synchronized(transactionState)) + // will never see COMMITTED with empty commit info. + transactionState.setTransactionStatus(TransactionStatus.COMMITTED); // Update in-memory state only; caller handles edit log persistence unprotectUpdateInMemoryState(transactionState, false); transactionState.setInvolvedBackends(totalInvolvedBackends); @@ -1619,7 +1622,6 @@ protected void unprotectedCommitTransaction(TransactionState transactionState, S if (MetricRepo.isInit) { MetricRepo.HISTO_TXN_EXEC_LATENCY.update(commitTime - transactionState.getPrepareTime()); } - transactionState.setTransactionStatus(TransactionStatus.COMMITTED); transactionState.setErrorReplicas(errorReplicaIds); Map> tableToSubTransactionState = new HashMap<>(); @@ -1662,6 +1664,10 @@ protected void unprotectedCommitTransaction(TransactionState transactionState, S transactionState.addSubTxnTableCommitInfo(subTransactionState, tableCommitInfo); } } + // set COMMITTED only after all commit info is fully populated, so that + // PublishVersionDaemon (which checks status without synchronized(transactionState)) + // will never see COMMITTED with empty commit info. + transactionState.setTransactionStatus(TransactionStatus.COMMITTED); // Update in-memory state only; caller handles edit log persistence unprotectUpdateInMemoryState(transactionState, false); transactionState.setInvolvedBackends(totalInvolvedBackends);