@@ -443,9 +443,11 @@ void TxnImpl::ScheduleHeartBeat() {
443443void TxnImpl::DoHeartBeat (int64_t start_ts, std::string primary_key) {
444444 State state = state_.load ();
445445 if (state != kPreCommitted && state != kPreCommitting && state != kCommitting ) {
446+ DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] heartbeat stop, state({})." , ID (), StateName (state));
446447 return ;
447448 }
448- if (use_async_commit_.load () && state == kPreCommitted ) {
449+ if (use_async_commit_.load () && state != kPreCommitting ) {
450+ DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] heartbeat stop for async commit, state({})." , ID (), StateName (state));
449451 return ;
450452 }
451453 std::shared_ptr<TxnHeartbeatTask> heartbeat_task = std::make_shared<TxnHeartbeatTask>(stub_, start_ts, primary_key);
@@ -500,6 +502,8 @@ Status TxnImpl::DoPreCommit() {
500502
501503 use_async_commit_.store (buffer_->MutationsSize () < FLAGS_txn_max_async_commit_count && FLAGS_enable_txn_async_commit);
502504
505+ use_concurrent_precommit_.store (FLAGS_enable_txn_concurrent_prewrite);
506+
503507 Status status = is_one_pc_.load () ? PreCommit1PC () : PreCommit2PC ();
504508
505509 if (!status.ok ()) {
@@ -554,6 +558,20 @@ Status TxnImpl::PreCommit1PC() {
554558Status TxnImpl::PreCommit2PC () {
555559 DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] precommit primary key, pk({})." , ID (),
556560 StringToHex (buffer_->GetPrimaryKey ()));
561+
562+ bool is_one_pc = is_one_pc_.load ();
563+ CHECK (!is_one_pc) << fmt::format (" [sdk.txn.{}] precommit 2pc but is_one_pc is true." , ID ());
564+
565+ if (use_concurrent_precommit_.load ()) {
566+ DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] precommit use concurrent prewrite." , ID ());
567+ return PreCommit2PCConcurrent ();
568+ } else {
569+ DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] precommit use sequential prewrite." , ID ());
570+ return PreCommit2PCSequential ();
571+ }
572+ }
573+
574+ Status TxnImpl::PreCommit2PCSequential () {
557575 // primary key map
558576 std::map<std::string, const TxnMutation*> mutations_map_primary_key;
559577 mutations_map_primary_key.emplace (
@@ -566,8 +584,10 @@ Status TxnImpl::PreCommit2PC() {
566584 }
567585 mutations_map_ordinary_keys.emplace (std::make_pair (key, &mutation));
568586 }
569- bool is_one_pc = is_one_pc_.load ();
570- CHECK (!is_one_pc) << fmt::format (" [sdk.txn.{}] precommit 2pc but is_one_pc is true." , ID ());
587+
588+ // precommit primary key
589+ DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] precommit primary key." , ID ());
590+ bool is_one_pc = false ;
571591 bool use_async_commit = use_async_commit_.load ();
572592 uint64_t min_commit_ts = 0 ;
573593 TxnPrewriteTask task_primary (stub_, buffer_->GetPrimaryKey (), mutations_map_primary_key, shared_from_this (),
@@ -584,14 +604,9 @@ Status TxnImpl::PreCommit2PC() {
584604 if (!use_async_commit) {
585605 use_async_commit_.store (false );
586606 } else {
587- CHECK (min_commit_ts > 0 ) << fmt::format (" [sdk.txn.{}] min_commit_ts({}) invalid." , ID (), min_commit_ts);
588- min_commit_ts = std::max (min_commit_ts, commit_ts_.load ());
589- commit_ts_.store (min_commit_ts);
607+ UpdateAsyncCommitTs (min_commit_ts);
590608 }
591609
592- // 2pc need schedule heartbeat to update lock ttl
593- ScheduleHeartBeat ();
594-
595610 // precommit ordinary keys
596611 DINGO_LOG (DEBUG) << fmt::format (" [sdk.txn.{}] precommit ordinary keys." , ID ());
597612 min_commit_ts = 0 ;
@@ -607,14 +622,57 @@ Status TxnImpl::PreCommit2PC() {
607622 if (!use_async_commit) {
608623 use_async_commit_.store (false );
609624 } else {
610- CHECK (min_commit_ts > 0 ) << fmt::format (" [sdk.txn.{}] min_commit_ts({}) invalid." , ID (), min_commit_ts);
611- min_commit_ts = std::max (min_commit_ts, commit_ts_.load ());
612- commit_ts_.store (min_commit_ts);
625+ UpdateAsyncCommitTs (min_commit_ts);
626+ }
627+
628+ return Status::OK ();
629+ }
630+
631+ Status TxnImpl::PreCommit2PCConcurrent () {
632+ // all keys map
633+ std::map<std::string, const TxnMutation*> mutations_map_all_keys;
634+ // ordinary keys map for async commit
635+ std::map<std::string, const TxnMutation*> mutations_map_ordinary_keys;
636+ bool use_async_commit = use_async_commit_.load ();
637+ for (const auto & [key, mutation] : buffer_->Mutations ()) {
638+ if (key == buffer_->GetPrimaryKey ()) {
639+ mutations_map_all_keys.emplace (std::make_pair (key, &mutation));
640+ continue ;
641+ }
642+ mutations_map_all_keys.emplace (std::make_pair (key, &mutation));
643+ if (use_async_commit) {
644+ // for async commit, need to save ordinary keys info
645+ mutations_map_ordinary_keys.emplace (std::make_pair (key, &mutation));
646+ }
647+ }
648+
649+ bool is_one_pc = false ;
650+ uint64_t min_commit_ts = 0 ;
651+ TxnPrewriteTask task_primary (stub_, buffer_->GetPrimaryKey (), mutations_map_all_keys, shared_from_this (),
652+ mutations_map_ordinary_keys, is_one_pc, use_async_commit, min_commit_ts);
653+
654+ Status status = task_primary.Run ();
655+ if (!status.ok ()) {
656+ DINGO_LOG (WARNING) << fmt::format (" [sdk.txn.{}] 2pc concurrent precommit keys fail, status({})." , ID (),
657+ status.ToString ());
658+ return status;
659+ }
660+
661+ if (!use_async_commit) {
662+ use_async_commit_.store (false );
663+ } else {
664+ UpdateAsyncCommitTs (min_commit_ts);
613665 }
614666
615667 return Status::OK ();
616668}
617669
670+ void TxnImpl::UpdateAsyncCommitTs (uint64_t min_commit_ts) {
671+ CHECK (min_commit_ts > 0 ) << fmt::format (" [sdk.txn.{}] min_commit_ts({}) invalid." , ID (), min_commit_ts);
672+ min_commit_ts = std::max (min_commit_ts, commit_ts_.load ());
673+ commit_ts_.store (min_commit_ts);
674+ }
675+
618676Status TxnImpl::CommitPrimaryKey () {
619677 std::vector<std::string> keys = {buffer_->GetPrimaryKey ()};
620678 Status status;
0 commit comments