@@ -421,7 +421,7 @@ csn_t MtmTransactionSnapshot(TransactionId xid)
421
421
422
422
MtmLock (LW_SHARED );
423
423
if (Mtm -> status == MTM_ONLINE ) {
424
- MtmTransState * ts = hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
424
+ MtmTransState * ts = ( MtmTransState * ) hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
425
425
if (ts != NULL && !ts -> isLocal ) {
426
426
snapshot = ts -> snapshot ;
427
427
Assert (ts -> gtid .node == MtmNodeId || MtmIsRecoverySession );
@@ -811,7 +811,7 @@ static MtmTransState*
811
811
MtmCreateTransState (MtmCurrentTrans * x )
812
812
{
813
813
bool found ;
814
- MtmTransState * ts = hash_search (MtmXid2State , & x -> xid , HASH_ENTER , & found );
814
+ MtmTransState * ts = ( MtmTransState * ) hash_search (MtmXid2State , & x -> xid , HASH_ENTER , & found );
815
815
ts -> status = TRANSACTION_STATUS_IN_PROGRESS ;
816
816
ts -> snapshot = x -> snapshot ;
817
817
ts -> isLocal = true;
@@ -864,6 +864,10 @@ MtmPrePrepareTransaction(MtmCurrentTrans* x)
864
864
/* Do not take in account bg-workers which are performing recovery */
865
865
elog (ERROR , "Abort current transaction because this cluster node is in %s status" , MtmNodeStatusMnem [Mtm -> status ]);
866
866
}
867
+ if (TransactionIdIsValid (x -> gtid .xid ) && BIT_CHECK (Mtm -> disabledNodeMask , x -> gtid .node - 1 )) {
868
+ /* Coordinator of transaction is disabled: just abort transaction without any further steps */
869
+ elog (ERROR , "Abort transaction %d because it's coordinator %d was disabled" , x -> xid , x -> gtid .node );
870
+ }
867
871
868
872
MtmLock (LW_EXCLUSIVE );
869
873
@@ -925,6 +929,32 @@ bool MtmWatchdog(timestamp_t now)
925
929
return allAlive ;
926
930
}
927
931
932
+ /*
933
+ * Mark transaction as precommitted
934
+ */
935
+ void MtmPrecommitTransaction (char const * gid )
936
+ {
937
+ MtmLock (LW_EXCLUSIVE );
938
+ {
939
+ MtmTransMap * tm = (MtmTransMap * )hash_search (MtmGid2State , gid , HASH_FIND , NULL );
940
+ if (tm == NULL ) {
941
+ elog (WARNING , "MtmPrecommitTransaction: transaciton '%s' is not found" , gid );
942
+ } else {
943
+ MtmTransState * ts = tm -> state ;
944
+ Assert (ts != NULL );
945
+ Assert (ts -> status == TRANSACTION_STATUS_IN_PROGRESS );
946
+ ts -> status = TRANSACTION_STATUS_UNKNOWN ;
947
+ ts -> csn = MtmAssignCSN ();
948
+ MtmAdjustSubtransactions (ts );
949
+ MtmSend2PCMessage (ts , MSG_PRECOMMITTED );
950
+ }
951
+ }
952
+ MtmUnlock ();
953
+ }
954
+
955
+
956
+
957
+
928
958
929
959
static bool
930
960
MtmVotingCompleted (MtmTransState * ts )
@@ -949,7 +979,8 @@ MtmVotingCompleted(MtmTransState* ts)
949
979
return true;
950
980
} else if (MtmUseDtm ) {
951
981
ts -> votedMask = 0 ;
952
- MtmSend2PCMessage (ts , MSG_PRECOMMIT );
982
+ SetPrepareTransactionState (ts -> gid , "precommitted" );
983
+ //MtmSend2PCMessage(ts, MSG_PRECOMMIT);
953
984
return false;
954
985
} else {
955
986
ts -> status = TRANSACTION_STATUS_UNKNOWN ;
@@ -969,7 +1000,8 @@ Mtm2PCVoting(MtmCurrentTrans* x, MtmTransState* ts)
969
1000
int nConfigChanges = Mtm -> nConfigChanges ;
970
1001
timestamp_t prepareTime = ts -> csn - ts -> snapshot ;
971
1002
timestamp_t timeout = Max (prepareTime + MSEC_TO_USEC (MtmMin2PCTimeout ), prepareTime * MtmMax2PCRatio /100 );
972
- timestamp_t deadline = MtmGetSystemTime () + timeout ;
1003
+ timestamp_t start = MtmGetSystemTime ();
1004
+ timestamp_t deadline = start + timeout ;
973
1005
timestamp_t now ;
974
1006
975
1007
Assert (ts -> csn > ts -> snapshot );
@@ -994,7 +1026,8 @@ Mtm2PCVoting(MtmCurrentTrans* x, MtmTransState* ts)
994
1026
if (now > deadline ) {
995
1027
if (ts -> isPrepared ) {
996
1028
/* resend precommit message */
997
- MtmSend2PCMessage (ts , MSG_PRECOMMIT );
1029
+ // MtmSend2PCMessage(ts, MSG_PRECOMMIT);
1030
+ elog (LOG , "Distributes transaction is not committed in %ld msec" , USEC_TO_MSEC (now - start ));
998
1031
} else {
999
1032
elog (WARNING , "Commit of distributed transaction is canceled because of %ld msec timeout expiration" , USEC_TO_MSEC (timeout ));
1000
1033
MtmAbortTransaction (ts );
@@ -1037,15 +1070,15 @@ MtmPostPrepareTransaction(MtmCurrentTrans* x)
1037
1070
elog (ERROR , "ERROR INJECTION for transaction %d (%s)" , x -> xid , x -> gid );
1038
1071
}
1039
1072
MtmLock (LW_EXCLUSIVE );
1040
- ts = hash_search (MtmXid2State , & x -> xid , HASH_FIND , NULL );
1073
+ ts = ( MtmTransState * ) hash_search (MtmXid2State , & x -> xid , HASH_FIND , NULL );
1041
1074
Assert (ts != NULL );
1042
1075
//if (x->gid[0]) MTM_LOG1("Preparing transaction %d (%s) at %ld", x->xid, x->gid, MtmGetCurrentTime());
1043
1076
if (!MtmIsCoordinator (ts ) || Mtm -> status == MTM_RECOVERY ) {
1044
1077
MTM_TXTRACE (x , "recovery?" );
1045
1078
Assert (x -> gid [0 ]);
1046
1079
ts -> votingCompleted = true;
1047
1080
MTM_TXTRACE (x , "recovery? 1" );
1048
- if (Mtm -> status != MTM_RECOVERY || Mtm -> recoverySlot != MtmReplicationNodeId ) {
1081
+ if (Mtm -> status != MTM_RECOVERY /* || Mtm->recoverySlot != MtmReplicationNodeId*/ ) {
1049
1082
MTM_TXTRACE (x , "recovery? 2" );
1050
1083
MtmSend2PCMessage (ts , MSG_PREPARED ); /* send notification to coordinator */
1051
1084
if (!MtmUseDtm ) {
@@ -1102,7 +1135,8 @@ MtmCommitPreparedTransaction(MtmCurrentTrans* x)
1102
1135
ts -> votedMask = 0 ;
1103
1136
ts -> procno = MyProc -> pgprocno ;
1104
1137
MTM_TXTRACE (ts , "Coordinator sends MSG_PRECOMMIT" );
1105
- MtmSend2PCMessage (ts , MSG_PRECOMMIT );
1138
+ SetPrepareTransactionState (ts -> gid , "precommitted" );
1139
+ //MtmSend2PCMessage(ts, MSG_PRECOMMIT);
1106
1140
1107
1141
Mtm2PCVoting (x , ts );
1108
1142
@@ -1159,7 +1193,7 @@ MtmEndTransaction(MtmCurrentTrans* x, bool commit)
1159
1193
MtmTransState * ts = NULL ;
1160
1194
MtmLock (LW_EXCLUSIVE );
1161
1195
if (x -> isPrepared ) {
1162
- ts = hash_search (MtmXid2State , & x -> xid , HASH_FIND , NULL );
1196
+ ts = ( MtmTransState * ) hash_search (MtmXid2State , & x -> xid , HASH_FIND , NULL );
1163
1197
Assert (ts != NULL );
1164
1198
Assert (strcmp (x -> gid , ts -> gid ) == 0 );
1165
1199
} else if (x -> gid [0 ]) {
@@ -1211,7 +1245,7 @@ MtmEndTransaction(MtmCurrentTrans* x, bool commit)
1211
1245
if (ts == NULL ) {
1212
1246
bool found ;
1213
1247
Assert (TransactionIdIsValid (x -> xid ));
1214
- ts = hash_search (MtmXid2State , & x -> xid , HASH_ENTER , & found );
1248
+ ts = ( MtmTransState * ) hash_search (MtmXid2State , & x -> xid , HASH_ENTER , & found );
1215
1249
if (!found ) {
1216
1250
ts -> isEnqueued = false;
1217
1251
ts -> isActive = false;
@@ -1321,6 +1355,53 @@ static void MtmBroadcastPollMessage(MtmTransState* ts)
1321
1355
}
1322
1356
}
1323
1357
1358
+ /*
1359
+ * Restore state of recovered prepared transaction in memory
1360
+ */
1361
+ static void MtmLoadPreparedTransactions (void )
1362
+ {
1363
+ PreparedTransaction pxacts ;
1364
+ int n = GetPreparedTransactions (& pxacts );
1365
+ int i ;
1366
+
1367
+ for (i = 0 ; i < n ; i ++ ) {
1368
+ bool found ;
1369
+ char const * gid = pxacts [i ].gid ;
1370
+ MtmTransMap * tm = (MtmTransMap * )hash_search (MtmGid2State , gid , HASH_ENTER , & found );
1371
+ if (!found ) {
1372
+ TransactionId xid = GetNewTransactionId (false);
1373
+ MtmTransState * ts = (MtmTransState * )hash_search (MtmXid2State , & xid , HASH_ENTER , & found );
1374
+ MTM_LOG1 ("Recover prepared transaction %s xid %d" , gid , xid );
1375
+ MyPgXact -> xid = InvalidTransactionId ; /* dirty hack:((( */
1376
+ Assert (!found );
1377
+ Mtm -> nActiveTransactions += 1 ;
1378
+ ts -> isEnqueued = false;
1379
+ ts -> isActive = true;
1380
+ ts -> status = strcmp (pxacts [i ].state_3pc , "precommitted" ) == 0 ? TRANSACTION_STATUS_UNKNOWN : TRANSACTION_STATUS_IN_PROGRESS ;
1381
+ ts -> isLocal = true;
1382
+ ts -> isPrepared = false;
1383
+ ts -> isPinned = false;
1384
+ ts -> snapshot = INVALID_CSN ;
1385
+ ts -> isTwoPhase = false;
1386
+ ts -> csn = 0 ; /* should be replaced with real CSN by poll result */
1387
+ ts -> gtid .node = MtmNodeId ;
1388
+ ts -> gtid .xid = xid ;
1389
+ ts -> nSubxids = 0 ;
1390
+ ts -> votingCompleted = true;
1391
+ ts -> participantsMask = (((nodemask_t )1 << Mtm -> nAllNodes ) - 1 ) & ~Mtm -> disabledNodeMask & ~((nodemask_t )1 << (MtmNodeId - 1 ));
1392
+ ts -> votedMask = 0 ;
1393
+ strcpy (ts -> gid , gid );
1394
+ MtmTransactionListAppend (ts );
1395
+ tm -> status = ts -> status ;
1396
+ tm -> state = ts ;
1397
+ MtmBroadcastPollMessage (ts );
1398
+ }
1399
+ }
1400
+ MTM_LOG1 ("Recover %d prepared transactions" , n );
1401
+ if (pxacts ) {
1402
+ pfree (pxacts );
1403
+ }
1404
+ }
1324
1405
1325
1406
static void MtmStartRecovery ()
1326
1407
{
@@ -2084,6 +2165,7 @@ static void MtmCheckControlFile(void)
2084
2165
}
2085
2166
}
2086
2167
2168
+
2087
2169
static void MtmInitialize ()
2088
2170
{
2089
2171
bool found ;
@@ -2120,6 +2202,7 @@ static void MtmInitialize()
2120
2202
Mtm -> nConfigChanges = 0 ;
2121
2203
Mtm -> recoveryCount = 0 ;
2122
2204
Mtm -> localTablesHashLoaded = false;
2205
+ Mtm -> preparedTransactionsLoaded = false;
2123
2206
Mtm -> inject2PCError = 0 ;
2124
2207
Mtm -> sendQueue = NULL ;
2125
2208
Mtm -> freeQueue = NULL ;
@@ -2923,6 +3006,13 @@ MtmReplicationMode MtmGetReplicationMode(int nodeId, sig_atomic_t volatile* shut
2923
3006
MtmReplicationMode mode = REPLMODE_OPEN_EXISTED ;
2924
3007
2925
3008
MtmLock (LW_EXCLUSIVE );
3009
+
3010
+ if (!Mtm -> preparedTransactionsLoaded )
3011
+ {
3012
+ MtmLoadPreparedTransactions ();
3013
+ Mtm -> preparedTransactionsLoaded = true;
3014
+ }
3015
+
2926
3016
while ((Mtm -> status != MTM_CONNECTED && Mtm -> status != MTM_ONLINE ) || BIT_CHECK (Mtm -> disabledNodeMask , nodeId - 1 ))
2927
3017
{
2928
3018
if (* shutdown )
@@ -3402,7 +3492,7 @@ mtm_get_csn(PG_FUNCTION_ARGS)
3402
3492
csn_t csn = INVALID_CSN ;
3403
3493
3404
3494
MtmLock (LW_SHARED );
3405
- ts = hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
3495
+ ts = ( MtmTransState * ) hash_search (MtmXid2State , & xid , HASH_FIND , NULL );
3406
3496
if (ts != NULL ) {
3407
3497
csn = ts -> csn ;
3408
3498
}
@@ -3926,14 +4016,12 @@ static inline void MtmGucUpdate(const char *key, char *value)
3926
4016
MtmGucEntry * hentry ;
3927
4017
bool found ;
3928
4018
3929
- hentry = hash_search (MtmGucHash , key , HASH_FIND , & found );
4019
+ hentry = ( MtmGucEntry * ) hash_search (MtmGucHash , key , HASH_ENTER , & found );
3930
4020
if (found )
3931
4021
{
3932
4022
pfree (hentry -> value );
3933
4023
dlist_delete (& hentry -> list_node );
3934
4024
}
3935
-
3936
- hentry = hash_search (MtmGucHash , key , HASH_ENTER , NULL );
3937
4025
hentry -> value = value ;
3938
4026
dlist_push_tail (& MtmGucList , & hentry -> list_node );
3939
4027
}
@@ -3943,7 +4031,7 @@ static inline void MtmGucRemove(const char *key)
3943
4031
MtmGucEntry * hentry ;
3944
4032
bool found ;
3945
4033
3946
- hentry = hash_search (MtmGucHash , key , HASH_FIND , & found );
4034
+ hentry = ( MtmGucEntry * ) hash_search (MtmGucHash , key , HASH_FIND , & found );
3947
4035
if (found )
3948
4036
{
3949
4037
pfree (hentry -> value );
@@ -4531,7 +4619,7 @@ MtmSerializeLock(PROCLOCK* proclock, void* arg)
4531
4619
}
4532
4620
4533
4621
static bool
4534
- MtmDetectGlobalDeadLockFortXid (TransactionId xid )
4622
+ MtmDetectGlobalDeadLockForXid (TransactionId xid )
4535
4623
{
4536
4624
bool hasDeadlock = false;
4537
4625
if (TransactionIdIsValid (xid )) {
@@ -4587,11 +4675,11 @@ MtmDetectGlobalDeadLock(PGPROC* proc)
4587
4675
4588
4676
MTM_LOG1 ("Detect global deadlock for %d by backend %d" , pgxact -> xid , MyProcPid );
4589
4677
4590
- return MtmDetectGlobalDeadLockFortXid (pgxact -> xid );
4678
+ return MtmDetectGlobalDeadLockForXid (pgxact -> xid );
4591
4679
}
4592
4680
4593
4681
Datum mtm_check_deadlock (PG_FUNCTION_ARGS )
4594
4682
{
4595
4683
TransactionId xid = PG_GETARG_INT32 (0 );
4596
- PG_RETURN_BOOL (MtmDetectGlobalDeadLockFortXid (xid ));
4684
+ PG_RETURN_BOOL (MtmDetectGlobalDeadLockForXid (xid ));
4597
4685
}
0 commit comments