Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb5b418b

Browse files
committed
Fix MVCC bug with prepared xact with subxacts on standby
We did not recover the subtransaction IDs of prepared transactionswhen starting a hot standby from a shutdown checkpoint. As a result,such subtransactions were considered as aborted, rather thanin-progress. That would lead to hint bits being set incorrectly, andthe subtransactions suddenly becoming visible to old snapshots whenthe prepared transaction was committed.To fix, update pg_subtrans with prepared transactions's subxids whenstarting hot standby from a shutdown checkpoint. The snapshots takenfrom that state need to be marked as "suboverflowed", so that we alsocheck the pg_subtrans.Backport to all supported versions.Discussion:https://www.postgresql.org/message-id/6b852e98-2d49-4ca1-9e95-db419a2696e0@iki.fi
1 parente00a9a4 commitb5b418b

File tree

7 files changed

+85
-17
lines changed

7 files changed

+85
-17
lines changed

‎src/backend/access/transam/twophase.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,9 +2011,8 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
20112011
* This is never called at the end of recovery - we use
20122012
* RecoverPreparedTransactions() at that point.
20132013
*
2014-
* The lack of calls to SubTransSetParent() calls here is by design;
2015-
* those calls are made by RecoverPreparedTransactions() at the end of recovery
2016-
* for those xacts that need this.
2014+
* This updates pg_subtrans, so that any subtransactions will be correctly
2015+
* seen as in-progress in snapshots taken during recovery.
20172016
*/
20182017
void
20192018
StandbyRecoverPreparedTransactions(void)
@@ -2033,7 +2032,7 @@ StandbyRecoverPreparedTransactions(void)
20332032

20342033
buf=ProcessTwoPhaseBuffer(xid,
20352034
gxact->prepare_start_lsn,
2036-
gxact->ondisk,false, false);
2035+
gxact->ondisk,true, false);
20372036
if (buf!=NULL)
20382037
pfree(buf);
20392038
}

‎src/backend/access/transam/xlog.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5420,6 +5420,9 @@ StartupXLOG(void)
54205420
RunningTransactionsDatarunning;
54215421
TransactionIdlatestCompletedXid;
54225422

5423+
/* Update pg_subtrans entries for any prepared transactions */
5424+
StandbyRecoverPreparedTransactions();
5425+
54235426
/*
54245427
* Construct a RunningTransactions snapshot representing a
54255428
* shut down server, with only prepared transactions still
@@ -5428,7 +5431,7 @@ StartupXLOG(void)
54285431
*/
54295432
running.xcnt=nxids;
54305433
running.subxcnt=0;
5431-
running.subxid_overflow=false;
5434+
running.subxid_status=SUBXIDS_IN_SUBTRANS;
54325435
running.nextXid=XidFromFullTransactionId(checkPoint.nextXid);
54335436
running.oldestRunningXid=oldestActiveXID;
54345437
latestCompletedXid=XidFromFullTransactionId(checkPoint.nextXid);
@@ -5438,8 +5441,6 @@ StartupXLOG(void)
54385441
running.xids=xids;
54395442

54405443
ProcArrayApplyRecoveryInfo(&running);
5441-
5442-
StandbyRecoverPreparedTransactions();
54435444
}
54445445
}
54455446

@@ -7808,6 +7809,9 @@ xlog_redo(XLogReaderState *record)
78087809

78097810
oldestActiveXID=PrescanPreparedTransactions(&xids,&nxids);
78107811

7812+
/* Update pg_subtrans entries for any prepared transactions */
7813+
StandbyRecoverPreparedTransactions();
7814+
78117815
/*
78127816
* Construct a RunningTransactions snapshot representing a shut
78137817
* down server, with only prepared transactions still alive. We're
@@ -7816,7 +7820,7 @@ xlog_redo(XLogReaderState *record)
78167820
*/
78177821
running.xcnt=nxids;
78187822
running.subxcnt=0;
7819-
running.subxid_overflow=false;
7823+
running.subxid_status=SUBXIDS_IN_SUBTRANS;
78207824
running.nextXid=XidFromFullTransactionId(checkPoint.nextXid);
78217825
running.oldestRunningXid=oldestActiveXID;
78227826
latestCompletedXid=XidFromFullTransactionId(checkPoint.nextXid);
@@ -7826,8 +7830,6 @@ xlog_redo(XLogReaderState *record)
78267830
running.xids=xids;
78277831

