diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index e34fc0f3a6..5e8549a2c0 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -1,4 +1,4 @@ - + Backup and Restore @@ -1174,11 +1174,9 @@ restore_command = 'copy /mnt/server/archivedir/%f "%p"' # Windows To deal with these problems, PostgreSQL has a notion - of 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 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 diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 4958f36053..f258b7f7f0 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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.282 2007/09/26 22:36:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.283 2007/09/29 01:36:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -4518,7 +4518,8 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) * * 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); @@ -4700,7 +4701,7 @@ StartupXLOG(void) XLogCtlInsert *Insert; CheckPoint checkPoint; bool wasShutdown; - bool needNewTimeLine = false; + bool reachedStopPoint = false; bool haveBackupLabel = false; XLogRecPtr RecPtr, LastRec, @@ -5010,7 +5011,7 @@ StartupXLOG(void) */ if (recoveryStopsHere(record, &recoveryApply)) { - needNewTimeLine = true; /* see below */ + reachedStopPoint = true; /* see below */ recoveryContinue = false; if (!recoveryApply) break; @@ -5078,11 +5079,10 @@ StartupXLOG(void) */ if (XLByteLT(EndOfLog, ControlFile->minRecoveryPoint)) { - 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"))); } @@ -5090,12 +5090,18 @@ StartupXLOG(void) /* * 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,