Skip to content

Commit e74e090

Browse files
committed
Treat 2PC commit/abort the same as regular xacts in recovery.
There were several oversights in recovery code where COMMIT/ABORT PREPARED records were ignored: * pg_last_xact_replay_timestamp() (wasn't updated for 2PC commits) * recovery_min_apply_delay (2PC commits were applied immediately) * recovery_target_xid (recovery would not stop if the XID used 2PC) The first of those was reported by Sergiy Zuban in bug #11032, analyzed by Tom Lane and Andres Freund. The bug was always there, but was masked before commit d19bd29, because COMMIT PREPARED always created an extra regular transaction that was WAL-logged. Backpatch to all supported versions (older versions didn't have all the features and therefore didn't have all of the above bugs).
1 parent 61e48ef commit e74e090

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

src/backend/access/transam/xlog.c

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5457,11 +5457,21 @@ getRecordTimestamp(XLogRecord *record, TimestampTz *recordXtime)
54575457
*recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
54585458
return true;
54595459
}
5460+
if (record->xl_rmid == RM_XACT_ID && record_info == XLOG_XACT_COMMIT_PREPARED)
5461+
{
5462+
*recordXtime = ((xl_xact_commit_prepared *) XLogRecGetData(record))->crec.xact_time;
5463+
return true;
5464+
}
54605465
if (record->xl_rmid == RM_XACT_ID && record_info == XLOG_XACT_ABORT)
54615466
{
54625467
*recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
54635468
return true;
54645469
}
5470+
if (record->xl_rmid == RM_XACT_ID && record_info == XLOG_XACT_ABORT_PREPARED)
5471+
{
5472+
*recordXtime = ((xl_xact_abort_prepared *) XLogRecGetData(record))->arec.xact_time;
5473+
return true;
5474+
}
54655475
return false;
54665476
}
54675477

@@ -5480,6 +5490,7 @@ recoveryStopsBefore(XLogRecord *record)
54805490
uint8 record_info;
54815491
bool isCommit;
54825492
TimestampTz recordXtime = 0;
5493+
TransactionId recordXid;
54835494

54845495
/* Check if we should stop as soon as reaching consistency */
54855496
if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
@@ -5498,10 +5509,27 @@ recoveryStopsBefore(XLogRecord *record)
54985509
if (record->xl_rmid != RM_XACT_ID)
54995510
return false;
55005511
record_info = record->xl_info & ~XLR_INFO_MASK;
5512+
55015513
if (record_info == XLOG_XACT_COMMIT_COMPACT || record_info == XLOG_XACT_COMMIT)
5514+
{
5515+
isCommit = true;
5516+
recordXid = record->xl_xid;
5517+
}
5518+
if (record_info == XLOG_XACT_COMMIT_PREPARED)
5519+
{
55025520
isCommit = true;
5521+
recordXid = ((xl_xact_commit_prepared *) XLogRecGetData(record))->xid;
5522+
}
55035523
else if (record_info == XLOG_XACT_ABORT)
5524+
{
5525+
isCommit = false;
5526+
recordXid = record->xl_xid;
5527+
}
5528+
else if (record_info == XLOG_XACT_ABORT_PREPARED)
5529+
{
55045530
isCommit = false;
5531+
recordXid = ((xl_xact_abort_prepared *) XLogRecGetData(record))->xid;
5532+
}
55055533
else
55065534
return false;
55075535

@@ -5516,7 +5544,7 @@ recoveryStopsBefore(XLogRecord *record)
55165544
* they complete. A higher numbered xid will complete before you about
55175545
* 50% of the time...
55185546
*/
5519-
stopsHere = (record->xl_xid == recoveryTargetXid);
5547+
stopsHere = (recordXid == recoveryTargetXid);
55205548
}
55215549

