<!--
-$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.75.2.2 2006/11/04 18:20:40 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.75.2.3 2007/09/29 01:36:29 tgl Exp $
-->
<chapter id="backup">
<title>Backup and Restore</title>
<para>
To deal with these problems, <productname>PostgreSQL</> has a notion
- of <firstterm>timelines</>. Each time you recover to a point-in-time
- earlier than the end of the WAL sequence, a new timeline is created
- to identify the series of WAL records generated after that recovery.
- (If recovery proceeds all the way to the end of WAL, however, we do not
- start a new timeline: we just extend the existing one.) The timeline
+ of <firstterm>timelines</>. Whenever an archive recovery is completed,
+ a new timeline is created to identify the series of WAL records
+ generated after that recovery. The timeline
ID number is part of WAL segment file names, and so a new timeline does
not overwrite the WAL data generated by previous timelines. It is
in fact possible to archive many different timelines. While that might
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.222.2.5 2007/08/04 01:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.222.2.6 2007/09/29 01:36:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* Note that if we are establishing a new timeline, ThisTimeLineID is
* already set to the new value, and so we will create a new file instead
- * of overwriting any existing file.
+ * of overwriting any existing file. (This is, in fact, always the case
+ * at present.)
*/
snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYXLOG");
XLogFilePath(xlogpath, ThisTimeLineID, endLogId, endLogSeg);
XLogCtlInsert *Insert;
CheckPoint checkPoint;
bool wasShutdown;
- bool needNewTimeLine = false;
+ bool reachedStopPoint = false;
XLogRecPtr RecPtr,
LastRec,
checkPointLoc,
*/
if (recoveryStopsHere(record, &recoveryApply))
{
- needNewTimeLine = true; /* see below */
+ reachedStopPoint = true; /* see below */
recoveryContinue = false;
if (!recoveryApply)
break;
*/
if (XLByteLT(EndOfLog, recoveryMinXlogOffset))
{
- if (needNewTimeLine) /* stopped because of stop request */
+ if (reachedStopPoint) /* stopped because of stop request */
ereport(FATAL,
(errmsg("requested recovery stop point is before end time of backup dump")));
- else
- /* ran off end of WAL */
+ else /* ran off end of WAL */
ereport(FATAL,
(errmsg("WAL ends before end time of backup dump")));
}
/*
* Consider whether we need to assign a new timeline ID.
*
- * If we stopped short of the end of WAL during recovery, then we are
- * generating a new timeline and must assign it a unique new ID.
- * Otherwise, we can just extend the timeline we were in when we ran out
- * of WAL.
+ * If we are doing an archive recovery, we always assign a new ID. This
+ * handles a couple of issues. If we stopped short of the end of WAL
+ * during recovery, then we are clearly generating a new timeline and must
+ * assign it a unique new ID. Even if we ran to the end, modifying the
+ * current last segment is problematic because it may result in trying
+ * to overwrite an already-archived copy of that segment, and we encourage
+ * DBAs to make their archive_commands reject that. We can dodge the
+ * problem by making the new active segment have a new timeline ID.
+ *
+ * In a normal crash recovery, we can just extend the timeline we were in.
*/
- if (needNewTimeLine)
+ if (InArchiveRecovery)
{
ThisTimeLineID = findNewestTimeLine(recoveryTargetTLI) + 1;
ereport(LOG,