diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index e8f093d4f01..770bec6df55 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -1,5 +1,5 @@ Backup and Restore @@ -1084,11 +1084,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 466c3f5dd18..8ce08bcdec3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -4155,7 +4155,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); @@ -4330,7 +4331,7 @@ StartupXLOG(void) XLogCtlInsert *Insert; CheckPoint checkPoint; bool wasShutdown; - bool needNewTimeLine = false; + bool reachedStopPoint = false; XLogRecPtr RecPtr, LastRec, checkPointLoc, @@ -4598,7 +4599,7 @@ StartupXLOG(void) */ if (recoveryStopsHere(record, &recoveryApply)) { - needNewTimeLine = true; /* see below */ + reachedStopPoint = true; /* see below */ recoveryContinue = false; if (!recoveryApply) break; @@ -4653,11 +4654,10 @@ StartupXLOG(void) */ 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"))); } @@ -4665,12 +4665,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,