with_blocksize
with_segsize
with_wal_blocksize
-with_wal_segsize
with_CC
enable_depend
enable_cassert
--with-segsize=SEGSIZE set table segment size in GB [1]
--with-wal-blocksize=BLOCKSIZE
set WAL block size in kB [8]
- --with-wal-segsize=SEGSIZE
- set WAL segment size in MB [16]
--with-CC=CMD set compiler (deprecated)
--with-icu build with ICU support
--with-tcl build Tcl modules (PL/Tcl)
_ACEOF
-#
-# WAL segment size
-#
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for WAL segment size" >&5
-$as_echo_n "checking for WAL segment size... " >&6; }
-
-
-
-# Check whether --with-wal-segsize was given.
-if test "${with_wal_segsize+set}" = set; then :
- withval=$with_wal_segsize;
- case $withval in
- yes)
- as_fn_error $? "argument required for --with-wal-segsize option" "$LINENO" 5
- ;;
- no)
- as_fn_error $? "argument required for --with-wal-segsize option" "$LINENO" 5
- ;;
- *)
- wal_segsize=$withval
- ;;
- esac
-
-else
- wal_segsize=16
-fi
-
-
-case ${wal_segsize} in
- 1) ;;
- 2) ;;
- 4) ;;
- 8) ;;
- 16) ;;
- 32) ;;
- 64) ;;
- 128) ;;
- 256) ;;
- 512) ;;
- 1024) ;;
- *) as_fn_error $? "Invalid WAL segment size. Allowed values are 1,2,4,8,16,32,64,128,256,512,1024." "$LINENO" 5
-esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${wal_segsize}MB" >&5
-$as_echo "${wal_segsize}MB" >&6; }
-
-
-cat >>confdefs.h <<_ACEOF
-#define XLOG_SEG_SIZE (${wal_segsize} * 1024 * 1024)
-_ACEOF
-
-
#
# C compiler
#
Changing XLOG_BLCKSZ requires an initdb.
])
-#
-# WAL segment size
-#
-AC_MSG_CHECKING([for WAL segment size])
-PGAC_ARG_REQ(with, wal-segsize, [SEGSIZE], [set WAL segment size in MB [16]],
- [wal_segsize=$withval],
- [wal_segsize=16])
-case ${wal_segsize} in
- 1) ;;
- 2) ;;
- 4) ;;
- 8) ;;
- 16) ;;
- 32) ;;
- 64) ;;
- 128) ;;
- 256) ;;
- 512) ;;
- 1024) ;;
- *) AC_MSG_ERROR([Invalid WAL segment size. Allowed values are 1,2,4,8,16,32,64,128,256,512,1024.])
-esac
-AC_MSG_RESULT([${wal_segsize}MB])
-
-AC_DEFINE_UNQUOTED([XLOG_SEG_SIZE], [(${wal_segsize} * 1024 * 1024)], [
- XLOG_SEG_SIZE is the size of a single WAL file. This must be a power of 2
- and larger than XLOG_BLCKSZ (preferably, a great deal larger than
- XLOG_BLCKSZ).
-
- Changing XLOG_SEG_SIZE requires an initdb.
-])
-
#
# C compiler
#
const char *progname;
+int WalSegSz = -1;
+
/* Options and defaults */
int sleeptime = 5; /* amount of time to sleep between file checks */
int waittime = -1; /* how long we have been waiting, -1 no wait
struct stat stat_buf;
+static bool SetWALFileNameForCleanup(void);
+static bool SetWALSegSize(void);
+
+
/* =====================================================================
*
* Customizable section
{
if (stat(WALFilePath, &stat_buf) == 0)
{
+ /*
+ * If we've not seen any WAL segments, we don't know the WAL segment
+ * size, which we need. If it looks like a WAL segment, determine size
+ * of segments for the cluster.
+ */
+ if (WalSegSz == -1 && IsXLogFileName(nextWALFileName))
+ {
+ if (SetWALSegSize())
+ {
+ /*
+ * Successfully determined WAL segment size. Can compute
+ * cleanup cutoff now.
+ */
+ need_cleanup = SetWALFileNameForCleanup();
+ if (debug)
+ {
+ fprintf(stderr,
+ _("WAL segment size: %d \n"), WalSegSz);
+ fprintf(stderr, "Keep archive history: ");
+
+ if (need_cleanup)
+ fprintf(stderr, "%s and later\n",
+ exclusiveCleanupFileName);
+ else
+ fprintf(stderr, "no cleanup required\n");
+ }
+ }
+ }
+
/*
* If it's a backup file, return immediately. If it's a regular file
* return only if it's the right size already.
nextWALFileType = XLOG_BACKUP_LABEL;
return true;
}
- else if (stat_buf.st_size == XLOG_SEG_SIZE)
+ else if (WalSegSz > 0 && stat_buf.st_size == WalSegSz)
{
#ifdef WIN32
/*
* If still too small, wait until it is the correct size
*/
- if (stat_buf.st_size > XLOG_SEG_SIZE)
+ if (WalSegSz > 0 && stat_buf.st_size > WalSegSz)
{
if (debug)
{
return false;
}
-#define MaxSegmentsPerLogFile ( 0xFFFFFFFF / XLOG_SEG_SIZE )
-
static void
CustomizableCleanupPriorWALFiles(void)
{
uint32 log_diff = 0,
seg_diff = 0;
bool cleanup = false;
+ int max_segments_per_logfile = (0xFFFFFFFF / WalSegSz);
if (restartWALFileName)
{
sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg);
if (tli > 0 && seg > 0)
{
- log_diff = keepfiles / MaxSegmentsPerLogFile;
- seg_diff = keepfiles % MaxSegmentsPerLogFile;
+ log_diff = keepfiles / max_segments_per_logfile;
+ seg_diff = keepfiles % max_segments_per_logfile;
if (seg_diff > seg)
{
log_diff++;
- seg = MaxSegmentsPerLogFile - (seg_diff - seg);
+ seg = max_segments_per_logfile - (seg_diff - seg);
}
else
seg -= seg_diff;
return cleanup;
}
+/*
+ * Try to set the wal segment size from the WAL file specified by WALFilePath.
+ *
+ * Return true if size could be determined, false otherwise.
+ */
+static bool
+SetWALSegSize(void)
+{
+ bool ret_val = false;
+ int fd;
+ char *buf = (char *) malloc(XLOG_BLCKSZ);
+
+ Assert(WalSegSz == -1);
+
+ if ((fd = open(WALFilePath, O_RDWR, 0)) < 0)
+ {
+ fprintf(stderr, "%s: couldn't open WAL file \"%s\"\n",
+ progname, WALFilePath);
+ return false;
+ }
+ if (read(fd, buf, XLOG_BLCKSZ) == XLOG_BLCKSZ)
+ {
+ XLogLongPageHeader longhdr = (XLogLongPageHeader) buf;
+
+ WalSegSz = longhdr->xlp_seg_size;
+
+ if (IsValidWalSegSize(WalSegSz))
+ {
+ /* successfully retrieved WAL segment size */
+ ret_val = true;
+ }
+ else
+ fprintf(stderr,
+ "%s: WAL segment size must be a power of two between 1MB and 1GB, but the WAL file header specifies %d bytes\n",
+ progname, WalSegSz);
+ close(fd);
+ }
+ else
+ {
+ /*
+ * Don't complain loudly, this is to be expected for segments being
+ * created.
+ */
+ if (errno != 0)
+ {
+ if (debug)
+ fprintf(stderr, "could not read file \"%s\": %s",
+ WALFilePath, strerror(errno));
+ }
+ else
+ {
+ if (debug)
+ fprintf(stderr, "not enough data in file \"%s\"", WALFilePath);
+ }
+ }
+
+ fflush(stderr);
+ return ret_val;
+}
+
/*
* CheckForExternalTrigger()
*
CustomizableInitialize();
- need_cleanup = SetWALFileNameForCleanup();
-
if (debug)
{
fprintf(stderr, "Trigger file: %s\n", triggerPath ? triggerPath : "<not set>");
fprintf(stderr, "Max wait interval: %d %s\n",
maxwaittime, (maxwaittime > 0 ? "seconds" : "forever"));
fprintf(stderr, "Command for restore: %s\n", restoreCommand);
- fprintf(stderr, "Keep archive history: ");
- if (need_cleanup)
- fprintf(stderr, "%s and later\n", exclusiveCleanupFileName);
- else
- fprintf(stderr, "no cleanup required\n");
fflush(stderr);
}
produces an indefinitely long sequence of WAL records. The system
physically divides this sequence into WAL <firstterm>segment
files</>, which are normally 16MB apiece (although the segment size
- can be altered when building <productname>PostgreSQL</>). The segment
+ can be altered during <application>initdb</>). The segment
files are given numeric names that reflect their position in the
abstract WAL sequence. When not using WAL archiving, the system
normally creates just a few segment files and then
</listitem>
</varlistentry>
- <varlistentry>
- <term><option>--with-wal-segsize=<replaceable>SEGSIZE</replaceable></option></term>
- <listitem>
- <para>
- Set the <firstterm>WAL segment size</>, in megabytes. This is
- the size of each individual file in the WAL log. It may be useful
- to adjust this size to control the granularity of WAL log shipping.
- The default size is 16 megabytes.
- The value must be a power of 2 between 1 and 1024 (megabytes).
- Note that changing this value requires an initdb.
- </para>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><option>--with-wal-blocksize=<replaceable>BLOCKSIZE</replaceable></option></term>
<listitem>
</varlistentry>
<varlistentry>
+ <term><option>--wal-segsize=<replaceable>SEGSIZE</replaceable></option></term>
+ <listitem>
+ <para>
+ Set the <firstterm>WAL segment size</>, in megabytes. This is
+ the size of each individual file in the WAL log. It may be useful
+ to adjust this size to control the granularity of WAL log shipping.
+ This option can only be set during initialization, and cannot be
+ changed later.
+ The default size is 16 megabytes.
+ The value must be a power of 2 between 1 and 1024 (megabytes).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-X <replaceable class="parameter">directory</replaceable></option></term>
<term><option>--waldir=<replaceable class="parameter">directory</replaceable></option></term>
<listitem>
<acronym>WAL</acronym> logs are stored in the directory
<filename>pg_wal</filename> under the data directory, as a set of
segment files, normally each 16 MB in size (but the size can be changed
- by altering the <option>--with-wal-segsize</> configure option when
- building the server). Each segment is divided into pages, normally
- 8 kB each (this size can be changed via the <option>--with-wal-blocksize</>
- configure option). The log record headers are described in
- <filename>access/xlogrecord.h</filename>; the record content is dependent
- on the type of event that is being logged. Segment files are given
- ever-increasing numbers as names, starting at
+ by altering the <option>--wal-segsize</> initdb option). Each segment is
+ divided into pages, normally 8 kB each (this size can be changed via the
+ <option>--with-wal-blocksize</> configure option). The log record headers
+ are described in <filename>access/xlogrecord.h</filename>; the record
+ content is dependent on the type of event that is being logged. Segment
+ files are given ever-increasing numbers as names, starting at
<filename>000000010000000000000000</filename>. The numbers do not wrap,
but it will take a very, very long time to exhaust the
available stock of numbers.
XLogReaderState *xlogreader;
char *errormsg;
- xlogreader = XLogReaderAllocate(&read_local_xlog_page, NULL);
+ xlogreader = XLogReaderAllocate(wal_segment_size, &read_local_xlog_page,
+ NULL);
if (!xlogreader)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
bool XLOG_DEBUG = false;
#endif
+int wal_segment_size = DEFAULT_XLOG_SEG_SIZE;
+
/*
* Number of WAL insertion locks to use. A higher value allows more insertions
* to happen concurrently, but adds some CPU overhead to flushing the WAL,
(((recptr) / XLOG_BLCKSZ) % (XLogCtl->XLogCacheBlck + 1))
/*
- * These are the number of bytes in a WAL page and segment usable for WAL data.
+ * These are the number of bytes in a WAL page usable for WAL data.
*/
#define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)
-#define UsableBytesInSegment ((XLOG_SEG_SIZE / XLOG_BLCKSZ) * UsableBytesInPage - (SizeOfXLogLongPHD - SizeOfXLogShortPHD))
/* Convert min_wal_size_mb and max wal_size_mb to equivalent segment count */
-#define ConvertToXSegs(x) \
- (x / (XLOG_SEG_SIZE / (1024 * 1024)))
+#define ConvertToXSegs(x, segsize) \
+ (x / ((segsize) / (1024 * 1024)))
+
+/* The number of bytes in a WAL segment usable for WAL data. */
+static int UsableBytesInSegment;
/*
* Private, possibly out-of-date copy of shared LogwrtResult.
EndPos = StartPos + SizeOfXLogRecord;
if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
{
- if (EndPos % XLOG_SEG_SIZE == EndPos % XLOG_BLCKSZ)
+ uint64 offset = XLogSegmentOffset(EndPos, wal_segment_size);
+
+ if (offset == EndPos % XLOG_BLCKSZ)
EndPos += SizeOfXLogLongPHD;
else
EndPos += SizeOfXLogShortPHD;
appendBinaryStringInfo(&recordBuf, rdata->data, rdata->len);
if (!debug_reader)
- debug_reader = XLogReaderAllocate(NULL, NULL);
+ debug_reader = XLogReaderAllocate(wal_segment_size, NULL, NULL);
if (!debug_reader)
{
startbytepos = Insert->CurrBytePos;
ptr = XLogBytePosToEndRecPtr(startbytepos);
- if (ptr % XLOG_SEG_SIZE == 0)
+ if (XLogSegmentOffset(ptr, wal_segment_size) == 0)
{
SpinLockRelease(&Insert->insertpos_lck);
*EndPos = *StartPos = ptr;
*StartPos = XLogBytePosToRecPtr(startbytepos);
*EndPos = XLogBytePosToEndRecPtr(endbytepos);
- segleft = XLOG_SEG_SIZE - ((*EndPos) % XLOG_SEG_SIZE);
- if (segleft != XLOG_SEG_SIZE)
+ segleft = wal_segment_size - XLogSegmentOffset(*EndPos, wal_segment_size);
+ if (segleft != wal_segment_size)
{
/* consume the rest of the segment */
*EndPos += segleft;
*PrevPtr = XLogBytePosToRecPtr(prevbytepos);
- Assert((*EndPos) % XLOG_SEG_SIZE == 0);
+ Assert(XLogSegmentOffset(*EndPos, wal_segment_size) == 0);
Assert(XLogRecPtrToBytePos(*EndPos) == endbytepos);
Assert(XLogRecPtrToBytePos(*StartPos) == startbytepos);
Assert(XLogRecPtrToBytePos(*PrevPtr) == prevbytepos);
pagehdr->xlp_info |= XLP_FIRST_IS_CONTRECORD;
/* skip over the page header */
- if (CurrPos % XLogSegSize == 0)
+ if (XLogSegmentOffset(CurrPos, wal_segment_size) == 0)
{
CurrPos += SizeOfXLogLongPHD;
currpos += SizeOfXLogLongPHD;
* allocated and zeroed in the WAL buffers so that when the caller (or
* someone else) does XLogWrite(), it can really write out all the zeros.
*/
- if (isLogSwitch && CurrPos % XLOG_SEG_SIZE != 0)
+ if (isLogSwitch && XLogSegmentOffset(CurrPos, wal_segment_size) != 0)
{
/* An xlog-switch record doesn't contain any data besides the header */
Assert(write_len == SizeOfXLogRecord);
/*
* We do this one page at a time, to make sure we don't deadlock
- * against ourselves if wal_buffers < XLOG_SEG_SIZE.
+ * against ourselves if wal_buffers < wal_segment_size.
*/
- Assert(EndPos % XLogSegSize == 0);
+ Assert(XLogSegmentOffset(EndPos, wal_segment_size) == 0);
/* Use up all the remaining space on the first page */
CurrPos += freespace;
* the page header.
*/
if (ptr % XLOG_BLCKSZ == SizeOfXLogShortPHD &&
- ptr % XLOG_SEG_SIZE > XLOG_BLCKSZ)
+ XLogSegmentOffset(ptr, wal_segment_size) > XLOG_BLCKSZ)
initializedUpto = ptr - SizeOfXLogShortPHD;
else if (ptr % XLOG_BLCKSZ == SizeOfXLogLongPHD &&
- ptr % XLOG_SEG_SIZE < XLOG_BLCKSZ)
+ XLogSegmentOffset(ptr, wal_segment_size) < XLOG_BLCKSZ)
initializedUpto = ptr - SizeOfXLogLongPHD;
else
initializedUpto = ptr;
seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
}
- XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result);
+ XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result, wal_segment_size);
return result;
}
seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
}
- XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result);
+ XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result, wal_segment_size);
return result;
}
uint32 offset;
uint64 result;
- XLByteToSeg(ptr, fullsegs);
+ XLByteToSeg(ptr, fullsegs, wal_segment_size);
- fullpages = (ptr % XLOG_SEG_SIZE) / XLOG_BLCKSZ;
+ fullpages = (XLogSegmentOffset(ptr, wal_segment_size)) / XLOG_BLCKSZ;
offset = ptr % XLOG_BLCKSZ;
if (fullpages == 0)
/*
* If first page of an XLOG segment file, make it a long header.
*/
- if ((NewPage->xlp_pageaddr % XLogSegSize) == 0)
+ if ((XLogSegmentOffset(NewPage->xlp_pageaddr, wal_segment_size)) == 0)
{
XLogLongPageHeader NewLongPage = (XLogLongPageHeader) NewPage;
NewLongPage->xlp_sysid = ControlFile->system_identifier;
- NewLongPage->xlp_seg_size = XLogSegSize;
+ NewLongPage->xlp_seg_size = wal_segment_size;
NewLongPage->xlp_xlog_blcksz = XLOG_BLCKSZ;
NewPage->xlp_info |= XLP_LONG_HEADER;
}
* number of segments consumed between checkpoints.
*-------
*/
- target = (double) ConvertToXSegs(max_wal_size_mb) / (2.0 + CheckPointCompletionTarget);
+ target = (double) ConvertToXSegs(max_wal_size_mb, wal_segment_size) /
+ (2.0 + CheckPointCompletionTarget);
/* round down */
CheckPointSegments = (int) target;
* correspond to. Always recycle enough segments to meet the minimum, and
* remove enough segments to stay below the maximum.
*/
- minSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(min_wal_size_mb) - 1;
- maxSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(max_wal_size_mb) - 1;
+ minSegNo = PriorRedoPtr / wal_segment_size +
+ ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1;
+ maxSegNo = PriorRedoPtr / wal_segment_size +
+ ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1;
/*
* Between those limits, recycle enough segments to get us through to the
/* add 10% for good measure. */
distance *= 1.10;
- recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) / XLOG_SEG_SIZE);
+ recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) /
+ wal_segment_size);
if (recycleSegNo < minSegNo)
recycleSegNo = minSegNo;
{
XLogSegNo old_segno;
- XLByteToSeg(RedoRecPtr, old_segno);
+ XLByteToSeg(RedoRecPtr, old_segno, wal_segment_size);
if (new_segno >= old_segno + (uint64) (CheckPointSegments - 1))
return true;
LogwrtResult.Write = EndPtr;
ispartialpage = WriteRqst.Write < LogwrtResult.Write;
- if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+ if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size))
{
/*
* Switch to new logfile segment. We cannot have any pending
Assert(npages == 0);
if (openLogFile >= 0)
XLogFileClose();
- XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+ XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size);
/* create/use new log file */
use_existent = true;
/* Make sure we have the current logfile open */
if (openLogFile < 0)
{
- XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+ XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size);
openLogFile = XLogFileOpen(openLogSegNo);
openLogOff = 0;
}
{
/* first of group */
startidx = curridx;
- startoffset = (LogwrtResult.Write - XLOG_BLCKSZ) % XLogSegSize;
+ startoffset = XLogSegmentOffset(LogwrtResult.Write - XLOG_BLCKSZ,
+ wal_segment_size);
}
npages++;
last_iteration = WriteRqst.Write <= LogwrtResult.Write;
finishing_seg = !ispartialpage &&
- (startoffset + npages * XLOG_BLCKSZ) >= XLogSegSize;
+ (startoffset + npages * XLOG_BLCKSZ) >= wal_segment_size;
if (last_iteration ||
curridx == XLogCtl->XLogCacheBlck ||
sync_method != SYNC_METHOD_OPEN_DSYNC)
{
if (openLogFile >= 0 &&
- !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+ !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size))
XLogFileClose();
if (openLogFile < 0)
{
- XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+ XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size);
openLogFile = XLogFileOpen(openLogSegNo);
openLogOff = 0;
}
{
if (openLogFile >= 0)
{
- if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+ if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+ wal_segment_size))
{
XLogFileClose();
}
int fd;
int nbytes;
- XLogFilePath(path, ThisTimeLineID, logsegno);
+ XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size);
/*
* Try to use existent file (checkpoint maker may have created it already)
*/
zbuffer = (char *) MAXALIGN(zbuffer_raw);
memset(zbuffer, 0, XLOG_BLCKSZ);
- for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
+ for (nbytes = 0; nbytes < wal_segment_size; nbytes += XLOG_BLCKSZ)
{
errno = 0;
pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_WRITE);
/*
* Open the source file
*/
- XLogFilePath(path, srcTLI, srcsegno);
+ XLogFilePath(path, srcTLI, srcsegno, wal_segment_size);
srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
if (srcfd < 0)
ereport(ERROR,
/*
* Do the data copying.
*/
- for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))
+ for (nbytes = 0; nbytes < wal_segment_size; nbytes += sizeof(buffer))
{
int nread;
char path[MAXPGPATH];
struct stat stat_buf;
- XLogFilePath(path, ThisTimeLineID, *segno);
+ XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size);
/*
* We want to be sure that only one process does this at a time.
return false;
}
(*segno)++;
- XLogFilePath(path, ThisTimeLineID, *segno);
+ XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size);
}
}
char path[MAXPGPATH];
int fd;
- XLogFilePath(path, ThisTimeLineID, segno);
+ XLogFilePath(path, ThisTimeLineID, segno, wal_segment_size);
fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
S_IRUSR | S_IWUSR);
char path[MAXPGPATH];
int fd;
- XLogFileName(xlogfname, tli, segno);
+ XLogFileName(xlogfname, tli, segno, wal_segment_size);
switch (source)
{
restoredFromArchive = RestoreArchivedFile(path, xlogfname,
"RECOVERYXLOG",
- XLogSegSize,
+ wal_segment_size,
InRedo);
if (!restoredFromArchive)
return -1;
case XLOG_FROM_PG_WAL:
case XLOG_FROM_STREAM:
- XLogFilePath(path, tli, segno);
+ XLogFilePath(path, tli, segno, wal_segment_size);
restoredFromArchive = false;
break;
}
/* Couldn't find it. For simplicity, complain about front timeline */
- XLogFilePath(path, recoveryTargetTLI, segno);
+ XLogFilePath(path, recoveryTargetTLI, segno, wal_segment_size);
errno = ENOENT;
ereport(emode,
(errcode_for_file_access(),
XLogSegNo _logSegNo;
int lf;
bool use_existent;
+ uint64 offset;
- XLByteToPrevSeg(endptr, _logSegNo);
- if ((endptr - 1) % XLogSegSize >= (uint32) (0.75 * XLogSegSize))
+ XLByteToPrevSeg(endptr, _logSegNo, wal_segment_size);
+ offset = XLogSegmentOffset(endptr - 1, wal_segment_size);
+ if (offset >= (uint32) (0.75 * wal_segment_size))
{
_logSegNo++;
use_existent = true;
{
char filename[MAXFNAMELEN];
- XLogFileName(filename, tli, segno);
+ XLogFileName(filename, tli, segno, wal_segment_size);
ereport(ERROR,
(errcode_for_file_access(),
errmsg("requested WAL segment %s has already been removed",
uint32 tli;
XLogSegNo segno;
- XLogFromFileName(filename, &tli, &segno);
+ XLogFromFileName(filename, &tli, &segno, wal_segment_size);
SpinLockAcquire(&XLogCtl->info_lck);
if (segno > XLogCtl->lastRemovedSegNo)
* doesn't matter, we ignore that in the comparison. (During recovery,
* ThisTimeLineID isn't set, so we can't use that.)
*/
- XLogFileName(lastoff, 0, segno);
+ XLogFileName(lastoff, 0, segno, wal_segment_size);
elog(DEBUG2, "attempting to remove WAL segments older than log file %s",
lastoff);
char switchseg[MAXFNAMELEN];
XLogSegNo endLogSegNo;
- XLByteToPrevSeg(switchpoint, endLogSegNo);
+ XLByteToPrevSeg(switchpoint, endLogSegNo, wal_segment_size);
xldir = AllocateDir(XLOGDIR);
if (xldir == NULL)
/*
* Construct a filename of the last segment to be kept.
*/
- XLogFileName(switchseg, newTLI, endLogSegNo);
+ XLogFileName(switchseg, newTLI, endLogSegNo, wal_segment_size);
elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
switchseg);
/*
* Initialize info about where to try to recycle to.
*/
- XLByteToSeg(endptr, endlogSegNo);
+ XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
if (PriorRedoPtr == InvalidXLogRecPtr)
recycleSegNo = endlogSegNo + 10;
else
XLogSegNo segno;
int32 offset;
- XLByteToSeg(xlogreader->latestPagePtr, segno);
- offset = xlogreader->latestPagePtr % XLogSegSize;
- XLogFileName(fname, xlogreader->readPageTLI, segno);
+ XLByteToSeg(xlogreader->latestPagePtr, segno, wal_segment_size);
+ offset = XLogSegmentOffset(xlogreader->latestPagePtr,
+ wal_segment_size);
+ XLogFileName(fname, xlogreader->readPageTLI, segno,
+ wal_segment_size);
ereport(emode_for_corrupt_record(emode,
RecPtr ? RecPtr : EndRecPtr),
(errmsg("unexpected timeline ID %u in log segment %s, offset %u",
ControlFile->blcksz = BLCKSZ;
ControlFile->relseg_size = RELSEG_SIZE;
ControlFile->xlog_blcksz = XLOG_BLCKSZ;
- ControlFile->xlog_seg_size = XLOG_SEG_SIZE;
+ ControlFile->xlog_seg_size = wal_segment_size;
ControlFile->nameDataLen = NAMEDATALEN;
ControlFile->indexMaxKeys = INDEX_MAX_KEYS;
{
pg_crc32c crc;
int fd;
+ static char wal_segsz_str[20];
/*
* Read data...
" but the server was compiled with XLOG_BLCKSZ %d.",
ControlFile->xlog_blcksz, XLOG_BLCKSZ),
errhint("It looks like you need to recompile or initdb.")));
- if (ControlFile->xlog_seg_size != XLOG_SEG_SIZE)
- ereport(FATAL,
- (errmsg("database files are incompatible with server"),
- errdetail("The database cluster was initialized with XLOG_SEG_SIZE %d,"
- " but the server was compiled with XLOG_SEG_SIZE %d.",
- ControlFile->xlog_seg_size, XLOG_SEG_SIZE),
- errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->nameDataLen != NAMEDATALEN)
ereport(FATAL,
(errmsg("database files are incompatible with server"),
errhint("It looks like you need to recompile or initdb.")));
#endif
+ wal_segment_size = ControlFile->xlog_seg_size;
+
+ if (!IsValidWalSegSize(wal_segment_size))
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("WAL segment size must be a power of two between 1MB and 1GB, but the control file specifies %d bytes",
+ wal_segment_size)));
+
+ snprintf(wal_segsz_str, sizeof(wal_segsz_str), "%d", wal_segment_size);
+ SetConfigOption("wal_segment_size", wal_segsz_str, PGC_INTERNAL,
+ PGC_S_OVERRIDE);
+
+ /* check and update variables dependent on wal_segment_size */
+ if (ConvertToXSegs(min_wal_size_mb, wal_segment_size) < 2)
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"min_wal_size\" must be at least twice \"wal_segment_size\".")));
+
+ if (ConvertToXSegs(max_wal_size_mb, wal_segment_size) < 2)
+ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"max_wal_size\" must be at least twice \"wal_segment_size\".")));
+
+ UsableBytesInSegment =
+ (wal_segment_size / XLOG_BLCKSZ * UsableBytesInPage) -
+ (SizeOfXLogLongPHD - SizeOfXLogShortPHD);
+
+ CalculateCheckpointSegments();
+
/* Make the initdb settings visible as GUC variables, too */
SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
PGC_INTERNAL, PGC_S_OVERRIDE);
int xbuffers;
xbuffers = NBuffers / 32;
- if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
- xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
+ if (xbuffers > (wal_segment_size / XLOG_BLCKSZ))
+ xbuffers = (wal_segment_size / XLOG_BLCKSZ);
if (xbuffers < 8)
xbuffers = 8;
return xbuffers;
* segment with logid=0 logseg=1. The very first WAL segment, 0/0, is not
* used, so that we can use 0/0 to mean "before any valid WAL segment".
*/
- checkPoint.redo = XLogSegSize + SizeOfXLogLongPHD;
+ checkPoint.redo = wal_segment_size + SizeOfXLogLongPHD;
checkPoint.ThisTimeLineID = ThisTimeLineID;
checkPoint.PrevTimeLineID = ThisTimeLineID;
checkPoint.fullPageWrites = fullPageWrites;
page->xlp_magic = XLOG_PAGE_MAGIC;
page->xlp_info = XLP_LONG_HEADER;
page->xlp_tli = ThisTimeLineID;
- page->xlp_pageaddr = XLogSegSize;
+ page->xlp_pageaddr = wal_segment_size;
longpage = (XLogLongPageHeader) page;
longpage->xlp_sysid = sysidentifier;
- longpage->xlp_seg_size = XLogSegSize;
+ longpage->xlp_seg_size = wal_segment_size;
longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
/* Insert the initial checkpoint record */
* they are the same, but if the switch happens exactly at a segment
* boundary, startLogSegNo will be endLogSegNo + 1.
*/
- XLByteToPrevSeg(endOfLog, endLogSegNo);
- XLByteToSeg(endOfLog, startLogSegNo);
+ XLByteToPrevSeg(endOfLog, endLogSegNo, wal_segment_size);
+ XLByteToSeg(endOfLog, startLogSegNo, wal_segment_size);
/*
* Initialize the starting WAL segment for the new timeline. If the switch
* avoid emplacing a bogus file.
*/
XLogFileCopy(endLogSegNo, endTLI, endLogSegNo,
- endOfLog % XLOG_SEG_SIZE);
+ XLogSegmentOffset(endOfLog, wal_segment_size));
}
else
{
* Let's just make real sure there are not .ready or .done flags posted
* for the new segment.
*/
- XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo);
+ XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo, wal_segment_size);
XLogArchiveCleanup(xlogfname);
/*
/* Set up XLOG reader facility */
MemSet(&private, 0, sizeof(XLogPageReadPrivate));
- xlogreader = XLogReaderAllocate(&XLogPageRead, &private);
+ xlogreader = XLogReaderAllocate(wal_segment_size, &XLogPageRead, &private);
if (!xlogreader)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
XLogRecPtr pageBeginPtr;
pageBeginPtr = EndOfLog - (EndOfLog % XLOG_BLCKSZ);
- Assert(readOff == pageBeginPtr % XLogSegSize);
+ Assert(readOff == XLogSegmentOffset(pageBeginPtr, wal_segment_size));
firstIdx = XLogRecPtrToBufIdx(EndOfLog);
* restored from the archive to begin with, it's expected to have a
* .done file).
*/
- if (EndOfLog % XLOG_SEG_SIZE != 0 && XLogArchivingActive())
+ if (XLogSegmentOffset(EndOfLog, wal_segment_size) != 0 &&
+ XLogArchivingActive())
{
char origfname[MAXFNAMELEN];
XLogSegNo endLogSegNo;
- XLByteToPrevSeg(EndOfLog, endLogSegNo);
- XLogFileName(origfname, EndOfLogTLI, endLogSegNo);
+ XLByteToPrevSeg(EndOfLog, endLogSegNo, wal_segment_size);
+ XLogFileName(origfname, EndOfLogTLI, endLogSegNo, wal_segment_size);
if (!XLogArchiveIsReadyOrDone(origfname))
{
char partialfname[MAXFNAMELEN];
char partialpath[MAXPGPATH];
- XLogFilePath(origpath, EndOfLogTLI, endLogSegNo);
+ XLogFilePath(origpath, EndOfLogTLI, endLogSegNo, wal_segment_size);
snprintf(partialfname, MAXFNAMELEN, "%s.partial", origfname);
snprintf(partialpath, MAXPGPATH, "%s.partial", origpath);
ThisTimeLineID = XLogCtl->ThisTimeLineID;
Assert(ThisTimeLineID != 0 || IsBootstrapProcessingMode());
+ /* set wal_segment_size */
+ wal_segment_size = ControlFile->xlog_seg_size;
+
/* Use GetRedoRecPtr to copy the RedoRecPtr safely */
(void) GetRedoRecPtr();
/* Also update our copy of doPageWrites. */
* more.
*
* When checkpoints are triggered by max_wal_size, this should converge to
- * CheckpointSegments * XLOG_SEG_SIZE,
+ * CheckpointSegments * wal_segment_size,
*
* Note: This doesn't pay any attention to what caused the checkpoint.
* Checkpoints triggered manually with CHECKPOINT command, or by e.g.
freespace = INSERT_FREESPACE(curInsert);
if (freespace == 0)
{
- if (curInsert % XLogSegSize == 0)
+ if (XLogSegmentOffset(curInsert, wal_segment_size) == 0)
curInsert += SizeOfXLogLongPHD;
else
curInsert += SizeOfXLogShortPHD;
/* Update the average distance between checkpoints. */
UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
- XLByteToSeg(PriorRedoPtr, _logSegNo);
+ XLByteToSeg(PriorRedoPtr, _logSegNo, wal_segment_size);
KeepLogSeg(recptr, &_logSegNo);
_logSegNo--;
RemoveOldXlogFiles(_logSegNo, PriorRedoPtr, recptr);
/* Update the average distance between checkpoints/restartpoints. */
UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
- XLByteToSeg(PriorRedoPtr, _logSegNo);
+ XLByteToSeg(PriorRedoPtr, _logSegNo, wal_segment_size);
/*
* Get the current end of xlog replayed or received, whichever is
XLogSegNo segno;
XLogRecPtr keep;
- XLByteToSeg(recptr, segno);
+ XLByteToSeg(recptr, segno, wal_segment_size);
keep = XLogGetReplicationSlotMinimumLSN();
/* compute limit for wal_keep_segments first */
{
XLogSegNo slotSegNo;
- XLByteToSeg(keep, slotSegNo);
+ XLByteToSeg(keep, slotSegNo, wal_segment_size);
if (slotSegNo <= 0)
segno = 1;
{
char *result = palloc(MAXFNAMELEN);
- XLogFileName(result, tli, segno);
+ XLogFileName(result, tli, segno, wal_segment_size);
return result;
}
WALInsertLockRelease();
} while (!gotUniqueStartpoint);
- XLByteToSeg(startpoint, _logSegNo);
- XLogFileName(xlogfilename, starttli, _logSegNo);
+ XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
+ XLogFileName(xlogfilename, starttli, _logSegNo, wal_segment_size);
/*
* Construct tablespace_map file
*/
RequestXLogSwitch(false);
- XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(stopxlogfilename, stoptli, _logSegNo);
+ XLByteToPrevSeg(stoppoint, _logSegNo, wal_segment_size);
+ XLogFileName(stopxlogfilename, stoptli, _logSegNo, wal_segment_size);
/* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL);
/*
* Write the backup history file
*/
- XLByteToSeg(startpoint, _logSegNo);
+ XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
BackupHistoryFilePath(histfilepath, stoptli, _logSegNo,
- (uint32) (startpoint % XLogSegSize));
+ startpoint, wal_segment_size);
fp = AllocateFile(histfilepath, "w");
if (!fp)
ereport(ERROR,
((!backup_started_in_recovery && XLogArchivingActive()) ||
(backup_started_in_recovery && XLogArchivingAlways())))
{
- XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(lastxlogfilename, stoptli, _logSegNo);
+ XLByteToPrevSeg(stoppoint, _logSegNo, wal_segment_size);
+ XLogFileName(lastxlogfilename, stoptli, _logSegNo, wal_segment_size);
- XLByteToSeg(startpoint, _logSegNo);
+ XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
BackupHistoryFileName(histfilename, stoptli, _logSegNo,
- (uint32) (startpoint % XLogSegSize));
+ startpoint, wal_segment_size);
seconds_before_warning = 60;
waits = 0;
uint32 targetPageOff;
XLogSegNo targetSegNo PG_USED_FOR_ASSERTS_ONLY;
- XLByteToSeg(targetPagePtr, targetSegNo);
- targetPageOff = targetPagePtr % XLogSegSize;
+ XLByteToSeg(targetPagePtr, targetSegNo, wal_segment_size);
+ targetPageOff = XLogSegmentOffset(targetPagePtr, wal_segment_size);
/*
* See if we need to switch to a new segment because the requested record
* is not in the currently open one.
*/
- if (readFile >= 0 && !XLByteInSeg(targetPagePtr, readSegNo))
+ if (readFile >= 0 &&
+ !XLByteInSeg(targetPagePtr, readSegNo, wal_segment_size))
{
/*
* Request a restartpoint if we've replayed too much xlog since the
readSource = 0;
}
- XLByteToSeg(targetPagePtr, readSegNo);
+ XLByteToSeg(targetPagePtr, readSegNo, wal_segment_size);
retry:
/* See if we need to retrieve more data */
if (((targetPagePtr) / XLOG_BLCKSZ) != (receivedUpto / XLOG_BLCKSZ))
readLen = XLOG_BLCKSZ;
else
- readLen = receivedUpto % XLogSegSize - targetPageOff;
+ readLen = XLogSegmentOffset(receivedUpto, wal_segment_size) -
+ targetPageOff;
}
else
readLen = XLOG_BLCKSZ;
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, curFileTLI, readSegNo);
+ XLogFileName(fname, curFileTLI, readSegNo, wal_segment_size);
ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
(errcode_for_file_access(),
errmsg("could not seek in log segment %s to offset %u: %m",
char fname[MAXFNAMELEN];
pgstat_report_wait_end();
- XLogFileName(fname, curFileTLI, readSegNo);
+ XLogFileName(fname, curFileTLI, readSegNo, wal_segment_size);
ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
(errcode_for_file_access(),
errmsg("could not read from log segment %s, offset %u: %m",
if (cleanupEnabled)
{
GetOldestRestartPoint(&restartRedoPtr, &restartTli);
- XLByteToSeg(restartRedoPtr, restartSegNo);
- XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+ XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+ XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+ wal_segment_size);
/* we shouldn't need anything earlier than last restart point */
Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
}
else
- XLogFileName(lastRestartPointFname, 0, 0L);
+ XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
/*
* construct the command to be executed
* archive, though there is no requirement to do so.
*/
GetOldestRestartPoint(&restartRedoPtr, &restartTli);
- XLByteToSeg(restartRedoPtr, restartSegNo);
- XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+ XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+ XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+ wal_segment_size);
/*
* construct the command to be executed
{
char xlog[MAXFNAMELEN];
- XLogFileName(xlog, ThisTimeLineID, segno);
+ XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
XLogArchiveNotify(xlog);
}
/*
* xlogfilename
*/
- XLByteToPrevSeg(locationpoint, xlogsegno);
- XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
+ XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
+ XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
values[0] = CStringGetTextDatum(xlogfilename);
isnull[0] = false;
/*
* offset
*/
- xrecoff = locationpoint % XLogSegSize;
+ xrecoff = XLogSegmentOffset(locationpoint, wal_segment_size);
values[1] = UInt32GetDatum(xrecoff);
isnull[1] = false;
errmsg("recovery is in progress"),
errhint("pg_walfile_name() cannot be executed during recovery.")));
- XLByteToPrevSeg(locationpoint, xlogsegno);
- XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
+ XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
+ XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
}
* Returns NULL if the xlogreader couldn't be allocated.
*/
XLogReaderState *
-XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
+XLogReaderAllocate(int wal_segment_size, XLogPageReadCB pagereadfunc,
+ void *private_data)
{
XLogReaderState *state;
return NULL;
}
+ state->wal_segment_size = wal_segment_size;
state->read_page = pagereadfunc;
/* system_identifier initialized to zeroes above */
state->private_data = private_data;
(record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH)
{
/* Pretend it extends to end of segment */
- state->EndRecPtr += XLogSegSize - 1;
- state->EndRecPtr -= state->EndRecPtr % XLogSegSize;
+ state->EndRecPtr += state->wal_segment_size - 1;
+ state->EndRecPtr -= XLogSegmentOffset(state->EndRecPtr, state->wal_segment_size);
}
if (DecodeXLogRecord(state, record, errormsg))
Assert((pageptr % XLOG_BLCKSZ) == 0);
- XLByteToSeg(pageptr, targetSegNo);
- targetPageOff = (pageptr % XLogSegSize);
+ XLByteToSeg(pageptr, targetSegNo, state->wal_segment_size);
+ targetPageOff = XLogSegmentOffset(pageptr, state->wal_segment_size);
/* check whether we have all the requested data already */
if (targetSegNo == state->readSegNo && targetPageOff == state->readOff &&
Assert((recptr % XLOG_BLCKSZ) == 0);
- XLByteToSeg(recptr, segno);
- offset = recptr % XLogSegSize;
+ XLByteToSeg(recptr, segno, state->wal_segment_size);
+ offset = XLogSegmentOffset(recptr, state->wal_segment_size);
- XLogSegNoOffsetToRecPtr(segno, offset, recaddr);
+ XLogSegNoOffsetToRecPtr(segno, offset, recaddr, state->wal_segment_size);
if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, state->readPageTLI, segno);
+ XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state,
"invalid magic number %04X in log segment %s, offset %u",
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, state->readPageTLI, segno);
+ XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state,
"invalid info bits %04X in log segment %s, offset %u",
fhdrident_str, sysident_str);
return false;
}
- else if (longhdr->xlp_seg_size != XLogSegSize)
+ else if (longhdr->xlp_seg_size != state->wal_segment_size)
{
report_invalid_record(state,
- "WAL file is from different database system: incorrect XLOG_SEG_SIZE in page header");
+ "WAL file is from different database system: incorrect segment size in page header");
return false;
}
else if (longhdr->xlp_xlog_blcksz != XLOG_BLCKSZ)
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, state->readPageTLI, segno);
+ XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
/* hmm, first page of file doesn't have a long header? */
report_invalid_record(state,
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, state->readPageTLI, segno);
+ XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state,
"unexpected pageaddr %X/%X in log segment %s, offset %u",
{
char fname[MAXFNAMELEN];
- XLogFileName(fname, state->readPageTLI, segno);
+ XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state,
"out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u",
* frontend). Probably these should be merged at some point.
*/
static void
-XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
+XLogRead(char *buf, int segsize, TimeLineID tli, XLogRecPtr startptr,
+ Size count)
{
char *p;
XLogRecPtr recptr;
static TimeLineID sendTLI = 0;
static uint32 sendOff = 0;
+ Assert(segsize == wal_segment_size);
+
p = buf;
recptr = startptr;
nbytes = count;
int segbytes;
int readbytes;
- startoff = recptr % XLogSegSize;
+ startoff = XLogSegmentOffset(recptr, segsize);
/* Do we need to switch to a different xlog segment? */
- if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo) ||
+ if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo, segsize) ||
sendTLI != tli)
{
char path[MAXPGPATH];
if (sendFile >= 0)
close(sendFile);
- XLByteToSeg(recptr, sendSegNo);
+ XLByteToSeg(recptr, sendSegNo, segsize);
- XLogFilePath(path, tli, sendSegNo);
+ XLogFilePath(path, tli, sendSegNo, segsize);
sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
{
char path[MAXPGPATH];
- XLogFilePath(path, tli, sendSegNo);
+ XLogFilePath(path, tli, sendSegNo, segsize);
ereport(ERROR,
(errcode_for_file_access(),
}
/* How many bytes are within this segment? */
- if (nbytes > (XLogSegSize - startoff))
- segbytes = XLogSegSize - startoff;
+ if (nbytes > (segsize - startoff))
+ segbytes = segsize - startoff;
else
segbytes = nbytes;
{
char path[MAXPGPATH];
- XLogFilePath(path, tli, sendSegNo);
+ XLogFilePath(path, tli, sendSegNo, segsize);
ereport(ERROR,
(errcode_for_file_access(),
void
XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
{
- const XLogRecPtr lastReadPage = state->readSegNo * XLogSegSize + state->readOff;
+ const XLogRecPtr lastReadPage = state->readSegNo *
+ state->wal_segment_size + state->readOff;
Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
Assert(wantLength <= XLOG_BLCKSZ);
if (state->currTLIValidUntil != InvalidXLogRecPtr &&
state->currTLI != ThisTimeLineID &&
state->currTLI != 0 &&
- (wantPage + wantLength) / XLogSegSize < state->currTLIValidUntil / XLogSegSize)
+ ((wantPage + wantLength) / state->wal_segment_size) <
+ (state->currTLIValidUntil / state->wal_segment_size))
return;
/*
*/
List *timelineHistory = readTimeLineHistory(ThisTimeLineID);
- XLogRecPtr endOfSegment = (((wantPage / XLogSegSize) + 1) * XLogSegSize) - 1;
+ XLogRecPtr endOfSegment = (((wantPage / state->wal_segment_size) + 1)
+ * state->wal_segment_size) - 1;
- Assert(wantPage / XLogSegSize == endOfSegment / XLogSegSize);
+ Assert(wantPage / state->wal_segment_size ==
+ endOfSegment / state->wal_segment_size);
/*
* Find the timeline of the last LSN on the segment containing
* as 'count', read the whole page anyway. It's guaranteed to be
* zero-padded up to the page boundary if it's incomplete.
*/
- XLogRead(cur_page, *pageTLI, targetPagePtr, XLOG_BLCKSZ);
+ XLogRead(cur_page, state->wal_segment_size, *pageTLI, targetPagePtr,
+ XLOG_BLCKSZ);
/* number of valid bytes in the buffer */
return count;
#include "access/htup_details.h"
#include "access/xact.h"
+#include "access/xlog_internal.h"
#include "bootstrap/bootstrap.h"
#include "catalog/index.h"
#include "catalog/pg_collation.h"
/* If no -x argument, we are a CheckerProcess */
MyAuxProcType = CheckerProcess;
- while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
+ while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:X:-:")) != -1)
{
switch (flag)
{
case 'x':
MyAuxProcType = atoi(optarg);
break;
+ case 'X':
+ {
+ int WalSegSz = strtoul(optarg, NULL, 0);
+
+ if (!IsValidWalSegSize(WalSegSz))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("-X requires a power of 2 value between 1MB and 1GB")));
+ SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL,
+ PGC_S_OVERRIDE);
+ }
+ break;
case 'c':
case '-':
{
* If the returned pointer points exactly to a segment boundary,
* assume nothing happened.
*/
- if ((switchpoint % XLogSegSize) != 0)
+ if (XLogSegmentOffset(switchpoint, wal_segment_size) != 0)
elog(DEBUG1, "write-ahead log switch forced (archive_timeout=%d)",
XLogArchiveTimeout);
}
recptr = GetXLogReplayRecPtr(NULL);
else
recptr = GetInsertRecPtr();
- elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) / XLogSegSize) / CheckPointSegments;
+ elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) /
+ wal_segment_size) / CheckPointSegments;
if (progress < elapsed_xlogs)
{
* shouldn't be such files, but if there are, there's little harm in
* including them.
*/
- XLByteToSeg(startptr, startsegno);
- XLogFileName(firstoff, ThisTimeLineID, startsegno);
- XLByteToPrevSeg(endptr, endsegno);
- XLogFileName(lastoff, ThisTimeLineID, endsegno);
+ XLByteToSeg(startptr, startsegno, wal_segment_size);
+ XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+ XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+ XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
dir = AllocateDir("pg_wal");
if (!dir)
* Sanity check: the first and last segment should cover startptr and
* endptr, with no gaps in between.
*/
- XLogFromFileName(walFiles[0], &tli, &segno);
+ XLogFromFileName(walFiles[0], &tli, &segno, wal_segment_size);
if (segno != startsegno)
{
char startfname[MAXFNAMELEN];
- XLogFileName(startfname, ThisTimeLineID, startsegno);
+ XLogFileName(startfname, ThisTimeLineID, startsegno,
+ wal_segment_size);
ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", startfname)));
}
XLogSegNo currsegno = segno;
XLogSegNo nextsegno = segno + 1;
- XLogFromFileName(walFiles[i], &tli, &segno);
+ XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
if (!(nextsegno == segno || currsegno == segno))
{
char nextfname[MAXFNAMELEN];
- XLogFileName(nextfname, ThisTimeLineID, nextsegno);
+ XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+ wal_segment_size);
ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", nextfname)));
}
{
char endfname[MAXFNAMELEN];
- XLogFileName(endfname, ThisTimeLineID, endsegno);
+ XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", endfname)));
}
pgoff_t len = 0;
snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
- XLogFromFileName(walFiles[i], &tli, &segno);
+ XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
fp = AllocateFile(pathbuf, "rb");
if (fp == NULL)
(errcode_for_file_access(),
errmsg("could not stat file \"%s\": %m",
pathbuf)));
- if (statbuf.st_size != XLogSegSize)
+ if (statbuf.st_size != wal_segment_size)
{
CheckXLogRemoved(segno, tli);
ereport(ERROR,
/* send the WAL file itself */
_tarWriteHeader(pathbuf, NULL, &statbuf, false);
- while ((cnt = fread(buf, 1, Min(sizeof(buf), XLogSegSize - len), fp)) > 0)
+ while ((cnt = fread(buf, 1,
+ Min(sizeof(buf), wal_segment_size - len),
+ fp)) > 0)
{
CheckXLogRemoved(segno, tli);
/* Send the chunk as a CopyData message */
len += cnt;
throttle(cnt);
- if (len == XLogSegSize)
+ if (len == wal_segment_size)
break;
}
- if (len != XLogSegSize)
+ if (len != wal_segment_size)
{
CheckXLogRemoved(segno, tli);
ereport(ERROR,
errmsg("unexpected WAL file size \"%s\"", walFiles[i])));
}
- /* XLogSegSize is a multiple of 512, so no need for padding */
+ /* wal_segment_size is a multiple of 512, so no need for padding */
FreeFile(fp);
ctx->slot = slot;
- ctx->reader = XLogReaderAllocate(read_page, ctx);
+ ctx->reader = XLogReaderAllocate(wal_segment_size, read_page, ctx);
if (!ctx->reader)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
* store in segment in which it belongs by start lsn, don't split over
* multiple segments tho
*/
- if (fd == -1 || !XLByteInSeg(change->lsn, curOpenSegNo))
+ if (fd == -1 ||
+ !XLByteInSeg(change->lsn, curOpenSegNo, wal_segment_size))
{
XLogRecPtr recptr;
if (fd != -1)
CloseTransientFile(fd);
- XLByteToSeg(change->lsn, curOpenSegNo);
- XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr);
+ XLByteToSeg(change->lsn, curOpenSegNo, wal_segment_size);
+ XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr, wal_segment_size);
/*
* No need to care about TLIs here, only used during a single run,
txn->nentries_mem = 0;
Assert(dlist_is_empty(&txn->changes));
- XLByteToSeg(txn->final_lsn, last_segno);
+ XLByteToSeg(txn->final_lsn, last_segno, wal_segment_size);
while (restored < max_changes_in_memory && *segno <= last_segno)
{
/* first time in */
if (*segno == 0)
{
- XLByteToSeg(txn->first_lsn, *segno);
+ XLByteToSeg(txn->first_lsn, *segno, wal_segment_size);
}
Assert(*segno != 0 || dlist_is_empty(&txn->changes));
- XLogSegNoOffsetToRecPtr(*segno, 0, recptr);
+ XLogSegNoOffsetToRecPtr(*segno, 0, recptr, wal_segment_size);
/*
* No need to care about TLIs here, only used during a single run,
Assert(txn->first_lsn != InvalidXLogRecPtr);
Assert(txn->final_lsn != InvalidXLogRecPtr);
- XLByteToSeg(txn->first_lsn, first);
- XLByteToSeg(txn->final_lsn, last);
+ XLByteToSeg(txn->first_lsn, first, wal_segment_size);
+ XLByteToSeg(txn->final_lsn, last, wal_segment_size);
/* iterate over all possible filenames, and delete them */
for (cur = first; cur <= last; cur++)
char path[MAXPGPATH];
XLogRecPtr recptr;
- XLogSegNoOffsetToRecPtr(cur, 0, recptr);
+ XLogSegNoOffsetToRecPtr(cur, 0, recptr, wal_segment_size);
sprintf(path, "pg_replslot/%s/xid-%u-lsn-%X-%X.snap",
NameStr(MyReplicationSlot->data.name), txn->xid,
* the new restart_lsn above, so normally we should never need to loop
* more than twice.
*/
- XLByteToSeg(slot->data.restart_lsn, segno);
+ XLByteToSeg(slot->data.restart_lsn, segno, wal_segment_size);
if (XLogGetLastRemovedSegno() < segno)
break;
}
* Create .done file forcibly to prevent the streamed segment from
* being archived later.
*/
- XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+ XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
XLogArchiveForceDone(xlogfname);
else
{
int segbytes;
- if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo))
+ if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
{
bool use_existent;
* Create .done file forcibly to prevent the streamed segment
* from being archived later.
*/
- XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+ XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
XLogArchiveForceDone(xlogfname);
else
recvFile = -1;
/* Create/use new log file */
- XLByteToSeg(recptr, recvSegNo);
+ XLByteToSeg(recptr, recvSegNo, wal_segment_size);
use_existent = true;
recvFile = XLogFileInit(recvSegNo, &use_existent, true);
recvFileTLI = ThisTimeLineID;
}
/* Calculate the start offset of the received logs */
- startoff = recptr % XLogSegSize;
+ startoff = XLogSegmentOffset(recptr, wal_segment_size);
- if (startoff + nbytes > XLogSegSize)
- segbytes = XLogSegSize - startoff;
+ if (startoff + nbytes > wal_segment_size)
+ segbytes = wal_segment_size - startoff;
else
segbytes = nbytes;
* being created by XLOG streaming, which might cause trouble later on if
* the segment is e.g archived.
*/
- if (recptr % XLogSegSize != 0)
- recptr -= recptr % XLogSegSize;
+ if (XLogSegmentOffset(recptr, wal_segment_size) != 0)
+ recptr -= XLogSegmentOffset(recptr, wal_segment_size);
SpinLockAcquire(&walrcv->mutex);