1 /*-------------------------------------------------------------------------
4 * Functions for reading and writing timeline history files.
6 * A timeline history file lists the timeline changes of the timeline, in
7 * a simple text format. They are archived along with the WAL segments.
9 * The files are named like "<tli>.history". For example, if the database
10 * starts up and switches to timeline 5, the timeline history file would be
11 * called "00000005.history".
13 * Each line in the file represents a timeline switch:
15 * <parentTLI> <switchpoint> <reason>
17 * parentTLI ID of the parent timeline
18 * switchpoint XLogRecPtr of the WAL position where the switch happened
19 * reason human-readable explanation of why the timeline was changed
21 * The fields are separated by tabs. Lines beginning with # are comments, and
22 * are ignored. Empty lines are also ignored.
24 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
25 * Portions Copyright (c) 1994, Regents of the University of California
27 * src/backend/access/transam/timeline.c
29 *-------------------------------------------------------------------------
38 #include "access/timeline.h"
39 #include "access/xlog.h"
40 #include "access/xlog_internal.h"
41 #include "access/xlogdefs.h"
42 #include "storage/fd.h"
45 * Copies all timeline history files with id's between 'begin' and 'end'
46 * from archive to pg_xlog.
49 restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
52 char histfname[MAXFNAMELEN];
55 for (tli = begin; tli < end; tli++)
60 TLHistoryFileName(histfname, tli);
61 if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
62 KeepFileRestoredFromArchive(path, histfname);
67 * Try to read a timeline's history file.
69 * If successful, return the list of component TLIs (the given TLI followed by
70 * its ancestor TLIs). If we can't find the history file, assume that the
71 * timeline has no parents, and return a list of just the specified timeline
75 readTimeLineHistory(TimeLineID targetTLI)
79 char histfname[MAXFNAMELEN];
80 char fline[MAXPGPATH];
82 TimeLineHistoryEntry *entry;
83 TimeLineID lasttli = 0;
85 bool fromArchive = false;
87 /* Timeline 1 does not have a history file, so no need to check */
90 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
91 entry->tli = targetTLI;
92 entry->begin = entry->end = InvalidXLogRecPtr;
93 return list_make1(entry);
96 if (ArchiveRecoveryRequested)
98 TLHistoryFileName(histfname, targetTLI);
100 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
103 TLHistoryFilePath(path, targetTLI);
105 fd = AllocateFile(path, "r");
110 (errcode_for_file_access(),
111 errmsg("could not open file \"%s\": %m", path)));
112 /* Not there, so assume no parents */
113 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
114 entry->tli = targetTLI;
115 entry->begin = entry->end = InvalidXLogRecPtr;
116 return list_make1(entry);
124 prevend = InvalidXLogRecPtr;
125 while (fgets(fline, sizeof(fline), fd) != NULL)
127 /* skip leading whitespace and check for # comment */
130 uint32 switchpoint_hi;
131 uint32 switchpoint_lo;
134 for (ptr = fline; *ptr; ptr++)
136 if (!isspace((unsigned char) *ptr))
139 if (*ptr == '\0' || *ptr == '#')
142 nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
146 /* expect a numeric timeline ID as first field of line */
148 (errmsg("syntax error in history file: %s", fline),
149 errhint("Expected a numeric timeline ID.")));
153 (errmsg("syntax error in history file: %s", fline),
154 errhint("Expected a transaction log switchpoint location.")));
156 if (result && tli <= lasttli)
158 (errmsg("invalid data in history file: %s", fline),
159 errhint("Timeline IDs must be in increasing sequence.")));
163 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
165 entry->begin = prevend;
166 entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
167 prevend = entry->end;
169 /* Build list with newest item first */
170 result = lcons(entry, result);
172 /* we ignore the remainder of each line */
177 if (result && targetTLI <= lasttli)
179 (errmsg("invalid data in history file \"%s\"", path),
180 errhint("Timeline IDs must be less than child timeline's ID.")));
183 * Create one more entry for the "tip" of the timeline, which has no entry
184 * in the history file.
186 entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
187 entry->tli = targetTLI;
188 entry->begin = prevend;
189 entry->end = InvalidXLogRecPtr;
191 result = lcons(entry, result);
194 * If the history file was fetched from archive, save it in pg_xlog for
198 KeepFileRestoredFromArchive(path, histfname);
204 * Probe whether a timeline history file exists for the given timeline ID
207 existsTimeLineHistory(TimeLineID probeTLI)
209 char path[MAXPGPATH];
210 char histfname[MAXFNAMELEN];
213 /* Timeline 1 does not have a history file, so no need to check */
217 if (ArchiveRecoveryRequested)
219 TLHistoryFileName(histfname, probeTLI);
220 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
223 TLHistoryFilePath(path, probeTLI);
225 fd = AllocateFile(path, "r");
235 (errcode_for_file_access(),
236 errmsg("could not open file \"%s\": %m", path)));
242 * Find the newest existing timeline, assuming that startTLI exists.
244 * Note: while this is somewhat heuristic, it does positively guarantee
245 * that (result + 1) is not a known timeline, and therefore it should
246 * be safe to assign that ID to a new timeline.
249 findNewestTimeLine(TimeLineID startTLI)
251 TimeLineID newestTLI;
255 * The algorithm is just to probe for the existence of timeline history
256 * files. XXX is it useful to allow gaps in the sequence?
258 newestTLI = startTLI;
260 for (probeTLI = startTLI + 1;; probeTLI++)
262 if (existsTimeLineHistory(probeTLI))
264 newestTLI = probeTLI; /* probeTLI exists */
268 /* doesn't exist, assume we're done */
277 * Create a new timeline history file.
279 * newTLI: ID of the new timeline
280 * parentTLI: ID of its immediate parent
281 * switchpoint: XLOG position where the system switched to the new timeline
282 * reason: human-readable explanation of why the timeline was switched
284 * Currently this is only used at the end recovery, and so there are no locking
285 * considerations. But we should be just as tense as XLogFileInit to avoid
286 * emplacing a bogus file.
289 writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
290 XLogRecPtr switchpoint, char *reason)
292 char path[MAXPGPATH];
293 char tmppath[MAXPGPATH];
294 char histfname[MAXFNAMELEN];
300 Assert(newTLI > parentTLI); /* else bad selection of newTLI */
303 * Write into a temp file name.
305 snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
309 /* do not use get_sync_bit() here --- want to fsync only at end of fill */
310 fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
314 (errcode_for_file_access(),
315 errmsg("could not create file \"%s\": %m", tmppath)));
318 * If a history file exists for the parent, copy it verbatim
320 if (ArchiveRecoveryRequested)
322 TLHistoryFileName(histfname, parentTLI);
323 RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
326 TLHistoryFilePath(path, parentTLI);
328 srcfd = OpenTransientFile(path, O_RDONLY, 0);
333 (errcode_for_file_access(),
334 errmsg("could not open file \"%s\": %m", path)));
335 /* Not there, so assume parent has no parents */
342 nbytes = (int) read(srcfd, buffer, sizeof(buffer));
343 if (nbytes < 0 || errno != 0)
345 (errcode_for_file_access(),
346 errmsg("could not read file \"%s\": %m", path)));
350 if ((int) write(fd, buffer, nbytes) != nbytes)
352 int save_errno = errno;
355 * If we fail to make the file, delete it to release disk
361 * if write didn't set errno, assume problem is no disk space
363 errno = save_errno ? save_errno : ENOSPC;
366 (errcode_for_file_access(),
367 errmsg("could not write to file \"%s\": %m", tmppath)));
370 CloseTransientFile(srcfd);
374 * Append one line with the details of this timeline split.
376 * If we did have a parent file, insert an extra newline just in case the
377 * parent file failed to end with one.
379 snprintf(buffer, sizeof(buffer),
381 (srcfd < 0) ? "" : "\n",
383 (uint32) (switchpoint >> 32), (uint32) (switchpoint),
386 nbytes = strlen(buffer);
388 if ((int) write(fd, buffer, nbytes) != nbytes)
390 int save_errno = errno;
393 * If we fail to make the file, delete it to release disk space
396 /* if write didn't set errno, assume problem is no disk space */
397 errno = save_errno ? save_errno : ENOSPC;
400 (errcode_for_file_access(),
401 errmsg("could not write to file \"%s\": %m", tmppath)));
404 if (pg_fsync(fd) != 0)
406 (errcode_for_file_access(),
407 errmsg("could not fsync file \"%s\": %m", tmppath)));
409 if (CloseTransientFile(fd))
411 (errcode_for_file_access(),
412 errmsg("could not close file \"%s\": %m", tmppath)));
416 * Now move the completed history file into place with its final name.
418 TLHistoryFilePath(path, newTLI);
421 * Prefer link() to rename() here just to be really sure that we don't
422 * overwrite an existing file. However, there shouldn't be one, so
423 * rename() is an acceptable substitute except for the truly paranoid.
425 #if HAVE_WORKING_LINK
426 if (link(tmppath, path) < 0)
428 (errcode_for_file_access(),
429 errmsg("could not link file \"%s\" to \"%s\": %m",
433 if (rename(tmppath, path) < 0)
435 (errcode_for_file_access(),
436 errmsg("could not rename file \"%s\" to \"%s\": %m",
440 /* The history file can be archived immediately. */
441 if (XLogArchivingActive())
443 TLHistoryFileName(histfname, newTLI);
444 XLogArchiveNotify(histfname);
449 * Writes a history file for given timeline and contents.
451 * Currently this is only used in the walreceiver process, and so there are
452 * no locking considerations. But we should be just as tense as XLogFileInit
453 * to avoid emplacing a bogus file.
456 writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
458 char path[MAXPGPATH];
459 char tmppath[MAXPGPATH];
463 * Write into a temp file name.
465 snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
469 /* do not use get_sync_bit() here --- want to fsync only at end of fill */
470 fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
474 (errcode_for_file_access(),
475 errmsg("could not create file \"%s\": %m", tmppath)));
478 if ((int) write(fd, content, size) != size)
480 int save_errno = errno;
483 * If we fail to make the file, delete it to release disk space
486 /* if write didn't set errno, assume problem is no disk space */
487 errno = save_errno ? save_errno : ENOSPC;
490 (errcode_for_file_access(),
491 errmsg("could not write to file \"%s\": %m", tmppath)));
494 if (pg_fsync(fd) != 0)
496 (errcode_for_file_access(),
497 errmsg("could not fsync file \"%s\": %m", tmppath)));
499 if (CloseTransientFile(fd))
501 (errcode_for_file_access(),
502 errmsg("could not close file \"%s\": %m", tmppath)));
506 * Now move the completed history file into place with its final name.
508 TLHistoryFilePath(path, tli);
511 * Prefer link() to rename() here just to be really sure that we don't
512 * overwrite an existing logfile. However, there shouldn't be one, so
513 * rename() is an acceptable substitute except for the truly paranoid.
515 #if HAVE_WORKING_LINK
516 if (link(tmppath, path) < 0)
518 (errcode_for_file_access(),
519 errmsg("could not link file \"%s\" to \"%s\": %m",
523 if (rename(tmppath, path) < 0)
525 (errcode_for_file_access(),
526 errmsg("could not rename file \"%s\" to \"%s\": %m",
532 * Returns true if 'expectedTLEs' contains a timeline with id 'tli'
535 tliInHistory(TimeLineID tli, List *expectedTLEs)
539 foreach(cell, expectedTLEs)
541 if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
549 * Returns the ID of the timeline in use at a particular point in time, in
550 * the given timeline history.
553 tliOfPointInHistory(XLogRecPtr ptr, List *history)
557 foreach(cell, history)
559 TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
561 if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
562 (XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
569 /* shouldn't happen. */
570 elog(ERROR, "timeline history was not contiguous");
571 return 0; /* keep compiler quiet */
575 * Returns the point in history where we branched off the given timeline,
576 * and the timeline we branched to (*nextTLI). Returns InvalidXLogRecPtr if
577 * the timeline is current, ie. we have not branched off from it, and throws
578 * an error if the timeline is not part of this server's history.
581 tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
587 foreach(cell, history)
589 TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
598 (errmsg("requested timeline %u is not in this server's history",
600 return InvalidXLogRecPtr; /* keep compiler quiet */