diff options
| author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2012-06-24 18:06:38 +0300 |
|---|---|---|
| committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2012-06-24 18:35:29 +0300 |
| commit | dfda6ebaec6763090fb78b458a979b558c50b39b (patch) | |
| tree | 15720cd5663330a8c0bc1875d1041fbecd413130 /src/bin | |
| parent | 47c7365e794a0a57382efefbf1f2b062c7a3e3d3 (diff) | |
| download | postgresql-dfda6ebaec6763090fb78b458a979b558c50b39b.tar.gz | |
Don't waste the last segment of each 4GB logical log file.
The comments claimed that wasting the last segment made it easier to do
calculations with XLogRecPtrs, because you don't have problems representing
last-byte-position-plus-1 that way. In my experience, however, it only made
things more complicated, because the there was two ways to represent the
boundary at the beginning of a logical log file: logid = n+1 and xrecoff = 0,
or as xlogid = n and xrecoff = 4GB - XLOG_SEG_SIZE. Some functions were
picky about which representation was used.
Also, use a 64-bit segment number instead of the log/seg combination, to
point to a certain WAL segment. We assume that all platforms have a working
64-bit integer type nowadays.
This is an incompatible change in WAL format, so bumping WAL version number.
Diffstat (limited to 'src/bin')
| -rw-r--r-- | src/bin/pg_basebackup/pg_receivexlog.c | 22 | ||||
| -rw-r--r-- | src/bin/pg_basebackup/receivelog.c | 5 | ||||
| -rw-r--r-- | src/bin/pg_resetxlog/pg_resetxlog.c | 83 |
3 files changed, 42 insertions, 68 deletions
diff --git a/src/bin/pg_basebackup/pg_receivexlog.c b/src/bin/pg_basebackup/pg_receivexlog.c index 20adb653cf..4b109f4b96 100644 --- a/src/bin/pg_basebackup/pg_receivexlog.c +++ b/src/bin/pg_basebackup/pg_receivexlog.c @@ -102,8 +102,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) struct dirent *dirent; int i; bool b; - uint32 high_log = 0; - uint32 high_seg = 0; + XLogSegNo high_segno = 0; dir = opendir(basedir); if (dir == NULL) @@ -117,9 +116,10 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) { char fullpath[MAXPGPATH]; struct stat statbuf; - uint32 tli, - log, + uint32 tli; + unsigned int log, seg; + XLogSegNo segno; if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; @@ -151,6 +151,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) progname, dirent->d_name); disconnect_and_exit(1); } + segno = ((uint64) log) << 32 | seg; /* Ignore any files that are for another timeline */ if (tli != currenttimeline) @@ -168,11 +169,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) if (statbuf.st_size == XLOG_SEG_SIZE) { /* Completed segment */ - if (log > high_log || - (log == high_log && seg > high_seg)) + if (segno > high_segno) { - high_log = log; - high_seg = seg; + high_segno = segno; continue; } } @@ -186,7 +185,7 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) closedir(dir); - if (high_log > 0 || high_seg > 0) + if (high_segno > 0) { XLogRecPtr high_ptr; @@ -194,10 +193,9 @@ FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline) * Move the starting pointer to the start of the next segment, since * the highest one we've seen was completed. */ - NextLogSeg(high_log, high_seg); + high_segno++; - high_ptr.xlogid = high_log; - high_ptr.xrecoff = high_seg * XLOG_SEG_SIZE; + XLogSegNoOffsetToRecPtr(high_segno, 0, high_ptr); return high_ptr; } diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c index 9dd94e1140..8c6755caa9 100644 --- a/src/bin/pg_basebackup/receivelog.c +++ b/src/bin/pg_basebackup/receivelog.c @@ -55,9 +55,10 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu struct stat statbuf; char *zerobuf; int bytes; + XLogSegNo segno; - XLogFileName(namebuf, timeline, startpoint.xlogid, - startpoint.xrecoff / XLOG_SEG_SIZE); + XLByteToSeg(startpoint, segno); + XLogFileName(namebuf, timeline, segno); snprintf(fn, sizeof(fn), "%s/%s.partial", basedir, namebuf); f = open(fn, O_WRONLY | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c index 5ecf5c4930..554e08c98c 100644 --- a/src/bin/pg_resetxlog/pg_resetxlog.c +++ b/src/bin/pg_resetxlog/pg_resetxlog.c @@ -60,8 +60,7 @@ extern char *optarg; static ControlFileData ControlFile; /* pg_control values */ -static uint32 newXlogId, - newXlogSeg; /* ID/Segment of new XLOG segment */ +static XLogSegNo newXlogSegNo; /* new XLOG segment # */ static bool guessed = false; /* T if we had to guess at any values */ static const char *progname; @@ -87,12 +86,9 @@ main(int argc, char *argv[]) Oid set_oid = 0; MultiXactId set_mxid = 0; MultiXactOffset set_mxoff = (MultiXactOffset) -1; - uint32 minXlogTli = 0, - minXlogId = 0, - minXlogSeg = 0; + uint32 minXlogTli = 0; + XLogSegNo minXlogSegNo = 0; char *endptr; - char *endptr2; - char *endptr3; char *DataDir; int fd; char path[MAXPGPATH]; @@ -204,27 +200,13 @@ main(int argc, char *argv[]) break; case 'l': - minXlogTli = 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); - } - minXlogId = strtoul(endptr + 1, &endptr2, 0); - if (endptr2 == endptr + 1 || *endptr2 != ',') - { - fprintf(stderr, _("%s: invalid argument for option -l\n"), progname); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); - exit(1); - } - minXlogSeg = strtoul(endptr2 + 1, &endptr3, 0); - if (endptr3 == endptr2 + 1 || *endptr3 != '\0') + 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: @@ -295,7 +277,7 @@ main(int argc, char *argv[]) GuessControlValues(); /* - * Also look at existing segment files to set up newXlogId/newXlogSeg + * Also look at existing segment files to set up newXlogSegNo */ FindEndOfXLOG(); @@ -335,13 +317,8 @@ main(int argc, char *argv[]) if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID) ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli; - if (minXlogId > newXlogId || - (minXlogId == newXlogId && - minXlogSeg > newXlogSeg)) - { - newXlogId = minXlogId; - newXlogSeg = minXlogSeg; - } + if (minXlogSegNo > newXlogSegNo) + newXlogSegNo = minXlogSegNo; /* * If we had to guess anything, and -f was not given, just print the @@ -545,6 +522,7 @@ static void PrintControlValues(bool guessed) { char sysident_str[32]; + char fname[MAXFNAMELEN]; if (guessed) printf(_("Guessed pg_control values:\n\n")); @@ -558,10 +536,10 @@ PrintControlValues(bool guessed) snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT, ControlFile.system_identifier); - printf(_("First log file ID after reset: %u\n"), - newXlogId); - printf(_("First log file segment after reset: %u\n"), - newXlogSeg); + 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"), @@ -624,11 +602,10 @@ RewriteControlFile(void) /* * Adjust fields as needed to force an empty XLOG starting at - * newXlogId/newXlogSeg. + * newXlogSegNo. */ - ControlFile.checkPointCopy.redo.xlogid = newXlogId; - ControlFile.checkPointCopy.redo.xrecoff = - newXlogSeg * XLogSegSize + SizeOfXLogLongPHD; + XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, + ControlFile.checkPointCopy.redo); ControlFile.checkPointCopy.time = (pg_time_t) time(NULL); ControlFile.state = DB_SHUTDOWNED; @@ -728,14 +705,17 @@ FindEndOfXLOG(void) { 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. */ - newXlogId = ControlFile.checkPointCopy.redo.xlogid; - newXlogSeg = ControlFile.checkPointCopy.redo.xrecoff / ControlFile.xlog_seg_size; + segs_per_xlogid = (0x100000000L / ControlFile.xlog_seg_size); + newXlogSegNo = ((uint64) ControlFile.checkPointCopy.redo.xlogid) * segs_per_xlogid + + (ControlFile.checkPointCopy.redo.xrecoff / ControlFile.xlog_seg_size); /* * Scan the pg_xlog directory to find existing WAL segment files. We @@ -759,8 +739,10 @@ FindEndOfXLOG(void) 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 @@ -768,12 +750,8 @@ FindEndOfXLOG(void) * timelines other than the target TLI, but this seems safer. * Better too large a result than too small... */ - if (log > newXlogId || - (log == newXlogId && seg > newXlogSeg)) - { - newXlogId = log; - newXlogSeg = seg; - } + if (segno > newXlogSegNo) + newXlogSegNo = segno; } errno = 0; } @@ -799,11 +777,9 @@ FindEndOfXLOG(void) * Finally, convert to new xlog seg size, and advance by one to ensure we * are in virgin territory. */ - newXlogSeg *= ControlFile.xlog_seg_size; - newXlogSeg = (newXlogSeg + XLogSegSize - 1) / XLogSegSize; - - /* be sure we wrap around correctly at end of a logfile */ - NextLogSeg(newXlogId, newXlogSeg); + xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size; + newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize; + newXlogSegNo++; } @@ -972,8 +948,7 @@ WriteEmptyXLOG(void) record->xl_crc = crc; /* Write the first page */ - XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, - newXlogId, newXlogSeg); + XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo); unlink(path); |
