@@ -144,11 +144,7 @@ int max_prepared_xacts = 0;
144
144
*
145
145
* typedef struct GlobalTransactionData *GlobalTransaction appears in
146
146
* twophase.h
147
- *
148
- * Note that the max value of GIDSIZE must fit in the uint16 gidlen,
149
- * specified in TwoPhaseFileHeader.
150
147
*/
151
- #define GIDSIZE 200
152
148
153
149
typedef struct GlobalTransactionData
154
150
{
@@ -211,12 +207,14 @@ static void RecordTransactionCommitPrepared(TransactionId xid,
211
207
RelFileNode * rels ,
212
208
int ninvalmsgs ,
213
209
SharedInvalidationMessage * invalmsgs ,
214
- bool initfileinval );
210
+ bool initfileinval ,
211
+ const char * gid );
215
212
static void RecordTransactionAbortPrepared (TransactionId xid ,
216
213
int nchildren ,
217
214
TransactionId * children ,
218
215
int nrels ,
219
- RelFileNode * rels );
216
+ RelFileNode * rels ,
217
+ const char * gid );
220
218
static void ProcessRecords (char * bufptr , TransactionId xid ,
221
219
const TwoPhaseCallback callbacks []);
222
220
static void RemoveGXact (GlobalTransaction gxact );
@@ -898,7 +896,7 @@ TwoPhaseGetDummyProc(TransactionId xid)
898
896
/*
899
897
* Header for a 2PC state file
900
898
*/
901
- #define TWOPHASE_MAGIC 0x57F94533 /* format identifier */
899
+ #define TWOPHASE_MAGIC 0x57F94534 /* format identifier */
902
900
903
901
typedef struct TwoPhaseFileHeader
904
902
{
@@ -914,6 +912,8 @@ typedef struct TwoPhaseFileHeader
914
912
int32 ninvalmsgs ; /* number of cache invalidation messages */
915
913
bool initfileinval ; /* does relcache init file need invalidation? */
916
914
uint16 gidlen ; /* length of the GID - GID follows the header */
915
+ XLogRecPtr origin_lsn ; /* lsn of this record at origin node */
916
+ TimestampTz origin_timestamp ; /* time of prepare at origin node */
917
917
} TwoPhaseFileHeader ;
918
918
919
919
/*
@@ -1065,6 +1065,7 @@ EndPrepare(GlobalTransaction gxact)
1065
1065
{
1066
1066
TwoPhaseFileHeader * hdr ;
1067
1067
StateFileChunk * record ;
1068
+ bool replorigin ;
1068
1069
1069
1070
/* Add the end sentinel to the list of 2PC records */
1070
1071
RegisterTwoPhaseRecord (TWOPHASE_RM_END_ID , 0 ,
@@ -1075,6 +1076,21 @@ EndPrepare(GlobalTransaction gxact)
1075
1076
Assert (hdr -> magic == TWOPHASE_MAGIC );
1076
1077
hdr -> total_len = records .total_len + sizeof (pg_crc32c );
1077
1078
1079
+ replorigin = (replorigin_session_origin != InvalidRepOriginId &&
1080
+ replorigin_session_origin != DoNotReplicateId );
1081
+
1082
+ if (replorigin )
1083
+ {
1084
+ Assert (replorigin_session_origin_lsn != InvalidXLogRecPtr );
1085
+ hdr -> origin_lsn = replorigin_session_origin_lsn ;
1086
+ hdr -> origin_timestamp = replorigin_session_origin_timestamp ;
1087
+ }
1088
+ else
1089
+ {
1090
+ hdr -> origin_lsn = InvalidXLogRecPtr ;
1091
+ hdr -> origin_timestamp = 0 ;
1092
+ }
1093
+
1078
1094
/*
1079
1095
* If the data size exceeds MaxAllocSize, we won't be able to read it in
1080
1096
* ReadTwoPhaseFile. Check for that now, rather than fail in the case
@@ -1107,7 +1123,16 @@ EndPrepare(GlobalTransaction gxact)
1107
1123
XLogBeginInsert ();
1108
1124
for (record = records .head ; record != NULL ; record = record -> next )
1109
1125
XLogRegisterData (record -> data , record -> len );
1126
+
1127
+ XLogSetRecordFlags (XLOG_INCLUDE_ORIGIN );
1128
+
1110
1129
gxact -> prepare_end_lsn = XLogInsert (RM_XACT_ID , XLOG_XACT_PREPARE );
1130
+
1131
+ if (replorigin )
1132
+ /* Move LSNs forward for this replication origin */
1133
+ replorigin_session_advance (replorigin_session_origin_lsn ,
1134
+ gxact -> prepare_end_lsn );
1135
+
1111
1136
XLogFlush (gxact -> prepare_end_lsn );
1112
1137
1113
1138
/* If we crash now, we have prepared: WAL replay will fix things */
@@ -1283,6 +1308,44 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
1283
1308
return buf ;
1284
1309
}
1285
1310
1311
+ /*
1312
+ * ParsePrepareRecord
1313
+ */
1314
+ void
1315
+ ParsePrepareRecord (uint8 info , char * xlrec , xl_xact_parsed_prepare * parsed )
1316
+ {
1317
+ TwoPhaseFileHeader * hdr ;
1318
+ char * bufptr ;
1319
+
1320
+ hdr = (TwoPhaseFileHeader * ) xlrec ;
1321
+ bufptr = xlrec + MAXALIGN (sizeof (TwoPhaseFileHeader ));
1322
+
1323
+ parsed -> origin_lsn = hdr -> origin_lsn ;
1324
+ parsed -> origin_timestamp = hdr -> origin_timestamp ;
1325
+ parsed -> twophase_xid = hdr -> xid ;
1326
+ parsed -> dbId = hdr -> database ;
1327
+ parsed -> nsubxacts = hdr -> nsubxacts ;
1328
+ parsed -> nrels = hdr -> ncommitrels ;
1329
+ parsed -> nabortrels = hdr -> nabortrels ;
1330
+ parsed -> nmsgs = hdr -> ninvalmsgs ;
1331
+
1332
+ strncpy (parsed -> twophase_gid , bufptr , hdr -> gidlen );
1333
+ bufptr += MAXALIGN (hdr -> gidlen );
1334
+
1335
+ parsed -> subxacts = (TransactionId * ) bufptr ;
1336
+ bufptr += MAXALIGN (hdr -> nsubxacts * sizeof (TransactionId ));
1337
+
1338
+ parsed -> xnodes = (RelFileNode * ) bufptr ;
1339
+ bufptr += MAXALIGN (hdr -> ncommitrels * sizeof (RelFileNode ));
1340
+
1341
+ parsed -> abortnodes = (RelFileNode * ) bufptr ;
1342
+ bufptr += MAXALIGN (hdr -> nabortrels * sizeof (RelFileNode ));
1343
+
1344
+ parsed -> msgs = (SharedInvalidationMessage * ) bufptr ;
1345
+ bufptr += MAXALIGN (hdr -> ninvalmsgs * sizeof (SharedInvalidationMessage ));
1346
+ }
1347
+
1348
+
1286
1349
1287
1350
/*
1288
1351
* Reads 2PC data from xlog. During checkpoint this data will be moved to
@@ -1435,11 +1498,12 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
1435
1498
hdr -> nsubxacts , children ,
1436
1499
hdr -> ncommitrels , commitrels ,
1437
1500
hdr -> ninvalmsgs , invalmsgs ,
1438
- hdr -> initfileinval );
1501
+ hdr -> initfileinval , gid );
1439
1502
else
1440
1503
RecordTransactionAbortPrepared (xid ,
1441
1504
hdr -> nsubxacts , children ,
1442
- hdr -> nabortrels , abortrels );
1505
+ hdr -> nabortrels , abortrels ,
1506
+ gid );
1443
1507
1444
1508
ProcArrayRemove (proc , latestXid );
1445
1509
@@ -1752,7 +1816,8 @@ restoreTwoPhaseData(void)
1752
1816
if (buf == NULL )
1753
1817
continue ;
1754
1818
1755
- PrepareRedoAdd (buf , InvalidXLogRecPtr , InvalidXLogRecPtr );
1819
+ PrepareRedoAdd (buf , InvalidXLogRecPtr ,
1820
+ InvalidXLogRecPtr , InvalidRepOriginId );
1756
1821
}
1757
1822
}
1758
1823
LWLockRelease (TwoPhaseStateLock );
@@ -2165,7 +2230,8 @@ RecordTransactionCommitPrepared(TransactionId xid,
2165
2230
RelFileNode * rels ,
2166
2231
int ninvalmsgs ,
2167
2232
SharedInvalidationMessage * invalmsgs ,
2168
- bool initfileinval )
2233
+ bool initfileinval ,
2234
+ const char * gid )
2169
2235
{
2170
2236
XLogRecPtr recptr ;
2171
2237
TimestampTz committs = GetCurrentTimestamp ();
@@ -2193,7 +2259,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
2193
2259
ninvalmsgs , invalmsgs ,
2194
2260
initfileinval , false,
2195
2261
MyXactFlags | XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK ,
2196
- xid );
2262
+ xid , gid );
2197
2263
2198
2264
2199
2265
if (replorigin )
@@ -2255,7 +2321,8 @@ RecordTransactionAbortPrepared(TransactionId xid,
2255
2321
int nchildren ,
2256
2322
TransactionId * children ,
2257
2323
int nrels ,
2258
- RelFileNode * rels )
2324
+ RelFileNode * rels ,
2325
+ const char * gid )
2259
2326
{
2260
2327
XLogRecPtr recptr ;
2261
2328
@@ -2278,7 +2345,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
2278
2345
nchildren , children ,
2279
2346
nrels , rels ,
2280
2347
MyXactFlags | XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK ,
2281
- xid );
2348
+ xid , gid );
2282
2349
2283
2350
/* Always flush, since we're about to remove the 2PC state file */
2284
2351
XLogFlush (recptr );
@@ -2309,7 +2376,8 @@ RecordTransactionAbortPrepared(TransactionId xid,
2309
2376
* data, the entry is marked as located on disk.
2310
2377
*/
2311
2378
void
2312
- PrepareRedoAdd (char * buf , XLogRecPtr start_lsn , XLogRecPtr end_lsn )
2379
+ PrepareRedoAdd (char * buf , XLogRecPtr start_lsn ,
2380
+ XLogRecPtr end_lsn , RepOriginId origin_id )
2313
2381
{
2314
2382
TwoPhaseFileHeader * hdr = (TwoPhaseFileHeader * ) buf ;
2315
2383
char * bufptr ;
@@ -2358,6 +2426,13 @@ PrepareRedoAdd(char *buf, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
2358
2426
Assert (TwoPhaseState -> numPrepXacts < max_prepared_xacts );
2359
2427
TwoPhaseState -> prepXacts [TwoPhaseState -> numPrepXacts ++ ] = gxact ;
2360
2428
2429
+ if (origin_id != InvalidRepOriginId )
2430
+ {
2431
+ /* recover apply progress */
2432
+ replorigin_advance (origin_id , hdr -> origin_lsn , end_lsn ,
2433
+ false /* backward */ , false /* WAL */ );
2434
+ }
2435
+
2361
2436
elog (DEBUG2 , "added 2PC data in shared memory for transaction %u" , gxact -> xid );
2362
2437
}
2363
2438
0 commit comments