@@ -129,6 +129,7 @@ static void MtmBeginTransaction(MtmCurrentTrans* x);
129
129
static void MtmPrePrepareTransaction (MtmCurrentTrans * x );
130
130
static void MtmPostPrepareTransaction (MtmCurrentTrans * x );
131
131
static void MtmAbortPreparedTransaction (MtmCurrentTrans * x );
132
+ static void MtmCommitPreparedTransaction (MtmCurrentTrans * x );
132
133
static void MtmEndTransaction (MtmCurrentTrans * x , bool commit );
133
134
static bool MtmTwoPhaseCommit (MtmCurrentTrans * x );
134
135
static TransactionId MtmGetOldestXmin (Relation rel , bool ignoreVacuum );
@@ -684,6 +685,9 @@ MtmXactCallback(XactEvent event, void *arg)
684
685
case XACT_EVENT_ABORT_PREPARED :
685
686
MtmAbortPreparedTransaction (& MtmTx );
686
687
break ;
688
+ case XACT_EVENT_COMMIT_PREPARED :
689
+ MtmCommitPreparedTransaction (& MtmTx );
690
+ break ;
687
691
case XACT_EVENT_COMMIT :
688
692
MtmEndTransaction (& MtmTx , true);
689
693
break ;
@@ -792,6 +796,7 @@ MtmCreateTransState(MtmCurrentTrans* x)
792
796
ts -> status = TRANSACTION_STATUS_IN_PROGRESS ;
793
797
ts -> snapshot = x -> snapshot ;
794
798
ts -> isLocal = true;
799
+ ts -> isTwoPhase = x -> isTwoPhase ;
795
800
if (!found ) {
796
801
ts -> isEnqueued = false;
797
802
ts -> isActive = false;
@@ -969,6 +974,9 @@ MtmPostPrepareTransaction(MtmCurrentTrans* x)
969
974
x -> status = ts -> status ;
970
975
MTM_LOG3 ("%d: Result of vote: %d" , MyProcPid , ts -> status );
971
976
MtmUnlock ();
977
+ if (x -> isTwoPhase ) {
978
+ MtmResetTransaction ();
979
+ }
972
980
}
973
981
//if (x->gid[0]) MTM_LOG1("Prepared transaction %d (%s) csn=%ld at %ld: %d", x->xid, x->gid, ts->csn, MtmGetCurrentTime(), ts->status);
974
982
if (Mtm -> inject2PCError == 3 ) {
@@ -979,6 +987,74 @@ MtmPostPrepareTransaction(MtmCurrentTrans* x)
979
987
MTM_TXTRACE (x , "PostPrepareTransaction Finish" );
980
988
}
981
989
990
+ static void
991
+ MtmCommitPreparedTransaction (MtmCurrentTrans * x )
992
+ {
993
+ MtmTransMap * tm ;
994
+ MtmTransState * ts ;
995
+
996
+ if (Mtm -> status == MTM_RECOVERY || x -> isReplicated || x -> isPrepared ) { /* Ignore auto-2PC originated by multimaster */
997
+ return ;
998
+ }
999
+ MtmLock (LW_EXCLUSIVE );
1000
+ tm = (MtmTransMap * )hash_search (MtmGid2State , x -> gid , HASH_FIND , NULL );
1001
+ if (tm == NULL ) {
1002
+ elog (WARNING , "Global transaciton ID '%s' is not found" , x -> gid );
1003
+ } else {
1004
+ time_t transTimeout = MSEC_TO_USEC (Mtm2PCMinTimeout );
1005
+ int nConfigChanges = Mtm -> nConfigChanges ;
1006
+ timestamp_t start = MtmGetSystemTime ();
1007
+ int result = 0 ;
1008
+
1009
+ Assert (tm -> state != NULL );
1010
+ MTM_LOG1 ("Commit prepared transaction %d with gid='%s'" , x -> xid , x -> gid );
1011
+ ts = tm -> state ;
1012
+
1013
+ Assert (MtmIsCoordinator (ts ));
1014
+
1015
+ ts -> votingCompleted = false;
1016
+ ts -> nVotes = 1 ; /* I voted myself */
1017
+ ts -> procno = MyProc -> pgprocno ;
1018
+ MTM_TXTRACE (ts , "Coordinator sends MSG_PREPARE" );
1019
+ MtmSend2PCMessage (ts , MSG_PREPARE );
1020
+
1021
+ /* Wait votes from all nodes until: */
1022
+ while (!ts -> votingCompleted /* all nodes voted */
1023
+ && nConfigChanges == Mtm -> nConfigChanges /* configarion is changed */
1024
+ && Mtm -> status == MTM_ONLINE /* node is not online */
1025
+ && ts -> status != TRANSACTION_STATUS_ABORTED /* transaction is aborted */
1026
+ && start + transTimeout >= MtmGetSystemTime ()) /* timeout is expired */
1027
+ {
1028
+ MtmUnlock ();
1029
+ MTM_TXTRACE (x , "CommitPreparedTransaction WaitLatch Start" );
1030
+ result = WaitLatch (& MyProc -> procLatch , WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH , MtmHeartbeatRecvTimeout );
1031
+ MTM_TXTRACE (x , "CommitPreparedTransaction WaitLatch Finish" );
1032
+ /* Emergency bailout if postmaster has died */
1033
+ if (result & WL_POSTMASTER_DEATH ) {
1034
+ proc_exit (1 );
1035
+ }
1036
+ if (result & WL_LATCH_SET ) {
1037
+ MTM_LOG3 ("Latch signaled at %ld" , MtmGetSystemTime ());
1038
+ ResetLatch (& MyProc -> procLatch );
1039
+ }
1040
+ MtmLock (LW_EXCLUSIVE );
1041
+ }
1042
+ if (ts -> status != TRANSACTION_STATUS_ABORTED && (!ts -> votingCompleted || nConfigChanges != Mtm -> nConfigChanges )) {
1043
+ if (nConfigChanges != Mtm -> nConfigChanges ) {
1044
+ elog (WARNING , "Transaction %d (%s) is aborted because cluster configuration is changed during commit" , x -> xid , x -> gid );
1045
+ } else {
1046
+ elog (WARNING , "Transaction %d (%s) is aborted because of %d msec timeout expiration, prepare time %d msec" ,
1047
+ x -> xid , x -> gid , (int )USEC_TO_MSEC (transTimeout ), (int )USEC_TO_MSEC (ts -> csn - x -> snapshot ));
1048
+ }
1049
+ MtmAbortTransaction (ts );
1050
+ }
1051
+ x -> status = ts -> status ;
1052
+ x -> xid = ts -> xid ;
1053
+ x -> isPrepared = true;
1054
+ MTM_LOG3 ("%d: Result of vote: %d" , MyProcPid , ts -> status );
1055
+ }
1056
+ MtmUnlock ();
1057
+ }
982
1058
983
1059
static void
984
1060
MtmAbortPreparedTransaction (MtmCurrentTrans * x )
@@ -1008,9 +1084,9 @@ MtmAbortPreparedTransaction(MtmCurrentTrans* x)
1008
1084
static void
1009
1085
MtmEndTransaction (MtmCurrentTrans * x , bool commit )
1010
1086
{
1011
- MTM_LOG3 ("%d: End transaction %d, prepared=%d, replicated=%d, distributed=%d, gid=%s -> %s" ,
1012
- MyProcPid , x -> xid , x -> isPrepared , x -> isReplicated , x -> isDistributed , x -> gid , commit ? "commit" : "abort" );
1013
- if (x -> status != TRANSACTION_STATUS_ABORTED && x -> isDistributed && (x -> isPrepared || x -> isReplicated )) {
1087
+ MTM_LOG1 ("%d: End transaction %d, prepared=%d, replicated=%d, distributed=%d, 2pc =%d, gid=%s -> %s" ,
1088
+ MyProcPid , x -> xid , x -> isPrepared , x -> isReplicated , x -> isDistributed , x -> isTwoPhase , x -> gid , commit ? "commit" : "abort" );
1089
+ if (x -> status != TRANSACTION_STATUS_ABORTED && x -> isDistributed && (x -> isPrepared || x -> isReplicated ) && ! x -> isTwoPhase ) {
1014
1090
MtmTransState * ts = NULL ;
1015
1091
MtmLock (LW_EXCLUSIVE );
1016
1092
if (x -> isPrepared ) {
@@ -3819,9 +3895,13 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
3819
3895
}
3820
3896
break ;
3821
3897
case TRANS_STMT_PREPARE :
3898
+ MtmTx .isTwoPhase = true;
3899
+ strcpy (MtmTx .gid , stmt -> gid );
3900
+ break ;
3901
+ /* nobreak */
3822
3902
case TRANS_STMT_COMMIT_PREPARED :
3823
3903
case TRANS_STMT_ROLLBACK_PREPARED :
3824
- MtmTx .isTwoPhase = true ;
3904
+ Assert (! MtmTx .isTwoPhase ) ;
3825
3905
strcpy (MtmTx .gid , stmt -> gid );
3826
3906
break ;
3827
3907
default :
0 commit comments