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

Commit7abaa6b

Browse files
committed
Fix issues with checks for unsupported transaction states in Hot Standby.
The GUC check hooks for transaction_read_only and transaction_isolationtried to check RecoveryInProgress(), so as to disallow setting read/writemode or serializable isolation level (respectively) in hot standbysessions. However, GUC check hooks can be called in many situations wherewe're not connected to shared memory at all, resulting in a crash inRecoveryInProgress(). Among other cases, this results in EXEC_BACKENDbuilds crashing during child process start if default_transaction_isolationis serializable, as reported by Heikki Linnakangas. Protect those callsby silently allowing any setting when not inside a transaction; which isokay anyway since these GUCs are always reset at start of transaction.Also, add a check to GetSerializableTransactionSnapshot() to complainif we are in hot standby. We need that check despite the one incheck_XactIsoLevel() because default_transaction_isolation could beserializable. We don't want to complain any sooner than this in suchcases, since that would prevent running transactions at all in such astate; but a transaction can be run, if SET TRANSACTION ISOLATION is donebefore setting a snapshot. Per report some months ago from Robert Haas.Back-patch to 9.1, since these problems were introduced by the SSI patch.Kevin Grittner and Tom Lane, with ideas from Heikki Linnakangas
1 parent406473b commit7abaa6b

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

‎src/backend/commands/variable.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -533,11 +533,16 @@ show_log_timezone(void)
533533
* read-only may be changed to read-write only when in a top-level transaction
534534
* that has not yet taken an initial snapshot.Can't do it in a hot standby
535535
* slave, either.
536+
*
537+
* If we are not in a transaction at all, just allow the change; it means
538+
* nothing since XactReadOnly will be reset by the next StartTransaction().
539+
* The IsTransactionState() test protects us against trying to check
540+
* RecoveryInProgress() in contexts where shared memory is not accessible.
536541
*/
537542
bool
538543
check_transaction_read_only(bool*newval,void**extra,GucSourcesource)
539544
{
540-
if (*newval== false&&XactReadOnly)
545+
if (*newval== false&&XactReadOnly&&IsTransactionState())
541546
{
542547
/* Can't go to r/w mode inside a r/o transaction */
543548
if (IsSubTransaction())
@@ -556,6 +561,7 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
556561
/* Can't go to r/w mode while recovery is still active */
557562
if (RecoveryInProgress())
558563
{
564+
GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
559565
GUC_check_errmsg("cannot set transaction read-write mode during recovery");
560566
return false;
561567
}
@@ -569,6 +575,8 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
569575
*
570576
* We allow idempotent changes at any time, but otherwise this can only be
571577
* changed in a toplevel transaction that has not yet taken a snapshot.
578+
*
579+
* As in check_transaction_read_only, allow it if not inside a transaction.
572580
*/
573581
bool
574582
check_XactIsoLevel(char**newval,void**extra,GucSourcesource)
@@ -598,7 +606,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
598606
else
599607
return false;
600608

601-
if (newXactIsoLevel!=XactIsoLevel)
609+
if (newXactIsoLevel!=XactIsoLevel&&IsTransactionState())
602610
{
603611
if (FirstSnapshotSet)
604612
{
@@ -616,6 +624,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
616624
/* Can't go to serializable mode while recovery is still active */
617625
if (newXactIsoLevel==XACT_SERIALIZABLE&&RecoveryInProgress())
618626
{
627+
GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
619628
GUC_check_errmsg("cannot use serializable mode in a hot standby");
620629
GUC_check_errhint("You can use REPEATABLE READ instead.");
621630
return false;

‎src/backend/storage/lmgr/predicate.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,19 @@ GetSerializableTransactionSnapshot(Snapshot snapshot)
15711571
{
15721572
Assert(IsolationIsSerializable());
15731573

1574+
/*
1575+
* Can't use serializable mode while recovery is still active, as it is,
1576+
* for example, on a hot standby. We could get here despite the check
1577+
* in check_XactIsoLevel() if default_transaction_isolation is set to
1578+
* serializable, so phrase the hint accordingly.
1579+
*/
1580+
if (RecoveryInProgress())
1581+
ereport(ERROR,
1582+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1583+
errmsg("cannot use serializable mode in a hot standby"),
1584+
errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1585+
errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1586+
15741587
/*
15751588
* A special optimization is available for SERIALIZABLE READ ONLY
15761589
* DEFERRABLE transactions -- we can wait for a suitable snapshot and

‎src/backend/utils/init/postinit.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,15 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
584584
/* statement_timestamp must be set for timeouts to work correctly */
585585
SetCurrentStatementStartTimestamp();
586586
StartTransactionCommand();
587+
588+
/*
589+
* transaction_isolation will have been set to the default by the
590+
* above. If the default is "serializable", and we are in hot
591+
* standby, we will fail if we don't change it to something lower.
592+
* Fortunately, "read committed" is plenty good enough.
593+
*/
594+
XactIsoLevel=XACT_READ_COMMITTED;
595+
587596
(void)GetTransactionSnapshot();
588597
}
589598

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp