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