* restart needs to be forced.)
*
*
- * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.51 2008/08/11 11:05:11 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.59 2009/06/04 18:33:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <unistd.h>
#include "access/xlog_internal.h"
+#include "catalog/pg_control.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
-#include "storage/freespace.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/pmsignal.h"
ExitOnAnyError = true;
/* Close down the database */
ShutdownXLOG(0, 0);
- DumpFreeSpaceMap(0, 0);
/* Normal exit from the bgwriter is here */
proc_exit(0); /* done */
}
*/
if (do_checkpoint)
{
+ bool ckpt_performed = false;
+ bool do_restartpoint;
+
/* use volatile pointer to prevent code rearrangement */
volatile BgWriterShmemStruct *bgs = BgWriterShmem;
+ /*
+ * Check if we should perform a checkpoint or a restartpoint.
+ * As a side-effect, RecoveryInProgress() initializes
+ * TimeLineID if it's not set yet.
+ */
+ do_restartpoint = RecoveryInProgress();
+
/*
* Atomically fetch the request flags to figure out what kind of a
* checkpoint we should perform, and increase the started-counter
* implementation will not generate warnings caused by
* CheckPointTimeout < CheckPointWarning.
*/
- if ((flags & CHECKPOINT_CAUSE_XLOG) &&
+ if (!do_restartpoint &&
+ (flags & CHECKPOINT_CAUSE_XLOG) &&
elapsed_secs < CheckPointWarning)
ereport(LOG,
- (errmsg("checkpoints are occurring too frequently (%d seconds apart)",
- elapsed_secs),
+ (errmsg_plural("checkpoints are occurring too frequently (%d second apart)",
+ "checkpoints are occurring too frequently (%d seconds apart)",
+ elapsed_secs,
+ elapsed_secs),
errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
/*
* Initialize bgwriter-private variables used during checkpoint.
*/
ckpt_active = true;
- ckpt_start_recptr = GetInsertRecPtr();
+ if (!do_restartpoint)
+ ckpt_start_recptr = GetInsertRecPtr();
ckpt_start_time = now;
ckpt_cached_elapsed = 0;
/*
* Do the checkpoint.
*/
- CreateCheckPoint(flags);
+ if (!do_restartpoint)
+ {
+ CreateCheckPoint(flags);
+ ckpt_performed = true;
+ }
+ else
+ ckpt_performed = CreateRestartPoint(flags);
/*
* After any checkpoint, close all smgr files. This is so we
bgs->ckpt_done = bgs->ckpt_started;
SpinLockRelease(&bgs->ckpt_lck);
- ckpt_active = false;
+ if (ckpt_performed)
+ {
+ /*
+ * Note we record the checkpoint start time not end time as
+ * last_checkpoint_time. This is so that time-driven
+ * checkpoints happen at a predictable spacing.
+ */
+ last_checkpoint_time = now;
+ }
+ else
+ {
+ /*
+ * We were not able to perform the restartpoint (checkpoints
+ * throw an ERROR in case of error). Most likely because we
+ * have not received any new checkpoint WAL records since the
+ * last restartpoint. Try again in 15 s.
+ */
+ last_checkpoint_time = now - CheckPointTimeout + 15;
+ }
- /*
- * Note we record the checkpoint start time not end time as
- * last_checkpoint_time. This is so that time-driven checkpoints
- * happen at a predictable spacing.
- */
- last_checkpoint_time = now;
+ ckpt_active = false;
}
else
BgBufferSync();
pg_time_t now;
pg_time_t last_time;
- if (XLogArchiveTimeout <= 0)
+ if (XLogArchiveTimeout <= 0 || RecoveryInProgress())
return;
now = (pg_time_t) time(NULL);
* However, it's good enough for our purposes, we're only calculating an
* estimate anyway.
*/
- recptr = GetInsertRecPtr();
- elapsed_xlogs =
- (((double) (int32) (recptr.xlogid - ckpt_start_recptr.xlogid)) * XLogSegsPerFile +
- ((double) recptr.xrecoff - (double) ckpt_start_recptr.xrecoff) / XLogSegSize) /
- CheckPointSegments;
-
- if (progress < elapsed_xlogs)
+ if (!RecoveryInProgress())
{
- ckpt_cached_elapsed = elapsed_xlogs;
- return false;
+ recptr = GetInsertRecPtr();
+ elapsed_xlogs =
+ (((double) (int32) (recptr.xlogid - ckpt_start_recptr.xlogid)) * XLogSegsPerFile +
+ ((double) recptr.xrecoff - (double) ckpt_start_recptr.xrecoff) / XLogSegSize) /
+ CheckPointSegments;
+
+ if (progress < elapsed_xlogs)
+ {
+ ckpt_cached_elapsed = elapsed_xlogs;
+ return false;
+ }
}
/*
PG_SETMASK(&BlockSig);
/*
- * DO NOT proc_exit() -- we're here because shared memory may be
- * corrupted, so we don't want to try to clean up our transaction. Just
- * nail the windows shut and get out of town.
- *
+ * We DO NOT want to run proc_exit() callbacks -- we're here because
+ * shared memory may be corrupted, so we don't want to try to clean up our
+ * transaction. Just nail the windows shut and get out of town. Now that
+ * there's an atexit callback to prevent third-party code from breaking
+ * things by calling exit() directly, we have to reset the callbacks
+ * explicitly to make this work as intended.
+ */
+ on_exit_reset();
+
+ /*
* Note we do exit(2) not exit(0). This is to force the postmaster into a
* system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
* backend. This is necessary precisely because we don't clean up our
- * shared memory state.
+ * shared memory state. (The "dead man switch" mechanism in pmsignal.c
+ * should ensure the postmaster sees this as a crash, too, but no harm
+ * in being doubly sure.)
*/
exit(2);
}
{
/* use volatile pointer to prevent code rearrangement */
volatile BgWriterShmemStruct *bgs = BgWriterShmem;
+ int ntries;
int old_failed,
old_started;
SpinLockRelease(&bgs->ckpt_lck);
/*
- * Send signal to request checkpoint. When not waiting, we consider
- * failure to send the signal to be nonfatal.
+ * Send signal to request checkpoint. It's possible that the bgwriter
+ * hasn't started yet, or is in process of restarting, so we will retry
+ * a few times if needed. Also, if not told to wait for the checkpoint
+ * to occur, we consider failure to send the signal to be nonfatal and
+ * merely LOG it.
*/
- if (BgWriterShmem->bgwriter_pid == 0)
- elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG,
- "could not request checkpoint because bgwriter not running");
- if (kill(BgWriterShmem->bgwriter_pid, SIGINT) != 0)
- elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG,
- "could not signal for checkpoint: %m");
+ for (ntries = 0; ; ntries++)
+ {
+ if (BgWriterShmem->bgwriter_pid == 0)
+ {
+ if (ntries >= 20) /* max wait 2.0 sec */
+ {
+ elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG,
+ "could not request checkpoint because bgwriter not running");
+ break;
+ }
+ }
+ else if (kill(BgWriterShmem->bgwriter_pid, SIGINT) != 0)
+ {
+ if (ntries >= 20) /* max wait 2.0 sec */
+ {
+ elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG,
+ "could not signal for checkpoint: %m");
+ break;
+ }
+ }
+ else
+ break; /* signal sent successfully */
+
+ CHECK_FOR_INTERRUPTS();
+ pg_usleep(100000L); /* wait 0.1 sec, then retry */
+ }
/*
* If requested, wait for completion. We detect completion according to
}
request = &BgWriterShmem->requests[BgWriterShmem->num_requests++];
request->rnode = rnode;
+ request->forknum = forknum;
request->segno = segno;
LWLockRelease(BgWriterCommLock);
return true;