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

Commit180ce0a

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 parentff122d3 commit180ce0a

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
@@ -569,11 +569,16 @@ show_log_timezone(void)
569569
* read-only may be changed to read-write only when in a top-level transaction
570570
* that has not yet taken an initial snapshot.Can't do it in a hot standby
571571
* slave, either.
572+
*
573+
* If we are not in a transaction at all, just allow the change; it means
574+
* nothing since XactReadOnly will be reset by the next StartTransaction().
575+
* The IsTransactionState() test protects us against trying to check
576+
* RecoveryInProgress() in contexts where shared memory is not accessible.
572577
*/
573578
bool
574579
check_transaction_read_only(bool*newval,void**extra,GucSourcesource)
575580
{
576-
if (*newval== false&&XactReadOnly)
581+
if (*newval== false&&XactReadOnly&&IsTransactionState())
577582
{
578583
/* Can't go to r/w mode inside a r/o transaction */
579584
if (IsSubTransaction())
@@ -592,6 +597,7 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
592597
/* Can't go to r/w mode while recovery is still active */
593598
if (RecoveryInProgress())
594599
{
600+
GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
595601
GUC_check_errmsg("cannot set transaction read-write mode during recovery");
596602
return false;
597603
}
@@ -605,6 +611,8 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
605611
*
606612
* We allow idempotent changes at any time, but otherwise this can only be
607613
* changed in a toplevel transaction that has not yet taken a snapshot.
614+
*
615+
* As in check_transaction_read_only, allow it if not inside a transaction.
608616
*/
609617
bool
610618
check_XactIsoLevel(char**newval,void**extra,GucSourcesource)
@@ -634,7 +642,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
634642
else
635643
return false;
636644

637-
if (newXactIsoLevel!=XactIsoLevel)
645+
if (newXactIsoLevel!=XactIsoLevel&&IsTransactionState())
638646
{
639647
if (FirstSnapshotSet)
640648
{
@@ -652,6 +660,7 @@ check_XactIsoLevel(char **newval, void **extra, GucSource source)
652660
/* Can't go to serializable mode while recovery is still active */
653661
if (newXactIsoLevel==XACT_SERIALIZABLE&&RecoveryInProgress())
654662
{
663+
GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
655664
GUC_check_errmsg("cannot use serializable mode in a hot standby");
656665
GUC_check_errhint("You can use REPEATABLE READ instead.");
657666
return false;

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,19 @@ RegisterSerializableTransaction(Snapshot snapshot)
15581558
{
15591559
Assert(IsolationIsSerializable());
15601560

1561+
/*
1562+
* Can't use serializable mode while recovery is still active, as it is,
1563+
* for example, on a hot standby. We could get here despite the check
1564+
* in check_XactIsoLevel() if default_transaction_isolation is set to
1565+
* serializable, so phrase the hint accordingly.
1566+
*/
1567+
if (RecoveryInProgress())
1568+
ereport(ERROR,
1569+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1570+
errmsg("cannot use serializable mode in a hot standby"),
1571+
errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1572+
errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1573+
15611574
/*
15621575
* A special optimization is available for SERIALIZABLE READ ONLY
15631576
* 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
@@ -574,6 +574,15 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
574574
/* statement_timestamp must be set for timeouts to work correctly */
575575
SetCurrentStatementStartTimestamp();
576576
StartTransactionCommand();
577+
578+
/*
579+
* transaction_isolation will have been set to the default by the
580+
* above. If the default is "serializable", and we are in hot
581+
* standby, we will fail if we don't change it to something lower.
582+
* Fortunately, "read committed" is plenty good enough.
583+
*/
584+
XactIsoLevel=XACT_READ_COMMITTED;
585+
577586
(void)GetTransactionSnapshot();
578587
}
579588

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp