Header And Logo

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

Defines | Functions | Variables

pg_resetxlog.c File Reference

#include "postgres.h"
#include <dirent.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include "access/transam.h"
#include "access/tuptoaster.h"
#include "access/multixact.h"
#include "access/xlog_internal.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
#include "common/fe_memutils.h"
Include dependency graph for pg_resetxlog.c:

Go to the source code of this file.

Defines

#define FRONTEND   1
#define ARCHSTATDIR   XLOGDIR "/archive_status"

Functions

static bool ReadControlFile (void)
static void GuessControlValues (void)
static void PrintControlValues (bool guessed)
static void RewriteControlFile (void)
static void FindEndOfXLOG (void)
static void KillExistingXLOG (void)
static void KillExistingArchiveStatus (void)
static void WriteEmptyXLOG (void)
static void usage (void)
int main (int argc, char *argv[])

Variables

int optind
char * optarg
static ControlFileData ControlFile
static XLogSegNo newXlogSegNo
static bool guessed = false
static const char * progname

Define Documentation

#define ARCHSTATDIR   XLOGDIR "/archive_status"
#define FRONTEND   1

Definition at line 36 of file pg_resetxlog.c.


Function Documentation

static void FindEndOfXLOG ( void   )  [static]

Definition at line 739 of file pg_resetxlog.c.

References _, ControlFileData::checkPointCopy, closedir(), dirent::d_name, newXlogSegNo, NULL, opendir(), progname, readdir(), CheckPoint::redo, strerror(), UINT64CONST, ControlFileData::xlog_seg_size, XLOGDIR, and XLogSegSize.

Referenced by main().

{
    DIR        *xldir;
    struct dirent *xlde;
    uint64      segs_per_xlogid;
    uint64      xlogbytepos;

    /*
     * Initialize the max() computation using the last checkpoint address from
     * old pg_control.  Note that for the moment we are working with segment
     * numbering according to the old xlog seg size.
     */
    segs_per_xlogid = (UINT64CONST(0x0000000100000000) / ControlFile.xlog_seg_size);
    newXlogSegNo = ControlFile.checkPointCopy.redo / ControlFile.xlog_seg_size;

    /*
     * Scan the pg_xlog directory to find existing WAL segment files. We
     * assume any present have been used; in most scenarios this should be
     * conservative, because of xlog.c's attempts to pre-create files.
     */
    xldir = opendir(XLOGDIR);
    if (xldir == NULL)
    {
        fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
                progname, XLOGDIR, strerror(errno));
        exit(1);
    }

    errno = 0;
    while ((xlde = readdir(xldir)) != NULL)
    {
        if (strlen(xlde->d_name) == 24 &&
            strspn(xlde->d_name, "0123456789ABCDEF") == 24)
        {
            unsigned int tli,
                        log,
                        seg;
            XLogSegNo   segno;

            sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
            segno = ((uint64) log) * segs_per_xlogid + seg;

            /*
             * Note: we take the max of all files found, regardless of their
             * timelines.  Another possibility would be to ignore files of
             * timelines other than the target TLI, but this seems safer.
             * Better too large a result than too small...
             */
            if (segno > newXlogSegNo)
                newXlogSegNo = segno;
        }
        errno = 0;
    }
#ifdef WIN32

    /*
     * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
     * released version
     */
    if (GetLastError() == ERROR_NO_MORE_FILES)
        errno = 0;
#endif

    if (errno)
    {
        fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
                progname, XLOGDIR, strerror(errno));
        exit(1);
    }
    closedir(xldir);

    /*
     * Finally, convert to new xlog seg size, and advance by one to ensure we
     * are in virgin territory.
     */
    xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
    newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize;
    newXlogSegNo++;
}

static void GuessControlValues ( void   )  [static]

Definition at line 471 of file pg_resetxlog.c.

References ControlFileData::blcksz, ControlFileData::catalog_version_no, ControlFileData::checkPoint, ControlFileData::checkPointCopy, ControlFileData::enableIntTimes, ControlFileData::float4ByVal, ControlFileData::float8ByVal, ControlFileData::floatFormat, CheckPoint::fullPageWrites, gettimeofday(), guessed, ControlFileData::indexMaxKeys, ControlFileData::max_locks_per_xact, ControlFileData::max_prepared_xacts, ControlFileData::maxAlign, ControlFileData::MaxConnections, ControlFileData::nameDataLen, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, CheckPoint::nextXidEpoch, NULL, CheckPoint::oldestActiveXid, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, ControlFileData::pg_control_version, CheckPoint::PrevTimeLineID, CheckPoint::redo, ControlFileData::relseg_size, ControlFileData::state, ControlFileData::system_identifier, CheckPoint::ThisTimeLineID, ControlFileData::time, CheckPoint::time, ControlFileData::toast_max_chunk_size, ControlFileData::unloggedLSN, ControlFileData::wal_level, ControlFileData::xlog_blcksz, and ControlFileData::xlog_seg_size.

Referenced by main().

{
    uint64      sysidentifier;
    struct timeval tv;

    /*
     * Set up a completely default set of pg_control values.
     */
    guessed = true;
    memset(&ControlFile, 0, sizeof(ControlFile));

    ControlFile.pg_control_version = PG_CONTROL_VERSION;
    ControlFile.catalog_version_no = CATALOG_VERSION_NO;

    /*
     * Create a new unique installation identifier, since we can no longer use
     * any old XLOG records.  See notes in xlog.c about the algorithm.
     */
    gettimeofday(&tv, NULL);
    sysidentifier = ((uint64) tv.tv_sec) << 32;
    sysidentifier |= (uint32) (tv.tv_sec | tv.tv_usec);

    ControlFile.system_identifier = sysidentifier;

    ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
    ControlFile.checkPointCopy.ThisTimeLineID = 1;
    ControlFile.checkPointCopy.PrevTimeLineID = 1;
    ControlFile.checkPointCopy.fullPageWrites = false;
    ControlFile.checkPointCopy.nextXidEpoch = 0;
    ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
    ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
    ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
    ControlFile.checkPointCopy.nextMultiOffset = 0;
    ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
    ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
    ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
    ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
    ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
    ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;

    ControlFile.state = DB_SHUTDOWNED;
    ControlFile.time = (pg_time_t) time(NULL);
    ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
    ControlFile.unloggedLSN = 1;

    /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */

    ControlFile.wal_level = WAL_LEVEL_MINIMAL;
    ControlFile.MaxConnections = 100;
    ControlFile.max_prepared_xacts = 0;
    ControlFile.max_locks_per_xact = 64;

    ControlFile.maxAlign = MAXIMUM_ALIGNOF;
    ControlFile.floatFormat = FLOATFORMAT_VALUE;
    ControlFile.blcksz = BLCKSZ;
    ControlFile.relseg_size = RELSEG_SIZE;
    ControlFile.xlog_blcksz = XLOG_BLCKSZ;
    ControlFile.xlog_seg_size = XLOG_SEG_SIZE;
    ControlFile.nameDataLen = NAMEDATALEN;
    ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
    ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
#ifdef HAVE_INT64_TIMESTAMP
    ControlFile.enableIntTimes = true;
#else
    ControlFile.enableIntTimes = false;
#endif
    ControlFile.float4ByVal = FLOAT4PASSBYVAL;
    ControlFile.float8ByVal = FLOAT8PASSBYVAL;

    /*
     * XXX eventually, should try to grovel through old XLOG to develop more
     * accurate values for TimeLineID, nextXID, etc.
     */
}

static void KillExistingArchiveStatus ( void   )  [static]

Definition at line 878 of file pg_resetxlog.c.

References _, ARCHSTATDIR, closedir(), dirent::d_name, MAXPGPATH, NULL, opendir(), progname, readdir(), snprintf(), strerror(), and unlink().

Referenced by main().

{
    DIR        *xldir;
    struct dirent *xlde;
    char        path[MAXPGPATH];

#define ARCHSTATDIR XLOGDIR "/archive_status"

    xldir = opendir(ARCHSTATDIR);
    if (xldir == NULL)
    {
        fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
                progname, ARCHSTATDIR, strerror(errno));
        exit(1);
    }

    errno = 0;
    while ((xlde = readdir(xldir)) != NULL)
    {
        if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
            (strcmp(xlde->d_name + 24, ".ready") == 0 ||
             strcmp(xlde->d_name + 24, ".done") == 0))
        {
            snprintf(path, MAXPGPATH, "%s/%s", ARCHSTATDIR, xlde->d_name);
            if (unlink(path) < 0)
            {
                fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
                        progname, path, strerror(errno));
                exit(1);
            }
        }
        errno = 0;
    }
#ifdef WIN32

    /*
     * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
     * released version
     */
    if (GetLastError() == ERROR_NO_MORE_FILES)
        errno = 0;
#endif

    if (errno)
    {
        fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
                progname, ARCHSTATDIR, strerror(errno));
        exit(1);
    }
    closedir(xldir);
}

static void KillExistingXLOG ( void   )  [static]

Definition at line 824 of file pg_resetxlog.c.

References _, closedir(), dirent::d_name, MAXPGPATH, NULL, opendir(), progname, readdir(), snprintf(), strerror(), unlink(), and XLOGDIR.

Referenced by main().

{
    DIR        *xldir;
    struct dirent *xlde;
    char        path[MAXPGPATH];

    xldir = opendir(XLOGDIR);
    if (xldir == NULL)
    {
        fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
                progname, XLOGDIR, strerror(errno));
        exit(1);
    }

    errno = 0;
    while ((xlde = readdir(xldir)) != NULL)
    {
        if (strlen(xlde->d_name) == 24 &&
            strspn(xlde->d_name, "0123456789ABCDEF") == 24)
        {
            snprintf(path, MAXPGPATH, "%s/%s", XLOGDIR, xlde->d_name);
            if (unlink(path) < 0)
            {
                fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
                        progname, path, strerror(errno));
                exit(1);
            }
        }
        errno = 0;
    }
#ifdef WIN32

    /*
     * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
     * released version
     */
    if (GetLastError() == ERROR_NO_MORE_FILES)
        errno = 0;
#endif

    if (errno)
    {
        fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
                progname, XLOGDIR, strerror(errno));
        exit(1);
    }
    closedir(xldir);
}

int main ( int  argc,
char *  argv[] 
)

Definition at line 80 of file pg_resetxlog.c.

References _, ControlFileData::checkPointCopy, DataDir, DB_SHUTDOWNED, FindEndOfXLOG(), FirstMultiXactId, FirstNormalTransactionId, get_progname(), getopt(), GuessControlValues(), guessed, KillExistingArchiveStatus(), KillExistingXLOG(), newXlogSegNo, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, CheckPoint::nextXidEpoch, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, optarg, optind, PG_TEXTDOMAIN, CheckPoint::PrevTimeLineID, PrintControlValues(), progname, ReadControlFile(), RewriteControlFile(), set_pglocale_pgservice(), ControlFileData::state, strerror(), CheckPoint::ThisTimeLineID, usage(), WriteEmptyXLOG(), and XLogFromFileName.

