hotstandby-serializable-4.patch

text/x-patch

Filename: hotstandby-serializable-4.patch
Type: text/x-patch
Part: 0
Message: Re: default_isolation_level='serializable' crashes on Windows

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/commands/variable.c 0 0
src/backend/storage/lmgr/predicate.c 0 0
src/backend/utils/init/postinit.c 0 0
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 0e9eb3a64f5db66dd2fca68252a597e68defdbf8..5d894ba77f74d02637008deedd4ca2919d8af6b8 100644
*** a/src/backend/commands/variable.c
--- b/src/backend/commands/variable.c
*************** show_log_timezone(void)
*** 533,543 ****
   * read-only may be changed to read-write only when in a top-level transaction
   * that has not yet taken an initial snapshot.	Can't do it in a hot standby
   * slave, either.
   */
  bool
  check_transaction_read_only(bool *newval, void **extra, GucSource source)
  {
! 	if (*newval == false && XactReadOnly)
  	{
  		/* Can't go to r/w mode inside a r/o transaction */
  		if (IsSubTransaction())
--- 533,548 ----
   * read-only may be changed to read-write only when in a top-level transaction
   * that has not yet taken an initial snapshot.	Can't do it in a hot standby
   * slave, either.
+  *
+  * If we are not in a transaction at all, just allow the change; it means
+  * nothing since XactReadOnly will be reset by the next StartTransaction().
+  * The IsTransactionState() test protects us against trying to check
+  * RecoveryInProgress() in contexts where shared memory is not accessible.
   */
  bool
  check_transaction_read_only(bool *newval, void **extra, GucSource source)
  {
! 	if (*newval == false && XactReadOnly && IsTransactionState())
  	{
  		/* Can't go to r/w mode inside a r/o transaction */
  		if (IsSubTransaction())
*************** check_transaction_read_only(bool *newval
*** 556,561 ****
--- 561,567 ----
  		/* Can't go to r/w mode while recovery is still active */
  		if (RecoveryInProgress())
  		{
+ 			GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
  			GUC_check_errmsg("cannot set transaction read-write mode during recovery");
  			return false;
  		}
*************** check_transaction_read_only(bool *newval
*** 569,574 ****
--- 575,582 ----
   *
   * We allow idempotent changes at any time, but otherwise this can only be
   * changed in a toplevel transaction that has not yet taken a snapshot.
+  *
+  * As in check_transaction_read_only, allow it if not inside a transaction.
   */
  bool
  check_XactIsoLevel(char **newval, void **extra, GucSource source)
*************** check_XactIsoLevel(char **newval, void *
*** 598,604 ****
  	else
  		return false;
  
! 	if (newXactIsoLevel != XactIsoLevel)
  	{
  		if (FirstSnapshotSet)
  		{
--- 606,612 ----
  	else
  		return false;
  
! 	if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
  	{
  		if (FirstSnapshotSet)
  		{
*************** check_XactIsoLevel(char **newval, void *
*** 616,621 ****
--- 624,630 ----
  		/* Can't go to serializable mode while recovery is still active */
  		if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
  		{
+ 			GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
  			GUC_check_errmsg("cannot use serializable mode in a hot standby");
  			GUC_check_errhint("You can use REPEATABLE READ instead.");
  			return false;
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index b22faf9607d87f1a2bc7ce306e923dc12b8cfcc7..8b5a95ceaa0ff460d34231dadc2d3562fa7b0c63 100644
*** a/src/backend/storage/lmgr/predicate.c
--- b/src/backend/storage/lmgr/predicate.c
*************** GetSerializableTransactionSnapshot(Snaps
*** 1572,1577 ****
--- 1572,1590 ----
  	Assert(IsolationIsSerializable());
  
  	/*
+ 	 * Can't use serializable mode while recovery is still active, as it is,
+ 	 * for example, on a hot standby.  We could get here despite the check
+ 	 * in check_XactIsoLevel() if default_transaction_isolation is set to
+ 	 * serializable, so phrase the hint accordingly.
+ 	 */
+ 	if (RecoveryInProgress())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 				 errmsg("cannot use serializable mode in a hot standby"),
+ 				 errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
+ 				 errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
+ 
+ 	/*
  	 * A special optimization is available for SERIALIZABLE READ ONLY
  	 * DEFERRABLE transactions -- we can wait for a suitable snapshot and
  	 * thereby avoid all SSI overhead once it's running.
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 6a3fc6f693f66304a487032e2099d1660590d836..bef301a79c8fea1f602f5bd8b340bb4950d285fa 100644
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
*************** InitPostgres(const char *in_dbname, Oid 
*** 584,589 ****
--- 584,598 ----
  		/* statement_timestamp must be set for timeouts to work correctly */
  		SetCurrentStatementStartTimestamp();
  		StartTransactionCommand();
+ 
+ 		/*
+ 		 * transaction_isolation will have been set to the default by the
+ 		 * above.  If the default is "serializable", and we are in hot
+ 		 * standby, we will fail if we don't change it to something lower.
+ 		 * Fortunately, "read committed" is plenty good enough.
+ 		 */
+ 		XactIsoLevel = XACT_READ_COMMITTED;
+ 
  		(void) GetTransactionSnapshot();
  	}