55225550
if (recoveryTarget == RECOVERY_TARGET_TIME &&
@@ -5536,7 +5564,7 @@ recoveryStopsBefore(XLogRecord *record)
55365564
if (stopsHere)
55375565
{
55385566
recoveryStopAfter = false;
5539-
recoveryStopXid = record->xl_xid;
5567+
recoveryStopXid = recordXid;
55405568
recoveryStopTime = recordXtime;
55415569
recoveryStopName[0] = '\0';
55425570

@@ -5602,12 +5630,24 @@ recoveryStopsAfter(XLogRecord *record)
56025630
if (record->xl_rmid == RM_XACT_ID &&
56035631
(record_info == XLOG_XACT_COMMIT_COMPACT ||
56045632
record_info == XLOG_XACT_COMMIT ||
5605-
record_info == XLOG_XACT_ABORT))
5633+
record_info == XLOG_XACT_COMMIT_PREPARED ||
5634+
record_info == XLOG_XACT_ABORT ||
5635+
record_info == XLOG_XACT_ABORT_PREPARED))
56065636
{
5637+
TransactionId recordXid;
5638+
56075639
/* Update the last applied transaction timestamp */
56085640
if (getRecordTimestamp(record, &recordXtime))
56095641
SetLatestXTime(recordXtime);
56105642

5643+
/* Extract the XID of the committed/aborted transaction */
5644+
if (record_info == XLOG_XACT_COMMIT_PREPARED)
5645+
recordXid = ((xl_xact_commit_prepared *) XLogRecGetData(record))->xid;
5646+
else if (record_info == XLOG_XACT_ABORT_PREPARED)
5647+
recordXid = ((xl_xact_abort_prepared *) XLogRecGetData(record))->xid;
5648+
else
5649+
recordXid = record->xl_xid;
5650+
56115651
/*
56125652
* There can be only one transaction end record with this exact
56135653
* transactionid
@@ -5618,21 +5658,24 @@ recoveryStopsAfter(XLogRecord *record)
56185658
* 50% of the time...
56195659
*/
56205660
if (recoveryTarget == RECOVERY_TARGET_XID && recoveryTargetInclusive &&
5621-
record->xl_xid == recoveryTargetXid)
5661+
recordXid == recoveryTargetXid)
56225662
{
56235663
recoveryStopAfter = true;
5624-
recoveryStopXid = record->xl_xid;
5664+
recoveryStopXid = recordXid;
56255665
recoveryStopTime = recordXtime;
56265666
recoveryStopName[0] = '\0';
56275667

5628-
if (record_info == XLOG_XACT_COMMIT_COMPACT || record_info == XLOG_XACT_COMMIT)
5668+
if (record_info == XLOG_XACT_COMMIT_COMPACT ||
5669+
record_info == XLOG_XACT_COMMIT ||
5670+
record_info == XLOG_XACT_COMMIT_PREPARED)
56295671
{
56305672
ereport(LOG,
56315673
(errmsg("recovery stopping after commit of transaction %u, time %s",
56325674
recoveryStopXid,
56335675
timestamptz_to_str(recoveryStopTime))));
56345676
}
5635-
else if (record_info == XLOG_XACT_ABORT)
5677+
else if (record_info == XLOG_XACT_ABORT ||
5678+
record_info == XLOG_XACT_ABORT_PREPARED)
56365679
{
56375680
ereport(LOG,
56385681
(errmsg("recovery stopping after abort of transaction %u, time %s",
@@ -5745,7 +5788,8 @@ recoveryApplyDelay(XLogRecord *record)
57455788
record_info = record->xl_info & ~XLR_INFO_MASK;
57465789
if (!(record->xl_rmid == RM_XACT_ID &&
57475790
(record_info == XLOG_XACT_COMMIT_COMPACT ||
5748-
record_info == XLOG_XACT_COMMIT)))
5791+
record_info == XLOG_XACT_COMMIT ||
5792+
record_info == XLOG_XACT_COMMIT_PREPARED)))
57495793
return false;
57505794

57515795
if (!getRecordTimestamp(record, &xtime))

src/include/access/xact.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ typedef struct xl_xact_abort
180180
/*
181181
* COMMIT_PREPARED and ABORT_PREPARED are identical to COMMIT/ABORT records
182182
* except that we have to store the XID of the prepared transaction explicitly
183-
* --- the XID in the record header will be for the transaction doing the
184-
* COMMIT PREPARED or ABORT PREPARED command.
183+
* --- the XID in the record header will be invalid.
185184
*/
186185

187186
typedef struct xl_xact_commit_prepared

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy