PostgreSQL Source Code  git master
timeline.c File Reference
#include "postgres.h"
#include <sys/stat.h>
#include <unistd.h>
#include "access/timeline.h"
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xlogarchive.h"
#include "access/xlogdefs.h"
#include "pgstat.h"
#include "storage/fd.h"
Include dependency graph for timeline.c:

Go to the source code of this file.

Functions

void restoreTimeLineHistoryFiles (TimeLineID begin, TimeLineID end)
 
ListreadTimeLineHistory (TimeLineID targetTLI)
 
bool existsTimeLineHistory (TimeLineID probeTLI)
 
TimeLineID findNewestTimeLine (TimeLineID startTLI)
 
void writeTimeLineHistory (TimeLineID newTLI, TimeLineID parentTLI, XLogRecPtr switchpoint, char *reason)
 
void writeTimeLineHistoryFile (TimeLineID tli, char *content, int size)
 
bool tliInHistory (TimeLineID tli, List *expectedTLEs)
 
TimeLineID tliOfPointInHistory (XLogRecPtr ptr, List *history)
 
XLogRecPtr tliSwitchPoint (TimeLineID tli, List *history, TimeLineID *nextTLI)
 

Function Documentation

◆ existsTimeLineHistory()

bool existsTimeLineHistory ( TimeLineID  probeTLI)

Definition at line 222 of file timeline.c.

223 {
224  char path[MAXPGPATH];
225  char histfname[MAXFNAMELEN];
226  FILE *fd;
227 
228  /* Timeline 1 does not have a history file, so no need to check */
229  if (probeTLI == 1)
230  return false;
231 
233  {
234  TLHistoryFileName(histfname, probeTLI);
235  RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
236  }
237  else
238  TLHistoryFilePath(path, probeTLI);
239 
240  fd = AllocateFile(path, "r");
241  if (fd != NULL)
242  {
243  FreeFile(fd);
244  return true;
245  }
246  else
247  {
248  if (errno != ENOENT)
249  ereport(FATAL,
251  errmsg("could not open file \"%s\": %m", path)));
252  return false;
253  }
254 }
int errcode_for_file_access(void)
Definition: elog.c:881
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2383
int FreeFile(FILE *file)
Definition: fd.c:2581
#define MAXPGPATH
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define MAXFNAMELEN
static void TLHistoryFilePath(char *path, TimeLineID tli)
static void TLHistoryFileName(char *fname, TimeLineID tli)
bool RestoreArchivedFile(char *path, const char *xlogfname, const char *recovername, off_t expectedSize, bool cleanupEnabled)
Definition: xlogarchive.c:54
bool ArchiveRecoveryRequested
Definition: xlogrecovery.c:137

References AllocateFile(), ArchiveRecoveryRequested, ereport, errcode_for_file_access(), errmsg(), FATAL, fd(), FreeFile(), MAXFNAMELEN, MAXPGPATH, RestoreArchivedFile(), TLHistoryFileName(), and TLHistoryFilePath().

Referenced by findNewestTimeLine(), validateRecoveryParameters(), and WalRcvFetchTimeLineHistoryFiles().

◆ findNewestTimeLine()

TimeLineID findNewestTimeLine ( TimeLineID  startTLI)

Definition at line 264 of file timeline.c.

265 {
266  TimeLineID newestTLI;
267  TimeLineID probeTLI;
268 
269  /*
270  * The algorithm is just to probe for the existence of timeline history
271  * files. XXX is it useful to allow gaps in the sequence?
272  */
273  newestTLI = startTLI;
274 
275  for (probeTLI = startTLI + 1;; probeTLI++)
276  {
277  if (existsTimeLineHistory(probeTLI))
278  {
279  newestTLI = probeTLI; /* probeTLI exists */
280  }
281  else
282  {
283  /* doesn't exist, assume we're done */
284  break;
285  }
286  }
287 
288  return newestTLI;
289 }
bool existsTimeLineHistory(TimeLineID probeTLI)
Definition: timeline.c:222
uint32 TimeLineID
Definition: xlogdefs.h:59

References existsTimeLineHistory().

Referenced by rescanLatestTimeLine(), StartupXLOG(), and validateRecoveryParameters().

◆ readTimeLineHistory()

List* readTimeLineHistory ( TimeLineID  targetTLI)

Definition at line 76 of file timeline.c.

77 {
78  List *result;
79  char path[MAXPGPATH];
80  char histfname[MAXFNAMELEN];
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  for (;;)
126  {
127  char fline[MAXPGPATH];
128  char *res;
129  char *ptr;
130  TimeLineID tli;
131  uint32 switchpoint_hi;
132  uint32 switchpoint_lo;
133  int nfields;
134 
136  res = fgets(fline, sizeof(fline), fd);
138  if (res == NULL)
139  {
140  if (ferror(fd))
141  ereport(ERROR,
143  errmsg("could not read file \"%s\": %m", path)));
144 
145  break;
146  }
147 
148  /* skip leading whitespace and check for # comment */
149  for (ptr = fline; *ptr; ptr++)
150  {
151  if (!isspace((unsigned char) *ptr))
152  break;
153  }
154  if (*ptr == '\0' || *ptr == '#')
155  continue;
156 
157  nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
158 
159  if (nfields < 1)
160  {
161  /* expect a numeric timeline ID as first field of line */
162  ereport(FATAL,
163  (errmsg("syntax error in history file: %s", fline),
164  errhint("Expected a numeric timeline ID.")));
165  }
166  if (nfields != 3)
167  ereport(FATAL,
168  (errmsg("syntax error in history file: %s", fline),
169  errhint("Expected a write-ahead log switchpoint location.")));
170 
171  if (result && tli <= lasttli)
172  ereport(FATAL,
173  (errmsg("invalid data in history file: %s", fline),
174  errhint("Timeline IDs must be in increasing sequence.")));
175 
176  lasttli = tli;
177 
178  entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
179  entry->tli = tli;
180  entry->begin = prevend;
181  entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
182  prevend = entry->end;
183 
184  /* Build list with newest item first */
185  result = lcons(entry, result);
186 
187  /* we ignore the remainder of each line */
188  }
189 
190  FreeFile(fd);
191 
192  if (result && targetTLI <= lasttli)
193  ereport(FATAL,
194  (errmsg("invalid data in history file \"%s\"", path),
195  errhint("Timeline IDs must be less than child timeline's ID.")));
196 
197  /*
198  * Create one more entry for the "tip" of the timeline, which has no entry
199  * in the history file.
200  */
201  entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
202  entry->tli = targetTLI;
203  entry->begin = prevend;
204  entry->end = InvalidXLogRecPtr;
205 
206  result = lcons(entry, result);
207 
208  /*
209  * If the history file was fetched from archive, save it in pg_wal for
210  * future reference.
211  */
212  if (fromArchive)
213  KeepFileRestoredFromArchive(path, histfname);
214 
215  return result;
216 }
unsigned int uint32
Definition: c.h:442
int errhint(const char *fmt,...)
Definition: elog.c:1316
#define ERROR
Definition: elog.h:39
List * lcons(void *datum, List *list)
Definition: list.c:494
void * palloc(Size size)
Definition: mcxt.c:1199
#define NIL
Definition: pg_list.h:66
#define list_make1(x1)
Definition: pg_list.h:210
Definition: pg_list.h:52
XLogRecPtr begin
Definition: timeline.h:28
TimeLineID tli
Definition: timeline.h:27
XLogRecPtr end
Definition: timeline.h:29
@ WAIT_EVENT_TIMELINE_HISTORY_READ
Definition: wait_event.h:216
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:268
static void pgstat_report_wait_end(void)
Definition: wait_event.h:284
void KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
Definition: xlogarchive.c:390
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References AllocateFile(), ArchiveRecoveryRequested, TimeLineHistoryEntry::begin, TimeLineHistoryEntry::end, ereport, errcode_for_file_access(), errhint(), errmsg(), ERROR, FATAL, fd(), FreeFile(), InvalidXLogRecPtr, KeepFileRestoredFromArchive(), lcons(), list_make1, MAXFNAMELEN, MAXPGPATH, NIL, palloc(), pgstat_report_wait_end(), pgstat_report_wait_start(), res, RestoreArchivedFile(), TLHistoryFileName(), TLHistoryFilePath(), TimeLineHistoryEntry::tli, and WAIT_EVENT_TIMELINE_HISTORY_READ.

Referenced by AddWALInfoToBackupManifest(), ReadReplicationSlot(), rescanLatestTimeLine(), StartReplication(), WaitForWALToBecomeAvailable(), XLogFileReadAnyTLI(), XLogReadDetermineTimeline(), and XLogSendPhysical().

◆ restoreTimeLineHistoryFiles()

void restoreTimeLineHistoryFiles ( TimeLineID  begin,
TimeLineID  end 
)

Definition at line 50 of file timeline.c.

51 {
52  char path[MAXPGPATH];
53  char histfname[MAXFNAMELEN];
54  TimeLineID tli;
55 
56  for (tli = begin; tli < end; tli++)
57  {
58  if (tli == 1)
59  continue;
60 
61  TLHistoryFileName(histfname, tli);
62  if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
63  KeepFileRestoredFromArchive(path, histfname);
64  }
65 }

References KeepFileRestoredFromArchive(), MAXFNAMELEN, MAXPGPATH, RestoreArchivedFile(), and TLHistoryFileName().

Referenced by rescanLatestTimeLine(), and StartupXLOG().

◆ tliInHistory()

bool tliInHistory ( TimeLineID  tli,
List expectedTLEs 
)

Definition at line 526 of file timeline.c.

527 {
528  ListCell *cell;
529 
530  foreach(cell, expectedTLEs)
531  {
532  if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
533  return true;
534  }
535 
536  return false;
537 }
#define lfirst(lc)
Definition: pg_list.h:170
static List * expectedTLEs
Definition: xlogrecovery.c:123

References expectedTLEs, and lfirst.

Referenced by checkTimeLineSwitch(), and ReadRecord().

◆ tliOfPointInHistory()

TimeLineID tliOfPointInHistory ( XLogRecPtr  ptr,
List history 
)

Definition at line 544 of file timeline.c.

545 {
546  ListCell *cell;
547 
548  foreach(cell, history)
549  {
551 
552  if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
553  (XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
554  {
555  /* found it */
556  return tle->tli;
557  }
558  }
559 
560  /* shouldn't happen. */
561  elog(ERROR, "timeline history was not contiguous");
562  return 0; /* keep compiler quiet */
563 }
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References TimeLineHistoryEntry::begin, elog(), TimeLineHistoryEntry::end, ERROR, lfirst, TimeLineHistoryEntry::tli, and XLogRecPtrIsInvalid.

Referenced by InitWalRecovery(), ReadReplicationSlot(), WaitForWALToBecomeAvailable(), and XLogReadDetermineTimeline().

◆ tliSwitchPoint()

XLogRecPtr tliSwitchPoint ( TimeLineID  tli,
List history,
TimeLineID nextTLI 
)

Definition at line 572 of file timeline.c.

573 {
574  ListCell *cell;
575 
576  if (nextTLI)
577  *nextTLI = 0;
578  foreach(cell, history)
579  {
581 
582  if (tle->tli == tli)
583  return tle->end;
584  if (nextTLI)
585  *nextTLI = tle->tli;
586  }
587 
588  ereport(ERROR,
589  (errmsg("requested timeline %u is not in this server's history",
590  tli)));
591  return InvalidXLogRecPtr; /* keep compiler quiet */
592 }

References TimeLineHistoryEntry::end, ereport, errmsg(), ERROR, InvalidXLogRecPtr, lfirst, and TimeLineHistoryEntry::tli.

Referenced by InitWalRecovery(), StartReplication(), XLogReadDetermineTimeline(), and XLogSendPhysical().

◆ writeTimeLineHistory()

void writeTimeLineHistory ( TimeLineID  newTLI,
TimeLineID  parentTLI,
XLogRecPtr  switchpoint,
char *  reason 
)

Definition at line 304 of file timeline.c.

306 {
307  char path[MAXPGPATH];
308  char tmppath[MAXPGPATH];
309  char histfname[MAXFNAMELEN];
310  char buffer[BLCKSZ];
311  int srcfd;
312  int fd;
313  int nbytes;
314 
315  Assert(newTLI > parentTLI); /* else bad selection of newTLI */
316 
317  /*
318  * Write into a temp file name.
319  */
320  snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
321 
322  unlink(tmppath);
323 
324  /* do not use get_sync_bit() here --- want to fsync only at end of fill */
325  fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
326  if (fd < 0)
327  ereport(ERROR,
329  errmsg("could not create file \"%s\": %m", tmppath)));
330 
331  /*
332  * If a history file exists for the parent, copy it verbatim
333  */
335  {
336  TLHistoryFileName(histfname, parentTLI);
337  RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
338  }
339  else
340  TLHistoryFilePath(path, parentTLI);
341 
342  srcfd = OpenTransientFile(path, O_RDONLY);
343  if (srcfd < 0)
344  {
345  if (errno != ENOENT)
346  ereport(ERROR,
348  errmsg("could not open file \"%s\": %m", path)));
349  /* Not there, so assume parent has no parents */
350  }
351  else
352  {
353  for (;;)
354  {
355  errno = 0;
357  nbytes = (int) read(srcfd, buffer, sizeof(buffer));
359  if (nbytes < 0 || errno != 0)
360  ereport(ERROR,
362  errmsg("could not read file \"%s\": %m", path)));
363  if (nbytes == 0)
364  break;
365  errno = 0;
367  if ((int) write(fd, buffer, nbytes) != nbytes)
368  {
369  int save_errno = errno;
370 
371  /*
372  * If we fail to make the file, delete it to release disk
373  * space
374  */
375  unlink(tmppath);
376 
377  /*
378  * if write didn't set errno, assume problem is no disk space
379  */
380  errno = save_errno ? save_errno : ENOSPC;
381 
382  ereport(ERROR,
384  errmsg("could not write to file \"%s\": %m", tmppath)));
385  }
387  }
388 
389  if (CloseTransientFile(srcfd) != 0)
390  ereport(ERROR,
392  errmsg("could not close file \"%s\": %m", path)));
393  }
394 
395  /*
396  * Append one line with the details of this timeline split.
397  *
398  * If we did have a parent file, insert an extra newline just in case the
399  * parent file failed to end with one.
400  */
401  snprintf(buffer, sizeof(buffer),
402  "%s%u\t%X/%X\t%s\n",
403  (srcfd < 0) ? "" : "\n",
404  parentTLI,
405  LSN_FORMAT_ARGS(switchpoint),
406  reason);
407 
408  nbytes = strlen(buffer);
409  errno = 0;
411  if ((int) write(fd, buffer, nbytes) != nbytes)
412  {
413  int save_errno = errno;
414 
415  /*
416  * If we fail to make the file, delete it to release disk space
417  */
418  unlink(tmppath);
419  /* if write didn't set errno, assume problem is no disk space */
420  errno = save_errno ? save_errno : ENOSPC;
421 
422  ereport(ERROR,
424  errmsg("could not write to file \"%s\": %m", tmppath)));
425  }
427 
429  if (pg_fsync(fd) != 0)
432  errmsg("could not fsync file \"%s\": %m", tmppath)));
434 
435  if (CloseTransientFile(fd) != 0)
436  ereport(ERROR,
438  errmsg("could not close file \"%s\": %m", tmppath)));
439 
440  /*
441  * Now move the completed history file into place with its final name.
442  */
443  TLHistoryFilePath(path, newTLI);
444  Assert(access(path, F_OK) != 0 && errno == ENOENT);
445  durable_rename(tmppath, path, ERROR);
446 
447  /* The history file can be archived immediately. */
448  if (XLogArchivingActive())
449  {
450  TLHistoryFileName(histfname, newTLI);
451  XLogArchiveNotify(histfname);
452  }
453 }
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:688
int CloseTransientFile(int fd)
Definition: fd.c:2609
int data_sync_elevel(int elevel)
Definition: fd.c:3736
int pg_fsync(int fd)
Definition: fd.c:356
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2433
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
Assert(fmt[strlen(fmt) - 1] !='\n')
#define snprintf
Definition: port.h:238
short access
Definition: preproc-type.c:36
@ WAIT_EVENT_TIMELINE_HISTORY_WRITE
Definition: wait_event.h:218
@ WAIT_EVENT_TIMELINE_HISTORY_SYNC
Definition: wait_event.h:217
#define XLogArchivingActive()
Definition: xlog.h:94
#define XLOGDIR
void XLogArchiveNotify(const char *xlog)
Definition: xlogarchive.c:476
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43

References ArchiveRecoveryRequested, Assert(), CloseTransientFile(), data_sync_elevel(), durable_rename(), ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), LSN_FORMAT_ARGS, MAXFNAMELEN, MAXPGPATH, OpenTransientFile(), pg_fsync(), pgstat_report_wait_end(), pgstat_report_wait_start(), read, RestoreArchivedFile(), snprintf, TLHistoryFileName(), TLHistoryFilePath(), WAIT_EVENT_TIMELINE_HISTORY_READ, WAIT_EVENT_TIMELINE_HISTORY_SYNC, WAIT_EVENT_TIMELINE_HISTORY_WRITE, write, XLogArchiveNotify(), XLogArchivingActive, and XLOGDIR.

Referenced by StartupXLOG().

◆ writeTimeLineHistoryFile()

void writeTimeLineHistoryFile ( TimeLineID  tli,
char *  content,
int  size 
)

Definition at line 463 of file timeline.c.

464 {
465  char path[MAXPGPATH];
466  char tmppath[MAXPGPATH];
467  int fd;
468 
469  /*
470  * Write into a temp file name.
471  */
472  snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());
473 
474  unlink(tmppath);
475 
476  /* do not use get_sync_bit() here --- want to fsync only at end of fill */
477  fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL);
478  if (fd < 0)
479  ereport(ERROR,
481  errmsg("could not create file \"%s\": %m", tmppath)));
482 
483  errno = 0;
485  if ((int) write(fd, content, size) != size)
486  {
487  int save_errno = errno;
488 
489  /*
490  * If we fail to make the file, delete it to release disk space
491  */
492  unlink(tmppath);
493  /* if write didn't set errno, assume problem is no disk space */
494  errno = save_errno ? save_errno : ENOSPC;
495 
496  ereport(ERROR,
498  errmsg("could not write to file \"%s\": %m", tmppath)));
499  }
501 
503  if (pg_fsync(fd) != 0)
506  errmsg("could not fsync file \"%s\": %m", tmppath)));
508 
509  if (CloseTransientFile(fd) != 0)
510  ereport(ERROR,
512  errmsg("could not close file \"%s\": %m", tmppath)));
513 
514  /*
515  * Now move the completed history file into place with its final name,
516  * replacing any existing file with the same name.
517  */
518  TLHistoryFilePath(path, tli);
519  durable_rename(tmppath, path, ERROR);
520 }
@ WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE
Definition: wait_event.h:215
@ WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC
Definition: wait_event.h:214

References CloseTransientFile(), data_sync_elevel(), durable_rename(), ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), MAXPGPATH, OpenTransientFile(), pg_fsync(), pgstat_report_wait_end(), pgstat_report_wait_start(), snprintf, TLHistoryFilePath(), WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC, WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE, write, and XLOGDIR.

Referenced by WalRcvFetchTimeLineHistoryFiles().