78287832
ProcArrayApplyRecoveryInfo(&running);
7829-
7830-
StandbyRecoverPreparedTransactions();
78317833
}
78327834

78337835
/* ControlFile->checkPointCopy always tracks the latest ckpt XID */

‎src/backend/storage/ipc/procarray.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
10971097
* If the snapshot isn't overflowed or if its empty we can reset our
10981098
* pending state and use this snapshot instead.
10991099
*/
1100-
if (!running->subxid_overflow||running->xcnt==0)
1100+
if (running->subxid_status!=SUBXIDS_MISSING||running->xcnt==0)
11011101
{
11021102
/*
11031103
* If we have already collected known assigned xids, we need to
@@ -1249,7 +1249,7 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
12491249
* missing, so conservatively assume the last one is latestObservedXid.
12501250
* ----------
12511251
*/
1252-
if (running->subxid_overflow)
1252+
if (running->subxid_status==SUBXIDS_MISSING)
12531253
{
12541254
standbyState=STANDBY_SNAPSHOT_PENDING;
12551255

@@ -1261,6 +1261,18 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
12611261
standbyState=STANDBY_SNAPSHOT_READY;
12621262

12631263
standbySnapshotPendingXmin=InvalidTransactionId;
1264+
1265+
/*
1266+
* If the 'xids' array didn't include all subtransactions, we have to
1267+
* mark any snapshots taken as overflowed.
1268+
*/
1269+
if (running->subxid_status==SUBXIDS_IN_SUBTRANS)
1270+
procArray->lastOverflowedXid=latestObservedXid;
1271+
else
1272+
{
1273+
Assert(running->subxid_status==SUBXIDS_IN_ARRAY);
1274+
procArray->lastOverflowedXid=InvalidTransactionId;
1275+
}
12641276
}
12651277

12661278
/*
@@ -2842,7 +2854,7 @@ GetRunningTransactionData(void)
28422854

28432855
CurrentRunningXacts->xcnt=count-subcount;
28442856
CurrentRunningXacts->subxcnt=subcount;
2845-
CurrentRunningXacts->subxid_overflow=suboverflowed;
2857+
CurrentRunningXacts->subxid_status=suboverflowed ?SUBXIDS_IN_SUBTRANS :SUBXIDS_IN_ARRAY;
28462858
CurrentRunningXacts->nextXid=XidFromFullTransactionId(ShmemVariableCache->nextXid);
28472859
CurrentRunningXacts->oldestRunningXid=oldestRunningXid;
28482860
CurrentRunningXacts->latestCompletedXid=latestCompletedXid;

‎src/backend/storage/ipc/standby.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ standby_redo(XLogReaderState *record)
11861186

11871187
running.xcnt=xlrec->xcnt;
11881188
running.subxcnt=xlrec->subxcnt;
1189-
running.subxid_overflow=xlrec->subxid_overflow;
1189+
running.subxid_status=xlrec->subxid_overflow ?SUBXIDS_MISSING :SUBXIDS_IN_ARRAY;
11901190
running.nextXid=xlrec->nextXid;
11911191
running.latestCompletedXid=xlrec->latestCompletedXid;
11921192
running.oldestRunningXid=xlrec->oldestRunningXid;
@@ -1351,7 +1351,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
13511351

13521352
xlrec.xcnt=CurrRunningXacts->xcnt;
13531353
xlrec.subxcnt=CurrRunningXacts->subxcnt;
1354-
xlrec.subxid_overflow=CurrRunningXacts->subxid_overflow;
1354+
xlrec.subxid_overflow=(CurrRunningXacts->subxid_status!=SUBXIDS_IN_ARRAY);
13551355
xlrec.nextXid=CurrRunningXacts->nextXid;
13561356
xlrec.oldestRunningXid=CurrRunningXacts->oldestRunningXid;
13571357
xlrec.latestCompletedXid=CurrRunningXacts->latestCompletedXid;
@@ -1368,7 +1368,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
13681368

13691369
recptr=XLogInsert(RM_STANDBY_ID,XLOG_RUNNING_XACTS);
13701370

1371-
if (CurrRunningXacts->subxid_overflow)
1371+
if (xlrec.subxid_overflow)
13721372
elog(trace_recovery(DEBUG2),
13731373
"snapshot of %d running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
13741374
CurrRunningXacts->xcnt,

‎src/include/storage/standby.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,19 @@ extern void StandbyReleaseOldLocks(TransactionId oldxid);
7575
* almost immediately see the data we need to begin executing queries.
7676
*/
7777

78+
typedefenum
79+
{
80+
SUBXIDS_IN_ARRAY,/* xids array includes all running subxids */
81+
SUBXIDS_MISSING,/* snapshot overflowed, subxids are missing */
82+
SUBXIDS_IN_SUBTRANS,/* subxids are not included in 'xids', but
83+
* pg_subtrans is fully up-to-date */
84+
}subxids_array_status;
85+
7886
typedefstructRunningTransactionsData
7987
{
8088
intxcnt;/* # of xact ids in xids[] */
8189
intsubxcnt;/* # of subxact ids in xids[] */
82-
boolsubxid_overflow;/* snapshot overflowed, subxids missing */
90+
subxids_array_statussubxid_status;
8391
TransactionIdnextXid;/* xid from ShmemVariableCache->nextXid */
8492
TransactionIdoldestRunningXid;/* *not* oldestXmin */
8593
TransactionIdlatestCompletedXid;/* so we can set xmax */

‎src/test/recovery/t/009_twophase.pl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,52 @@ sub configure_and_reload
308308

309309
$cur_primary->psql('postgres',"COMMIT PREPARED 'xact_009_12'");
310310

311+
###############################################################################
312+
# Check visibility of prepared transactions in standby after a restart while
313+
# primary is down.
314+
###############################################################################
315+
316+
$cur_primary->psql(
317+
'postgres',"
318+
CREATE TABLE t_009_tbl_standby_mvcc (id int, msg text);
319+
BEGIN;
320+
INSERT INTO t_009_tbl_standby_mvcc VALUES (1, 'issued to${cur_primary_name}');
321+
SAVEPOINT s1;
322+
INSERT INTO t_009_tbl_standby_mvcc VALUES (2, 'issued to${cur_primary_name}');
323+
PREPARE TRANSACTION 'xact_009_standby_mvcc';
324+
");
325+
$cur_primary->stop;
326+
$cur_standby->restart;
327+
328+
# Acquire a snapshot in standby, before we commit the prepared transaction
329+
my$standby_session =$cur_standby->background_psql('postgres',on_error_die=> 1);
330+
$standby_session->query_safe("BEGIN ISOLATION LEVEL REPEATABLE READ");
331+
$psql_out =$standby_session->query_safe(
332+
"SELECT count(*) FROM t_009_tbl_standby_mvcc");
333+
is($psql_out,'0',
334+
"Prepared transaction not visible in standby before commit");
335+
336+
# Commit the transaction in primary
337+
$cur_primary->start;
338+
$cur_primary->psql('postgres',"
339+
SET synchronous_commit='remote_apply'; -- To ensure the standby is caught up
340+
COMMIT PREPARED 'xact_009_standby_mvcc';
341+
");
342+
343+
# Still not visible to the old snapshot
344+
$psql_out =$standby_session->query_safe(
345+
"SELECT count(*) FROM t_009_tbl_standby_mvcc");
346+
is($psql_out,'0',
347+
"Committed prepared transaction not visible to old snapshot in standby");
348+
349+
# Is visible to a new snapshot
350+
$standby_session->query_safe("COMMIT");
351+
$psql_out =$standby_session->query_safe(
352+
"SELECT count(*) FROM t_009_tbl_standby_mvcc");
353+
is($psql_out,'2',
354+
"Committed prepared transaction is visible to new snapshot in standby");
355+
$standby_session->quit;
356+
311357
###############################################################################
312358
# Check for a lock conflict between prepared transaction with DDL inside and
313359
# replay of XLOG_STANDBY_LOCK wal record.

‎src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3769,6 +3769,7 @@ string
37693769
substitute_actual_parameters_context
37703770
substitute_actual_srf_parameters_context
37713771
substitute_phv_relids_context
3772+
subxids_array_status
37723773
symbol
37733774
tablespaceinfo
37743775
teSection

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp