Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * timeline.c
4 : * timeline-related functions.
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : *
8 : *-------------------------------------------------------------------------
9 : */
10 : #include "postgres_fe.h"
11 :
12 : #include "access/timeline.h"
13 : #include "access/xlog_internal.h"
14 : #include "pg_rewind.h"
15 :
16 : /*
17 : * This is copy-pasted from the backend readTimeLineHistory, modified to
18 : * return a malloc'd array and to work without backend functions.
19 : */
20 : /*
21 : * Try to read a timeline's history file.
22 : *
23 : * If successful, return the list of component TLIs (the given TLI followed by
24 : * its ancestor TLIs). If we can't find the history file, assume that the
25 : * timeline has no parents, and return a list of just the specified timeline
26 : * ID.
27 : */
28 : TimeLineHistoryEntry *
2939 heikki.linnakangas 29 CBC 14 : rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
30 : {
31 : char *fline;
32 : TimeLineHistoryEntry *entry;
33 14 : TimeLineHistoryEntry *entries = NULL;
34 14 : int nlines = 0;
35 14 : TimeLineID lasttli = 0;
36 : XLogRecPtr prevend;
37 : char *bufptr;
38 14 : bool lastline = false;
39 :
40 : /*
41 : * Parse the file...
42 : */
43 14 : prevend = InvalidXLogRecPtr;
44 14 : bufptr = buffer;
45 44 : while (!lastline)
46 : {
47 : char *ptr;
48 : TimeLineID tli;
49 : uint32 switchpoint_hi;
50 : uint32 switchpoint_lo;
51 : int nfields;
52 :
53 30 : fline = bufptr;
54 630 : while (*bufptr && *bufptr != '\n')
55 600 : bufptr++;
56 30 : if (!(*bufptr))
57 14 : lastline = true;
58 : else
59 16 : *bufptr++ = '\0';
60 :
61 : /* skip leading whitespace and check for # comment */
62 30 : for (ptr = fline; *ptr; ptr++)
63 : {
64 15 : if (!isspace((unsigned char) *ptr))
65 15 : break;
66 : }
67 30 : if (*ptr == '\0' || *ptr == '#')
68 15 : continue;
69 :
70 15 : nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
71 :
72 15 : if (nfields < 1)
73 : {
74 : /* expect a numeric timeline ID as first field of line */
1469 peter 75 UBC 0 : pg_log_error("syntax error in history file: %s", fline);
366 tgl 76 0 : pg_log_error_detail("Expected a numeric timeline ID.");
2939 heikki.linnakangas 77 0 : exit(1);
78 : }
2939 heikki.linnakangas 79 CBC 15 : if (nfields != 3)
80 : {
1469 peter 81 UBC 0 : pg_log_error("syntax error in history file: %s", fline);
366 tgl 82 0 : pg_log_error_detail("Expected a write-ahead log switchpoint location.");
2939 heikki.linnakangas 83 0 : exit(1);
84 : }
2939 heikki.linnakangas 85 CBC 15 : if (entries && tli <= lasttli)
86 : {
1469 peter 87 UBC 0 : pg_log_error("invalid data in history file: %s", fline);
366 tgl 88 0 : pg_log_error_detail("Timeline IDs must be in increasing sequence.");
2939 heikki.linnakangas 89 0 : exit(1);
90 : }
91 :
2939 heikki.linnakangas 92 CBC 15 : lasttli = tli;
93 :
94 15 : nlines++;
95 15 : entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
96 :
97 15 : entry = &entries[nlines - 1];
98 15 : entry->tli = tli;
99 15 : entry->begin = prevend;
100 15 : entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
101 15 : prevend = entry->end;
102 :
103 : /* we ignore the remainder of each line */
104 : }
105 :
106 14 : if (entries && targetTLI <= lasttli)
107 : {
1469 peter 108 UBC 0 : pg_log_error("invalid data in history file");
366 tgl 109 0 : pg_log_error_detail("Timeline IDs must be less than child timeline's ID.");
2939 heikki.linnakangas 110 0 : exit(1);
111 : }
112 :
113 : /*
114 : * Create one more entry for the "tip" of the timeline, which has no entry
115 : * in the history file.
116 : */
2939 heikki.linnakangas 117 CBC 14 : nlines++;
118 14 : if (entries)
119 14 : entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
120 : else
2939 heikki.linnakangas 121 UBC 0 : entries = pg_malloc(1 * sizeof(TimeLineHistoryEntry));
122 :
2939 heikki.linnakangas 123 CBC 14 : entry = &entries[nlines - 1];
124 14 : entry->tli = targetTLI;
125 14 : entry->begin = prevend;
126 14 : entry->end = InvalidXLogRecPtr;
127 :
128 14 : *nentries = nlines;
129 14 : return entries;
130 : }
|