1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

Introduce wal_level GUC to explicitly control if information needed for

archival or hot standby should be WAL-logged, instead of deducing that from
other options like archive_mode. This replaces recovery_connections GUC in
the primary, where it now has no effect, but it's still used in the standby
to enable/disable hot standby.

Remove the WAL-logging of "unlogged operations", like creating an index
without WAL-logging and fsyncing it at the end. Instead, we keep a copy of
the wal_mode setting and the settings that affect how much shared memory a
hot standby server needs to track master transactions (max_connections,
max_prepared_xacts, max_locks_per_xact) in pg_control. Whenever the settings
change, at server restart, write a WAL record noting the new settings and
update pg_control. This allows us to notice the change in those settings in
the standby at the right moment, they used to be included in checkpoint
records, but that meant that a changed value was not reflected in the
standby until the first checkpoint after the change.

Bump PG_CONTROL_VERSION and XLOG_PAGE_MAGIC. Whack XLOG_PAGE_MAGIC back to
the sequence it used to follow, before hot standby and subsequent patches
changed it to 0x9003.
This commit is contained in:
Heikki Linnakangas
2010-04-28 16:10:43 +00:00
parent a2de4826e9
commit 9b8a73326e
22 changed files with 340 additions and 224 deletions

View File

@@ -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
@@ -500,6 +508,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.
*/
@@ -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")));
@@ -6400,6 +6446,13 @@ StartupXLOG(void)
readRecordBufSize = 0;
}
/*
* 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
@@ -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;
XLogInsert(RM_XLOG_ID, XLOG_UNLOGGED, &rdata);
rdata.buffer = InvalidBuffer;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.next = NULL;
XLogInsert(RM_XLOG_ID, XLOG_PARAMETER_CHANGE, &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;
appendStringInfo(buf, "unlogged operation: %s", reason);
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, "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");