pg_resetxlog_find_max_lsn_from_datafiles.patch
text/plain
Filename: pg_resetxlog_find_max_lsn_from_datafiles.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/bin/pg_resetxlog/pg_resetxlog.c | 366 | 1 |
diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index d5d89ec..dcb62d1 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -54,6 +54,20 @@
#include "access/xlog_internal.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
+#include "catalog/catalog.h"
+#include "storage/bufpage.h"
+#include "storage/fd.h"
+
+
+/* Page header size */
+#define PAGEHDRSZ (sizeof(PageHeaderData))
+
+
+/*
+ * relfile nodename validation allow only file name start with digit
+ */
+#define validateRelfilenodename(name) ((name[0] >= '0') && (name[0] <= '9'))
+
extern int optind;
extern char *optarg;
@@ -72,6 +86,9 @@ static void FindEndOfXLOG(void);
static void KillExistingXLOG(void);
static void KillExistingArchiveStatus(void);
static void WriteEmptyXLOG(void);
+static void FindMaxLSNinFile(char *filename, XLogRecPtr *maxlsn);
+static void FindMaxLSNinDir(char *path, XLogRecPtr *maxlsn);
+static void FindMaxLSNinPgData(XLogRecPtr *maxlsn);
static void usage(void);
@@ -92,6 +109,10 @@ main(int argc, char *argv[])
char *DataDir;
int fd;
char path[MAXPGPATH];
+ bool print_max_lsn = false;
+ bool print_pgdata_max_lsn = false;
+ char *LsnSearchPath;
+ uint64 maxLSN = 0;
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetxlog"));
@@ -112,7 +133,7 @@ main(int argc, char *argv[])
}
- while ((c = getopt(argc, argv, "fl:m:no:O:x:e:")) != -1)
+ while ((c = getopt(argc, argv, "fl:m:no:O:x:e:p:P")) != -1)
{
switch (c)
{
@@ -209,6 +230,15 @@ main(int argc, char *argv[])
XLogFromFileName(optarg, &minXlogTli, &minXlogSegNo);
break;
+ case 'p':
+ print_max_lsn = true;
+ LsnSearchPath = optarg;
+ break;
+
+ case 'P':
+ print_pgdata_max_lsn = true;
+ break;
+
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
@@ -270,6 +300,55 @@ main(int argc, char *argv[])
exit(1);
}
+
+ if (print_max_lsn || print_pgdata_max_lsn)
+ {
+ XLogSegNo logSegNo = 0;
+
+ if (print_pgdata_max_lsn)
+ {
+ FindMaxLSNinPgData(&maxLSN);
+ }
+ else
+ {
+ struct stat fst;
+
+ if (stat(LsnSearchPath, &fst) < 0)
+ {
+ if (errno == ENOENT)
+ {
+ fprintf(stderr, _("%s: file or directory \"%s\" does not exists"),
+ progname, LsnSearchPath);
+ }
+ else
+ {
+ fprintf(stderr, _("%s: file or directory \"%s\" exists\n"
+ "\n"),
+ progname, LsnSearchPath);
+ }
+ exit(1);
+ }
+
+ if (S_ISDIR(fst.st_mode))
+ {
+ FindMaxLSNinDir(LsnSearchPath, &maxLSN);
+ }
+ else
+ {
+ FindMaxLSNinFile(LsnSearchPath, &maxLSN);
+ }
+ }
+
+ XLByteToSeg(maxLSN, logSegNo);
+
+ printf ("Maximum LSN found is: " UINT64_FORMAT ", "
+ "WAL segment file name (fileid,seg): %08X%08X\n",
+ maxLSN,
+ (uint32) ((logSegNo) / XLogSegmentsPerXLogId),
+ (uint32) ((logSegNo) % XLogSegmentsPerXLogId));
+ exit(0);
+ }
+
/*
* Attempt to read the existing pg_control file
*/
@@ -986,6 +1065,290 @@ WriteEmptyXLOG(void)
}
+/*
+ * PageHeaderIsValid: Check page is valid or not
+ */
+bool
+PageHeaderIsValid(PageHeader page)
+{
+ char *pagebytes;
+ int i;
+
+ /* Check normal case */
+ if (PageGetPageSize(page) == BLCKSZ &&
+ PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
+ (page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
+ page->pd_lower >= SizeOfPageHeaderData &&
+ page->pd_lower <= page->pd_upper &&
+ page->pd_upper <= page->pd_special &&
+ page->pd_special <= BLCKSZ &&
+ page->pd_special == MAXALIGN(page->pd_special))
+ return true;
+
+ /*
+ * Check all-zeroes till page header; this is used only to log the page
+ * details even we detect invalid page we will continue to nex pages
+ */
+ pagebytes = (char *) page;
+ for (i = 0; i < PAGEHDRSZ; i++)
+ {
+ if (pagebytes[i] != 0)
+ return false;
+ }
+ return true;
+}
+
+
+/*
+ * Read the maximum LSN number in the one of data file (relnode file).
+ *
+ */
+static void
+FindMaxLSNinFile(char *filename, XLogRecPtr *maxlsn)
+{
+ XLogRecPtr pagelsn;
+ off_t len,
+ seekpos;
+ uint32 nblocks,
+ blocknum;
+ char buffer[PAGEHDRSZ];
+ int nbytes;
+ int fd;
+
+ if ((fd = open(filename, O_RDONLY | PG_BINARY, 0)) < 0)
+ {
+ /*
+ * If file does not exist or or we can't read it. give error
+ */
+ fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+ progname, filename, strerror(errno));
+ return;
+ }
+
+ /* Calculate the number of pages in file */
+ len = lseek(fd, 0L, SEEK_END);
+ if (len < 0)
+ {
+ close(fd);
+ fprintf(stderr, _("%s: .. file \"%s\" for seeking: %s\n"),
+ progname, filename, strerror(errno));
+ return;
+ }
+
+ nblocks = (len / BLCKSZ);
+ if (nblocks > RELSEG_SIZE)
+ {
+ /*
+ * In one relfilenode file length can't be more that RELSEG_SIZE
+ */
+ close(fd);
+ fprintf(stderr, _("%s: .. file \"%s\" legth is more than RELSEG_SIZE.\n"),
+ progname, filename);
+ return;
+ }
+
+ /*
+ * Read the only page header and validate; if we find invalid page log the
+ * details of page and continue to next page.
+ */
+ seekpos = 0;
+ for (blocknum = 0; blocknum < nblocks; blocknum++)
+ {
+ len = lseek(fd, seekpos, SEEK_SET);
+ if (len != seekpos)
+ {
+ close(fd);
+ fprintf(stderr, _("%s: could not seek to next page \"%s\": %s\n"),
+ progname, filename, strerror(errno));
+ return;
+ }
+
+ nbytes = read(fd, buffer, PAGEHDRSZ);
+ if (nbytes < 0)
+ {
+ close(fd);
+ fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
+ progname, filename, strerror(errno));
+ return;
+ }
+
+ if (PageHeaderIsValid((PageHeader) buffer))
+ {
+ pagelsn = PageGetLSN(buffer);
+ if (XLByteLE(*maxlsn, pagelsn))
+ {
+ *maxlsn = pagelsn;
+ }
+ }
+ else
+ {
+ /*
+ * If page is invalid log the error and continue
+ */
+ fprintf(stderr, _("%s: Invalid page found in file \"%s\" pagid:%d\n"),
+ progname, filename, blocknum);
+ }
+ seekpos += (off_t) BLCKSZ;
+ }
+
+ close(fd);
+ return;
+}
+
+/*
+ * Read the maximum LSN number in current directory; ignore sub directories.
+ */
+static void
+FindMaxLSNinDir(char *path, XLogRecPtr *maxlsn)
+{
+ DIR *dir;
+ struct dirent *de;
+ char pathbuf[MAXPGPATH];
+ struct stat statbuf;
+
+ dir = opendir(path);
+ if (NULL == dir)
+ {
+ fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+ progname, path, strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(dir)) != NULL)
+ {
+ /* Skip special stuff */
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+
+ /* Skip temporary files */
+ if (strncmp(de->d_name,
+ PG_TEMP_FILE_PREFIX,
+ strlen(PG_TEMP_FILE_PREFIX)) == 0)
+ continue;
+
+ /*
+ * Skip all the local/global temporary files, and read and read all
+ * reamining relfinenode files
+ */
+ if (!validateRelfilenodename(de->d_name))
+ continue;
+
+ snprintf(pathbuf, MAXPGPATH, "%s/%s", path, de->d_name);
+
+ if (stat(pathbuf, &statbuf) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ fprintf(stderr, "could not stat file or directory \"%s\"",
+ pathbuf);
+ }
+ /* If the file went away while scanning, it's no error. */
+ continue;
+ }
+
+ /*
+ * Skip all directories
+ */
+ if (!S_ISDIR(statbuf.st_mode))
+ {
+ FindMaxLSNinFile(pathbuf, maxlsn);
+ }
+ }
+
+ closedir(dir);
+ return;
+}
+
+/*
+ * Read the maximum LSN number in the DATA directory.
+ */
+static void
+FindMaxLSNinPgData(XLogRecPtr *maxlsn)
+{
+ DIR *dir,
+ *dir2;
+ struct dirent *de,
+ *de2;
+ char pathbuf[MAXPGPATH],
+ pathbuf2[MAXPGPATH];
+
+ /*
+ * scan all the relfilenodes in global directory
+ */
+ FindMaxLSNinDir("global", maxlsn);
+
+ /*
+ * scan all the relfilenodes in base directory like base/<database-id>
+ */
+ dir = opendir("base");
+ if (NULL == dir)
+ {
+ fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+ progname, "base", strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(dir)) != NULL)
+ {
+ /* Skip special stuff */
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+
+ /* Skip template database */
+ if (strcmp(de->d_name, "0") == 0 || strcmp(de->d_name, "1") == 0)
+ continue;
+
+ snprintf(pathbuf, MAXPGPATH, "%s/%s", "base", de->d_name);
+
+ FindMaxLSNinDir(pathbuf, maxlsn);
+ }
+ closedir(dir);
+
+ /* Scan all tablespaces */
+ dir = opendir("pg_tblspc");
+ if (NULL == dir)
+ {
+ fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+ progname, "pg_tblspc", strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(dir)) != NULL)
+ {
+ /* Skip special stuff */
+ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+ continue;
+
+ /*
+ * Scan all directories in tablespace
+ * ./pg_tblspc/tablespaceid/TABLESPACE_VERSION_DIRECTORY/ *
+ */
+ snprintf(pathbuf, MAXPGPATH, "%s/%s/%s", "pg_tblspc", de->d_name, TABLESPACE_VERSION_DIRECTORY);
+ dir2 = opendir(pathbuf);
+ if (NULL == dir2)
+ {
+ fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+ progname, pathbuf, strerror(errno));
+ return;
+ }
+
+ while ((de2 = readdir(dir2)) != NULL)
+ {
+ /* Skip special stuff */
+ if (strcmp(de2->d_name, ".") == 0 || strcmp(de2->d_name, "..") == 0)
+ continue;
+
+ snprintf(pathbuf2, MAXPGPATH, "%s/%s", pathbuf, de2->d_name);
+
+ FindMaxLSNinDir(pathbuf2, maxlsn);
+ }
+ closedir(dir2);
+ }
+ closedir(dir);
+
+ return;
+}
+
static void
usage(void)
{
@@ -997,6 +1360,8 @@ usage(void)
printf(_(" -l xlogfile force minimum WAL starting location for new transaction log\n"));
printf(_(" -m XID set next multitransaction ID\n"));
printf(_(" -n no update, just show extracted control values (for testing)\n"));
+ printf(_(" -p {file | dir} print max LSN from specified file or directory path\n"));
+ printf(_(" -P print max LSN from whole database\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"));