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

Commit9dbf8ab

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 parent34221af commit9dbf8ab

File tree

7 files changed

+86
-18
lines changed

7 files changed

+86
-18
lines changed

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,9 +1986,8 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
19861986
* This is never called at the end of recovery - we use
19871987
* RecoverPreparedTransactions() at that point.
19881988
*
1989-
* The lack of calls to SubTransSetParent() calls here is by design;
1990-
* those calls are made by RecoverPreparedTransactions() at the end of recovery
1991-
* for those xacts that need this.
1989+
* This updates pg_subtrans, so that any subtransactions will be correctly
1990+
* seen as in-progress in snapshots taken during recovery.
19921991
*/
19931992
void
19941993
StandbyRecoverPreparedTransactions(void)
@@ -2008,7 +2007,7 @@ StandbyRecoverPreparedTransactions(void)
20082007

20092008
buf=ProcessTwoPhaseBuffer(xid,
20102009
gxact->prepare_start_lsn,
2011-
gxact->ondisk,false, false);
2010+
gxact->ondisk,true, false);
20122011
if (buf!=NULL)
20132012
pfree(buf);
20142013
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7283,6 +7283,9 @@ StartupXLOG(void)
72837283
RunningTransactionsDatarunning;
72847284
TransactionIdlatestCompletedXid;
72857285

7286+
/* Update pg_subtrans entries for any prepared transactions */
7287+
StandbyRecoverPreparedTransactions();
7288+
72867289
/*
72877290
* Construct a RunningTransactions snapshot representing a
72887291
* shut down server, with only prepared transactions still
@@ -7291,7 +7294,7 @@ StartupXLOG(void)
72917294
*/
72927295
running.xcnt=nxids;
72937296
running.subxcnt=0;
7294-
running.subxid_overflow=false;
7297+
running.subxid_status=SUBXIDS_IN_SUBTRANS;
72957298
running.nextXid=XidFromFullTransactionId(checkPoint.nextXid);
72967299
running.oldestRunningXid=oldestActiveXID;
72977300
latestCompletedXid=XidFromFullTransactionId(checkPoint.nextXid);
@@ -7301,8 +7304,6 @@ StartupXLOG(void)
73017304
running.xids=xids;
73027305

73037306
ProcArrayApplyRecoveryInfo(&running);
7304-
7305-
StandbyRecoverPreparedTransactions();
73067307
}
73077308
}
73087309

@@ -10424,6 +10425,9 @@ xlog_redo(XLogReaderState *record)
1042410425

1042510426
oldestActiveXID=PrescanPreparedTransactions(&xids,&nxids);
1042610427

10428+
/* Update pg_subtrans entries for any prepared transactions */
10429+
StandbyRecoverPreparedTransactions();
10430+
1042710431
/*
1042810432
* Construct a RunningTransactions snapshot representing a shut
1042910433
* down server, with only prepared transactions still alive. We're
@@ -10432,7 +10436,7 @@ xlog_redo(XLogReaderState *record)
1043210436
*/
1043310437
running.xcnt=nxids;
1043410438
running.subxcnt=0;
10435-
running.subxid_overflow=false;
10439+
running.subxid_status=SUBXIDS_IN_SUBTRANS;
1043610440
running.nextXid=XidFromFullTransactionId(checkPoint.nextXid);
1043710441
running.oldestRunningXid=oldestActiveXID;
1043810442
latestCompletedXid=XidFromFullTransactionId(checkPoint.nextXid);
@@ -10442,8 +10446,6 @@ xlog_redo(XLogReaderState *record)
1044210446
running.xids=xids;
1044310447

1044410448
ProcArrayApplyRecoveryInfo(&running);
10445-
10446-
StandbyRecoverPreparedTransactions();
1044710449
}
1044810450