{
    int         c;
    bool        force = false;
    bool        noupdate = false;
    uint32      set_xid_epoch = (uint32) -1;
    TransactionId set_xid = 0;
    Oid         set_oid = 0;
    MultiXactId set_mxid = 0;
    MultiXactId set_oldestmxid = 0;
    MultiXactOffset set_mxoff = (MultiXactOffset) -1;
    uint32      minXlogTli = 0;
    XLogSegNo   minXlogSegNo = 0;
    char       *endptr;
    char       *endptr2;
    char       *DataDir;
    int         fd;

    set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetxlog"));

    progname = get_progname(argv[0]);

    if (argc > 1)
    {
        if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
        {
            usage();
            exit(0);
        }
        if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
        {
            puts("pg_resetxlog (PostgreSQL) " PG_VERSION);
            exit(0);
        }
    }


    while ((c = getopt(argc, argv, "fl:m:no:O:x:e:")) != -1)
    {
        switch (c)
        {
            case 'f':
                force = true;
                break;

            case 'n':
                noupdate = true;
                break;

            case 'e':
                set_xid_epoch = strtoul(optarg, &endptr, 0);
                if (endptr == optarg || *endptr != '\0')
                {
                    fprintf(stderr, _("%s: invalid argument for option -e\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                if (set_xid_epoch == -1)
                {
                    fprintf(stderr, _("%s: transaction ID epoch (-e) must not be -1\n"), progname);
                    exit(1);
                }
                break;

            case 'x':
                set_xid = strtoul(optarg, &endptr, 0);
                if (endptr == optarg || *endptr != '\0')
                {
                    fprintf(stderr, _("%s: invalid argument for option -x\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                if (set_xid == 0)
                {
                    fprintf(stderr, _("%s: transaction ID (-x) must not be 0\n"), progname);
                    exit(1);
                }
                break;

            case 'o':
                set_oid = strtoul(optarg, &endptr, 0);
                if (endptr == optarg || *endptr != '\0')
                {
                    fprintf(stderr, _("%s: invalid argument for option -o\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                if (set_oid == 0)
                {
                    fprintf(stderr, _("%s: OID (-o) must not be 0\n"), progname);
                    exit(1);
                }
                break;

            case 'm':
                set_mxid = strtoul(optarg, &endptr, 0);
                if (endptr == optarg || *endptr != ',')
                {
                    fprintf(stderr, _("%s: invalid argument for option -m\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }

                set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
                if (endptr2 == endptr + 1 || *endptr2 != '\0')
                {
                    fprintf(stderr, _("%s: invalid argument for option -m\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                if (set_mxid == 0)
                {
                    fprintf(stderr, _("%s: multitransaction ID (-m) must not be 0\n"), progname);
                    exit(1);
                }
                /*
                 * XXX It'd be nice to have more sanity checks here, e.g. so
                 * that oldest is not wrapped around w.r.t. nextMulti.
                 */
                if (set_oldestmxid == 0)
                {
                    fprintf(stderr, _("%s: oldest multitransaction ID (-m) must not be 0\n"),
                            progname);
                    exit(1);
                }
                break;

            case 'O':
                set_mxoff = strtoul(optarg, &endptr, 0);
                if (endptr == optarg || *endptr != '\0')
                {
                    fprintf(stderr, _("%s: invalid argument for option -O\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                if (set_mxoff == -1)
                {
                    fprintf(stderr, _("%s: multitransaction offset (-O) must not be -1\n"), progname);
                    exit(1);
                }
                break;

            case 'l':
                if (strspn(optarg, "01234567890ABCDEFabcdef") != 24)
                {
                    fprintf(stderr, _("%s: invalid argument for option -l\n"), progname);
                    fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                    exit(1);
                }
                XLogFromFileName(optarg, &minXlogTli, &minXlogSegNo);
                break;

            default:
                fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                exit(1);
        }
    }

    if (optind == argc)
    {
        fprintf(stderr, _("%s: no data directory specified\n"), progname);
        fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
        exit(1);
    }

    /*
     * Don't allow pg_resetxlog to be run as root, to avoid overwriting the
     * ownership of files in the data directory. We need only check for root
     * -- any other user won't have sufficient permissions to modify files in
     * the data directory.
     */
#ifndef WIN32
    if (geteuid() == 0)
    {
        fprintf(stderr, _("%s: cannot be executed by \"root\"\n"),
                progname);
        fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
                progname);
        exit(1);
    }
#endif

    DataDir = argv[optind];

    if (chdir(DataDir) < 0)
    {
        fprintf(stderr, _("%s: could not change directory to \"%s\": %s\n"),
                progname, DataDir, strerror(errno));
        exit(1);
    }

    /*
     * Check for a postmaster lock file --- if there is one, refuse to
     * proceed, on grounds we might be interfering with a live installation.
     */
    if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
    {
        if (errno != ENOENT)
        {
            fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
                    progname, "postmaster.pid", strerror(errno));
            exit(1);
        }
    }
    else
    {
        fprintf(stderr, _("%s: lock file \"%s\" exists\n"
                          "Is a server running?  If not, delete the lock file and try again.\n"),
                progname, "postmaster.pid");
        exit(1);
    }

    /*
     * Attempt to read the existing pg_control file
     */
    if (!ReadControlFile())
        GuessControlValues();

    /*
     * Also look at existing segment files to set up newXlogSegNo
     */
    FindEndOfXLOG();

    /*
     * Adjust fields if required by switches.  (Do this now so that printout,
     * if any, includes these values.)
     */
    if (set_xid_epoch != -1)
        ControlFile.checkPointCopy.nextXidEpoch = set_xid_epoch;

    if (set_xid != 0)
    {
        ControlFile.checkPointCopy.nextXid = set_xid;

        /*
         * For the moment, just set oldestXid to a value that will force
         * immediate autovacuum-for-wraparound.  It's not clear whether adding
         * user control of this is useful, so let's just do something that's
         * reasonably safe.  The magic constant here corresponds to the
         * maximum allowed value of autovacuum_freeze_max_age.
         */
        ControlFile.checkPointCopy.oldestXid = set_xid - 2000000000;
        if (ControlFile.checkPointCopy.oldestXid < FirstNormalTransactionId)
            ControlFile.checkPointCopy.oldestXid += FirstNormalTransactionId;
        ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
    }

    if (set_oid != 0)
        ControlFile.checkPointCopy.nextOid = set_oid;

    if (set_mxid != 0)
    {
        ControlFile.checkPointCopy.nextMulti = set_mxid;

        ControlFile.checkPointCopy.oldestMulti = set_oldestmxid;
        if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
            ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
        ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
    }

    if (set_mxoff != -1)
        ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;

    if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
    {
        ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
        ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
    }

    if (minXlogSegNo > newXlogSegNo)
        newXlogSegNo = minXlogSegNo;

    /*
     * If we had to guess anything, and -f was not given, just print the
     * guessed values and exit.  Also print if -n is given.
     */
    if ((guessed && !force) || noupdate)
    {
        PrintControlValues(guessed);
        if (!noupdate)
        {
            printf(_("\nIf these values seem acceptable, use -f to force reset.\n"));
            exit(1);
        }
        else
            exit(0);
    }

    /*
     * Don't reset from a dirty pg_control without -f, either.
     */
    if (ControlFile.state != DB_SHUTDOWNED && !force)
    {
        printf(_("The database server was not shut down cleanly.\n"
               "Resetting the transaction log might cause data to be lost.\n"
                 "If you want to proceed anyway, use -f to force reset.\n"));
        exit(1);
    }

    /*
     * Else, do the dirty deed.
     */
    RewriteControlFile();
    KillExistingXLOG();
    KillExistingArchiveStatus();
    WriteEmptyXLOG();

    printf(_("Transaction log reset\n"));
    return 0;
}

static void PrintControlValues ( bool  guessed  )  [static]

Definition at line 554 of file pg_resetxlog.c.

References _, ControlFileData::blcksz, ControlFileData::catalog_version_no, ControlFileData::checkPointCopy, ControlFileData::data_checksum_version, ControlFileData::enableIntTimes, ControlFileData::float4ByVal, ControlFileData::float8ByVal, CheckPoint::fullPageWrites, ControlFileData::indexMaxKeys, ControlFileData::maxAlign, ControlFileData::nameDataLen, newXlogSegNo, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, CheckPoint::nextXidEpoch, CheckPoint::oldestActiveXid, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, ControlFileData::pg_control_version, ControlFileData::relseg_size, snprintf(), ControlFileData::system_identifier, CheckPoint::ThisTimeLineID, ControlFileData::toast_max_chunk_size, ControlFileData::xlog_blcksz, ControlFileData::xlog_seg_size, and XLogFileName.

Referenced by main().

{
    char        sysident_str[32];
    char        fname[MAXFNAMELEN];

    if (guessed)
        printf(_("Guessed pg_control values:\n\n"));
    else
        printf(_("pg_control values:\n\n"));

    /*
     * Format system_identifier separately to keep platform-dependent format
     * code out of the translatable message string.
     */
    snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
             ControlFile.system_identifier);

    XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);

    printf(_("First log segment after reset:        %s\n"),
           fname);
    printf(_("pg_control version number:            %u\n"),
           ControlFile.pg_control_version);
    printf(_("Catalog version number:               %u\n"),
           ControlFile.catalog_version_no);
    printf(_("Database system identifier:           %s\n"),
           sysident_str);
    printf(_("Latest checkpoint's TimeLineID:       %u\n"),
           ControlFile.checkPointCopy.ThisTimeLineID);
    printf(_("Latest checkpoint's full_page_writes: %s\n"),
           ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
    printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
           ControlFile.checkPointCopy.nextXidEpoch,
           ControlFile.checkPointCopy.nextXid);
    printf(_("Latest checkpoint's NextOID:          %u\n"),
           ControlFile.checkPointCopy.nextOid);
    printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
           ControlFile.checkPointCopy.nextMulti);
    printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
           ControlFile.checkPointCopy.nextMultiOffset);
    printf(_("Latest checkpoint's oldestXID:        %u\n"),
           ControlFile.checkPointCopy.oldestXid);
    printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
           ControlFile.checkPointCopy.oldestXidDB);
    printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
           ControlFile.checkPointCopy.oldestActiveXid);
    printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
           ControlFile.checkPointCopy.oldestMulti);
    printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
           ControlFile.checkPointCopy.oldestMultiDB);
    printf(_("Maximum data alignment:               %u\n"),
           ControlFile.maxAlign);
    /* we don't print floatFormat since can't say much useful about it */
    printf(_("Database block size:                  %u\n"),
           ControlFile.blcksz);
    printf(_("Blocks per segment of large relation: %u\n"),
           ControlFile.relseg_size);
    printf(_("WAL block size:                       %u\n"),
           ControlFile.xlog_blcksz);
    printf(_("Bytes per WAL segment:                %u\n"),
           ControlFile.xlog_seg_size);
    printf(_("Maximum length of identifiers:        %u\n"),
           ControlFile.nameDataLen);
    printf(_("Maximum columns in an index:          %u\n"),
           ControlFile.indexMaxKeys);
    printf(_("Maximum size of a TOAST chunk:        %u\n"),
           ControlFile.toast_max_chunk_size);
    printf(_("Date/time type storage:               %s\n"),
           (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
    printf(_("Float4 argument passing:              %s\n"),
           (ControlFile.float4ByVal ? _("by value") : _("by reference")));
    printf(_("Float8 argument passing:              %s\n"),
           (ControlFile.float8ByVal ? _("by value") : _("by reference")));
    printf(_("Data page checksum version:           %u\n"),
           ControlFile.data_checksum_version);
}

static bool ReadControlFile ( void   )  [static]

Definition at line 399 of file pg_resetxlog.c.

References _, close, COMP_CRC32, EQ_CRC32, FIN_CRC32, guessed, INIT_CRC32, offsetof, PG_BINARY, PG_CONTROL_SIZE, PG_CONTROL_VERSION, pg_malloc(), progname, read, strerror(), and XLOG_CONTROL_FILE.

Referenced by main().

{
    int         fd;
    int         len;
    char       *buffer;
    pg_crc32    crc;

    if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
    {
        /*
         * If pg_control is not there at all, or we can't read it, the odds
         * are we've been handed a bad DataDir path, so give up. User can do
         * "touch pg_control" to force us to proceed.
         */
        fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
                progname, XLOG_CONTROL_FILE, strerror(errno));
        if (errno == ENOENT)
            fprintf(stderr, _("If you are sure the data directory path is correct, execute\n"
                              "  touch %s\n"
                              "and try again.\n"),
                    XLOG_CONTROL_FILE);
        exit(1);
    }

    /* Use malloc to ensure we have a maxaligned buffer */
    buffer = (char *) pg_malloc(PG_CONTROL_SIZE);

    len = read(fd, buffer, PG_CONTROL_SIZE);
    if (len < 0)
    {
        fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
                progname, XLOG_CONTROL_FILE, strerror(errno));
        exit(1);
    }
    close(fd);

    if (len >= sizeof(ControlFileData) &&
      ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
    {
        /* Check the CRC. */
        INIT_CRC32(crc);
        COMP_CRC32(crc,
                   buffer,
                   offsetof(ControlFileData, crc));
        FIN_CRC32(crc);

        if (EQ_CRC32(crc, ((ControlFileData *) buffer)->crc))
        {
            /* Valid data... */
            memcpy(&ControlFile, buffer, sizeof(ControlFile));
            return true;
        }

        fprintf(stderr, _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
                progname);
        /* We will use the data anyway, but treat it as guessed. */
        memcpy(&ControlFile, buffer, sizeof(ControlFile));
        guessed = true;
        return true;
    }

    /* Looks like it's a mess. */
    fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"),
            progname);
    return false;
}

static void RewriteControlFile ( void   )  [static]

Definition at line 636 of file pg_resetxlog.c.

References _, ControlFileData::backupEndPoint, ControlFileData::backupEndRequired, ControlFileData::backupStartPoint, ControlFileData::checkPoint, ControlFileData::checkPointCopy, close, COMP_CRC32, ControlFileData::crc, FIN_CRC32, fsync, INIT_CRC32, ControlFileData::max_locks_per_xact, ControlFileData::max_prepared_xacts, ControlFileData::MaxConnections, ControlFileData::minRecoveryPoint, ControlFileData::minRecoveryPointTLI, newXlogSegNo, NULL, offsetof, PG_BINARY, PG_CONTROL_SIZE, ControlFileData::prevCheckPoint, progname, CheckPoint::redo, SizeOfXLogLongPHD, ControlFileData::state, strerror(), ControlFileData::time, CheckPoint::time, unlink(), ControlFileData::wal_level, write, XLOG_CONTROL_FILE, ControlFileData::xlog_seg_size, and XLogSegNoOffsetToRecPtr.

Referenced by main().

{
    int         fd;
    char        buffer[PG_CONTROL_SIZE];        /* need not be aligned */

    /*
     * Adjust fields as needed to force an empty XLOG starting at
     * newXlogSegNo.
     */
    XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
                            ControlFile.checkPointCopy.redo);
    ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);

    ControlFile.state = DB_SHUTDOWNED;
    ControlFile.time = (pg_time_t) time(NULL);
    ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
    ControlFile.prevCheckPoint = 0;
    ControlFile.minRecoveryPoint = 0;
    ControlFile.minRecoveryPointTLI = 0;
    ControlFile.backupStartPoint = 0;
    ControlFile.backupEndPoint = 0;
    ControlFile.backupEndRequired = false;

    /*
     * Force the defaults for max_* settings. The values don't really matter
     * as long as wal_level='minimal'; the postmaster will reset these fields
     * anyway at startup.
     */
    ControlFile.wal_level = WAL_LEVEL_MINIMAL;
    ControlFile.MaxConnections = 100;
    ControlFile.max_prepared_xacts = 0;
    ControlFile.max_locks_per_xact = 64;

    /* Now we can force the recorded xlog seg size to the right thing. */
    ControlFile.xlog_seg_size = XLogSegSize;

    /* Contents are protected with a CRC */
    INIT_CRC32(ControlFile.crc);
    COMP_CRC32(ControlFile.crc,
               (char *) &ControlFile,
               offsetof(ControlFileData, crc));
    FIN_CRC32(ControlFile.crc);

    /*
     * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
     * excess over sizeof(ControlFileData).  This reduces the odds of
     * premature-EOF errors when reading pg_control.  We'll still fail when we
     * check the contents of the file, but hopefully with a more specific
     * error than "couldn't read pg_control".
     */
    if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
    {
        fprintf(stderr,
                _("%s: internal error -- sizeof(ControlFileData) is too large ... fix PG_CONTROL_SIZE\n"),
                progname);
        exit(1);
    }

    memset(buffer, 0, PG_CONTROL_SIZE);
    memcpy(buffer, &ControlFile, sizeof(ControlFileData));

    unlink(XLOG_CONTROL_FILE);

    fd = open(XLOG_CONTROL_FILE,
              O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
              S_IRUSR | S_IWUSR);
    if (fd < 0)
    {
        fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
                progname, strerror(errno));
        exit(1);
    }

    errno = 0;
    if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
    {
        /* if write didn't set errno, assume problem is no disk space */
        if (errno == 0)
            errno = ENOSPC;
        fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
                progname, strerror(errno));
        exit(1);
    }

    if (fsync(fd) != 0)
    {
        fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
        exit(1);
    }

    close(fd);
}

static void usage ( void   )  [static]

Definition at line 1030 of file pg_resetxlog.c.

References _, and progname.

{
    printf(_("%s resets the PostgreSQL transaction log.\n\n"), progname);
    printf(_("Usage:\n  %s [OPTION]... DATADIR\n\n"), progname);
    printf(_("Options:\n"));
    printf(_("  -e XIDEPOCH      set next transaction ID epoch\n"));
    printf(_("  -f               force update to be done\n"));
    printf(_("  -l XLOGFILE      force minimum WAL starting location for new transaction log\n"));
    printf(_("  -m XID,OLDEST    set next multitransaction ID and oldest value\n"));
    printf(_("  -n               no update, just show extracted control values (for testing)\n"));
    printf(_("  -o OID           set next OID\n"));
    printf(_("  -O OFFSET        set next multitransaction offset\n"));
    printf(_("  -V, --version    output version information, then exit\n"));
    printf(_("  -x XID           set next transaction ID\n"));
    printf(_("  -?, --help       show this help, then exit\n"));
    printf(_("\nReport bugs to <[email protected]>.\n"));
}

static void WriteEmptyXLOG ( void   )  [static]

Definition at line 936 of file pg_resetxlog.c.

References _, ControlFileData::checkPointCopy, close, COMP_CRC32, FIN_CRC32, fsync, INIT_CRC32, newXlogSegNo, offsetof, PG_BINARY, pg_malloc(), progname, CheckPoint::redo, SizeOfXLogRecord, strerror(), ControlFileData::system_identifier, CheckPoint::ThisTimeLineID, unlink(), write, XLogRecord::xl_info, XLogRecord::xl_len, XLogRecord::xl_prev, XLogRecord::xl_rmid, XLogRecord::xl_tot_len, XLogRecord::xl_xid, XLogFilePath, XLogRecGetData, XLogPageHeaderData::xlp_info, XLogPageHeaderData::xlp_magic, XLogPageHeaderData::xlp_pageaddr, XLogLongPageHeaderData::xlp_seg_size, XLogLongPageHeaderData::xlp_sysid, XLogPageHeaderData::xlp_tli, and XLogLongPageHeaderData::xlp_xlog_blcksz.

Referenced by main().

{
    char       *buffer;
    XLogPageHeader page;
    XLogLongPageHeader longpage;
    XLogRecord *record;
    pg_crc32    crc;
    char        path[MAXPGPATH];
    int         fd;
    int         nbytes;

    /* Use malloc() to ensure buffer is MAXALIGNED */
    buffer = (char *) pg_malloc(XLOG_BLCKSZ);
    page = (XLogPageHeader) buffer;
    memset(buffer, 0, XLOG_BLCKSZ);

    /* Set up the XLOG page header */
    page->xlp_magic = XLOG_PAGE_MAGIC;
    page->xlp_info = XLP_LONG_HEADER;
    page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
    page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
    longpage = (XLogLongPageHeader) page;
    longpage->xlp_sysid = ControlFile.system_identifier;
    longpage->xlp_seg_size = XLogSegSize;
    longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;

    /* Insert the initial checkpoint record */
    record = (XLogRecord *) ((char *) page + SizeOfXLogLongPHD);
    record->xl_prev = 0;
    record->xl_xid = InvalidTransactionId;
    record->xl_tot_len = SizeOfXLogRecord + sizeof(CheckPoint);
    record->xl_len = sizeof(CheckPoint);
    record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
    record->xl_rmid = RM_XLOG_ID;
    memcpy(XLogRecGetData(record), &ControlFile.checkPointCopy,
           sizeof(CheckPoint));

    INIT_CRC32(crc);
    COMP_CRC32(crc, &ControlFile.checkPointCopy, sizeof(CheckPoint));
    COMP_CRC32(crc, (char *) record, offsetof(XLogRecord, xl_crc));
    FIN_CRC32(crc);
    record->xl_crc = crc;

    /* Write the first page */
    XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);

    unlink(path);

    fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
              S_IRUSR | S_IWUSR);
    if (fd < 0)
    {
        fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
                progname, path, strerror(errno));
        exit(1);
    }

    errno = 0;
    if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
    {
        /* if write didn't set errno, assume problem is no disk space */
        if (errno == 0)
            errno = ENOSPC;
        fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
                progname, path, strerror(errno));
        exit(1);
    }

    /* Fill the rest of the file with zeroes */
    memset(buffer, 0, XLOG_BLCKSZ);
    for (nbytes = XLOG_BLCKSZ; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
    {
        errno = 0;
        if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
        {
            if (errno == 0)
                errno = ENOSPC;
            fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
                    progname, path, strerror(errno));
            exit(1);
        }
    }

    if (fsync(fd) != 0)
    {
        fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
        exit(1);
    }

    close(fd);
}


Variable Documentation

Definition at line 63 of file pg_resetxlog.c.

bool guessed = false [static]

Definition at line 65 of file pg_resetxlog.c.

Referenced by GuessControlValues(), main(), and ReadControlFile().

char* optarg

Definition at line 51 of file getopt.c.

int optind

Definition at line 49 of file getopt.c.

const char* progname [static]

Definition at line 66 of file pg_resetxlog.c.