1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Implement archive_timeout feature to force xlog file switches to occur no more

than N seconds apart.  This allows a simple, if not very high performance,
means of guaranteeing that a PITR archive is no more than N seconds behind
real time.  Also make pg_current_xlog_location return the WAL Write pointer,
add pg_current_xlog_insert_location to return the Insert pointer, and fix
pg_xlogfile_name_offset to return its results as a two-element record instead
of a smashed-together string, as per recent discussion.

Simon Riggs
This commit is contained in:
Tom Lane
2006-08-17 23:04:10 +00:00
parent bb764e94ce
commit e8ea9e9587
11 changed files with 279 additions and 74 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.247 2006/08/07 16:57:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.248 2006/08/17 23:04:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,6 +23,7 @@
#include <sys/time.h>
#include "access/clog.h"
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/subtrans.h"
#include "access/transam.h"
@ -32,6 +33,8 @@
#include "access/xlogutils.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
@ -128,6 +131,7 @@
/* User-settable parameters */
int CheckPointSegments = 3;
int XLOGbuffers = 8;
int XLogArchiveTimeout = 0;
char *XLogArchiveCommand = NULL;
char *XLOG_sync_method = NULL;
const char XLOG_sync_method_default[] = DEFAULT_SYNC_METHOD_STR;
@ -347,8 +351,9 @@ typedef struct XLogCtlInsert
*/
typedef struct XLogCtlWrite
{
XLogwrtResult LogwrtResult; /* current value of LogwrtResult */
int curridx; /* cache index of next block to write */
XLogwrtResult LogwrtResult; /* current value of LogwrtResult */
int curridx; /* cache index of next block to write */
time_t lastSegSwitchTime; /* time of last xlog segment switch */
} XLogCtlWrite;
/*
@ -1660,7 +1665,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
* switch.
*
* This is also the right place to notify the Archiver that the
* segment is ready to copy to archival storage.
* segment is ready to copy to archival storage, and to update
* the timer for archive_timeout.
*/
if (finishing_seg || (xlog_switch && last_iteration))
{
@ -1669,6 +1675,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
if (XLogArchivingActive())
XLogArchiveNotifySeg(openLogId, openLogSeg);
Write->lastSegSwitchTime = time(NULL);
}
}
@ -5124,6 +5132,9 @@ StartupXLOG(void)
ControlFile->time = time(NULL);
UpdateControlFile();
/* start the archive_timeout timer running */
XLogCtl->Write.lastSegSwitchTime = ControlFile->time;
/* Start up the commit log and related stuff, too */
StartupCLOG();
StartupSUBTRANS(oldestActiveXID);
@ -5307,6 +5318,22 @@ GetRedoRecPtr(void)
return RedoRecPtr;
}
/*
* Get the time of the last xlog segment switch
*/
time_t
GetLastSegSwitchTime(void)
{
time_t result;
/* Need WALWriteLock, but shared lock is sufficient */
LWLockAcquire(WALWriteLock, LW_SHARED);
result = XLogCtl->Write.lastSegSwitchTime;
LWLockRelease(WALWriteLock);
return result;
}
/*
* GetRecentNextXid - get the nextXid value saved by the most recent checkpoint
*
@ -5728,7 +5755,7 @@ XLogPutNextOid(Oid nextOid)
* or the end+1 address of the prior segment if we did not need to
* write a switch record because we are already at segment start.
*/
static XLogRecPtr
XLogRecPtr
RequestXLogSwitch(void)
{
XLogRecPtr RecPtr;
@ -6335,10 +6362,43 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
}
/*
* Report the current WAL location (same format as pg_start_backup etc)
* Report the current WAL write location (same format as pg_start_backup etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
* to the kernel, but is not necessarily synced to disk.
*/
Datum
pg_current_xlog_location(PG_FUNCTION_ARGS)
{
text *result;
char location[MAXFNAMELEN];
/* Make sure we have an up-to-date local LogwrtResult */
{
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
SpinLockAcquire(&xlogctl->info_lck);
LogwrtResult = xlogctl->LogwrtResult;
SpinLockRelease(&xlogctl->info_lck);
}
snprintf(location, sizeof(location), "%X/%X",
LogwrtResult.Write.xlogid, LogwrtResult.Write.xrecoff);
result = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(location)));
PG_RETURN_TEXT_P(result);
}
/*
* Report the current WAL insert location (same format as pg_start_backup etc)
*
* This function is mostly for debugging purposes.
*/
Datum
pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
{
text *result;
XLogCtlInsert *Insert = &XLogCtl->Insert;
@ -6372,7 +6432,6 @@ Datum
pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
{
text *location = PG_GETARG_TEXT_P(0);
text *result;
char *locationstr;
unsigned int uxlogid;
unsigned int uxrecoff;
@ -6381,7 +6440,15 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
uint32 xrecoff;
XLogRecPtr locationpoint;
char xlogfilename[MAXFNAMELEN];
Datum values[2];
bool isnull[2];
TupleDesc resultTupleDesc;
HeapTuple resultHeapTuple;
Datum result;
/*
* Read input and parse
*/
locationstr = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(location)));
@ -6394,18 +6461,44 @@ pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
locationpoint.xlogid = uxlogid;
locationpoint.xrecoff = uxrecoff;
/*
* Construct a tuple descriptor for the result row. This must match
* this function's pg_proc entry!
*/
resultTupleDesc = CreateTemplateTupleDesc(2, false);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
TEXTOID, -1, 0);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
INT4OID, -1, 0);
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
/*
* xlogfilename
*/
XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize;
snprintf(xlogfilename + strlen(xlogfilename),
sizeof(xlogfilename) - strlen(xlogfilename),
" %u",
(unsigned int) xrecoff);
values[0] = DirectFunctionCall1(textin,
CStringGetDatum(xlogfilename));
isnull[0] = false;
result = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(xlogfilename)));
PG_RETURN_TEXT_P(result);
/*
* offset
*/
xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize;
values[1] = UInt32GetDatum(xrecoff);
isnull[1] = false;
/*
* Tuple jam: Having first prepared your Datums, then squash together
*/
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
result = HeapTupleGetDatum(resultHeapTuple);
PG_RETURN_DATUM(result);
}
/*

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.26 2006/07/14 14:52:22 momjian Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.27 2006/08/17 23:04:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,6 +46,7 @@
#include <signal.h>
#include <time.h>
#include "access/xlog_internal.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "postmaster/bgwriter.h"
@ -144,6 +145,7 @@ static bool am_bg_writer = false;
static bool ckpt_active = false;
static time_t last_checkpoint_time;
static time_t last_xlog_switch_time;
static void bg_quickdie(SIGNAL_ARGS);
@ -205,10 +207,10 @@ BackgroundWriterMain(void)
#endif
/*
* Initialize so that first time-driven checkpoint happens at the correct
* Initialize so that first time-driven event happens at the correct
* time.
*/
last_checkpoint_time = time(NULL);
last_checkpoint_time = last_xlog_switch_time = time(NULL);
/*
* Create a resource owner to keep track of our resources (currently
@ -403,6 +405,49 @@ BackgroundWriterMain(void)
else
BgBufferSync();
/*
* Check for archive_timeout, if so, switch xlog files. First
* we do a quick check using possibly-stale local state.
*/
if (XLogArchiveTimeout > 0 &&
(int) (now - last_xlog_switch_time) >= XLogArchiveTimeout)
{
/*
* Update local state ... note that last_xlog_switch_time is
* the last time a switch was performed *or requested*.
*/
time_t last_time = GetLastSegSwitchTime();
last_xlog_switch_time = Max(last_xlog_switch_time, last_time);
/* if we did a checkpoint, 'now' might be stale too */
if (do_checkpoint)
now = time(NULL);
/* Now we can do the real check */
if ((int) (now - last_xlog_switch_time) >= XLogArchiveTimeout)
{
XLogRecPtr switchpoint;
/* OK, it's time to switch */
switchpoint = RequestXLogSwitch();
/*
* If the returned pointer points exactly to a segment
* boundary, assume nothing happened.
*/
if ((switchpoint.xrecoff % XLogSegSize) != 0)
ereport(DEBUG1,
(errmsg("xlog switch forced (archive_timeout=%d)",
XLogArchiveTimeout)));
/*
* Update state in any case, so we don't retry constantly
* when the system is idle.
*/
last_xlog_switch_time = now;
}
}
/*
* Nap for the configured time, or sleep for 10 seconds if there is no
* bgwriter activity configured.
@ -417,9 +462,12 @@ BackgroundWriterMain(void)
if ((bgwriter_all_percent > 0.0 && bgwriter_all_maxpages > 0) ||
(bgwriter_lru_percent > 0.0 && bgwriter_lru_maxpages > 0))
udelay = BgWriterDelay * 1000L;
else if (XLogArchiveTimeout > 0)
udelay = 1000000L; /* One second */
else
udelay = 10000000L;
while (udelay > 1000000L)
udelay = 10000000L; /* Ten seconds */
while (udelay > 999999L)
{
if (got_SIGHUP || checkpoint_requested || shutdown_requested)
break;
@ -427,6 +475,7 @@ BackgroundWriterMain(void)
AbsorbFsyncRequests();
udelay -= 1000000L;
}
if (!(got_SIGHUP || checkpoint_requested || shutdown_requested))
pg_usleep(udelay);
}

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.342 2006/08/15 18:26:59 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.343 2006/08/17 23:04:06 tgl Exp $
*
*--------------------------------------------------------------------
*/
@ -1001,7 +1001,7 @@ static struct config_bool ConfigureNamesBool[] =
{
{"ignore_system_indexes", PGC_BACKEND, DEVELOPER_OPTIONS,
gettext_noop("Disabled reading from system indexes."),
gettext_noop("Disables reading from system indexes."),
gettext_noop("It does not prevent updating the indexes, so it is safe "
"to use. The worst consequence is slowness."),
GUC_NOT_IN_SAMPLE
@ -1019,6 +1019,16 @@ static struct config_bool ConfigureNamesBool[] =
static struct config_int ConfigureNamesInt[] =
{
{
{"archive_timeout", PGC_SIGHUP, WAL_SETTINGS,
gettext_noop("Forces a switch to the next xlog file if a "
"new file has not been started within N seconds."),
NULL,
GUC_UNIT_S
},
&XLogArchiveTimeout,
0, 0, INT_MAX, NULL, NULL
},
{
{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
gettext_noop("Waits N seconds on connection startup after authentication."),

View File

@ -167,8 +167,9 @@
# - Archiving -
#archive_command = '' # command to use to archive a logfile
# segment
#archive_command = '' # command to use to archive a logfile segment
#archive_timeout = 0 # force a logfile segment switch after this
# many seconds; 0 is off
#---------------------------------------------------------------------------

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.72 2006/07/13 16:49:19 momjian Exp $
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.73 2006/08/17 23:04:08 tgl Exp $
*/
#ifndef XLOG_H
#define XLOG_H
@ -139,6 +139,7 @@ extern XLogRecPtr ProcLastRecEnd;
extern int CheckPointSegments;
extern int XLOGbuffers;
extern char *XLogArchiveCommand;
extern int XLogArchiveTimeout;
extern char *XLOG_sync_method;
extern const char XLOG_sync_method_default[];

View File

@ -11,11 +11,13 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.15 2006/08/07 16:57:57 tgl Exp $
* $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.16 2006/08/17 23:04:08 tgl Exp $
*/
#ifndef XLOG_INTERNAL_H
#define XLOG_INTERNAL_H
#include <time.h>
#include "access/xlog.h"
#include "fmgr.h"
#include "storage/block.h"
@ -237,6 +239,12 @@ typedef struct RmgrData
extern const RmgrData RmgrTable[];
/*
* Exported to support xlog switching from bgwriter
*/
extern time_t GetLastSegSwitchTime(void);
extern XLogRecPtr RequestXLogSwitch(void);
/*
* These aren't in xlog.h because I'd rather not include fmgr.h there.
*/
@ -244,6 +252,7 @@ extern Datum pg_start_backup(PG_FUNCTION_ARGS);
extern Datum pg_stop_backup(PG_FUNCTION_ARGS);
extern Datum pg_switch_xlog(PG_FUNCTION_ARGS);
extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS);
extern Datum pg_current_xlog_insert_location(PG_FUNCTION_ARGS);
extern Datum pg_xlogfile_name_offset(PG_FUNCTION_ARGS);
extern Datum pg_xlogfile_name(PG_FUNCTION_ARGS);

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.349 2006/08/12 02:52:06 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.350 2006/08/17 23:04:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200608101
#define CATALOG_VERSION_NO 200608171
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.420 2006/08/06 03:53:44 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.421 2006/08/17 23:04:10 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -3104,8 +3104,10 @@ DESCR("Finish taking an online backup");
DATA(insert OID = 2848 ( pg_switch_xlog PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_switch_xlog - _null_ ));
DESCR("Switch to new xlog file");
DATA(insert OID = 2849 ( pg_current_xlog_location PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_location - _null_ ));
DESCR("current xlog location");
DATA(insert OID = 2850 ( pg_xlogfile_name_offset PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ pg_xlogfile_name_offset - _null_ ));
DESCR("current xlog write location");
DATA(insert OID = 2852 ( pg_current_xlog_insert_location PGNSP PGUID 12 f f t f v 0 25 "" _null_ _null_ _null_ pg_current_xlog_insert_location - _null_ ));
DESCR("current xlog insert location");
DATA(insert OID = 2850 ( pg_xlogfile_name_offset PGNSP PGUID 12 f f t f i 1 2249 "25" "{25,25,23}" "{i,o,o}" "{wal_location,file_name,file_offset}" pg_xlogfile_name_offset - _null_ ));
DESCR("xlog filename and byte offset, given an xlog location");
DATA(insert OID = 2851 ( pg_xlogfile_name PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ pg_xlogfile_name - _null_ ));
DESCR("xlog filename, given an xlog location");