aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlog.c
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2020-03-30 09:19:40 +0200
committerPeter Eisentraut <peter@eisentraut.org>2020-03-30 09:53:45 +0200
commit246f136e76ecd26844840f2b2057e2c87ec9868d (patch)
treea9cc27e699122e2a8c9a43d4a783aba43af290d5 /src/backend/access/transam/xlog.c
parenta01e1b8b9d937894a916465643d9707861ffb838 (diff)
downloadpostgresql-246f136e76ecd26844840f2b2057e2c87ec9868d.tar.gz
postgresql-246f136e76ecd26844840f2b2057e2c87ec9868d.zip
Improve handling of parameter differences in physical replication
When certain parameters are changed on a physical replication primary, this is communicated to standbys using the XLOG_PARAMETER_CHANGE WAL record. The standby then checks whether its own settings are at least as big as the ones on the primary. If not, the standby shuts down with a fatal error. The correspondence of settings between primary and standby is required because those settings influence certain shared memory sizings that are required for processing WAL records that the primary might send. For example, if the primary sends a prepared transaction, the standby must have had max_prepared_transaction set appropriately or it won't be able to process those WAL records. However, fatally shutting down the standby immediately upon receipt of the parameter change record might be a bit of an overreaction. The resources related to those settings are not required immediately at that point, and might never be required if the activity on the primary does not exhaust all those resources. If we just let the standby roll on with recovery, it will eventually produce an appropriate error when those resources are used. So this patch relaxes this a bit. Upon receipt of XLOG_PARAMETER_CHANGE, we still check the settings but only issue a warning and set a global flag if there is a problem. Then when we actually hit the resource issue and the flag was set, we issue another warning message with relevant information. At that point we pause recovery, so a hot standby remains usable. We also repeat the last warning message once a minute so it is harder to miss or ignore. Reviewed-by: Sergei Kornilov <sk@zsrv.org> Reviewed-by: Masahiko Sawada <masahiko.sawada@2ndquadrant.com> Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/4ad69a4c-cc9b-0dfe-0352-8b1b0cd36c7b@2ndquadrant.com
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r--src/backend/access/transam/xlog.c74
1 files changed, 64 insertions, 10 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 8fe92962b0d..1951103b262 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -264,6 +264,8 @@ bool InArchiveRecovery = false;
static bool standby_signal_file_found = false;
static bool recovery_signal_file_found = false;
+static bool need_restart_for_parameter_values = false;
+
/* Was the last xlog file restored from archive, or local? */
static bool restoredFromArchive = false;
@@ -5999,6 +6001,54 @@ SetRecoveryPause(bool recoveryPause)
}
/*
+ * If in hot standby, pause recovery because of a parameter conflict.
+ *
+ * Similar to recoveryPausesHere() but with a different messaging. The user
+ * is expected to make the parameter change and restart the server. If they
+ * just unpause recovery, they will then run into whatever error is after this
+ * function call for the non-hot-standby case.
+ *
+ * We intentionally do not give advice about specific parameters or values
+ * here because it might be misleading. For example, if we run out of lock
+ * space, then in the single-server case we would recommend raising
+ * max_locks_per_transaction, but in recovery it could equally be the case
+ * that max_connections is out of sync with the primary. If we get here, we
+ * have already logged any parameter discrepancies in
+ * RecoveryRequiresIntParameter(), so users can go back to that and get
+ * concrete and accurate information.
+ */
+void
+StandbyParamErrorPauseRecovery(void)
+{
+ TimestampTz last_warning = 0;
+
+ if (!AmStartupProcess() || !need_restart_for_parameter_values)
+ return;
+
+ SetRecoveryPause(true);
+
+ do
+ {
+ TimestampTz now = GetCurrentTimestamp();
+
+ if (TimestampDifferenceExceeds(last_warning, now, 60000))
+ {
+ ereport(WARNING,
+ (errmsg("recovery paused because of insufficient parameter settings"),
+ errdetail("See earlier in the log about which settings are insufficient."),
+ errhint("Recovery cannot continue unless the configuration is changed and the server restarted.")));
+ last_warning = now;
+ }
+
+ pgstat_report_wait_start(WAIT_EVENT_RECOVERY_PAUSE);
+ pg_usleep(1000000L); /* 1000 ms */
+ pgstat_report_wait_end();
+ HandleStartupProcInterrupts();
+ }
+ while (RecoveryIsPaused());
+}
+
+/*
* When recovery_min_apply_delay is set, we wait long enough to make sure
* certain record types are applied at least that interval behind the master.
*
@@ -6177,16 +6227,20 @@ GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream)
* Note that text field supplied is a parameter name and does not require
* translation
*/
-#define RecoveryRequiresIntParameter(param_name, currValue, minValue) \
-do { \
- if ((currValue) < (minValue)) \
- ereport(ERROR, \
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
- errmsg("hot standby is not possible because %s = %d is a lower setting than on the master server (its value was %d)", \
- param_name, \
- currValue, \
- minValue))); \
-} while(0)
+static void
+RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue)
+{
+ if (currValue < minValue)
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("insufficient setting for parameter %s", param_name),
+ errdetail("%s = %d is a lower setting than on the master server (where its value was %d).",
+ param_name, currValue, minValue),
+ errhint("Change parameters and restart the server, or there may be resource exhaustion errors sooner or later.")));
+ need_restart_for_parameter_values = true;
+ }
+}
/*
* Check to see if required parameters are set high enough on this server