1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +03:00

Improve logging of checkpoints. Patch by Greg Smith, worked over

by Heikki and a little bit by me.
This commit is contained in:
Tom Lane
2007-06-30 19:12:02 +00:00
parent 2910ccefb4
commit 9fc25c0511
7 changed files with 246 additions and 111 deletions

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.273 2007/06/28 00:02:37 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.274 2007/06/30 19:12:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -66,6 +66,7 @@ char *XLogArchiveCommand = NULL;
char *XLOG_sync_method = NULL;
const char XLOG_sync_method_default[] = DEFAULT_SYNC_METHOD_STR;
bool fullPageWrites = true;
bool log_checkpoints = false;
#ifdef WAL_DEBUG
bool XLOG_DEBUG = false;
@ -92,6 +93,13 @@ static int open_sync_bit = DEFAULT_SYNC_FLAGBIT;
#define XLOG_SYNC_BIT (enableFsync ? open_sync_bit : 0)
/*
* Statistics for current checkpoint are collected in this global struct.
* Because only the background writer or a stand-alone backend can perform
* checkpoints, this will be unused in normal backends.
*/
CheckpointStatsData CheckpointStats;
/*
* ThisTimeLineID will be same in all backends --- it identifies current
* WAL timeline for the database system.
@ -414,9 +422,8 @@ static int XLogFileRead(uint32 log, uint32 seg, int emode);
static void XLogFileClose(void);
static bool RestoreArchivedFile(char *path, const char *xlogfname,
const char *recovername, off_t expectedSize);
static int PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr,
int *nsegsremoved, int *nsegsrecycled);
static void PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr);
static void CleanupBackupHistory(void);
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, int emode);
static bool ValidXLOGHeader(XLogPageHeader hdr, int emode);
@ -1578,10 +1585,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
Write->lastSegSwitchTime = time(NULL);
/*
* Signal bgwriter to start a checkpoint if it's been too long
* since the last one. (We look at local copy of RedoRecPtr
* which might be a little out of date, but should be close
* enough for this purpose.)
* Signal bgwriter to start a checkpoint if we've consumed too
* much xlog since the last one. (We look at local copy of
* RedoRecPtr which might be a little out of date, but should
* be close enough for this purpose.)
*
* A straight computation of segment number could overflow 32
* bits. Rather than assuming we have working 64-bit
@ -1603,13 +1610,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
new_highbits = openLogId / XLogSegSize;
if (new_highbits != old_highbits ||
new_segno >= old_segno + (uint32) (CheckPointSegments-1))
{
#ifdef WAL_DEBUG
if (XLOG_DEBUG)
elog(LOG, "time for a checkpoint, signaling bgwriter");
#endif
RequestCheckpoint(CHECKPOINT_WARNONTIME);
}
RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
}
}
}
@ -1855,7 +1856,7 @@ XLogFileInit(uint32 log, uint32 seg,
{
char path[MAXPGPATH];
char tmppath[MAXPGPATH];
char zbuffer[XLOG_BLCKSZ];
char *zbuffer;
uint32 installed_log;
uint32 installed_seg;
int max_advance;
@ -1889,6 +1890,8 @@ XLogFileInit(uint32 log, uint32 seg,
* pre-creating an extra log segment. That seems OK, and better than
* holding the lock throughout this lengthy process.
*/
elog(DEBUG2, "creating and filling new WAL file");
snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
unlink(tmppath);
@ -1909,12 +1912,16 @@ XLogFileInit(uint32 log, uint32 seg,
* fsync below) that all the indirect blocks are down on disk. Therefore,
* fdatasync(2) or O_DSYNC will be sufficient to sync future writes to the
* log file.
*
* Note: palloc zbuffer, instead of just using a local char array, to
* ensure it is reasonably well-aligned; this may save a few cycles
* transferring data to the kernel.
*/
MemSet(zbuffer, 0, sizeof(zbuffer));
for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(zbuffer))
zbuffer = (char *) palloc0(XLOG_BLCKSZ);
for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
{
errno = 0;
if ((int) write(fd, zbuffer, sizeof(zbuffer)) != (int) sizeof(zbuffer))
if ((int) write(fd, zbuffer, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
{
int save_errno = errno;
@ -1930,6 +1937,7 @@ XLogFileInit(uint32 log, uint32 seg,
errmsg("could not write to file \"%s\": %m", tmppath)));
}
}
pfree(zbuffer);
if (pg_fsync(fd) != 0)
ereport(ERROR,
@ -1960,6 +1968,8 @@ XLogFileInit(uint32 log, uint32 seg,
unlink(tmppath);
}
elog(DEBUG2, "done creating and filling new WAL file");
/* Set flag to tell caller there was no existent file */
*use_existent = false;
@ -2525,10 +2535,9 @@ RestoreArchivedFile(char *path, const char *xlogfname,
* recycled log segments, but the startup transient is likely to include
* a lot of segment creations by foreground processes, which is not so good.
*/
static int
static void
PreallocXlogFiles(XLogRecPtr endptr)
{
int nsegsadded = 0;
uint32 _logId;
uint32 _logSeg;
int lf;
@ -2543,9 +2552,8 @@ PreallocXlogFiles(XLogRecPtr endptr)
lf = XLogFileInit(_logId, _logSeg, &use_existent, true);
close(lf);
if (!use_existent)
nsegsadded++;
CheckpointStats.ckpt_segs_added++;
}
return nsegsadded;
}
/*
@ -2555,8 +2563,7 @@ PreallocXlogFiles(XLogRecPtr endptr)
* whether we want to recycle rather than delete no-longer-wanted log files.
*/
static void
RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr,
int *nsegsremoved, int *nsegsrecycled)
RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
{
uint32 endlogId;
uint32 endlogSeg;
@ -2566,9 +2573,6 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr,
char lastoff[MAXFNAMELEN];
char path[MAXPGPATH];
*nsegsremoved = 0;
*nsegsrecycled = 0;
/*
* Initialize info about where to try to recycle to. We allow recycling
* segments up to XLOGfileslop segments beyond the current XLOG location.
@ -2617,7 +2621,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr,
ereport(DEBUG2,
(errmsg("recycled transaction log file \"%s\"",
xlde->d_name)));
(*nsegsrecycled)++;
CheckpointStats.ckpt_segs_recycled++;
/* Needn't recheck that slot on future iterations */
if (max_advance > 0)
{
@ -2632,7 +2636,7 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr,
(errmsg("removing transaction log file \"%s\"",
xlde->d_name)));
unlink(path);
(*nsegsremoved)++;
CheckpointStats.ckpt_segs_removed++;
}
XLogArchiveCleanup(xlde->d_name);
@ -5127,7 +5131,7 @@ StartupXLOG(void)
/*
* Preallocate additional log files, if wanted.
*/
(void) PreallocXlogFiles(EndOfLog);
PreallocXlogFiles(EndOfLog);
/*
* Okay, we're officially UP.
@ -5421,6 +5425,57 @@ ShutdownXLOG(int code, Datum arg)
(errmsg("database system is shut down")));
}
/*
* Log start of a checkpoint.
*/
static void
LogCheckpointStart(int flags)
{
elog(LOG, "checkpoint starting:%s%s%s%s%s%s",
(flags & CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
(flags & CHECKPOINT_IMMEDIATE) ? " immediate" : "",
(flags & CHECKPOINT_FORCE) ? " force" : "",
(flags & CHECKPOINT_WAIT) ? " wait" : "",
(flags & CHECKPOINT_CAUSE_XLOG) ? " xlog" : "",
(flags & CHECKPOINT_CAUSE_TIME) ? " time" : "");
}
/*
* Log end of a checkpoint.
*/
static void
LogCheckpointEnd(void)
{
long write_secs, sync_secs, total_secs;
int write_usecs, sync_usecs, total_usecs;
CheckpointStats.ckpt_end_t = GetCurrentTimestamp();
TimestampDifference(CheckpointStats.ckpt_start_t,
CheckpointStats.ckpt_end_t,
&total_secs, &total_usecs);
TimestampDifference(CheckpointStats.ckpt_write_t,
CheckpointStats.ckpt_sync_t,
&write_secs, &write_usecs);
TimestampDifference(CheckpointStats.ckpt_sync_t,
CheckpointStats.ckpt_sync_end_t,
&sync_secs, &sync_usecs);
elog(LOG, "checkpoint complete: wrote %d buffers (%.1f%%); "
"%d transaction log file(s) added, %d removed, %d recycled; "
"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s",
CheckpointStats.ckpt_bufs_written,
(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
CheckpointStats.ckpt_segs_added,
CheckpointStats.ckpt_segs_removed,
CheckpointStats.ckpt_segs_recycled,
write_secs, write_usecs/1000,
sync_secs, sync_usecs/1000,
total_secs, total_usecs/1000);
}
/*
* Perform a checkpoint --- either during shutdown, or on-the-fly
*
@ -5431,7 +5486,7 @@ ShutdownXLOG(int code, Datum arg)
* CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has occured
* since the last one (implied by CHECKPOINT_IS_SHUTDOWN).
*
* Note: flags might contain other bits of interest to RequestCheckpoint.
* Note: flags contains other bits, of interest here only for logging purposes.
* In particular note that this routine is synchronous and does not pay
* attention to CHECKPOINT_WAIT.
*/
@ -5446,9 +5501,6 @@ CreateCheckPoint(int flags)
uint32 freespace;
uint32 _logId;
uint32 _logSeg;
int nsegsadded = 0;
int nsegsremoved = 0;
int nsegsrecycled = 0;
TransactionId *inCommitXids;
int nInCommit;
@ -5460,6 +5512,16 @@ CreateCheckPoint(int flags)
*/
LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
/*
* Prepare to accumulate statistics.
*
* Note: because it is possible for log_checkpoints to change while a
* checkpoint proceeds, we always accumulate stats, even if
* log_checkpoints is currently off.
*/
MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
/*
* Use a critical section to force system panic if we have trouble.
*/
@ -5560,9 +5622,12 @@ CreateCheckPoint(int flags)
*/
LWLockRelease(WALInsertLock);
if (!shutdown)
ereport(DEBUG2,
(errmsg("checkpoint starting")));
/*
* If enabled, log checkpoint start. We postpone this until now
* so as not to log anything if we decided to skip the checkpoint.
*/
if (log_checkpoints)
LogCheckpointStart(flags);
/*
* Before flushing data, we must wait for any transactions that are
@ -5699,8 +5764,7 @@ CreateCheckPoint(int flags)
if (_logId || _logSeg)
{
PrevLogSeg(_logId, _logSeg);
RemoveOldXlogFiles(_logId, _logSeg, recptr,
&nsegsremoved, &nsegsrecycled);
RemoveOldXlogFiles(_logId, _logSeg, recptr);
}
/*
@ -5708,7 +5772,7 @@ CreateCheckPoint(int flags)
* segments, since that may supply some of the needed files.)
*/
if (!shutdown)
nsegsadded = PreallocXlogFiles(recptr);
PreallocXlogFiles(recptr);
/*
* Truncate pg_subtrans if possible. We can throw away all data before
@ -5720,10 +5784,9 @@ CreateCheckPoint(int flags)
if (!InRecovery)
TruncateSUBTRANS(GetOldestXmin(true, false));
if (!shutdown)
ereport(DEBUG2,
(errmsg("checkpoint complete; %d transaction log file(s) added, %d removed, %d recycled",
nsegsadded, nsegsremoved, nsegsrecycled)));
/* All real work is done, but log before releasing lock. */
if (log_checkpoints)
LogCheckpointEnd();
LWLockRelease(CheckpointLock);
}