This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 9732f6cae36 branch-4.1: [fix](cloud) Preserve transaction metadata on
precommit replay #69005 (#69022)
9732f6cae36 is described below
commit 9732f6cae36c69f89b3854e2c27d3b015d39342b
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Oct 14 14:44:22 2026 +0800
branch-4.1: [fix](cloud) Preserve transaction metadata on precommit replay
#69005 (#69022)
Cherry-picked from #69005
Co-authored-by: Yixuan Wang <[email protected]>
---
cloud/src/meta-service/meta_service_txn.cpp | 2 +
cloud/test/meta_service_test.cpp | 79 +++++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/cloud/src/meta-service/meta_service_txn.cpp
b/cloud/src/meta-service/meta_service_txn.cpp
index 974fac54fae..b003a5baa14 100644
--- a/cloud/src/meta-service/meta_service_txn.cpp
+++ b/cloud/src/meta-service/meta_service_txn.cpp
@@ -474,12 +474,14 @@ void
MetaServiceImpl::precommit_txn(::google::protobuf::RpcController* controlle
code = MetaServiceCode::TXN_ALREADY_VISIBLE;
ss << "transaction is already visible: db_id=" << db_id << " txn_id="
<< txn_id;
msg = ss.str();
+ return;
}
if (txn_info.status() == TxnStatusPB::TXN_STATUS_PRECOMMITTED) {
code = MetaServiceCode::TXN_ALREADY_PRECOMMITED;
ss << "transaction is already precommited: db_id=" << db_id << "
txn_id=" << txn_id;
msg = ss.str();
+ return;
}
LOG(INFO) << "before update txn_info=" << txn_info.ShortDebugString();
diff --git a/cloud/test/meta_service_test.cpp b/cloud/test/meta_service_test.cpp
index 9cd64a21b27..f66fb04c262 100644
--- a/cloud/test/meta_service_test.cpp
+++ b/cloud/test/meta_service_test.cpp
@@ -1879,6 +1879,85 @@ TEST(MetaServiceTest, PrecommitTxnTest2) {
}
}
+TEST(MetaServiceTest, PrecommitTxnReplayDoesNotChangeTxnMetadata) {
+ auto meta_service = get_meta_service();
+ const int64_t db_id = 563413;
+ const int64_t table_id = 417417878;
+
+ brpc::Controller begin_cntl;
+ BeginTxnRequest begin_req;
+ begin_req.set_cloud_unique_id("test_cloud_unique_id");
+ TxnInfoPB begin_info;
+ begin_info.set_db_id(db_id);
+ begin_info.set_label("precommit_replay_terminal_state");
+ begin_info.add_table_ids(table_id);
+ begin_info.set_timeout_ms(36000);
+ begin_req.mutable_txn_info()->CopyFrom(begin_info);
+ BeginTxnResponse begin_res;
+
meta_service->begin_txn(reinterpret_cast<::google::protobuf::RpcController*>(&begin_cntl),
+ &begin_req, &begin_res, nullptr);
+ ASSERT_EQ(begin_res.status().code(), MetaServiceCode::OK);
+ const int64_t txn_id = begin_res.txn_id();
+
+ PrecommitTxnRequest precommit_req;
+ precommit_req.set_cloud_unique_id("test_cloud_unique_id");
+ precommit_req.set_db_id(db_id);
+ precommit_req.set_txn_id(txn_id);
+ precommit_req.set_precommit_timeout_ms(36000);
+ brpc::Controller precommit_cntl;
+ PrecommitTxnResponse precommit_res;
+ meta_service->precommit_txn(
+
reinterpret_cast<::google::protobuf::RpcController*>(&precommit_cntl),
&precommit_req,
+ &precommit_res, nullptr);
+ ASSERT_EQ(precommit_res.status().code(), MetaServiceCode::OK);
+
+ const std::string info_key = txn_info_key({mock_instance, db_id, txn_id});
+ const std::string running_key = txn_running_key({mock_instance, db_id,
txn_id});
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string info_val;
+ ASSERT_EQ(txn->get(info_key, &info_val), TxnErrorCode::TXN_OK);
+ TxnInfoPB txn_info;
+ ASSERT_TRUE(txn_info.ParseFromString(info_val));
+ ASSERT_EQ(txn_info.status(), TxnStatusPB::TXN_STATUS_PRECOMMITTED);
+ // A fixed old timestamp makes a replayed precommit write observable.
+ txn_info.set_precommit_time(1);
+ const std::string precommitted_info_val = txn_info.SerializeAsString();
+ txn->put(info_key, precommitted_info_val);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string running_val;
+ ASSERT_EQ(txn->get(running_key, &running_val), TxnErrorCode::TXN_OK);
+ meta_service->precommit_txn(
+
reinterpret_cast<::google::protobuf::RpcController*>(&precommit_cntl),
&precommit_req,
+ &precommit_res, nullptr);
+ ASSERT_EQ(precommit_res.status().code(),
MetaServiceCode::TXN_ALREADY_PRECOMMITED);
+
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ ASSERT_EQ(txn->get(info_key, &info_val), TxnErrorCode::TXN_OK);
+ ASSERT_EQ(info_val, precommitted_info_val);
+ std::string replay_running_val;
+ ASSERT_EQ(txn->get(running_key, &replay_running_val),
TxnErrorCode::TXN_OK);
+ ASSERT_EQ(replay_running_val, running_val);
+
+ txn_info.set_status(TxnStatusPB::TXN_STATUS_VISIBLE);
+ const std::string visible_info_val = txn_info.SerializeAsString();
+ txn->put(info_key, visible_info_val);
+ txn->remove(running_key);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ meta_service->precommit_txn(
+
reinterpret_cast<::google::protobuf::RpcController*>(&precommit_cntl),
&precommit_req,
+ &precommit_res, nullptr);
+ ASSERT_EQ(precommit_res.status().code(),
MetaServiceCode::TXN_ALREADY_VISIBLE);
+
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ ASSERT_EQ(txn->get(info_key, &info_val), TxnErrorCode::TXN_OK);
+ ASSERT_EQ(info_val, visible_info_val);
+ ASSERT_EQ(txn->get(running_key, &replay_running_val),
TxnErrorCode::TXN_KEY_NOT_FOUND);
+}
+
TEST(MetaServiceTest, CommitTxnTest) {
auto meta_service = get_meta_service();
int64_t table_id = 1234;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]