133 lines
3.2 KiB
C
133 lines
3.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* timeline.c
|
|
* timeline-related functions.
|
|
*
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres_fe.h"
|
|
|
|
#include "pg_rewind.h"
|
|
|
|
#include "access/timeline.h"
|
|
#include "access/xlog_internal.h"
|
|
#include "fe_utils/logging.h"
|
|
|
|
/*
|
|
* This is copy-pasted from the backend readTimeLineHistory, modified to
|
|
* return a malloc'd array and to work without backend functions.
|
|
*/
|
|
/*
|
|
* Try to read a timeline's history file.
|
|
*
|
|
* If successful, return the list of component TLIs (the given TLI followed by
|
|
* its ancestor TLIs). If we can't find the history file, assume that the
|
|
* timeline has no parents, and return a list of just the specified timeline
|
|
* ID.
|
|
*/
|
|
TimeLineHistoryEntry *
|
|
rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
|
|
{
|
|
char *fline;
|
|
TimeLineHistoryEntry *entry;
|
|
TimeLineHistoryEntry *entries = NULL;
|
|
int nlines = 0;
|
|
TimeLineID lasttli = 0;
|
|
XLogRecPtr prevend;
|
|
char *bufptr;
|
|
bool lastline = false;
|
|
|
|
/*
|
|
* Parse the file...
|
|
*/
|
|
prevend = InvalidXLogRecPtr;
|
|
bufptr = buffer;
|
|
while (!lastline)
|
|
{
|
|
char *ptr;
|
|
TimeLineID tli;
|
|
uint32 switchpoint_hi;
|
|
uint32 switchpoint_lo;
|
|
int nfields;
|
|
|
|
fline = bufptr;
|
|
while (*bufptr && *bufptr != '\n')
|
|
bufptr++;
|
|
if (!(*bufptr))
|
|
lastline = true;
|
|
else
|
|
*bufptr++ = '\0';
|
|
|
|
/* skip leading whitespace and check for # comment */
|
|
for (ptr = fline; *ptr; ptr++)
|
|
{
|
|
if (!isspace((unsigned char) *ptr))
|
|
break;
|
|
}
|
|
if (*ptr == '\0' || *ptr == '#')
|
|
continue;
|
|
|
|
nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
|
|
|
|
if (nfields < 1)
|
|
{
|
|
/* expect a numeric timeline ID as first field of line */
|
|
pg_log_error("syntax error in history file: %s", fline);
|
|
pg_log_error("Expected a numeric timeline ID.");
|
|
exit(1);
|
|
}
|
|
if (nfields != 3)
|
|
{
|
|
pg_log_error("syntax error in history file: %s", fline);
|
|
pg_log_error("Expected a write-ahead log switchpoint location.");
|
|
exit(1);
|
|
}
|
|
if (entries && tli <= lasttli)
|
|
{
|
|
pg_log_error("invalid data in history file: %s", fline);
|
|
pg_log_error("Timeline IDs must be in increasing sequence.");
|
|
exit(1);
|
|
}
|
|
|
|
lasttli = tli;
|
|
|
|
nlines++;
|
|
entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
|
|
|
|
entry = &entries[nlines - 1];
|
|
entry->tli = tli;
|
|
entry->begin = prevend;
|
|
entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
|
|
prevend = entry->end;
|
|
|
|
/* we ignore the remainder of each line */
|
|
}
|
|
|
|
if (entries && targetTLI <= lasttli)
|
|
{
|
|
pg_log_error("invalid data in history file");
|
|
pg_log_error("Timeline IDs must be less than child timeline's ID.");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Create one more entry for the "tip" of the timeline, which has no entry
|
|
* in the history file.
|
|
*/
|
|
nlines++;
|
|
if (entries)
|
|
entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
|
|
else
|
|
entries = pg_malloc(1 * sizeof(TimeLineHistoryEntry));
|
|
|
|
entry = &entries[nlines - 1];
|
|
entry->tli = targetTLI;
|
|
entry->begin = prevend;
|
|
entry->end = InvalidXLogRecPtr;
|
|
|
|
*nentries = nlines;
|
|
return entries;
|
|
}
|