Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Functions

timeline.h File Reference

#include "access/xlogdefs.h"
#include "nodes/pg_list.h"
Include dependency graph for timeline.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TimeLineHistoryEntry

Functions

List * readTimeLineHistory (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)
void restoreTimeLineHistoryFiles (TimeLineID begin, TimeLineID end)
bool tliInHistory (TimeLineID tli, List *expectedTLIs)
TimeLineID tliOfPointInHistory (XLogRecPtr ptr, List *history)
XLogRecPtr tliSwitchPoint (TimeLineID tli, List *history, TimeLineID *nextTLI)

Function Documentation

bool existsTimeLineHistory ( TimeLineID  probeTLI  ) 

Definition at line 206 of file timeline.c.

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

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

{
    char        path[MAXPGPATH];
    char        histfname[MAXFNAMELEN];
    FILE       *fd;

    /* Timeline 1 does not have a history file, so no need to check */
    if (probeTLI == 1)
        return false;

    if (ArchiveRecoveryRequested)
    {
        TLHistoryFileName(histfname, probeTLI);
        RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
    }
    else
        TLHistoryFilePath(path, probeTLI);

    fd = AllocateFile(path, "r");
    if (fd != NULL)
    {
        FreeFile(fd);
        return true;
    }
    else
    {
        if (errno != ENOENT)
            ereport(FATAL,
                    (errcode_for_file_access(),
                     errmsg("could not open file \"%s\": %m", path)));
        return false;
    }
}

TimeLineID findNewestTimeLine ( TimeLineID  startTLI  ) 

Definition at line 248 of file timeline.c.

References existsTimeLineHistory().

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

{
    TimeLineID  newestTLI;
    TimeLineID  probeTLI;

    /*
     * The algorithm is just to probe for the existence of timeline history
     * files.  XXX is it useful to allow gaps in the sequence?
     */
    newestTLI = startTLI;

    for (probeTLI = startTLI + 1;; probeTLI++)
    {
        if (existsTimeLineHistory(probeTLI))
        {
            newestTLI = probeTLI;       /* probeTLI exists */
        }
        else
        {
            /* doesn't exist, assume we're done */
            break;
        }
    }

    return newestTLI;
}

List* readTimeLineHistory ( TimeLineID  targetTLI  ) 

Definition at line 74 of file timeline.c.

References AllocateFile(), ArchiveRecoveryRequested, TimeLineHistoryEntry::begin, TimeLineHistoryEntry::end, ereport, errcode_for_file_access(), errhint(), errmsg(), FATAL, FreeFile(), KeepFileRestoredFromArchive(), lcons(), list_make1, NULL, palloc(), RestoreArchivedFile(), TLHistoryFileName, TLHistoryFilePath, and TimeLineHistoryEntry::tli.

Referenced by rescanLatestTimeLine(), StartReplication(), WaitForWALToBecomeAvailable(), XLogFileReadAnyTLI(), and XLogSend().

{
    List       *result;
    char        path[MAXPGPATH];
    char        histfname[MAXFNAMELEN];
    char        fline[MAXPGPATH];
    FILE       *fd;
    TimeLineHistoryEntry *entry;
    TimeLineID  lasttli = 0;
    XLogRecPtr  prevend;
    bool        fromArchive = false;

    /* Timeline 1 does not have a history file, so no need to check */
    if (targetTLI == 1)
    {
        entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
        entry->tli = targetTLI;
        entry->begin = entry->end = InvalidXLogRecPtr;
        return list_make1(entry);
    }

    if (ArchiveRecoveryRequested)
    {
        TLHistoryFileName(histfname, targetTLI);
        fromArchive =
            RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
    }
    else
        TLHistoryFilePath(path, targetTLI);

    fd = AllocateFile(path, "r");
    if (fd == NULL)
    {
        if (errno != ENOENT)
            ereport(FATAL,
                    (errcode_for_file_access(),
                     errmsg("could not open file \"%s\": %m", path)));
        /* Not there, so assume no parents */
        entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
        entry->tli = targetTLI;
        entry->begin = entry->end = InvalidXLogRecPtr;
        return list_make1(entry);
    }

    result = NIL;

    /*
     * Parse the file...
     */
    prevend = InvalidXLogRecPtr;
    while (fgets(fline, sizeof(fline), fd) != NULL)
    {
        /* skip leading whitespace and check for # comment */
        char       *ptr;
        TimeLineID  tli;
        uint32      switchpoint_hi;
        uint32      switchpoint_lo;
        int         nfields;

        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 */
            ereport(FATAL,
                    (errmsg("syntax error in history file: %s", fline),
                     errhint("Expected a numeric timeline ID.")));
        }
        if (nfields != 3)
            ereport(FATAL,
                    (errmsg("syntax error in history file: %s", fline),
                     errhint("Expected an XLOG switchpoint location.")));

        if (result && tli <= lasttli)
            ereport(FATAL,
                    (errmsg("invalid data in history file: %s", fline),
                   errhint("Timeline IDs must be in increasing sequence.")));

        lasttli = tli;

        entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
        entry->tli = tli;
        entry->begin = prevend;
        entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
        prevend = entry->end;

        /* Build list with newest item first */
        result = lcons(entry, result);

        /* we ignore the remainder of each line */
    }

    FreeFile(fd);

    if (result && targetTLI <= lasttli)
        ereport(FATAL,
                (errmsg("invalid data in history file \"%s\"", path),
            errhint("Timeline IDs must be less than child timeline's ID.")));

    /*
     * Create one more entry for the "tip" of the timeline, which has no
     * entry in the history file.
     */
    entry = (TimeLineHistoryEntry *) palloc(sizeof(TimeLineHistoryEntry));
    entry->tli = targetTLI;
    entry->begin = prevend;
    entry->end = InvalidXLogRecPtr;

    result = lcons(entry, result);

    /*
     * If the history file was fetched from archive, save it in pg_xlog for
     * future reference.
     */
    if (fromArchive)
        KeepFileRestoredFromArchive(path, histfname);

    return result;
}

void restoreTimeLineHistoryFiles ( TimeLineID  begin,
TimeLineID  end 
)

Definition at line 48 of file timeline.c.

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

Referenced by rescanLatestTimeLine(), and StartupXLOG().

{
    char        path[MAXPGPATH];
    char        histfname[MAXFNAMELEN];
    TimeLineID tli;

    for (tli = begin; tli < end; tli++)
    {
        if (tli == 1)
            continue;

        TLHistoryFileName(histfname, tli);
        if (RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false))
            KeepFileRestoredFromArchive(path, histfname);
    }
}

bool tliInHistory ( TimeLineID  tli,
List *  expectedTLIs 
)

Definition at line 531 of file timeline.c.

References lfirst.

Referenced by checkTimeLineSwitch(), and ReadRecord().

{
    ListCell *cell;

    foreach(cell, expectedTLEs)
    {
        if (((TimeLineHistoryEntry *) lfirst(cell))->tli == tli)
            return true;
    }

    return false;
}

TimeLineID tliOfPointInHistory ( XLogRecPtr  ptr,
List *  history 
)

Definition at line 549 of file timeline.c.

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

Referenced by StartupXLOG(), and WaitForWALToBecomeAvailable().

{
    ListCell *cell;

    foreach(cell, history)
    {
        TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
        if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
            (XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
        {
            /* found it */
            return tle->tli;
        }
    }

    /* shouldn't happen. */
    elog(ERROR, "timeline history was not contiguous");
    return 0;   /* keep compiler quiet */
}

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

Definition at line 576 of file timeline.c.

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

Referenced by StartReplication(), StartupXLOG(), and XLogSend().

{
    ListCell   *cell;

    if (nextTLI)
        *nextTLI = 0;
    foreach (cell, history)
    {
        TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);

        if (tle->tli == tli)
            return tle->end;
        if (nextTLI)
            *nextTLI = tle->tli;
    }

    ereport(ERROR,
            (errmsg("requested timeline %u is not in this server's history",
                    tli)));
    return InvalidXLogRecPtr; /* keep compiler quiet */
}

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

Definition at line 288 of file timeline.c.

References ArchiveRecoveryRequested, Assert, CloseTransientFile(), ereport, errcode_for_file_access(), errmsg(), ERROR, link(), MAXPGPATH, OpenTransientFile(), pg_fsync(), read, RestoreArchivedFile(), snprintf(), TLHistoryFileName, TLHistoryFilePath, unlink(), write, XLogArchiveNotify(), and XLOGDIR.

Referenced by StartupXLOG().

{
    char        path[MAXPGPATH];
    char        tmppath[MAXPGPATH];
    char        histfname[MAXFNAMELEN];
    char        buffer[BLCKSZ];
    int         srcfd;
    int         fd;
    int         nbytes;

    Assert(newTLI > parentTLI); /* else bad selection of newTLI */

    /*
     * Write into a temp file name.
     */
    snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());

    unlink(tmppath);

    /* do not use get_sync_bit() here --- want to fsync only at end of fill */
    fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
                           S_IRUSR | S_IWUSR);
    if (fd < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not create file \"%s\": %m", tmppath)));

    /*
     * If a history file exists for the parent, copy it verbatim
     */
    if (ArchiveRecoveryRequested)
    {
        TLHistoryFileName(histfname, parentTLI);
        RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
    }
    else
        TLHistoryFilePath(path, parentTLI);

    srcfd = OpenTransientFile(path, O_RDONLY, 0);
    if (srcfd < 0)
    {
        if (errno != ENOENT)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not open file \"%s\": %m", path)));
        /* Not there, so assume parent has no parents */
    }
    else
    {
        for (;;)
        {
            errno = 0;
            nbytes = (int) read(srcfd, buffer, sizeof(buffer));
            if (nbytes < 0 || errno != 0)
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not read file \"%s\": %m", path)));
            if (nbytes == 0)
                break;
            errno = 0;
            if ((int) write(fd, buffer, nbytes) != nbytes)
            {
                int         save_errno = errno;

                /*
                 * If we fail to make the file, delete it to release disk
                 * space
                 */
                unlink(tmppath);

                /*
                 * if write didn't set errno, assume problem is no disk space
                 */
                errno = save_errno ? save_errno : ENOSPC;

                ereport(ERROR,
                        (errcode_for_file_access(),
                     errmsg("could not write to file \"%s\": %m", tmppath)));
            }
        }
        CloseTransientFile(srcfd);
    }

    /*
     * Append one line with the details of this timeline split.
     *
     * If we did have a parent file, insert an extra newline just in case the
     * parent file failed to end with one.
     */
    snprintf(buffer, sizeof(buffer),
             "%s%u\t%X/%X\t%s\n",
             (srcfd < 0) ? "" : "\n",
             parentTLI,
             (uint32) (switchpoint >> 32), (uint32) (switchpoint),
             reason);

    nbytes = strlen(buffer);
    errno = 0;
    if ((int) write(fd, buffer, nbytes) != nbytes)
    {
        int         save_errno = errno;

        /*
         * If we fail to make the file, delete it to release disk space
         */
        unlink(tmppath);
        /* if write didn't set errno, assume problem is no disk space */
        errno = save_errno ? save_errno : ENOSPC;

        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not write to file \"%s\": %m", tmppath)));
    }

    if (pg_fsync(fd) != 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not fsync file \"%s\": %m", tmppath)));

    if (CloseTransientFile(fd))
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not close file \"%s\": %m", tmppath)));


    /*
     * Now move the completed history file into place with its final name.
     */
    TLHistoryFilePath(path, newTLI);

    /*
     * Prefer link() to rename() here just to be really sure that we don't
     * overwrite an existing file.  However, there shouldn't be one, so
     * rename() is an acceptable substitute except for the truly paranoid.
     */
#if HAVE_WORKING_LINK
    if (link(tmppath, path) < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not link file \"%s\" to \"%s\": %m",
                        tmppath, path)));
    unlink(tmppath);
#else
    if (rename(tmppath, path) < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not rename file \"%s\" to \"%s\": %m",
                        tmppath, path)));
#endif

    /* The history file can be archived immediately. */
    TLHistoryFileName(histfname, newTLI);
    XLogArchiveNotify(histfname);
}

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

Definition at line 452 of file timeline.c.

References CloseTransientFile(), ereport, errcode_for_file_access(), errmsg(), ERROR, link(), MAXPGPATH, OpenTransientFile(), pg_fsync(), snprintf(), TLHistoryFilePath, unlink(), write, and XLOGDIR.

Referenced by ReceiveXlogStream(), and WalRcvFetchTimeLineHistoryFiles().

{
    char        path[MAXPGPATH];
    char        tmppath[MAXPGPATH];
    int         fd;

    /*
     * Write into a temp file name.
     */
    snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());

    unlink(tmppath);

    /* do not use get_sync_bit() here --- want to fsync only at end of fill */
    fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL,
                           S_IRUSR | S_IWUSR);
    if (fd < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not create file \"%s\": %m", tmppath)));

    errno = 0;
    if ((int) write(fd, content, size) != size)
    {
        int         save_errno = errno;

        /*
         * If we fail to make the file, delete it to release disk space
         */
        unlink(tmppath);
        /* if write didn't set errno, assume problem is no disk space */
        errno = save_errno ? save_errno : ENOSPC;

        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not write to file \"%s\": %m", tmppath)));
    }

    if (pg_fsync(fd) != 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not fsync file \"%s\": %m", tmppath)));

    if (CloseTransientFile(fd))
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not close file \"%s\": %m", tmppath)));


    /*
     * Now move the completed history file into place with its final name.
     */
    TLHistoryFilePath(path, tli);

    /*
     * Prefer link() to rename() here just to be really sure that we don't
     * overwrite an existing logfile.  However, there shouldn't be one, so
     * rename() is an acceptable substitute except for the truly paranoid.
     */
#if HAVE_WORKING_LINK
    if (link(tmppath, path) < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not link file \"%s\" to \"%s\": %m",
                        tmppath, path)));
    unlink(tmppath);
#else
    if (rename(tmppath, path) < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not rename file \"%s\" to \"%s\": %m",
                        tmppath, path)));
#endif
}