📄 pg_resetxlog.c
字号:
/*------------------------------------------------------------------------- * * pg_resetxlog.c * A utility to "zero out" the xlog when it's corrupt beyond recovery. * Can also rebuild pg_control if needed. * * The theory of operation is fairly simple: * 1. Read the existing pg_control (which will include the last * checkpoint record). If it is an old format then update to * current format. * 2. If pg_control is corrupt, attempt to intuit reasonable values, * by scanning the old xlog if necessary. * 3. Modify pg_control to reflect a "shutdown" state with a checkpoint * record at the start of xlog. * 4. Flush the existing xlog files and write a new segment with * just a checkpoint record in it. The new segment is positioned * just past the end of the old xlog, so that existing LSNs in * data pages will appear to be "in the past". * This is all pretty straightforward except for the intuition part of * step 2 ... * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * $Header: /cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.13 2003/09/07 03:43:53 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <errno.h>#include <unistd.h>#include <time.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>#include <locale.h>#include "access/xlog.h"#include "catalog/catversion.h"#include "catalog/pg_control.h"/******************** stuff copied from xlog.c ********************//* Increment an xlogid/segment pair */#define NextLogSeg(logId, logSeg) \ do { \ if ((logSeg) >= XLogSegsPerFile-1) \ { \ (logId)++; \ (logSeg) = 0; \ } \ else \ (logSeg)++; \ } while (0)#define XLogFileName(path, log, seg) \ snprintf(path, MAXPGPATH, "%s/%08X%08X", \ XLogDir, log, seg)/******************** end of stuff copied from xlog.c ********************/#define _(x) gettext((x))static char XLogDir[MAXPGPATH];static char ControlFilePath[MAXPGPATH];static ControlFileData ControlFile; /* pg_control values */static uint32 newXlogId, newXlogSeg; /* ID/Segment of new XLOG segment */static bool guessed = false; /* T if we had to guess at any values */static char *progname;static bool ReadControlFile(void);static void GuessControlValues(void);static void PrintControlValues(bool guessed);static void RewriteControlFile(void);static void KillExistingXLOG(void);static void WriteEmptyXLOG(void);static void usage(void);extern char *optarg;intmain(int argc, char *argv[]){ int c; bool force = false; bool noupdate = false; TransactionId set_xid = 0; Oid set_oid = 0; uint32 minXlogId = 0, minXlogSeg = 0; char *endptr; char *endptr2; char *DataDir; int fd; char path[MAXPGPATH]; setlocale(LC_ALL, "");#ifdef ENABLE_NLS bindtextdomain("pg_resetxlog", LOCALEDIR); textdomain("pg_resetxlog");#endif 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:no:x:")) != -1) { switch (c) { case 'f': force = true; break; case 'n': noupdate = true; 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 'l': minXlogId = strtoul(optarg, &endptr, 0); if (endptr == optarg || *endptr != ',') { fprintf(stderr, _("%s: invalid argument for option -l\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } minXlogSeg = strtoul(endptr + 1, &endptr2, 0); if (endptr2 == endptr + 1 || *endptr2 != '\0') { fprintf(stderr, _("%s: invalid argument for option -l\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } 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); } DataDir = argv[optind]; snprintf(XLogDir, MAXPGPATH, "%s/pg_xlog", DataDir); snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir); /* * Check for a postmaster lock file --- if there is one, refuse to * proceed, on grounds we might be interfering with a live * installation. */ snprintf(path, MAXPGPATH, "%s/postmaster.pid", DataDir); if ((fd = open(path, O_RDONLY)) < 0) { if (errno != ENOENT) { fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), progname, path, 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, path); exit(1); } /* * Attempt to read the existing pg_control file */ if (!ReadControlFile()) GuessControlValues(); /* * Adjust fields if required by switches. (Do this now so that * printout, if any, includes these values.) */ if (set_xid != 0) ControlFile.checkPointCopy.nextXid = set_xid; if (set_oid != 0) ControlFile.checkPointCopy.nextOid = set_oid; if (minXlogId > ControlFile.logId || (minXlogId == ControlFile.logId && minXlogSeg > ControlFile.logSeg)) { ControlFile.logId = minXlogId; ControlFile.logSeg = minXlogSeg; } /* * 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 may 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(); WriteEmptyXLOG(); printf(_("Transaction log reset\n")); return 0;}/* * Try to read the existing pg_control file. * * This routine is also responsible for updating old pg_control versions * to the current format. */static boolReadControlFile(void){ int fd; int len; char *buffer; crc64 crc; if ((fd = open(ControlFilePath, O_RDONLY)) < 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, ControlFilePath, 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"), ControlFilePath); exit(1); } /* Use malloc to ensure we have a maxaligned buffer */ buffer = (char *) malloc(BLCKSZ); len = read(fd, buffer, BLCKSZ); if (len < 0) { fprintf(stderr, _("%s: could not read file \"%s\": %s\n"), progname, ControlFilePath, strerror(errno)); exit(1); } close(fd); if (len >= sizeof(ControlFileData) && ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION) { /* Check the CRC. */ INIT_CRC64(crc); COMP_CRC64(crc, buffer + sizeof(crc64), sizeof(ControlFileData) - sizeof(crc64)); FIN_CRC64(crc); if (EQ_CRC64(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -