diff options
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r-- | src/backend/access/transam/xlog.c | 210 |
1 files changed, 148 insertions, 62 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 6812cf5e9a4..2d3dab39fe5 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.404 2010/04/27 09:25:18 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.405 2010/04/28 16:10:40 heikki Exp $ * *------------------------------------------------------------------------- */ @@ -76,6 +76,7 @@ int MaxStandbyDelay = 30; bool fullPageWrites = true; bool log_checkpoints = false; int sync_method = DEFAULT_SYNC_METHOD; +int wal_level = WAL_LEVEL_MINIMAL; #ifdef WAL_DEBUG bool XLOG_DEBUG = false; @@ -97,6 +98,13 @@ bool XLOG_DEBUG = false; /* * GUC support */ +const struct config_enum_entry wal_level_options[] = { + {"minimal", WAL_LEVEL_MINIMAL, false}, + {"archive", WAL_LEVEL_ARCHIVE, false}, + {"hot_standby", WAL_LEVEL_HOT_STANDBY, false}, + {NULL, 0, false} +}; + const struct config_enum_entry sync_method_options[] = { {"fsync", SYNC_METHOD_FSYNC, false}, #ifdef HAVE_FSYNC_WRITETHROUGH @@ -501,6 +509,18 @@ static bool reachedMinRecoveryPoint = false; static bool InRedo = false; /* + * Information logged when we detect a change in one of the parameters + * important for Hot Standby. + */ +typedef struct xl_parameter_change +{ + int MaxConnections; + int max_prepared_xacts; + int max_locks_per_xact; + int wal_level; +} xl_parameter_change; + +/* * Flags set by interrupt handlers for later service in the redo loop. */ static volatile sig_atomic_t got_SIGHUP = false; @@ -522,7 +542,8 @@ static void readRecoveryCommandFile(void); static void exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg); static bool recoveryStopsHere(XLogRecord *record, bool *includeThis); -static void CheckRequiredParameterValues(CheckPoint checkPoint); +static void CheckRequiredParameterValues(void); +static void XLogReportParameters(void); static void LocalSetXLogInsertAllowed(void); static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags); @@ -4922,6 +4943,13 @@ BootStrapXLOG(void) ControlFile->time = checkPoint.time; ControlFile->checkPoint = checkPoint.redo; ControlFile->checkPointCopy = checkPoint; + + /* Set important parameter values for use when replaying WAL */ + ControlFile->MaxConnections = MaxConnections; + ControlFile->max_prepared_xacts = max_prepared_xacts; + ControlFile->max_locks_per_xact = max_locks_per_xact; + ControlFile->wal_level = wal_level; + /* some additional ControlFile fields are set in WriteControlFile() */ WriteControlFile(); @@ -5539,17 +5567,18 @@ GetLatestXLogTime(void) } /* - * Note that text field supplied is a parameter name and does not require translation + * Note that text field supplied is a parameter name and does not require + * translation */ -#define RecoveryRequiresIntParameter(param_name, currValue, checkpointValue) \ +#define RecoveryRequiresIntParameter(param_name, currValue, minValue) \ { \ - if (currValue < checkpointValue) \ + if (currValue < minValue) \ ereport(ERROR, \ (errmsg("recovery connections cannot continue because " \ "%s = %u is a lower setting than on WAL source server (value was %u)", \ param_name, \ currValue, \ - checkpointValue))); \ + minValue))); \ } /* @@ -5557,21 +5586,37 @@ GetLatestXLogTime(void) * for various aspects of recovery operation. */ static void -CheckRequiredParameterValues(CheckPoint checkPoint) +CheckRequiredParameterValues(void) { - /* We ignore autovacuum_max_workers when we make this test. */ - RecoveryRequiresIntParameter("max_connections", - MaxConnections, checkPoint.MaxConnections); + /* + * For archive recovery, the WAL must be generated with at least + * 'archive' wal_level. + */ + if (InArchiveRecovery && ControlFile->wal_level == WAL_LEVEL_MINIMAL) + { + ereport(WARNING, + (errmsg("WAL was generated with wal_level='minimal', data may be missing"), + errhint("This happens if you temporarily set wal_level='minimal' without taking a new base backup."))); + } - RecoveryRequiresIntParameter("max_prepared_xacts", - max_prepared_xacts, checkPoint.max_prepared_xacts); - RecoveryRequiresIntParameter("max_locks_per_xact", - max_locks_per_xact, checkPoint.max_locks_per_xact); + /* + * For Hot Standby, the WAL must be generated with 'hot_standby' mode, + * and we must have at least as many backend slots as the primary. + */ + if (InArchiveRecovery && XLogRequestRecoveryConnections) + { + if (ControlFile->wal_level < WAL_LEVEL_HOT_STANDBY) + ereport(ERROR, + (errmsg("recovery connections cannot start because wal_level was not set to 'hot_standby' on the WAL source server"))); - if (!checkPoint.XLogStandbyInfoMode) - ereport(ERROR, - (errmsg("recovery connections cannot start because the recovery_connections " - "parameter is disabled on the WAL source server"))); + /* We ignore autovacuum_max_workers when we make this test. */ + RecoveryRequiresIntParameter("max_connections", + MaxConnections, ControlFile->MaxConnections); + RecoveryRequiresIntParameter("max_prepared_xacts", + max_prepared_xacts, ControlFile->max_prepared_xacts); + RecoveryRequiresIntParameter("max_locks_per_xact", + max_locks_per_xact, ControlFile->max_locks_per_xact); + } } /* @@ -5904,6 +5949,9 @@ StartupXLOG(void) BACKUP_LABEL_FILE, BACKUP_LABEL_OLD))); } + /* Check that the GUCs used to generate the WAL allow recovery */ + CheckRequiredParameterValues(); + /* * Initialize recovery connections, if enabled. We won't let backends * in yet, not until we've reached the min recovery point specified in @@ -5915,8 +5963,6 @@ StartupXLOG(void) TransactionId *xids; int nxids; - CheckRequiredParameterValues(checkPoint); - ereport(DEBUG1, (errmsg("initializing recovery connections"))); @@ -6401,6 +6447,13 @@ StartupXLOG(void) } /* + * If any of the critical GUCs have changed, log them before we allow + * backends to write WAL. + */ + LocalSetXLogInsertAllowed(); + XLogReportParameters(); + + /* * All done. Allow backends to write WAL. (Although the bool flag is * probably atomic in itself, we use the info_lck here to ensure that * there are no race conditions concerning visibility of other recent @@ -6998,12 +7051,6 @@ CreateCheckPoint(int flags) MemSet(&checkPoint, 0, sizeof(checkPoint)); checkPoint.time = (pg_time_t) time(NULL); - /* Set important parameter values for use when replaying WAL */ - checkPoint.MaxConnections = MaxConnections; - checkPoint.max_prepared_xacts = max_prepared_xacts; - checkPoint.max_locks_per_xact = max_locks_per_xact; - checkPoint.XLogStandbyInfoMode = XLogStandbyInfoActive(); - /* * We must hold WALInsertLock while examining insert state to determine * the checkpoint REDO pointer. @@ -7647,28 +7694,49 @@ RequestXLogSwitch(void) } /* - * Write an XLOG UNLOGGED record, indicating that some operation was - * performed on data that we fsync()'d directly to disk, skipping - * WAL-logging. - * - * Such operations screw up archive recovery, so we complain if we see - * these records during archive recovery. That shouldn't happen in a - * correctly configured server, but you can induce it by temporarily - * disabling archiving and restarting, so it's good to at least get a - * warning of silent data loss in such cases. These records serve no - * other purpose and are simply ignored during crash recovery. + * Check if any of the GUC parameters that are critical for hot standby + * have changed, and update the value in pg_control file if necessary. */ -void -XLogReportUnloggedStatement(char *reason) +static void +XLogReportParameters(void) { - XLogRecData rdata; + if (wal_level != ControlFile->wal_level || + MaxConnections != ControlFile->MaxConnections || + max_prepared_xacts != ControlFile->max_prepared_xacts || + max_locks_per_xact != max_locks_per_xact) + { + /* + * The change in number of backend slots doesn't need to be + * WAL-logged if archiving is not enabled, as you can't start + * archive recovery with wal_level='minimal' anyway. We don't + * really care about the values in pg_control either if + * wal_level='minimal', but seems better to keep them up-to-date + * to avoid confusion. + */ + if (wal_level != ControlFile->wal_level || XLogIsNeeded()) + { + XLogRecData rdata; + xl_parameter_change xlrec; - rdata.buffer = InvalidBuffer; - rdata.data = reason; - rdata.len = strlen(reason) + 1; - rdata.next = NULL; + xlrec.MaxConnections = MaxConnections; + xlrec.max_prepared_xacts = max_prepared_xacts; + xlrec.max_locks_per_xact = max_locks_per_xact; + xlrec.wal_level = wal_level; + + rdata.buffer = InvalidBuffer; + rdata.data = (char *) &xlrec; + rdata.len = sizeof(xlrec); + rdata.next = NULL; + + XLogInsert(RM_XLOG_ID, XLOG_PARAMETER_CHANGE, &rdata); + } - XLogInsert(RM_XLOG_ID, XLOG_UNLOGGED, &rdata); + ControlFile->MaxConnections = MaxConnections; + ControlFile->max_prepared_xacts = max_prepared_xacts; + ControlFile->max_locks_per_xact = max_locks_per_xact; + ControlFile->wal_level = wal_level; + UpdateControlFile(); + } } /* @@ -7709,10 +7777,6 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record) checkPoint.nextMultiOffset); SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB); - /* Check to see if any changes to max_connections give problems */ - if (standbyState != STANDBY_DISABLED) - CheckRequiredParameterValues(checkPoint); - /* * If we see a shutdown checkpoint while waiting for an * end-of-backup record, the backup was cancelled and the @@ -7844,18 +7908,21 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record) LWLockRelease(ControlFileLock); } } - else if (info == XLOG_UNLOGGED) + else if (info == XLOG_PARAMETER_CHANGE) { - if (InArchiveRecovery) - { - /* - * Note: We don't print the reason string from the record, because - * that gets added as a line using xlog_desc() - */ - ereport(WARNING, - (errmsg("unlogged operation performed, data may be missing"), - errhint("This can happen if you temporarily disable archive_mode without taking a new base backup."))); - } + xl_parameter_change xlrec; + + /* Update our copy of the parameters in pg_control */ + memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_parameter_change)); + + ControlFile->MaxConnections = xlrec.MaxConnections; + ControlFile->max_prepared_xacts = xlrec.max_prepared_xacts; + ControlFile->max_locks_per_xact = xlrec.max_locks_per_xact; + ControlFile->wal_level = xlrec.wal_level; + UpdateControlFile(); + + /* Check to see if any changes to max_connections give problems */ + CheckRequiredParameterValues(); } } @@ -7906,11 +7973,30 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec) appendStringInfo(buf, "backup end: %X/%X", startpoint.xlogid, startpoint.xrecoff); } - else if (info == XLOG_UNLOGGED) + else if (info == XLOG_PARAMETER_CHANGE) { - char *reason = rec; + xl_parameter_change xlrec; + const char *wal_level_str; + const struct config_enum_entry *entry; + + memcpy(&xlrec, rec, sizeof(xl_parameter_change)); + + /* Find a string representation for wal_level */ + wal_level_str = "?"; + for (entry = wal_level_options; entry->name; entry++) + { + if (entry->val == xlrec.wal_level) + { + wal_level_str = entry->name; + break; + } + } - appendStringInfo(buf, "unlogged operation: %s", reason); + appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s", + xlrec.MaxConnections, + xlrec.max_prepared_xacts, + xlrec.max_locks_per_xact, + wal_level_str); } else appendStringInfo(buf, "UNKNOWN"); |