PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
timeline.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * timeline.c
4  * Functions for reading and writing timeline history files.
5  *
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.
8  *
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".
12  *
13  * Each line in the file represents a timeline switch:
14  *
15  * <parentTLI> <switchpoint> <reason>
16  *
17  * parentTLI ID of the parent timeline
18  * switchpoint XLogRecPtr of the WAL location where the switch happened
19  * reason human-readable explanation of why the timeline was changed
20  *
21  * The fields are separated by tabs. Lines beginning with # are comments, and
22  * are ignored. Empty lines are also ignored.
23  *
24  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
25  * Portions Copyright (c) 1994, Regents of the University of California
26  *
27  * src/backend/access/transam/timeline.c
28  *
29  *-------------------------------------------------------------------------
30  */
31 
32 #include "postgres.h"
33 
34 #include <sys/stat.h>
35 #include <unistd.h>
36 
37 #include "access/timeline.h"
38 #include "access/xlog.h"
39 #include "access/xlog_internal.h"
40 #include "access/xlogdefs.h"
41 #include "pgstat.h"
42 #include "storage/fd.h"
43 
44 /*
45  * Copies all timeline history files with id's between 'begin' and 'end'
46  * from archive to pg_wal.
47  */
48 void
50 {
51  char path[MAXPGPATH];
52  char histfname[MAXFNAMELEN];
53  TimeLineID tli;
54 
55  for (tli = begin; tli < end; tli++)
56  {
57  if (tli == 1)
58  continue;
59 
60  TLHistoryFileName(histfname, tli);
61  if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
62  KeepFileRestoredFromArchive(path, histfname);
63  }
64 }
65 
66 /*
67  * Try to read a timeline's history file.
68  *
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
72  * ID.
73  */
74 List *
76 {
77  List *result;
78  char path[MAXPGPATH];
79  char histfname[MAXFNAMELEN];
80  char fline[MAXPGPATH];
81  FILE *fd;
82  TimeLineHistoryEntry *entry;
83  TimeLineID lasttli = 0;
84  XLogRecPtr prevend;
85  bool fromArchive = false;
86 
87  /* Timeline 1 does not have a history file, so no need to check */
88  if (targetTLI == 1)
89  {
91  entry->tli = targetTLI;
92  entry->begin = entry->end = InvalidXLogRecPtr;
93  return list_make1(entry);
94  }
95 
97  {
98  TLHistoryFileName(histfname, targetTLI);
99  fromArchive =
100  RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
101  }
102  else
103  TLHistoryFilePath(path, targetTLI);
104 
105  fd = AllocateFile(path, "r");
106  if (fd == NULL)
107  {
108  if (errno != ENOENT)
109  ereport(FATAL,
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);
117  }
118 
119  result = NIL;
120 
121  /*
122  * Parse the file...
123  */
124  prevend = InvalidXLogRecPtr;
125  while (fgets(fline, sizeof(fline), fd) != NULL)
126  {
127  /* skip leading whitespace and check for # comment */
128  char *ptr;
129  TimeLineID tli;
130  uint32 switchpoint_hi;
131  uint32 switchpoint_lo;
132  int nfields;
133 
134  for (ptr = fline; *ptr; ptr++)
135  {
136  if (!isspace((unsigned char) *ptr))
137  break;
138  }
139  if (*ptr == '\0' || *ptr == '#')
140  continue;
141 
142  nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
143 
144  if (nfields < 1)
145  {
146  /* expect a numeric timeline ID as first field of line */
147  ereport(FATAL,
148  (errmsg("syntax error in history file: %s", fline),
149  errhint("Expected a numeric timeline ID.")));
150  }
151  if (nfields != 3)
152  ereport(FATAL,
153  (errmsg("syntax error in history file: %s", fline),
154  errhint("Expected a write-ahead log switchpoint location.")));
155 
156  if (result && tli <= lasttli)
157  ereport(FATAL,
158  (errmsg("invalid data in history file: %s", fline),
159  errhint("Timeline IDs must be in increasing sequence.")));
160 
161  lasttli = tli;
162 
163  entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
164  entry->tli = tli;
165  entry->begin = prevend;
166  entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
167  prevend = entry->end;
168 
169  /* Build list with newest item first */
170  result = lcons(entry, result);
171 
172  /* we ignore the remainder of each line */
173  }
174 
175  FreeFile(fd);
176 
177  if (result && targetTLI <= lasttli)
178  ereport(FATAL,
179  (errmsg("invalid data in history file \"%s\"", path),
180  errhint("Timeline IDs must be less than child timeline's ID.")));
181 
182  /*
183  * Create one more entry for the "tip" of the timeline, which has no entry
184  * in the history file.
185  */
186  entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
187  entry->tli = targetTLI;
188  entry->begin = prevend;
189  entry->end = InvalidXLogRecPtr;
190 
191  result = lcons(entry, result);
192 
193  /*
194  * If the history file was fetched from archive, save it in pg_wal for
195  * future reference.
196  */
197  if (fromArchive)
198  KeepFileRestoredFromArchive(path, histfname);
199 
200  return result;
201 }
202 
203 /*
204  * Probe whether a timeline history file exists for the given timeline ID
205  */
206 bool
208 {
209  char path[MAXPGPATH];
210  char histfname[MAXFNAMELEN];
211  FILE *fd;
212 
213  /* Timeline 1 does not have a history file, so no need to check */
214  if (probeTLI == 1)
215  return false;
216 
218  {
219  TLHistoryFileName(histfname, probeTLI);
220  RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
221  }
222  else
223  TLHistoryFilePath(path, probeTLI);
224 
225  fd = AllocateFile(path, "r");
226  if (fd != NULL)
227  {
228  FreeFile(fd);
229  return true;
230  }
231  else
232  {
233  if (errno != ENOENT)
234  ereport(FATAL,
236  errmsg("could not open file \"%s\": %m", path)));
237  return false;
238  }
239 }
240 
241 /*
242  * Find the newest existing timeline, assuming that startTLI exists.
243  *
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.
247  */
250 {
251  TimeLineID newestTLI;
252  TimeLineID probeTLI;
253 
254  /*
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?
257  */
258  newestTLI = startTLI;
259 
260  for (probeTLI = startTLI + 1;; probeTLI++)
261  {
262  if (existsTimeLineHistory(probeTLI))
263  {
264  newestTLI = probeTLI; /* probeTLI exists */
265  }
266  else
267  {
268  /* doesn't exist, assume we're done */
269  break;
270  }
271  }
272 
273  return newestTLI;
274 }
275 
276 /*
277  * Create a new timeline history file.
278  *
279  * newTLI: ID of the new timeline
280  * parentTLI: ID of its immediate parent
281  * switchpoint: WAL location where the system switched to the new timeline
282  * reason: human-readable explanation of why the timeline was switched
283  *
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.
287  */
288 void
290  XLogRecPtr switchpoint, char *reason)
291 {
292  char path[MAXPGPATH];
293  char tmppath[MAXPGPATH];
294  char histfname[MAXFNAMELEN];
295  char buffer[BLCKSZ];
296  int srcfd;
297  int fd;
298  int nbytes;
299 
300  Assert(newTLI > parentTLI); /* else bad selection of newTLI */
301 
302  /*
303  * Write into a temp file name.
304  */
305  snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
306 
307  unlink(tmppath);
308 
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,
311  S_IRUSR | S_IWUSR);
312  if (fd < 0)
313  ereport(ERROR,
315  errmsg("could not create file \"%s\": %m", tmppath)));
316 
317  /*
318  * If a history file exists for the parent, copy it verbatim
319  */
321  {
322  TLHistoryFileName(histfname, parentTLI);
323  RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
324  }
325  else
326  TLHistoryFilePath(path, parentTLI);
327 
328  srcfd = OpenTransientFile(path, O_RDONLY, 0);
329  if (srcfd < 0)
330  {
331  if (errno != ENOENT)
332  ereport(ERROR,
334  errmsg("could not open file \"%s\": %m", path)));
335  /* Not there, so assume parent has no parents */
336  }
337  else
338  {
339  for (;;)
340  {
341  errno = 0;
343  nbytes = (int) read(srcfd, buffer, sizeof(buffer));
345  if (nbytes < 0 || errno != 0)
346  ereport(ERROR,
348  errmsg("could not read file \"%s\": %m", path)));
349  if (nbytes == 0)
350  break;
351  errno = 0;
353  if ((int) write(fd, buffer, nbytes) != nbytes)
354  {
355  int save_errno = errno;
356 
357  /*
358  * If we fail to make the file, delete it to release disk
359  * space
360  */
361  unlink(tmppath);
362 
363  /*
364  * if write didn't set errno, assume problem is no disk space
365  */
366  errno = save_errno ? save_errno : ENOSPC;
367 
368  ereport(ERROR,
370  errmsg("could not write to file \"%s\": %m", tmppath)));
371  }
373  }
374  CloseTransientFile(srcfd);
375  }
376 
377  /*
378  * Append one line with the details of this timeline split.
379  *
380  * If we did have a parent file, insert an extra newline just in case the
381  * parent file failed to end with one.
382  */
383  snprintf(buffer, sizeof(buffer),
384  "%s%u\t%X/%X\t%s\n",
385  (srcfd < 0) ? "" : "\n",
386  parentTLI,
387  (uint32) (switchpoint >> 32), (uint32) (switchpoint),
388  reason);
389 
390  nbytes = strlen(buffer);
391  errno = 0;
392  if ((int) write(fd, buffer, nbytes) != nbytes)
393  {
394  int save_errno = errno;
395 
396  /*
397  * If we fail to make the file, delete it to release disk space
398  */
399  unlink(tmppath);
400  /* if write didn't set errno, assume problem is no disk space */
401  errno = save_errno ? save_errno : ENOSPC;
402 
403  ereport(ERROR,
405  errmsg("could not write to file \"%s\": %m", tmppath)));
406  }
407 
409  if (pg_fsync(fd) != 0)
410  ereport(ERROR,
412  errmsg("could not fsync file \"%s\": %m", tmppath)));
414 
415  if (CloseTransientFile(fd))
416  ereport(ERROR,
418  errmsg("could not close file \"%s\": %m", tmppath)));
419 
420 
421  /*
422  * Now move the completed history file into place with its final name.
423  */
424  TLHistoryFilePath(path, newTLI);
425 
426  /*
427  * Perform the rename using link if available, paranoidly trying to avoid
428  * overwriting an existing file (there shouldn't be one).
429  */
430  durable_link_or_rename(tmppath, path, ERROR);
431 
432  /* The history file can be archived immediately. */
433  if (XLogArchivingActive())
434  {
435  TLHistoryFileName(histfname, newTLI);
436  XLogArchiveNotify(histfname);
437  }
438 }
439 
440 /*
441  * Writes a history file for given timeline and contents.
442  *
443  * Currently this is only used in the walreceiver process, and so there are
444  * no locking considerations. But we should be just as tense as XLogFileInit
445  * to avoid emplacing a bogus file.
446  */
447 void
448 writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
449 {
450  char path[MAXPGPATH];
451  char tmppath[MAXPGPATH];
452  int fd;
453 
454  /*
455  * Write into a temp file name.
456  */
457  snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
458 
459  unlink(tmppath);
460 
461  /* do not use get_sync_bit() here --- want to fsync only at end of fill */
462  fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
463  S_IRUSR | S_IWUSR);
464  if (fd < 0)
465  ereport(ERROR,
467  errmsg("could not create file \"%s\": %m", tmppath)));
468 
469  errno = 0;
471  if ((int) write(fd, content, size) != size)
472  {
473  int save_errno = errno;
474 
475  /*
476  * If we fail to make the file, delete it to release disk space
477  */
478  unlink(tmppath);
479  /* if write didn't set errno, assume problem is no disk space */
480  errno = save_errno ? save_errno : ENOSPC;
481 
482  ereport(ERROR,
484  errmsg("could not write to file \"%s\": %m", tmppath)));
485  }
487 
489  if (pg_fsync(fd) != 0)
490  ereport(ERROR,
492  errmsg("could not fsync file \"%s\": %m", tmppath)));
494 
495  if (CloseTransientFile(fd))
496  ereport(ERROR,
498  errmsg("could not close file \"%s\": %m", tmppath)));
499 
500 
501  /*
502  * Now move the completed history file into place with its final name.
503  */
504  TLHistoryFilePath(path, tli);
505 
506  /*
507  * Perform the rename using link if available, paranoidly trying to avoid
508  * overwriting an existing file (there shouldn't be one).
509  */
510  durable_link_or_rename(tmppath, path, ERROR);
511 }
512 
513 /*
514  * Returns true if 'expectedTLEs' contains a timeline with id 'tli'
515  */
516 bool
518 {
519  ListCell *cell;
520 
521  foreach(cell, expectedTLEs)
522  {
523  if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
524  return true;
525  }
526 
527  return false;
528 }
529 
530 /*
531  * Returns the ID of the timeline in use at a particular point in time, in
532  * the given timeline history.
533  */
536 {
537  ListCell *cell;
538 
539  foreach(cell, history)
540  {
542 
543  if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
544  (XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
545  {
546  /* found it */
547  return tle->tli;
548  }
549  }
550 
551  /* shouldn't happen. */
552  elog(ERROR, "timeline history was not contiguous");
553  return 0; /* keep compiler quiet */
554 }
555 
556 /*
557  * Returns the point in history where we branched off the given timeline,
558  * and the timeline we branched to (*nextTLI). Returns InvalidXLogRecPtr if
559  * the timeline is current, ie. we have not branched off from it, and throws
560  * an error if the timeline is not part of this server's history.
561  */
563 tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
564 {
565  ListCell *cell;
566 
567  if (nextTLI)
568  *nextTLI = 0;
569  foreach(cell, history)
570  {
572 
573  if (tle->tli == tli)
574  return tle->end;
575  if (nextTLI)
576  *nextTLI = tle->tli;
577  }
578 
579  ereport(ERROR,
580  (errmsg("requested timeline %u is not in this server's history",
581  tli)));
582  return InvalidXLogRecPtr; /* keep compiler quiet */
583 }
bool ArchiveRecoveryRequested
Definition: xlog.c:246
#define NIL
Definition: pg_list.h:69
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:535
int errhint(const char *fmt,...)
Definition: elog.c:987
uint32 TimeLineID
Definition: xlogdefs.h:45
#define write(a, b, c)
Definition: win32.h:14
void KeepFileRestoredFromArchive(char *path, char *xlogfname)
Definition: xlogarchive.c:426
void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
Definition: timeline.c:49
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:75
static List * expectedTLEs
Definition: xlog.c:318
bool RestoreArchivedFile(char *path, const char *xlogfname, const char *recovername, off_t expectedSize, bool cleanupEnabled)
Definition: xlogarchive.c:51
return result
Definition: formatting.c:1632
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
TimeLineID tli
Definition: timeline.h:27
static int fd(const char *x, int i)
Definition: preproc-init.c:105
void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, XLogRecPtr switchpoint, char *reason)
Definition: timeline.c:289
#define list_make1(x1)
Definition: pg_list.h:139
void XLogArchiveNotify(const char *xlog)
Definition: xlogarchive.c:512
TimeLineID findNewestTimeLine(TimeLineID startTLI)
Definition: timeline.c:249
#define ERROR
Definition: elog.h:43
#define FATAL
Definition: elog.h:52
#define MAXPGPATH
#define TLHistoryFileName(fname, tli)
void writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
Definition: timeline.c:448
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2094
unsigned int uint32
Definition: c.h:268
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1232
bool existsTimeLineHistory(TimeLineID probeTLI)
Definition: timeline.c:207
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2305
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define MAXFNAMELEN
#define XLOGDIR
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:563
List * lcons(void *datum, List *list)
Definition: list.c:259
#define NULL
Definition: c.h:229
XLogRecPtr end
Definition: timeline.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define XLogArchivingActive()
Definition: xlog.h:134
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
int durable_link_or_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:712
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1208
int FreeFile(FILE *file)
Definition: fd.c:2277
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
XLogRecPtr begin
Definition: timeline.h:28
bool tliInHistory(TimeLineID tli, List *expectedTLEs)
Definition: timeline.c:517
int pg_fsync(int fd)
Definition: fd.c:333
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define read(a, b, c)
Definition: win32.h:13
#define TLHistoryFilePath(path, tli)