1044910451
/* 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
@@ -1108,7 +1108,7 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
11081108
* If the snapshot isn't overflowed or if its empty we can reset our
11091109
* pending state and use this snapshot instead.
11101110
*/
1111-
if (!running->subxid_overflow||running->xcnt==0)
1111+
if (running->subxid_status!=SUBXIDS_MISSING||running->xcnt==0)
11121112
{
11131113
/*
11141114
* If we have already collected known assigned xids, we need to
@@ -1260,7 +1260,7 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
12601260
* missing, so conservatively assume the last one is latestObservedXid.
12611261
* ----------
12621262
*/
1263-
if (running->subxid_overflow)
1263+
if (running->subxid_status==SUBXIDS_MISSING)
12641264
{
12651265
standbyState=STANDBY_SNAPSHOT_PENDING;
12661266

@@ -1272,6 +1272,18 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
12721272
standbyState=STANDBY_SNAPSHOT_READY;
12731273

12741274
standbySnapshotPendingXmin=InvalidTransactionId;
1275+
1276+
/*
1277+
* If the 'xids' array didn't include all subtransactions, we have to
1278+
* mark any snapshots taken as overflowed.
1279+
*/
1280+
if (running->subxid_status==SUBXIDS_IN_SUBTRANS)
1281+
procArray->lastOverflowedXid=latestObservedXid;
1282+
else
1283+
{
1284+
Assert(running->subxid_status==SUBXIDS_IN_ARRAY);
1285+
procArray->lastOverflowedXid=InvalidTransactionId;
1286+
}
12751287
}
12761288

12771289
/*
@@ -2898,7 +2910,7 @@ GetRunningTransactionData(void)
28982910

28992911
CurrentRunningXacts->xcnt=count-subcount;
29002912
CurrentRunningXacts->subxcnt=subcount;
2901-
CurrentRunningXacts->subxid_overflow=suboverflowed;
2913+
CurrentRunningXacts->subxid_status=suboverflowed ?SUBXIDS_IN_SUBTRANS :SUBXIDS_IN_ARRAY;
29022914
CurrentRunningXacts->nextXid=XidFromFullTransactionId(ShmemVariableCache->nextXid);
29032915
CurrentRunningXacts->oldestRunningXid=oldestRunningXid;
29042916
CurrentRunningXacts->latestCompletedXid=latestCompletedXid;

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

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

11311131
running.xcnt=xlrec->xcnt;
11321132
running.subxcnt=xlrec->subxcnt;
1133-
running.subxid_overflow=xlrec->subxid_overflow;
1133+
running.subxid_status=xlrec->subxid_overflow ?SUBXIDS_MISSING :SUBXIDS_IN_ARRAY;
11341134
running.nextXid=xlrec->nextXid;
11351135
running.latestCompletedXid=xlrec->latestCompletedXid;
11361136
running.oldestRunningXid=xlrec->oldestRunningXid;
@@ -1286,7 +1286,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
12861286

12871287
xlrec.xcnt=CurrRunningXacts->xcnt;
12881288
xlrec.subxcnt=CurrRunningXacts->subxcnt;
1289-
xlrec.subxid_overflow=CurrRunningXacts->subxid_overflow;
1289+
xlrec.subxid_overflow=(CurrRunningXacts->subxid_status!=SUBXIDS_IN_ARRAY);
12901290
xlrec.nextXid=CurrRunningXacts->nextXid;
12911291
xlrec.oldestRunningXid=CurrRunningXacts->oldestRunningXid;
12921292
xlrec.latestCompletedXid=CurrRunningXacts->latestCompletedXid;
@@ -1303,7 +1303,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
13031303

13041304
recptr=XLogInsert(RM_STANDBY_ID,XLOG_RUNNING_XACTS);
13051305

1306-
if (CurrRunningXacts->subxid_overflow)
1306+
if (xlrec.subxid_overflow)
13071307
elog(trace_recovery(DEBUG2),
13081308
"snapshot of %u running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
13091309
CurrRunningXacts->xcnt,

‎src/include/storage/standby.h

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

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

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use PostgresNode;
99
use TestLib;
10-
use Test::Moretests=>24;
10+
use Test::Moretests=>27;
1111

1212
my$psql_out ='';
1313
my$psql_rc ='';
@@ -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
@@ -3558,6 +3558,7 @@ string
35583558
substitute_actual_parameters_context
35593559
substitute_actual_srf_parameters_context
35603560
substitute_phv_relids_context
3561+
subxids_array_status
35613562
svtype
35623563
symbol
35633564
tablespaceinfo

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp