PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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)
251 errmsg("could not open file \"%s\": %m", path)));
252 return false;
253 }
254}
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
int FreeFile(FILE *file)
Definition: fd.c:2803
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2605
#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;
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)
111 errmsg("could not open file \"%s\": %m", path)));
112 /* Not there, so assume no parents */
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
135 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
136 res = fgets(fline, sizeof(fline), fd);
138 if (res == NULL)
139 {
140 if (ferror(fd))
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 */
163 (errmsg("syntax error in history file: %s", fline),
164 errhint("Expected a numeric timeline ID.")));
165 }
166 if (nfields != 3)
168 (errmsg("syntax error in history file: %s", fline),
169 errhint("Expected a write-ahead log switchpoint location.")));
170
171 if (result && tli <= lasttli)
173 (errmsg("invalid data in history file: %s", fline),
174 errhint("Timeline IDs must be in increasing sequence.")));
175
176 lasttli = tli;
177
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)
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 */
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}
uint64_t uint64
Definition: c.h:486
uint32_t uint32
Definition: c.h:485
int errhint(const char *fmt,...)
Definition: elog.c:1317
#define ERROR
Definition: elog.h:39
List * lcons(void *datum, List *list)
Definition: list.c:495
void * palloc(Size size)
Definition: mcxt.c:1317
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
Definition: pg_list.h:54
XLogRecPtr begin
Definition: timeline.h:28
TimeLineID tli
Definition: timeline.h:27
XLogRecPtr end
Definition: timeline.h:29
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:85
static void pgstat_report_wait_end(void)
Definition: wait_event.h:101
void KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
Definition: xlogarchive.c:358
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(), and TimeLineHistoryEntry::tli.

Referenced by AddWALInfoToBackupManifest(), GetOldestUnsummarizedLSN(), PrepareForIncrementalBackup(), ReadReplicationSlot(), rescanLatestTimeLine(), StartReplication(), summarizer_read_local_xlog_page(), WaitForWALToBecomeAvailable(), WalSummarizerMain(), 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:172
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 elog(elevel,...)
Definition: elog.h:225
#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
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(), summarizer_read_local_xlog_page(), WalSummarizerMain(), 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)
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)
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;
356 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
357 nbytes = (int) read(srcfd, buffer, sizeof(buffer));
359 if (nbytes < 0 || errno != 0)
362 errmsg("could not read file \"%s\": %m", path)));
363 if (nbytes == 0)
364 break;
365 errno = 0;
366 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_WRITE);
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
384 errmsg("could not write to file \"%s\": %m", tmppath)));
385 }
387 }
388
389 if (CloseTransientFile(srcfd) != 0)
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;
410 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_WRITE);
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
424 errmsg("could not write to file \"%s\": %m", tmppath)));
425 }
427
428 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_SYNC);
429 if (pg_fsync(fd) != 0)
432 errmsg("could not fsync file \"%s\": %m", tmppath)));
434
435 if (CloseTransientFile(fd) != 0)
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. */
449 {
450 TLHistoryFileName(histfname, newTLI);
451 XLogArchiveNotify(histfname);
452 }
453}
#define Assert(condition)
Definition: c.h:812
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:781
int CloseTransientFile(int fd)
Definition: fd.c:2831
int data_sync_elevel(int elevel)
Definition: fd.c:3959
int pg_fsync(int fd)
Definition: fd.c:385
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2655
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
#define snprintf
Definition: port.h:238
short access
Definition: preproc-type.c:36
#define XLogArchivingActive()
Definition: xlog.h:99
#define XLOGDIR
void XLogArchiveNotify(const char *xlog)
Definition: xlogarchive.c:444
#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(), 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)
481 errmsg("could not create file \"%s\": %m", tmppath)));
482
483 errno = 0;
484 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE);
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
498 errmsg("could not write to file \"%s\": %m", tmppath)));
499 }
501
502 pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC);
503 if (pg_fsync(fd) != 0)
506 errmsg("could not fsync file \"%s\": %m", tmppath)));
508
509 if (CloseTransientFile(fd) != 0)
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}
static pg_noinline void Size size
Definition: slab.c:607

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(), size, snprintf, TLHistoryFilePath(), write, and XLOGDIR.

Referenced by WalRcvFetchTimeLineHistoryFiles().