Commit fc49e24f authored by Andres Freund's avatar Andres Freund

Make WAL segment size configurable at initdb time.

For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.

But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.

This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured.  For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.

Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
    Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
parent 5ada1fcd
...@@ -821,7 +821,6 @@ enable_tap_tests ...@@ -821,7 +821,6 @@ enable_tap_tests
with_blocksize with_blocksize
with_segsize with_segsize
with_wal_blocksize with_wal_blocksize
with_wal_segsize
with_CC with_CC
enable_depend enable_depend
enable_cassert enable_cassert
...@@ -1518,8 +1517,6 @@ Optional Packages: ...@@ -1518,8 +1517,6 @@ Optional Packages:
--with-segsize=SEGSIZE set table segment size in GB [1] --with-segsize=SEGSIZE set table segment size in GB [1]
--with-wal-blocksize=BLOCKSIZE --with-wal-blocksize=BLOCKSIZE
set WAL block size in kB [8] 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-CC=CMD set compiler (deprecated)
--with-icu build with ICU support --with-icu build with ICU support
--with-tcl build Tcl modules (PL/Tcl) --with-tcl build Tcl modules (PL/Tcl)
...@@ -3733,57 +3730,6 @@ cat >>confdefs.h <<_ACEOF ...@@ -3733,57 +3730,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF _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 # C compiler
# #
......
...@@ -343,37 +343,6 @@ AC_DEFINE_UNQUOTED([XLOG_BLCKSZ], ${XLOG_BLCKSZ}, [ ...@@ -343,37 +343,6 @@ AC_DEFINE_UNQUOTED([XLOG_BLCKSZ], ${XLOG_BLCKSZ}, [
Changing XLOG_BLCKSZ requires an initdb. 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 # C compiler
# #
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
const char *progname; const char *progname;
int WalSegSz = -1;
/* Options and defaults */ /* Options and defaults */
int sleeptime = 5; /* amount of time to sleep between file checks */ int sleeptime = 5; /* amount of time to sleep between file checks */
int waittime = -1; /* how long we have been waiting, -1 no wait int waittime = -1; /* how long we have been waiting, -1 no wait
...@@ -100,6 +102,10 @@ int nextWALFileType; ...@@ -100,6 +102,10 @@ int nextWALFileType;
struct stat stat_buf; struct stat stat_buf;
static bool SetWALFileNameForCleanup(void);
static bool SetWALSegSize(void);
/* ===================================================================== /* =====================================================================
* *
* Customizable section * Customizable section
...@@ -175,6 +181,35 @@ CustomizableNextWALFileReady(void) ...@@ -175,6 +181,35 @@ CustomizableNextWALFileReady(void)
{ {
if (stat(WALFilePath, &stat_buf) == 0) 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 * If it's a backup file, return immediately. If it's a regular file
* return only if it's the right size already. * return only if it's the right size already.
...@@ -184,7 +219,7 @@ CustomizableNextWALFileReady(void) ...@@ -184,7 +219,7 @@ CustomizableNextWALFileReady(void)
nextWALFileType = XLOG_BACKUP_LABEL; nextWALFileType = XLOG_BACKUP_LABEL;
return true; return true;
} }
else if (stat_buf.st_size == XLOG_SEG_SIZE) else if (WalSegSz > 0 && stat_buf.st_size == WalSegSz)
{ {
#ifdef WIN32 #ifdef WIN32
...@@ -204,7 +239,7 @@ CustomizableNextWALFileReady(void) ...@@ -204,7 +239,7 @@ CustomizableNextWALFileReady(void)
/* /*
* If still too small, wait until it is the correct size * 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) if (debug)
{ {
...@@ -218,8 +253,6 @@ CustomizableNextWALFileReady(void) ...@@ -218,8 +253,6 @@ CustomizableNextWALFileReady(void)
return false; return false;
} }
#define MaxSegmentsPerLogFile ( 0xFFFFFFFF / XLOG_SEG_SIZE )
static void static void
CustomizableCleanupPriorWALFiles(void) CustomizableCleanupPriorWALFiles(void)
{ {
...@@ -315,6 +348,7 @@ SetWALFileNameForCleanup(void) ...@@ -315,6 +348,7 @@ SetWALFileNameForCleanup(void)
uint32 log_diff = 0, uint32 log_diff = 0,
seg_diff = 0; seg_diff = 0;
bool cleanup = false; bool cleanup = false;
int max_segments_per_logfile = (0xFFFFFFFF / WalSegSz);
if (restartWALFileName) if (restartWALFileName)
{ {
...@@ -336,12 +370,12 @@ SetWALFileNameForCleanup(void) ...@@ -336,12 +370,12 @@ SetWALFileNameForCleanup(void)
sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg); sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg);
if (tli > 0 && seg > 0) if (tli > 0 && seg > 0)
{ {
log_diff = keepfiles / MaxSegmentsPerLogFile; log_diff = keepfiles / max_segments_per_logfile;
seg_diff = keepfiles % MaxSegmentsPerLogFile; seg_diff = keepfiles % max_segments_per_logfile;
if (seg_diff > seg) if (seg_diff > seg)
{ {
log_diff++; log_diff++;
seg = MaxSegmentsPerLogFile - (seg_diff - seg); seg = max_segments_per_logfile - (seg_diff - seg);
} }
else else
seg -= seg_diff; seg -= seg_diff;
...@@ -364,6 +398,66 @@ SetWALFileNameForCleanup(void) ...@@ -364,6 +398,66 @@ SetWALFileNameForCleanup(void)
return cleanup; 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() * CheckForExternalTrigger()
* *
...@@ -708,8 +802,6 @@ main(int argc, char **argv) ...@@ -708,8 +802,6 @@ main(int argc, char **argv)
CustomizableInitialize(); CustomizableInitialize();
need_cleanup = SetWALFileNameForCleanup();
if (debug) if (debug)
{ {
fprintf(stderr, "Trigger file: %s\n", triggerPath ? triggerPath : "<not set>"); fprintf(stderr, "Trigger file: %s\n", triggerPath ? triggerPath : "<not set>");
...@@ -721,11 +813,6 @@ main(int argc, char **argv) ...@@ -721,11 +813,6 @@ main(int argc, char **argv)
fprintf(stderr, "Max wait interval: %d %s\n", fprintf(stderr, "Max wait interval: %d %s\n",
maxwaittime, (maxwaittime > 0 ? "seconds" : "forever")); maxwaittime, (maxwaittime > 0 ? "seconds" : "forever"));
fprintf(stderr, "Command for restore: %s\n", restoreCommand); 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); fflush(stderr);
} }
......
...@@ -562,7 +562,7 @@ tar -cf backup.tar /usr/local/pgsql/data ...@@ -562,7 +562,7 @@ tar -cf backup.tar /usr/local/pgsql/data
produces an indefinitely long sequence of WAL records. The system produces an indefinitely long sequence of WAL records. The system
physically divides this sequence into WAL <firstterm>segment physically divides this sequence into WAL <firstterm>segment
files</>, which are normally 16MB apiece (although the segment size 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 files are given numeric names that reflect their position in the
abstract WAL sequence. When not using WAL archiving, the system abstract WAL sequence. When not using WAL archiving, the system
normally creates just a few segment files and then normally creates just a few segment files and then
......
...@@ -1058,20 +1058,6 @@ su - postgres ...@@ -1058,20 +1058,6 @@ su - postgres
</listitem> </listitem>
</varlistentry> </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> <varlistentry>
<term><option>--with-wal-blocksize=<replaceable>BLOCKSIZE</replaceable></option></term> <term><option>--with-wal-blocksize=<replaceable>BLOCKSIZE</replaceable></option></term>
<listitem> <listitem>
......
...@@ -316,6 +316,21 @@ PostgreSQL documentation ...@@ -316,6 +316,21 @@ PostgreSQL documentation
</varlistentry> </varlistentry>
<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>-X <replaceable class="parameter">directory</replaceable></option></term>
<term><option>--waldir=<replaceable class="parameter">directory</replaceable></option></term> <term><option>--waldir=<replaceable class="parameter">directory</replaceable></option></term>
<listitem> <listitem>
......
...@@ -752,13 +752,12 @@ ...@@ -752,13 +752,12 @@
<acronym>WAL</acronym> logs are stored in the directory <acronym>WAL</acronym> logs are stored in the directory
<filename>pg_wal</filename> under the data directory, as a set of <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 segment files, normally each 16 MB in size (but the size can be changed
by altering the <option>--with-wal-segsize</> configure option when by altering the <option>--wal-segsize</> initdb option). Each segment is
building the server). Each segment is divided into pages, normally divided into pages, normally 8 kB each (this size can be changed via the
8 kB each (this size can be changed via the <option>--with-wal-blocksize</> <option>--with-wal-blocksize</> configure option). The log record headers
configure option). The log record headers are described in are described in <filename>access/xlogrecord.h</filename>; the record
<filename>access/xlogrecord.h</filename>; the record content is dependent content is dependent on the type of event that is being logged. Segment
on the type of event that is being logged. Segment files are given files are given ever-increasing numbers as names, starting at
ever-increasing numbers as names, starting at
<filename>000000010000000000000000</filename>. The numbers do not wrap, <filename>000000010000000000000000</filename>. The numbers do not wrap,
but it will take a very, very long time to exhaust the but it will take a very, very long time to exhaust the
available stock of numbers. available stock of numbers.
......
...@@ -1299,7 +1299,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len) ...@@ -1299,7 +1299,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
XLogReaderState *xlogreader; XLogReaderState *xlogreader;
char *errormsg; char *errormsg;
xlogreader = XLogReaderAllocate(&read_local_xlog_page, NULL); xlogreader = XLogReaderAllocate(wal_segment_size, &read_local_xlog_page,
NULL);
if (!xlogreader) if (!xlogreader)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
......
This diff is collapsed.
...@@ -134,13 +134,14 @@ RestoreArchivedFile(char *path, const char *xlogfname, ...@@ -134,13 +134,14 @@ RestoreArchivedFile(char *path, const char *xlogfname,
if (cleanupEnabled) if (cleanupEnabled)
{ {
GetOldestRestartPoint(&restartRedoPtr, &restartTli); GetOldestRestartPoint(&restartRedoPtr, &restartTli);
XLByteToSeg(restartRedoPtr, restartSegNo); XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
XLogFileName(lastRestartPointFname, restartTli, restartSegNo); XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
wal_segment_size);
/* we shouldn't need anything earlier than last restart point */ /* we shouldn't need anything earlier than last restart point */
Assert(strcmp(lastRestartPointFname, xlogfname) <= 0); Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
} }
else else
XLogFileName(lastRestartPointFname, 0, 0L); XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
/* /*
* construct the command to be executed * construct the command to be executed
...@@ -347,8 +348,9 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) ...@@ -347,8 +348,9 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
* archive, though there is no requirement to do so. * archive, though there is no requirement to do so.
*/ */
GetOldestRestartPoint(&restartRedoPtr, &restartTli); GetOldestRestartPoint(&restartRedoPtr, &restartTli);
XLByteToSeg(restartRedoPtr, restartSegNo); XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
XLogFileName(lastRestartPointFname, restartTli, restartSegNo); XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
wal_segment_size);
/* /*
* construct the command to be executed * construct the command to be executed
...@@ -547,7 +549,7 @@ XLogArchiveNotifySeg(XLogSegNo segno) ...@@ -547,7 +549,7 @@ XLogArchiveNotifySeg(XLogSegNo segno)
{ {
char xlog[MAXFNAMELEN]; char xlog[MAXFNAMELEN];
XLogFileName(xlog, ThisTimeLineID, segno); XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
XLogArchiveNotify(xlog); XLogArchiveNotify(xlog);
} }
......
...@@ -489,8 +489,8 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) ...@@ -489,8 +489,8 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/* /*
* xlogfilename * xlogfilename
*/ */
XLByteToPrevSeg(locationpoint, xlogsegno); XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno); XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
values[0] = CStringGetTextDatum(xlogfilename); values[0] = CStringGetTextDatum(xlogfilename);
isnull[0] = false; isnull[0] = false;
...@@ -498,7 +498,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) ...@@ -498,7 +498,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/* /*
* offset * offset
*/ */
xrecoff = locationpoint % XLogSegSize; xrecoff = XLogSegmentOffset(locationpoint, wal_segment_size);
values[1] = UInt32GetDatum(xrecoff); values[1] = UInt32GetDatum(xrecoff);
isnull[1] = false; isnull[1] = false;
...@@ -530,8 +530,8 @@ pg_walfile_name(PG_FUNCTION_ARGS) ...@@ -530,8 +530,8 @@ pg_walfile_name(PG_FUNCTION_ARGS)
errmsg("recovery is in progress"), errmsg("recovery is in progress"),
errhint("pg_walfile_name() cannot be executed during recovery."))); errhint("pg_walfile_name() cannot be executed during recovery.")));
XLByteToPrevSeg(locationpoint, xlogsegno); XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno); XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
} }
......
...@@ -64,7 +64,8 @@ report_invalid_record(XLogReaderState *state, const char *fmt,...) ...@@ -64,7 +64,8 @@ report_invalid_record(XLogReaderState *state, const char *fmt,...)
* Returns NULL if the xlogreader couldn't be allocated. * Returns NULL if the xlogreader couldn't be allocated.
*/ */
XLogReaderState * XLogReaderState *
XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data) XLogReaderAllocate(int wal_segment_size, XLogPageReadCB pagereadfunc,
void *private_data)
{ {
XLogReaderState *state; XLogReaderState *state;
...@@ -91,6 +92,7 @@ XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data) ...@@ -91,6 +92,7 @@ XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
return NULL; return NULL;
} }
state->wal_segment_size = wal_segment_size;
state->read_page = pagereadfunc; state->read_page = pagereadfunc;
/* system_identifier initialized to zeroes above */ /* system_identifier initialized to zeroes above */
state->private_data = private_data; state->private_data = private_data;
...@@ -466,8 +468,8 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg) ...@@ -466,8 +468,8 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
(record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH) (record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH)
{ {
/* Pretend it extends to end of segment */ /* Pretend it extends to end of segment */
state->EndRecPtr += XLogSegSize - 1; state->EndRecPtr += state->wal_segment_size - 1;
state->EndRecPtr -= state->EndRecPtr % XLogSegSize; state->EndRecPtr -= XLogSegmentOffset(state->EndRecPtr, state->wal_segment_size);
} }
if (DecodeXLogRecord(state, record, errormsg)) if (DecodeXLogRecord(state, record, errormsg))
...@@ -509,8 +511,8 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen) ...@@ -509,8 +511,8 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
Assert((pageptr % XLOG_BLCKSZ) == 0); Assert((pageptr % XLOG_BLCKSZ) == 0);
XLByteToSeg(pageptr, targetSegNo); XLByteToSeg(pageptr, targetSegNo, state->wal_segment_size);
targetPageOff = (pageptr % XLogSegSize); targetPageOff = XLogSegmentOffset(pageptr, state->wal_segment_size);
/* check whether we have all the requested data already */ /* check whether we have all the requested data already */
if (targetSegNo == state->readSegNo && targetPageOff == state->readOff && if (targetSegNo == state->readSegNo && targetPageOff == state->readOff &&
...@@ -719,16 +721,16 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -719,16 +721,16 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
Assert((recptr % XLOG_BLCKSZ) == 0); Assert((recptr % XLOG_BLCKSZ) == 0);
XLByteToSeg(recptr, segno); XLByteToSeg(recptr, segno, state->wal_segment_size);
offset = recptr % XLogSegSize; 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) if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
{ {
char fname[MAXFNAMELEN]; char fname[MAXFNAMELEN];
XLogFileName(fname, state->readPageTLI, segno); XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state, report_invalid_record(state,
"invalid magic number %04X in log segment %s, offset %u", "invalid magic number %04X in log segment %s, offset %u",
...@@ -742,7 +744,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -742,7 +744,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
{ {
char fname[MAXFNAMELEN]; char fname[MAXFNAMELEN];
XLogFileName(fname, state->readPageTLI, segno); XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state, report_invalid_record(state,
"invalid info bits %04X in log segment %s, offset %u", "invalid info bits %04X in log segment %s, offset %u",
...@@ -775,10 +777,10 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -775,10 +777,10 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
fhdrident_str, sysident_str); fhdrident_str, sysident_str);
return false; return false;
} }
else if (longhdr->xlp_seg_size != XLogSegSize) else if (longhdr->xlp_seg_size != state->wal_segment_size)
{ {
report_invalid_record(state, 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; return false;
} }
else if (longhdr->xlp_xlog_blcksz != XLOG_BLCKSZ) else if (longhdr->xlp_xlog_blcksz != XLOG_BLCKSZ)
...@@ -792,7 +794,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -792,7 +794,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
{ {
char fname[MAXFNAMELEN]; 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? */ /* hmm, first page of file doesn't have a long header? */
report_invalid_record(state, report_invalid_record(state,
...@@ -807,7 +809,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -807,7 +809,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
{ {
char fname[MAXFNAMELEN]; char fname[MAXFNAMELEN];
XLogFileName(fname, state->readPageTLI, segno); XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state, report_invalid_record(state,
"unexpected pageaddr %X/%X in log segment %s, offset %u", "unexpected pageaddr %X/%X in log segment %s, offset %u",
...@@ -832,7 +834,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, ...@@ -832,7 +834,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
{ {
char fname[MAXFNAMELEN]; char fname[MAXFNAMELEN];
XLogFileName(fname, state->readPageTLI, segno); XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
report_invalid_record(state, report_invalid_record(state,
"out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u", "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u",
......
...@@ -654,7 +654,8 @@ XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, ...@@ -654,7 +654,8 @@ XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
* frontend). Probably these should be merged at some point. * frontend). Probably these should be merged at some point.
*/ */
static void static void
XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) XLogRead(char *buf, int segsize, TimeLineID tli, XLogRecPtr startptr,
Size count)
{ {
char *p; char *p;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -666,6 +667,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -666,6 +667,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
static TimeLineID sendTLI = 0; static TimeLineID sendTLI = 0;
static uint32 sendOff = 0; static uint32 sendOff = 0;
Assert(segsize == wal_segment_size);
p = buf; p = buf;
recptr = startptr; recptr = startptr;
nbytes = count; nbytes = count;
...@@ -676,10 +679,10 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -676,10 +679,10 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
int segbytes; int segbytes;
int readbytes; int readbytes;
startoff = recptr % XLogSegSize; startoff = XLogSegmentOffset(recptr, segsize);
/* Do we need to switch to a different xlog segment? */ /* 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) sendTLI != tli)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
...@@ -687,9 +690,9 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -687,9 +690,9 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
if (sendFile >= 0) if (sendFile >= 0)
close(sendFile); 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); sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
...@@ -717,7 +720,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -717,7 +720,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
XLogFilePath(path, tli, sendSegNo); XLogFilePath(path, tli, sendSegNo, segsize);
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
...@@ -728,8 +731,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -728,8 +731,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
} }
/* How many bytes are within this segment? */ /* How many bytes are within this segment? */
if (nbytes > (XLogSegSize - startoff)) if (nbytes > (segsize - startoff))
segbytes = XLogSegSize - startoff; segbytes = segsize - startoff;
else else
segbytes = nbytes; segbytes = nbytes;
...@@ -740,7 +743,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -740,7 +743,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
XLogFilePath(path, tli, sendSegNo); XLogFilePath(path, tli, sendSegNo, segsize);
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
...@@ -798,7 +801,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count) ...@@ -798,7 +801,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
void void
XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength) 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(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
Assert(wantLength <= XLOG_BLCKSZ); Assert(wantLength <= XLOG_BLCKSZ);
...@@ -842,7 +846,8 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa ...@@ -842,7 +846,8 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
if (state->currTLIValidUntil != InvalidXLogRecPtr && if (state->currTLIValidUntil != InvalidXLogRecPtr &&
state->currTLI != ThisTimeLineID && state->currTLI != ThisTimeLineID &&
state->currTLI != 0 && state->currTLI != 0 &&
(wantPage + wantLength) / XLogSegSize < state->currTLIValidUntil / XLogSegSize) ((wantPage + wantLength) / state->wal_segment_size) <
(state->currTLIValidUntil / state->wal_segment_size))
return; return;
/* /*
...@@ -864,9 +869,11 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa ...@@ -864,9 +869,11 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
*/ */
List *timelineHistory = readTimeLineHistory(ThisTimeLineID); 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 * Find the timeline of the last LSN on the segment containing
...@@ -1014,7 +1021,8 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, ...@@ -1014,7 +1021,8 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
* as 'count', read the whole page anyway. It's guaranteed to be * as 'count', read the whole page anyway. It's guaranteed to be
* zero-padded up to the page boundary if it's incomplete. * 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 */ /* number of valid bytes in the buffer */
return count; return count;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "access/xact.h" #include "access/xact.h"
#include "access/xlog_internal.h"
#include "bootstrap/bootstrap.h" #include "bootstrap/bootstrap.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/pg_collation.h" #include "catalog/pg_collation.h"
...@@ -222,7 +223,7 @@ AuxiliaryProcessMain(int argc, char *argv[]) ...@@ -222,7 +223,7 @@ AuxiliaryProcessMain(int argc, char *argv[])
/* If no -x argument, we are a CheckerProcess */ /* If no -x argument, we are a CheckerProcess */
MyAuxProcType = 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) switch (flag)
{ {
...@@ -257,6 +258,18 @@ AuxiliaryProcessMain(int argc, char *argv[]) ...@@ -257,6 +258,18 @@ AuxiliaryProcessMain(int argc, char *argv[])
case 'x': case 'x':
MyAuxProcType = atoi(optarg); MyAuxProcType = atoi(optarg);
break; 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 'c':
case '-': case '-':
{ {
......
...@@ -624,7 +624,7 @@ CheckArchiveTimeout(void) ...@@ -624,7 +624,7 @@ CheckArchiveTimeout(void)
* If the returned pointer points exactly to a segment boundary, * If the returned pointer points exactly to a segment boundary,
* assume nothing happened. * assume nothing happened.
*/ */
if ((switchpoint % XLogSegSize) != 0) if (XLogSegmentOffset(switchpoint, wal_segment_size) != 0)
elog(DEBUG1, "write-ahead log switch forced (archive_timeout=%d)", elog(DEBUG1, "write-ahead log switch forced (archive_timeout=%d)",
XLogArchiveTimeout); XLogArchiveTimeout);
} }
...@@ -782,7 +782,8 @@ IsCheckpointOnSchedule(double progress) ...@@ -782,7 +782,8 @@ IsCheckpointOnSchedule(double progress)
recptr = GetXLogReplayRecPtr(NULL); recptr = GetXLogReplayRecPtr(NULL);
else else
recptr = GetInsertRecPtr(); 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) if (progress < elapsed_xlogs)
{ {
......
...@@ -357,10 +357,10 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -357,10 +357,10 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
* shouldn't be such files, but if there are, there's little harm in * shouldn't be such files, but if there are, there's little harm in
* including them. * including them.
*/ */
XLByteToSeg(startptr, startsegno); XLByteToSeg(startptr, startsegno, wal_segment_size);
XLogFileName(firstoff, ThisTimeLineID, startsegno); XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
XLByteToPrevSeg(endptr, endsegno); XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
XLogFileName(lastoff, ThisTimeLineID, endsegno); XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
dir = AllocateDir("pg_wal"); dir = AllocateDir("pg_wal");
if (!dir) if (!dir)
...@@ -415,12 +415,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -415,12 +415,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
* Sanity check: the first and last segment should cover startptr and * Sanity check: the first and last segment should cover startptr and
* endptr, with no gaps in between. * endptr, with no gaps in between.
*/ */
XLogFromFileName(walFiles[0], &tli, &segno); XLogFromFileName(walFiles[0], &tli, &segno, wal_segment_size);
if (segno != startsegno) if (segno != startsegno)
{ {
char startfname[MAXFNAMELEN]; char startfname[MAXFNAMELEN];
XLogFileName(startfname, ThisTimeLineID, startsegno); XLogFileName(startfname, ThisTimeLineID, startsegno,
wal_segment_size);
ereport(ERROR, ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", startfname))); (errmsg("could not find WAL file \"%s\"", startfname)));
} }
...@@ -429,12 +430,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -429,12 +430,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
XLogSegNo currsegno = segno; XLogSegNo currsegno = segno;
XLogSegNo nextsegno = segno + 1; XLogSegNo nextsegno = segno + 1;
XLogFromFileName(walFiles[i], &tli, &segno); XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
if (!(nextsegno == segno || currsegno == segno)) if (!(nextsegno == segno || currsegno == segno))
{ {
char nextfname[MAXFNAMELEN]; char nextfname[MAXFNAMELEN];
XLogFileName(nextfname, ThisTimeLineID, nextsegno); XLogFileName(nextfname, ThisTimeLineID, nextsegno,
wal_segment_size);
ereport(ERROR, ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", nextfname))); (errmsg("could not find WAL file \"%s\"", nextfname)));
} }
...@@ -443,7 +445,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -443,7 +445,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
{ {
char endfname[MAXFNAMELEN]; char endfname[MAXFNAMELEN];
XLogFileName(endfname, ThisTimeLineID, endsegno); XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
ereport(ERROR, ereport(ERROR,
(errmsg("could not find WAL file \"%s\"", endfname))); (errmsg("could not find WAL file \"%s\"", endfname)));
} }
...@@ -457,7 +459,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -457,7 +459,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
pgoff_t len = 0; pgoff_t len = 0;
snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]); snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
XLogFromFileName(walFiles[i], &tli, &segno); XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
fp = AllocateFile(pathbuf, "rb"); fp = AllocateFile(pathbuf, "rb");
if (fp == NULL) if (fp == NULL)
...@@ -479,7 +481,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -479,7 +481,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not stat file \"%s\": %m", errmsg("could not stat file \"%s\": %m",
pathbuf))); pathbuf)));
if (statbuf.st_size != XLogSegSize) if (statbuf.st_size != wal_segment_size)
{ {
CheckXLogRemoved(segno, tli); CheckXLogRemoved(segno, tli);
ereport(ERROR, ereport(ERROR,
...@@ -490,7 +492,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -490,7 +492,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
/* send the WAL file itself */ /* send the WAL file itself */
_tarWriteHeader(pathbuf, NULL, &statbuf, false); _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); CheckXLogRemoved(segno, tli);
/* Send the chunk as a CopyData message */ /* Send the chunk as a CopyData message */
...@@ -501,11 +505,11 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -501,11 +505,11 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
len += cnt; len += cnt;
throttle(cnt); throttle(cnt);
if (len == XLogSegSize) if (len == wal_segment_size)
break; break;
} }
if (len != XLogSegSize) if (len != wal_segment_size)
{ {
CheckXLogRemoved(segno, tli); CheckXLogRemoved(segno, tli);
ereport(ERROR, ereport(ERROR,
...@@ -513,7 +517,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir) ...@@ -513,7 +517,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
errmsg("unexpected WAL file size \"%s\"", walFiles[i]))); 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); FreeFile(fp);
......
...@@ -163,7 +163,7 @@ StartupDecodingContext(List *output_plugin_options, ...@@ -163,7 +163,7 @@ StartupDecodingContext(List *output_plugin_options,
ctx->slot = slot; ctx->slot = slot;
ctx->reader = XLogReaderAllocate(read_page, ctx); ctx->reader = XLogReaderAllocate(wal_segment_size, read_page, ctx);
if (!ctx->reader) if (!ctx->reader)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
......
...@@ -2083,15 +2083,16 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn) ...@@ -2083,15 +2083,16 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
* store in segment in which it belongs by start lsn, don't split over * store in segment in which it belongs by start lsn, don't split over
* multiple segments tho * multiple segments tho
*/ */
if (fd == -1 || !XLByteInSeg(change->lsn, curOpenSegNo)) if (fd == -1 ||
!XLByteInSeg(change->lsn, curOpenSegNo, wal_segment_size))
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
if (fd != -1) if (fd != -1)
CloseTransientFile(fd); CloseTransientFile(fd);
XLByteToSeg(change->lsn, curOpenSegNo); XLByteToSeg(change->lsn, curOpenSegNo, wal_segment_size);
XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr); XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr, wal_segment_size);
/* /*
* No need to care about TLIs here, only used during a single run, * No need to care about TLIs here, only used during a single run,
...@@ -2319,7 +2320,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn, ...@@ -2319,7 +2320,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
txn->nentries_mem = 0; txn->nentries_mem = 0;
Assert(dlist_is_empty(&txn->changes)); 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) while (restored < max_changes_in_memory && *segno <= last_segno)
{ {
...@@ -2334,11 +2335,11 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn, ...@@ -2334,11 +2335,11 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
/* first time in */ /* first time in */
if (*segno == 0) if (*segno == 0)
{ {
XLByteToSeg(txn->first_lsn, *segno); XLByteToSeg(txn->first_lsn, *segno, wal_segment_size);
} }
Assert(*segno != 0 || dlist_is_empty(&txn->changes)); 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, * No need to care about TLIs here, only used during a single run,
...@@ -2575,8 +2576,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn) ...@@ -2575,8 +2576,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
Assert(txn->first_lsn != InvalidXLogRecPtr); Assert(txn->first_lsn != InvalidXLogRecPtr);
Assert(txn->final_lsn != InvalidXLogRecPtr); Assert(txn->final_lsn != InvalidXLogRecPtr);
XLByteToSeg(txn->first_lsn, first); XLByteToSeg(txn->first_lsn, first, wal_segment_size);
XLByteToSeg(txn->final_lsn, last); XLByteToSeg(txn->final_lsn, last, wal_segment_size);
/* iterate over all possible filenames, and delete them */ /* iterate over all possible filenames, and delete them */
for (cur = first; cur <= last; cur++) for (cur = first; cur <= last; cur++)
...@@ -2584,7 +2585,7 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn) ...@@ -2584,7 +2585,7 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
char path[MAXPGPATH]; char path[MAXPGPATH];
XLogRecPtr recptr; XLogRecPtr recptr;
XLogSegNoOffsetToRecPtr(cur, 0, recptr); XLogSegNoOffsetToRecPtr(cur, 0, recptr, wal_segment_size);
sprintf(path, "pg_replslot/%s/xid-%u-lsn-%X-%X.snap", sprintf(path, "pg_replslot/%s/xid-%u-lsn-%X-%X.snap",
NameStr(MyReplicationSlot->data.name), txn->xid, NameStr(MyReplicationSlot->data.name), txn->xid,
......
...@@ -1039,7 +1039,7 @@ ReplicationSlotReserveWal(void) ...@@ -1039,7 +1039,7 @@ ReplicationSlotReserveWal(void)
* the new restart_lsn above, so normally we should never need to loop * the new restart_lsn above, so normally we should never need to loop
* more than twice. * more than twice.
*/ */
XLByteToSeg(slot->data.restart_lsn, segno); XLByteToSeg(slot->data.restart_lsn, segno, wal_segment_size);
if (XLogGetLastRemovedSegno() < segno) if (XLogGetLastRemovedSegno() < segno)
break; break;
} }
......
...@@ -613,7 +613,7 @@ WalReceiverMain(void) ...@@ -613,7 +613,7 @@ WalReceiverMain(void)
* Create .done file forcibly to prevent the streamed segment from * Create .done file forcibly to prevent the streamed segment from
* being archived later. * being archived later.
*/ */
XLogFileName(xlogfname, recvFileTLI, recvSegNo); XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS) if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
XLogArchiveForceDone(xlogfname); XLogArchiveForceDone(xlogfname);
else else
...@@ -943,7 +943,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -943,7 +943,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
{ {
int segbytes; int segbytes;
if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo)) if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
{ {
bool use_existent; bool use_existent;
...@@ -972,7 +972,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -972,7 +972,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
* Create .done file forcibly to prevent the streamed segment * Create .done file forcibly to prevent the streamed segment
* from being archived later. * from being archived later.
*/ */
XLogFileName(xlogfname, recvFileTLI, recvSegNo); XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS) if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
XLogArchiveForceDone(xlogfname); XLogArchiveForceDone(xlogfname);
else else
...@@ -981,7 +981,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -981,7 +981,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
recvFile = -1; recvFile = -1;
/* Create/use new log file */ /* Create/use new log file */
XLByteToSeg(recptr, recvSegNo); XLByteToSeg(recptr, recvSegNo, wal_segment_size);
use_existent = true; use_existent = true;
recvFile = XLogFileInit(recvSegNo, &use_existent, true); recvFile = XLogFileInit(recvSegNo, &use_existent, true);
recvFileTLI = ThisTimeLineID; recvFileTLI = ThisTimeLineID;
...@@ -989,10 +989,10 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) ...@@ -989,10 +989,10 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
} }
/* Calculate the start offset of the received logs */ /* Calculate the start offset of the received logs */
startoff = recptr % XLogSegSize; startoff = XLogSegmentOffset(recptr, wal_segment_size);
if (startoff + nbytes > XLogSegSize) if (startoff + nbytes > wal_segment_size)
segbytes = XLogSegSize - startoff; segbytes = wal_segment_size - startoff;
else else
segbytes = nbytes; segbytes = nbytes;
......
...@@ -233,8 +233,8 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, ...@@ -233,8 +233,8 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
* being created by XLOG streaming, which might cause trouble later on if * being created by XLOG streaming, which might cause trouble later on if
* the segment is e.g archived. * the segment is e.g archived.
*/ */
if (recptr % XLogSegSize != 0) if (XLogSegmentOffset(recptr, wal_segment_size) != 0)
recptr -= recptr % XLogSegSize; recptr -= XLogSegmentOffset(recptr, wal_segment_size);
SpinLockAcquire(&walrcv->mutex); SpinLockAcquire(&walrcv->mutex);
......
...@@ -2316,9 +2316,9 @@ retry: ...@@ -2316,9 +2316,9 @@ retry:
int segbytes; int segbytes;
int readbytes; int readbytes;
startoff = recptr % XLogSegSize; startoff = XLogSegmentOffset(recptr, wal_segment_size);
if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo)) if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo, wal_segment_size))
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
...@@ -2326,7 +2326,7 @@ retry: ...@@ -2326,7 +2326,7 @@ retry:
if (sendFile >= 0) if (sendFile >= 0)
close(sendFile); close(sendFile);
XLByteToSeg(recptr, sendSegNo); XLByteToSeg(recptr, sendSegNo, wal_segment_size);
/*------- /*-------
* When reading from a historic timeline, and there is a timeline * When reading from a historic timeline, and there is a timeline
...@@ -2359,12 +2359,12 @@ retry: ...@@ -2359,12 +2359,12 @@ retry:
{ {
XLogSegNo endSegNo; XLogSegNo endSegNo;
XLByteToSeg(sendTimeLineValidUpto, endSegNo); XLByteToSeg(sendTimeLineValidUpto, endSegNo, wal_segment_size);
if (sendSegNo == endSegNo) if (sendSegNo == endSegNo)
curFileTimeLine = sendTimeLineNextTLI; curFileTimeLine = sendTimeLineNextTLI;
} }
XLogFilePath(path, curFileTimeLine, sendSegNo); XLogFilePath(path, curFileTimeLine, sendSegNo, wal_segment_size);
sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
if (sendFile < 0) if (sendFile < 0)
...@@ -2401,8 +2401,8 @@ retry: ...@@ -2401,8 +2401,8 @@ retry:
} }
/* How many bytes are within this segment? */ /* How many bytes are within this segment? */
if (nbytes > (XLogSegSize - startoff)) if (nbytes > (wal_segment_size - startoff))
segbytes = XLogSegSize - startoff; segbytes = wal_segment_size - startoff;
else else
segbytes = nbytes; segbytes = nbytes;
...@@ -2433,7 +2433,7 @@ retry: ...@@ -2433,7 +2433,7 @@ retry:
* read() succeeds in that case, but the data we tried to read might * read() succeeds in that case, but the data we tried to read might
* already have been overwritten with new WAL records. * already have been overwritten with new WAL records.
*/ */
XLByteToSeg(startptr, segno); XLByteToSeg(startptr, segno, wal_segment_size);
CheckXLogRemoved(segno, ThisTimeLineID); CheckXLogRemoved(segno, ThisTimeLineID);
/* /*
......
...@@ -514,7 +514,6 @@ static int block_size; ...@@ -514,7 +514,6 @@ static int block_size;
static int segment_size; static int segment_size;
static int wal_block_size; static int wal_block_size;
static bool data_checksums; static bool data_checksums;
static int wal_segment_size;
static bool integer_datetimes; static bool integer_datetimes;
static bool assert_enabled; static bool assert_enabled;
...@@ -714,9 +713,6 @@ typedef struct ...@@ -714,9 +713,6 @@ typedef struct
#if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024) #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024)
#error XLOG_BLCKSZ must be between 1KB and 1MB #error XLOG_BLCKSZ must be between 1KB and 1MB
#endif #endif
#if XLOG_SEG_SIZE < (1024*1024) || XLOG_SEG_SIZE > (1024*1024*1024)
#error XLOG_SEG_SIZE must be between 1MB and 1GB
#endif
static const char *memory_units_hint = gettext_noop("Valid units for this parameter are \"kB\", \"MB\", \"GB\", and \"TB\"."); static const char *memory_units_hint = gettext_noop("Valid units for this parameter are \"kB\", \"MB\", \"GB\", and \"TB\".");
...@@ -2264,7 +2260,8 @@ static struct config_int ConfigureNamesInt[] = ...@@ -2264,7 +2260,8 @@ static struct config_int ConfigureNamesInt[] =
GUC_UNIT_MB GUC_UNIT_MB
}, },
&min_wal_size_mb, &min_wal_size_mb,
5 * (XLOG_SEG_SIZE / (1024 * 1024)), 2, MAX_KILOBYTES, DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
2, MAX_KILOBYTES,
NULL, NULL, NULL NULL, NULL, NULL
}, },
...@@ -2275,7 +2272,8 @@ static struct config_int ConfigureNamesInt[] = ...@@ -2275,7 +2272,8 @@ static struct config_int ConfigureNamesInt[] =
GUC_UNIT_MB GUC_UNIT_MB
}, },
&max_wal_size_mb, &max_wal_size_mb,
64 * (XLOG_SEG_SIZE / (1024 * 1024)), 2, MAX_KILOBYTES, DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
2, MAX_KILOBYTES,
NULL, assign_max_wal_size, NULL NULL, assign_max_wal_size, NULL
}, },
...@@ -2637,14 +2635,14 @@ static struct config_int ConfigureNamesInt[] = ...@@ -2637,14 +2635,14 @@ static struct config_int ConfigureNamesInt[] =
{ {
{"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS, {"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS,
gettext_noop("Shows the number of pages per write ahead log segment."), gettext_noop("Shows the size of write ahead log segments."),
NULL, NULL,
GUC_UNIT_XBLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
}, },
&wal_segment_size, &wal_segment_size,
(XLOG_SEG_SIZE / XLOG_BLCKSZ), DEFAULT_XLOG_SEG_SIZE,
(XLOG_SEG_SIZE / XLOG_BLCKSZ), WalSegMinSize,
(XLOG_SEG_SIZE / XLOG_BLCKSZ), WalSegMaxSize,
NULL, NULL, NULL NULL, NULL, NULL
}, },
......
...@@ -141,8 +141,9 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) ...@@ -141,8 +141,9 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
* Calculate name of the WAL file containing the latest checkpoint's REDO * Calculate name of the WAL file containing the latest checkpoint's REDO
* start point. * start point.
*/ */
XLByteToSeg(ControlFile->checkPointCopy.redo, segno); XLByteToSeg(ControlFile->checkPointCopy.redo, segno, wal_segment_size);
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno); XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
segno, wal_segment_size);
/* Populate the values and null arrays */ /* Populate the values and null arrays */
values[0] = LSNGetDatum(ControlFile->checkPoint); values[0] = LSNGetDatum(ControlFile->checkPoint);
......
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
#max_wal_senders = 10 # max number of walsender processes #max_wal_senders = 10 # max number of walsender processes
# (change requires restart) # (change requires restart)
#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables #wal_keep_segments = 0 # in logfile segments; 0 disables
#wal_sender_timeout = 60s # in milliseconds; 0 disables #wal_sender_timeout = 60s # in milliseconds; 0 disables
#max_replication_slots = 10 # max number of replication slots #max_replication_slots = 10 # max number of replication slots
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "sys/mman.h" #include "sys/mman.h"
#endif #endif
#include "access/xlog_internal.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/pg_authid.h" #include "catalog/pg_authid.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
...@@ -141,6 +142,8 @@ static bool sync_only = false; ...@@ -141,6 +142,8 @@ static bool sync_only = false;
static bool show_setting = false; static bool show_setting = false;
static bool data_checksums = false; static bool data_checksums = false;
static char *xlog_dir = NULL; static char *xlog_dir = NULL;
static char *str_wal_segment_size_mb = NULL;
static int wal_segment_size_mb;
/* internal vars */ /* internal vars */
...@@ -999,6 +1002,23 @@ test_config_settings(void) ...@@ -999,6 +1002,23 @@ test_config_settings(void)
printf("%s\n", dynamic_shared_memory_type); printf("%s\n", dynamic_shared_memory_type);
} }
/*
* Calculate the default wal_size with a "pretty" unit.
*/
static char *
pretty_wal_size(int segment_count)
{
int sz = wal_segment_size_mb * segment_count;
char *result = pg_malloc(10);
if ((sz % 1024) == 0)
snprintf(result, 10, "%dGB", sz / 1024);
else
snprintf(result, 10, "%dMB", sz);
return result;
}
/* /*
* set up all the config files * set up all the config files
*/ */
...@@ -1043,6 +1063,15 @@ setup_config(void) ...@@ -1043,6 +1063,15 @@ setup_config(void)
conflines = replace_token(conflines, "#port = 5432", repltok); conflines = replace_token(conflines, "#port = 5432", repltok);
#endif #endif
/* set default max_wal_size and min_wal_size */
snprintf(repltok, sizeof(repltok), "min_wal_size = %s",
pretty_wal_size(DEFAULT_MIN_WAL_SEGS));
conflines = replace_token(conflines, "#min_wal_size = 80MB", repltok);
snprintf(repltok, sizeof(repltok), "max_wal_size = %s",
pretty_wal_size(DEFAULT_MAX_WAL_SEGS));
conflines = replace_token(conflines, "#max_wal_size = 1GB", repltok);
snprintf(repltok, sizeof(repltok), "lc_messages = '%s'", snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
escape_quotes(lc_messages)); escape_quotes(lc_messages));
conflines = replace_token(conflines, "#lc_messages = 'C'", repltok); conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
...@@ -1352,8 +1381,9 @@ bootstrap_template1(void) ...@@ -1352,8 +1381,9 @@ bootstrap_template1(void)
unsetenv("PGCLIENTENCODING"); unsetenv("PGCLIENTENCODING");
snprintf(cmd, sizeof(cmd), snprintf(cmd, sizeof(cmd),
"\"%s\" --boot -x1 %s %s %s", "\"%s\" --boot -x1 -X %u %s %s %s",
backend_exec, backend_exec,
wal_segment_size_mb * (1024 * 1024),
data_checksums ? "-k" : "", data_checksums ? "-k" : "",
boot_options, boot_options,
debug ? "-d 5" : ""); debug ? "-d 5" : "");
...@@ -2293,6 +2323,7 @@ usage(const char *progname) ...@@ -2293,6 +2323,7 @@ usage(const char *progname)
printf(_(" -U, --username=NAME database superuser name\n")); printf(_(" -U, --username=NAME database superuser name\n"));
printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); printf(_(" -W, --pwprompt prompt for a password for the new superuser\n"));
printf(_(" -X, --waldir=WALDIR location for the write-ahead log directory\n")); printf(_(" -X, --waldir=WALDIR location for the write-ahead log directory\n"));
printf(_(" --wal-segsize=SIZE size of wal segment size\n"));
printf(_("\nLess commonly used options:\n")); printf(_("\nLess commonly used options:\n"));
printf(_(" -d, --debug generate lots of debugging output\n")); printf(_(" -d, --debug generate lots of debugging output\n"));
printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" -k, --data-checksums use data page checksums\n"));
...@@ -2983,6 +3014,7 @@ main(int argc, char *argv[]) ...@@ -2983,6 +3014,7 @@ main(int argc, char *argv[])
{"no-sync", no_argument, NULL, 'N'}, {"no-sync", no_argument, NULL, 'N'},
{"sync-only", no_argument, NULL, 'S'}, {"sync-only", no_argument, NULL, 'S'},
{"waldir", required_argument, NULL, 'X'}, {"waldir", required_argument, NULL, 'X'},
{"wal-segsize", required_argument, NULL, 12},
{"data-checksums", no_argument, NULL, 'k'}, {"data-checksums", no_argument, NULL, 'k'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
...@@ -3116,6 +3148,9 @@ main(int argc, char *argv[]) ...@@ -3116,6 +3148,9 @@ main(int argc, char *argv[])
case 'X': case 'X':
xlog_dir = pg_strdup(optarg); xlog_dir = pg_strdup(optarg);
break; break;
case 12:
str_wal_segment_size_mb = pg_strdup(optarg);
break;
default: default:
/* getopt_long already emitted a complaint */ /* getopt_long already emitted a complaint */
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
...@@ -3178,6 +3213,27 @@ main(int argc, char *argv[]) ...@@ -3178,6 +3213,27 @@ main(int argc, char *argv[])
check_need_password(authmethodlocal, authmethodhost); check_need_password(authmethodlocal, authmethodhost);
/* set wal segment size */
if (str_wal_segment_size_mb == NULL)
wal_segment_size_mb = (DEFAULT_XLOG_SEG_SIZE) / (1024 * 1024);
else
{
char *endptr;
/* check that the argument is a number */
wal_segment_size_mb = strtol(str_wal_segment_size_mb, &endptr, 10);
/* verify that wal segment size is valid */
if (*endptr != '\0' ||
!IsValidWalSegSize(wal_segment_size_mb * 1024 * 1024))
{
fprintf(stderr,
_("%s: --wal-segsize must be a power of two between 1 and 1024\n"),
progname);
exit(1);
}
}
get_restricted_token(progname); get_restricted_token(progname);
setup_pgdata(); setup_pgdata();
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <zlib.h> #include <zlib.h>
#endif #endif
#include "access/xlog_internal.h"
#include "common/file_utils.h" #include "common/file_utils.h"
#include "common/string.h" #include "common/string.h"
#include "fe_utils/string_utils.h" #include "fe_utils/string_utils.h"
...@@ -555,7 +556,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) ...@@ -555,7 +556,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
} }
param->startptr = ((uint64) hi) << 32 | lo; param->startptr = ((uint64) hi) << 32 | lo;
/* Round off to even segment position */ /* Round off to even segment position */
param->startptr -= param->startptr % XLOG_SEG_SIZE; param->startptr -= XLogSegmentOffset(param->startptr, WalSegSz);
#ifndef WIN32 #ifndef WIN32
/* Create our background pipe */ /* Create our background pipe */
...@@ -2397,6 +2398,10 @@ main(int argc, char **argv) ...@@ -2397,6 +2398,10 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
/* determine remote server's xlog segment size */
if (!RetrieveWalSegSize(conn))
disconnect_and_exit(1);
/* Create pg_wal symlink, if required */ /* Create pg_wal symlink, if required */
if (xlog_dir) if (xlog_dir)
{ {
......
...@@ -191,7 +191,7 @@ close_destination_dir(DIR *dest_dir, char *dest_folder) ...@@ -191,7 +191,7 @@ close_destination_dir(DIR *dest_dir, char *dest_folder)
/* /*
* Determine starting location for streaming, based on any existing xlog * Determine starting location for streaming, based on any existing xlog
* segments in the directory. We start at the end of the last one that is * segments in the directory. We start at the end of the last one that is
* complete (size matches XLogSegSize), on the timeline with highest ID. * complete (size matches wal segment size), on the timeline with highest ID.
* *
* If there are no WAL files in the directory, returns InvalidXLogRecPtr. * If there are no WAL files in the directory, returns InvalidXLogRecPtr.
*/ */
...@@ -242,7 +242,7 @@ FindStreamingStart(uint32 *tli) ...@@ -242,7 +242,7 @@ FindStreamingStart(uint32 *tli)
/* /*
* Looks like an xlog file. Parse its position. * Looks like an xlog file. Parse its position.
*/ */
XLogFromFileName(dirent->d_name, &tli, &segno); XLogFromFileName(dirent->d_name, &tli, &segno, WalSegSz);
/* /*
* Check that the segment has the right size, if it's supposed to be * Check that the segment has the right size, if it's supposed to be
...@@ -267,7 +267,7 @@ FindStreamingStart(uint32 *tli) ...@@ -267,7 +267,7 @@ FindStreamingStart(uint32 *tli)
disconnect_and_exit(1); disconnect_and_exit(1);
} }
if (statbuf.st_size != XLOG_SEG_SIZE) if (statbuf.st_size != WalSegSz)
{ {
fprintf(stderr, fprintf(stderr,
_("%s: segment file \"%s\" has incorrect size %d, skipping\n"), _("%s: segment file \"%s\" has incorrect size %d, skipping\n"),
...@@ -308,7 +308,7 @@ FindStreamingStart(uint32 *tli) ...@@ -308,7 +308,7 @@ FindStreamingStart(uint32 *tli)
bytes_out = (buf[3] << 24) | (buf[2] << 16) | bytes_out = (buf[3] << 24) | (buf[2] << 16) |
(buf[1] << 8) | buf[0]; (buf[1] << 8) | buf[0];
if (bytes_out != XLOG_SEG_SIZE) if (bytes_out != WalSegSz)
{ {
fprintf(stderr, fprintf(stderr,
_("%s: compressed segment file \"%s\" has incorrect uncompressed size %d, skipping\n"), _("%s: compressed segment file \"%s\" has incorrect uncompressed size %d, skipping\n"),
...@@ -349,7 +349,7 @@ FindStreamingStart(uint32 *tli) ...@@ -349,7 +349,7 @@ FindStreamingStart(uint32 *tli)
if (!high_ispartial) if (!high_ispartial)
high_segno++; high_segno++;
XLogSegNoOffsetToRecPtr(high_segno, 0, high_ptr); XLogSegNoOffsetToRecPtr(high_segno, 0, high_ptr, WalSegSz);
*tli = high_tli; *tli = high_tli;
return high_ptr; return high_ptr;
...@@ -410,7 +410,7 @@ StreamLog(void) ...@@ -410,7 +410,7 @@ StreamLog(void)
/* /*
* Always start streaming at the beginning of a segment * Always start streaming at the beginning of a segment
*/ */
stream.startpos -= stream.startpos % XLOG_SEG_SIZE; stream.startpos -= XLogSegmentOffset(stream.startpos, WalSegSz);
/* /*
* Start the replication * Start the replication
...@@ -689,6 +689,10 @@ main(int argc, char **argv) ...@@ -689,6 +689,10 @@ main(int argc, char **argv)
if (!RunIdentifySystem(conn, NULL, NULL, NULL, &db_name)) if (!RunIdentifySystem(conn, NULL, NULL, NULL, &db_name))
disconnect_and_exit(1); disconnect_and_exit(1);
/* determine remote server's xlog segment size */
if (!RetrieveWalSegSize(conn))
disconnect_and_exit(1);
/* /*
* Check that there is a database associated with connection, none should * Check that there is a database associated with connection, none should
* be defined in this context. * be defined in this context.
......
...@@ -95,17 +95,17 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -95,17 +95,17 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
ssize_t size; ssize_t size;
XLogSegNo segno; XLogSegNo segno;
XLByteToSeg(startpoint, segno); XLByteToSeg(startpoint, segno, WalSegSz);
XLogFileName(current_walfile_name, stream->timeline, segno); XLogFileName(current_walfile_name, stream->timeline, segno, WalSegSz);
snprintf(fn, sizeof(fn), "%s%s", current_walfile_name, snprintf(fn, sizeof(fn), "%s%s", current_walfile_name,
stream->partial_suffix ? stream->partial_suffix : ""); stream->partial_suffix ? stream->partial_suffix : "");
/* /*
* When streaming to files, if an existing file exists we verify that it's * When streaming to files, if an existing file exists we verify that it's
* either empty (just created), or a complete XLogSegSize segment (in * either empty (just created), or a complete WalSegSz segment (in which
* which case it has been created and padded). Anything else indicates a * case it has been created and padded). Anything else indicates a corrupt
* corrupt file. * file.
* *
* When streaming to tar, no file with this name will exist before, so we * When streaming to tar, no file with this name will exist before, so we
* never have to verify a size. * never have to verify a size.
...@@ -120,7 +120,7 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -120,7 +120,7 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
progname, fn, stream->walmethod->getlasterror()); progname, fn, stream->walmethod->getlasterror());
return false; return false;
} }
if (size == XLogSegSize) if (size == WalSegSz)
{ {
/* Already padded file. Open it for use */ /* Already padded file. Open it for use */
f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, 0); f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, 0);
...@@ -154,7 +154,7 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -154,7 +154,7 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
ngettext("%s: write-ahead log file \"%s\" has %d byte, should be 0 or %d\n", ngettext("%s: write-ahead log file \"%s\" has %d byte, should be 0 or %d\n",
"%s: write-ahead log file \"%s\" has %d bytes, should be 0 or %d\n", "%s: write-ahead log file \"%s\" has %d bytes, should be 0 or %d\n",
size), size),
progname, fn, (int) size, XLogSegSize); progname, fn, (int) size, WalSegSz);
return false; return false;
} }
/* File existed and was empty, so fall through and open */ /* File existed and was empty, so fall through and open */
...@@ -162,7 +162,8 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -162,7 +162,8 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
/* No file existed, so create one */ /* No file existed, so create one */
f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, XLogSegSize); f = stream->walmethod->open_for_write(current_walfile_name,
stream->partial_suffix, WalSegSz);
if (f == NULL) if (f == NULL)
{ {
fprintf(stderr, fprintf(stderr,
...@@ -203,7 +204,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) ...@@ -203,7 +204,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
if (stream->partial_suffix) if (stream->partial_suffix)
{ {
if (currpos == XLOG_SEG_SIZE) if (currpos == WalSegSz)
r = stream->walmethod->close(walfile, CLOSE_NORMAL); r = stream->walmethod->close(walfile, CLOSE_NORMAL);
else else
{ {
...@@ -231,7 +232,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) ...@@ -231,7 +232,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
* new node. This is in line with walreceiver.c always doing a * new node. This is in line with walreceiver.c always doing a
* XLogArchiveForceDone() after a complete segment. * XLogArchiveForceDone() after a complete segment.
*/ */
if (currpos == XLOG_SEG_SIZE && stream->mark_done) if (currpos == WalSegSz && stream->mark_done)
{ {
/* writes error message if failed */ /* writes error message if failed */
if (!mark_file_as_archived(stream, current_walfile_name)) if (!mark_file_as_archived(stream, current_walfile_name))
...@@ -676,7 +677,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream) ...@@ -676,7 +677,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
* start streaming at the beginning of a segment. * start streaming at the beginning of a segment.
*/ */
stream->timeline = newtimeline; stream->timeline = newtimeline;
stream->startpos = stream->startpos - (stream->startpos % XLOG_SEG_SIZE); stream->startpos = stream->startpos -
XLogSegmentOffset(stream->startpos, WalSegSz);
continue; continue;
} }
else if (PQresultStatus(res) == PGRES_COMMAND_OK) else if (PQresultStatus(res) == PGRES_COMMAND_OK)
...@@ -1111,7 +1113,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, ...@@ -1111,7 +1113,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
*blockpos = fe_recvint64(&copybuf[1]); *blockpos = fe_recvint64(&copybuf[1]);
/* Extract WAL location for this block */ /* Extract WAL location for this block */
xlogoff = *blockpos % XLOG_SEG_SIZE; xlogoff = XLogSegmentOffset(*blockpos, WalSegSz);
/* /*
* Verify that the initial location in the stream matches where we think * Verify that the initial location in the stream matches where we think
...@@ -1148,11 +1150,11 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, ...@@ -1148,11 +1150,11 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
int bytes_to_write; int bytes_to_write;
/* /*
* If crossing a WAL boundary, only write up until we reach * If crossing a WAL boundary, only write up until we reach wal
* XLOG_SEG_SIZE. * segment size.
*/ */
if (xlogoff + bytes_left > XLOG_SEG_SIZE) if (xlogoff + bytes_left > WalSegSz)
bytes_to_write = XLOG_SEG_SIZE - xlogoff; bytes_to_write = WalSegSz - xlogoff;
else else
bytes_to_write = bytes_left; bytes_to_write = bytes_left;
...@@ -1182,7 +1184,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, ...@@ -1182,7 +1184,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
xlogoff += bytes_to_write; xlogoff += bytes_to_write;
/* Did we reach the end of a WAL segment? */ /* Did we reach the end of a WAL segment? */
if (*blockpos % XLOG_SEG_SIZE == 0) if (XLogSegmentOffset(*blockpos, WalSegSz) == 0)
{ {
if (!close_walfile(stream, *blockpos)) if (!close_walfile(stream, *blockpos))
/* Error message written in close_walfile() */ /* Error message written in close_walfile() */
......
...@@ -25,12 +25,18 @@ ...@@ -25,12 +25,18 @@
#include "receivelog.h" #include "receivelog.h"
#include "streamutil.h" #include "streamutil.h"
#include "access/xlog_internal.h"
#include "pqexpbuffer.h" #include "pqexpbuffer.h"
#include "common/fe_memutils.h" #include "common/fe_memutils.h"
#include "datatype/timestamp.h" #include "datatype/timestamp.h"
#define ERRCODE_DUPLICATE_OBJECT "42710" #define ERRCODE_DUPLICATE_OBJECT "42710"
uint32 WalSegSz;
/* SHOW command for replication connection was introduced in version 10 */
#define MINIMUM_VERSION_FOR_SHOW_CMD 100000
const char *progname; const char *progname;
char *connection_string = NULL; char *connection_string = NULL;
char *dbhost = NULL; char *dbhost = NULL;
...@@ -231,6 +237,76 @@ GetConnection(void) ...@@ -231,6 +237,76 @@ GetConnection(void)
return tmpconn; return tmpconn;
} }
/*
* From version 10, explicitly set wal segment size using SHOW wal_segment_size
* since ControlFile is not accessible here.
*/
bool
RetrieveWalSegSize(PGconn *conn)
{
PGresult *res;
char xlog_unit[3];
int xlog_val,
multiplier = 1;
/* check connection existence */
Assert(conn != NULL);
/* for previous versions set the default xlog seg size */
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_SHOW_CMD)
{
WalSegSz = DEFAULT_XLOG_SEG_SIZE;
return true;
}
res = PQexec(conn, "SHOW wal_segment_size");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, _("%s: could not send replication command \"%s\": %s\n"),
progname, "SHOW wal_segment_size", PQerrorMessage(conn));
PQclear(res);
return false;
}
if (PQntuples(res) != 1 || PQnfields(res) < 1)
{
fprintf(stderr,
_("%s: could not fetch WAL segment size: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
progname, PQntuples(res), PQnfields(res), 1, 1);
PQclear(res);
return false;
}
/* fetch xlog value and unit from the result */
if (sscanf(PQgetvalue(res, 0, 0), "%d%s", &xlog_val, xlog_unit) != 2)
{
fprintf(stderr, _("%s: WAL segment size could not be parsed\n"),
progname);
return false;
}
/* set the multiplier based on unit to convert xlog_val to bytes */
if (strcmp(xlog_unit, "MB") == 0)
multiplier = 1024 * 1024;
else if (strcmp(xlog_unit, "GB") == 0)
multiplier = 1024 * 1024 * 1024;
/* convert and set WalSegSz */
WalSegSz = xlog_val * multiplier;
if (!IsValidWalSegSize(WalSegSz))
{
fprintf(stderr,
_("%s: WAL segment size must be a power of two between 1MB and 1GB, but the remote server reported a value of %d bytes\n"),
progname, WalSegSz);
return false;
}
PQclear(res);
return true;
}
/* /*
* Run IDENTIFY_SYSTEM through a given connection and give back to caller * Run IDENTIFY_SYSTEM through a given connection and give back to caller
* some result information if requested: * some result information if requested:
......
...@@ -24,6 +24,7 @@ extern char *dbuser; ...@@ -24,6 +24,7 @@ extern char *dbuser;
extern char *dbport; extern char *dbport;
extern char *dbname; extern char *dbname;
extern int dbgetpassword; extern int dbgetpassword;
extern uint32 WalSegSz;
/* Connection kept global so we can disconnect easily */ /* Connection kept global so we can disconnect easily */
extern PGconn *conn; extern PGconn *conn;
...@@ -39,6 +40,7 @@ extern bool RunIdentifySystem(PGconn *conn, char **sysid, ...@@ -39,6 +40,7 @@ extern bool RunIdentifySystem(PGconn *conn, char **sysid,
TimeLineID *starttli, TimeLineID *starttli,
XLogRecPtr *startpos, XLogRecPtr *startpos,
char **db_name); char **db_name);
extern bool RetrieveWalSegSize(PGconn *conn);
extern TimestampTz feGetCurrentTimestamp(void); extern TimestampTz feGetCurrentTimestamp(void);
extern void feTimestampDifference(TimestampTz start_time, TimestampTz stop_time, extern void feTimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs); long *secs, int *microsecs);
......
...@@ -99,6 +99,7 @@ main(int argc, char *argv[]) ...@@ -99,6 +99,7 @@ main(int argc, char *argv[])
char xlogfilename[MAXFNAMELEN]; char xlogfilename[MAXFNAMELEN];
int c; int c;
int i; int i;
int WalSegSz;
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata")); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
...@@ -164,6 +165,15 @@ main(int argc, char *argv[]) ...@@ -164,6 +165,15 @@ main(int argc, char *argv[])
"Either the file is corrupt, or it has a different layout than this program\n" "Either the file is corrupt, or it has a different layout than this program\n"
"is expecting. The results below are untrustworthy.\n\n")); "is expecting. The results below are untrustworthy.\n\n"));
/* set wal segment size */
WalSegSz = ControlFile->xlog_seg_size;
if (!IsValidWalSegSize(WalSegSz))
fprintf(stderr,
_("WARNING: WAL segment size specified, %d bytes, is not a power of two between 1MB and 1GB.\n"
"The file is corrupt and the results below are untrustworthy.\n"),
WalSegSz);
/* /*
* This slightly-chintzy coding will work as long as the control file * This slightly-chintzy coding will work as long as the control file
* timestamps are within the range of time_t; that should be the case in * timestamps are within the range of time_t; that should be the case in
...@@ -184,8 +194,9 @@ main(int argc, char *argv[]) ...@@ -184,8 +194,9 @@ main(int argc, char *argv[])
* Calculate name of the WAL file containing the latest checkpoint's REDO * Calculate name of the WAL file containing the latest checkpoint's REDO
* start point. * start point.
*/ */
XLByteToSeg(ControlFile->checkPointCopy.redo, segno); XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno); XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
segno, WalSegSz);
/* /*
* Format system_identifier and mock_authentication_nonce separately to * Format system_identifier and mock_authentication_nonce separately to
......
...@@ -70,6 +70,7 @@ static MultiXactId set_mxid = 0; ...@@ -70,6 +70,7 @@ static MultiXactId set_mxid = 0;
static MultiXactOffset set_mxoff = (MultiXactOffset) -1; static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
static uint32 minXlogTli = 0; static uint32 minXlogTli = 0;
static XLogSegNo minXlogSegNo = 0; static XLogSegNo minXlogSegNo = 0;
static int WalSegSz;
static void CheckDataVersion(void); static void CheckDataVersion(void);
static bool ReadControlFile(void); static bool ReadControlFile(void);
...@@ -94,6 +95,7 @@ main(int argc, char *argv[]) ...@@ -94,6 +95,7 @@ main(int argc, char *argv[])
char *endptr; char *endptr;
char *endptr2; char *endptr2;
char *DataDir = NULL; char *DataDir = NULL;
char *log_fname = NULL;
int fd; int fd;
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal")); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
...@@ -265,7 +267,12 @@ main(int argc, char *argv[]) ...@@ -265,7 +267,12 @@ main(int argc, char *argv[])
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1); exit(1);
} }
XLogFromFileName(optarg, &minXlogTli, &minXlogSegNo);
/*
* XLogFromFileName requires wal segment size which is not yet
* set. Hence wal details are set later on.
*/
log_fname = pg_strdup(optarg);
break; break;
default: default:
...@@ -350,6 +357,9 @@ main(int argc, char *argv[]) ...@@ -350,6 +357,9 @@ main(int argc, char *argv[])
if (!ReadControlFile()) if (!ReadControlFile())
GuessControlValues(); GuessControlValues();
if (log_fname != NULL)
XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
/* /*
* Also look at existing segment files to set up newXlogSegNo * Also look at existing segment files to set up newXlogSegNo
*/ */
...@@ -573,18 +583,27 @@ ReadControlFile(void) ...@@ -573,18 +583,27 @@ ReadControlFile(void)
offsetof(ControlFileData, crc)); offsetof(ControlFileData, crc));
FIN_CRC32C(crc); FIN_CRC32C(crc);
if (EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc)) if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
{ {
/* Valid data... */ /* We will use the data but treat it as guessed. */
memcpy(&ControlFile, buffer, sizeof(ControlFile)); fprintf(stderr,
return true; _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
progname);
guessed = 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)); memcpy(&ControlFile, buffer, sizeof(ControlFile));
guessed = true; WalSegSz = ControlFile.xlog_seg_size;
/* return false if WalSegSz is not valid */
if (!IsValidWalSegSize(WalSegSz))
{
fprintf(stderr,
_("%s: pg_control specifies invalid WAL segment size (%d bytes); proceed with caution \n"),
progname, WalSegSz);
guessed = true;
}
return true; return true;
} }
...@@ -660,7 +679,7 @@ GuessControlValues(void) ...@@ -660,7 +679,7 @@ GuessControlValues(void)
ControlFile.blcksz = BLCKSZ; ControlFile.blcksz = BLCKSZ;
ControlFile.relseg_size = RELSEG_SIZE; ControlFile.relseg_size = RELSEG_SIZE;
ControlFile.xlog_blcksz = XLOG_BLCKSZ; ControlFile.xlog_blcksz = XLOG_BLCKSZ;
ControlFile.xlog_seg_size = XLOG_SEG_SIZE; ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
ControlFile.nameDataLen = NAMEDATALEN; ControlFile.nameDataLen = NAMEDATALEN;
ControlFile.indexMaxKeys = INDEX_MAX_KEYS; ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE; ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
...@@ -773,7 +792,8 @@ PrintNewControlValues(void) ...@@ -773,7 +792,8 @@ PrintNewControlValues(void)
/* This will be always printed in order to keep format same. */ /* This will be always printed in order to keep format same. */
printf(_("\n\nValues to be changed:\n\n")); printf(_("\n\nValues to be changed:\n\n"));
XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo); XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
newXlogSegNo, WalSegSz);
printf(_("First log segment after reset: %s\n"), fname); printf(_("First log segment after reset: %s\n"), fname);
if (set_mxid != 0) if (set_mxid != 0)
...@@ -850,7 +870,7 @@ RewriteControlFile(void) ...@@ -850,7 +870,7 @@ RewriteControlFile(void)
* newXlogSegNo. * newXlogSegNo.
*/ */
XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
ControlFile.checkPointCopy.redo); ControlFile.checkPointCopy.redo, WalSegSz);
ControlFile.checkPointCopy.time = (pg_time_t) time(NULL); ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
ControlFile.state = DB_SHUTDOWNED; ControlFile.state = DB_SHUTDOWNED;
...@@ -877,7 +897,7 @@ RewriteControlFile(void) ...@@ -877,7 +897,7 @@ RewriteControlFile(void)
ControlFile.max_locks_per_xact = 64; ControlFile.max_locks_per_xact = 64;
/* Now we can force the recorded xlog seg size to the right thing. */ /* Now we can force the recorded xlog seg size to the right thing. */
ControlFile.xlog_seg_size = XLogSegSize; ControlFile.xlog_seg_size = WalSegSz;
/* Contents are protected with a CRC */ /* Contents are protected with a CRC */
INIT_CRC32C(ControlFile.crc); INIT_CRC32C(ControlFile.crc);
...@@ -1014,7 +1034,7 @@ FindEndOfXLOG(void) ...@@ -1014,7 +1034,7 @@ FindEndOfXLOG(void)
* are in virgin territory. * are in virgin territory.
*/ */
xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size; xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize; newXlogSegNo = (xlogbytepos + WalSegSz - 1) / WalSegSz;
newXlogSegNo++; newXlogSegNo++;
} }
...@@ -1151,7 +1171,7 @@ WriteEmptyXLOG(void) ...@@ -1151,7 +1171,7 @@ WriteEmptyXLOG(void)
page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD; page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
longpage = (XLogLongPageHeader) page; longpage = (XLogLongPageHeader) page;
longpage->xlp_sysid = ControlFile.system_identifier; longpage->xlp_sysid = ControlFile.system_identifier;
longpage->xlp_seg_size = XLogSegSize; longpage->xlp_seg_size = WalSegSz;
longpage->xlp_xlog_blcksz = XLOG_BLCKSZ; longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
/* Insert the initial checkpoint record */ /* Insert the initial checkpoint record */
...@@ -1176,7 +1196,8 @@ WriteEmptyXLOG(void) ...@@ -1176,7 +1196,8 @@ WriteEmptyXLOG(void)
record->xl_crc = crc; record->xl_crc = crc;
/* Write the first page */ /* Write the first page */
XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo); XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
newXlogSegNo, WalSegSz);
unlink(path); unlink(path);
...@@ -1202,7 +1223,7 @@ WriteEmptyXLOG(void) ...@@ -1202,7 +1223,7 @@ WriteEmptyXLOG(void)
/* Fill the rest of the file with zeroes */ /* Fill the rest of the file with zeroes */
memset(buffer, 0, XLOG_BLCKSZ); memset(buffer, 0, XLOG_BLCKSZ);
for (nbytes = XLOG_BLCKSZ; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ) for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
{ {
errno = 0; errno = 0;
if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ) if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
......
...@@ -69,7 +69,8 @@ extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex, ...@@ -69,7 +69,8 @@ extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex,
private.datadir = datadir; private.datadir = datadir;
private.tliIndex = tliIndex; private.tliIndex = tliIndex;
xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private); xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
&private);
if (xlogreader == NULL) if (xlogreader == NULL)
pg_fatal("out of memory\n"); pg_fatal("out of memory\n");
...@@ -122,7 +123,8 @@ readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex) ...@@ -122,7 +123,8 @@ readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex)
private.datadir = datadir; private.datadir = datadir;
private.tliIndex = tliIndex; private.tliIndex = tliIndex;
xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private); xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
&private);
if (xlogreader == NULL) if (xlogreader == NULL)
pg_fatal("out of memory\n"); pg_fatal("out of memory\n");
...@@ -170,11 +172,17 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex, ...@@ -170,11 +172,17 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex,
* header in that case to find the next record. * header in that case to find the next record.
*/ */
if (forkptr % XLOG_BLCKSZ == 0) if (forkptr % XLOG_BLCKSZ == 0)
forkptr += (forkptr % XLogSegSize == 0) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD; {
if (XLogSegmentOffset(forkptr, WalSegSz) == 0)
forkptr += SizeOfXLogLongPHD;
else
forkptr += SizeOfXLogShortPHD;
}
private.datadir = datadir; private.datadir = datadir;
private.tliIndex = tliIndex; private.tliIndex = tliIndex;
xlogreader = XLogReaderAllocate(&SimpleXLogPageRead, &private); xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
&private);
if (xlogreader == NULL) if (xlogreader == NULL)
pg_fatal("out of memory\n"); pg_fatal("out of memory\n");
...@@ -239,21 +247,22 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, ...@@ -239,21 +247,22 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
XLogRecPtr targetSegEnd; XLogRecPtr targetSegEnd;
XLogSegNo targetSegNo; XLogSegNo targetSegNo;
XLByteToSeg(targetPagePtr, targetSegNo); XLByteToSeg(targetPagePtr, targetSegNo, WalSegSz);
XLogSegNoOffsetToRecPtr(targetSegNo + 1, 0, targetSegEnd); XLogSegNoOffsetToRecPtr(targetSegNo + 1, 0, targetSegEnd, WalSegSz);
targetPageOff = targetPagePtr % XLogSegSize; targetPageOff = XLogSegmentOffset(targetPagePtr, WalSegSz);
/* /*
* See if we need to switch to a new segment because the requested record * See if we need to switch to a new segment because the requested record
* is not in the currently open one. * is not in the currently open one.
*/ */
if (xlogreadfd >= 0 && !XLByteInSeg(targetPagePtr, xlogreadsegno)) if (xlogreadfd >= 0 &&
!XLByteInSeg(targetPagePtr, xlogreadsegno, WalSegSz))
{ {
close(xlogreadfd); close(xlogreadfd);
xlogreadfd = -1; xlogreadfd = -1;
} }
XLByteToSeg(targetPagePtr, xlogreadsegno); XLByteToSeg(targetPagePtr, xlogreadsegno, WalSegSz);
if (xlogreadfd < 0) if (xlogreadfd < 0)
{ {
...@@ -272,7 +281,8 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, ...@@ -272,7 +281,8 @@ SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
targetHistory[private->tliIndex].begin >= targetSegEnd) targetHistory[private->tliIndex].begin >= targetSegEnd)
private->tliIndex--; private->tliIndex--;
XLogFileName(xlogfname, targetHistory[private->tliIndex].tli, xlogreadsegno); XLogFileName(xlogfname, targetHistory[private->tliIndex].tli,
xlogreadsegno, WalSegSz);
snprintf(xlogfpath, MAXPGPATH, "%s/" XLOGDIR "/%s", private->datadir, xlogfname); snprintf(xlogfpath, MAXPGPATH, "%s/" XLOGDIR "/%s", private->datadir, xlogfname);
......
...@@ -44,6 +44,7 @@ static ControlFileData ControlFile_target; ...@@ -44,6 +44,7 @@ static ControlFileData ControlFile_target;
static ControlFileData ControlFile_source; static ControlFileData ControlFile_source;
const char *progname; const char *progname;
int WalSegSz;
/* Configuration options */ /* Configuration options */
char *datadir_target = NULL; char *datadir_target = NULL;
...@@ -572,8 +573,8 @@ createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpo ...@@ -572,8 +573,8 @@ createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpo
char buf[1000]; char buf[1000];
int len; int len;
XLByteToSeg(startpoint, startsegno); XLByteToSeg(startpoint, startsegno, WalSegSz);
XLogFileName(xlogfilename, starttli, startsegno); XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
/* /*
* Construct backup label file * Construct backup label file
...@@ -631,6 +632,13 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size) ...@@ -631,6 +632,13 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
memcpy(ControlFile, src, sizeof(ControlFileData)); memcpy(ControlFile, src, sizeof(ControlFileData));
/* set and validate WalSegSz */
WalSegSz = ControlFile->xlog_seg_size;
if (!IsValidWalSegSize(WalSegSz))
pg_fatal("WAL segment size must be a power of two between 1MB and 1GB, but the control file specifies %d bytes\n",
WalSegSz);
/* Additional checks on control file */ /* Additional checks on control file */
checkControlFile(ControlFile); checkControlFile(ControlFile);
} }
......
...@@ -24,6 +24,7 @@ extern char *connstr_source; ...@@ -24,6 +24,7 @@ extern char *connstr_source;
extern bool debug; extern bool debug;
extern bool showprogress; extern bool showprogress;
extern bool dry_run; extern bool dry_run;
extern int WalSegSz;
/* Target history */ /* Target history */
extern TimeLineHistoryEntry *targetHistory; extern TimeLineHistoryEntry *targetHistory;
......
...@@ -64,7 +64,7 @@ static const char *progname; ...@@ -64,7 +64,7 @@ static const char *progname;
static int secs_per_test = 5; static int secs_per_test = 5;
static int needs_unlink = 0; static int needs_unlink = 0;
static char full_buf[XLOG_SEG_SIZE], static char full_buf[DEFAULT_XLOG_SEG_SIZE],
*buf, *buf,
*filename = FSYNC_FILENAME; *filename = FSYNC_FILENAME;
static struct timeval start_t, static struct timeval start_t,
...@@ -209,7 +209,7 @@ prepare_buf(void) ...@@ -209,7 +209,7 @@ prepare_buf(void)
int ops; int ops;
/* write random data into buffer */ /* write random data into buffer */
for (ops = 0; ops < XLOG_SEG_SIZE; ops++) for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
full_buf[ops] = random(); full_buf[ops] = random();
buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf); buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
...@@ -226,7 +226,8 @@ test_open(void) ...@@ -226,7 +226,8 @@ test_open(void)
if ((tmpfile = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) if ((tmpfile = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
die("could not open output file"); die("could not open output file");
needs_unlink = 1; needs_unlink = 1;
if (write(tmpfile, full_buf, XLOG_SEG_SIZE) != XLOG_SEG_SIZE) if (write(tmpfile, full_buf, DEFAULT_XLOG_SEG_SIZE) !=
DEFAULT_XLOG_SEG_SIZE)
die("write failed"); die("write failed");
/* fsync now so that dirty buffers don't skew later tests */ /* fsync now so that dirty buffers don't skew later tests */
......
...@@ -20,7 +20,9 @@ unset MAKELEVEL ...@@ -20,7 +20,9 @@ unset MAKELEVEL
# Run a given "initdb" binary and overlay the regression testing # Run a given "initdb" binary and overlay the regression testing
# authentication configuration. # authentication configuration.
standard_initdb() { standard_initdb() {
"$1" -N # To increase coverage of non-standard segment size without
# increase test runtime, run these tests with a lower setting.
"$1" -N --wal-segsize 1
if [ -n "$TEMP_CONFIG" -a -r "$TEMP_CONFIG" ] if [ -n "$TEMP_CONFIG" -a -r "$TEMP_CONFIG" ]
then then
cat "$TEMP_CONFIG" >> "$PGDATA/postgresql.conf" cat "$TEMP_CONFIG" >> "$PGDATA/postgresql.conf"
......
This diff is collapsed.
...@@ -94,6 +94,7 @@ extern PGDLLIMPORT XLogRecPtr XactLastCommitEnd; ...@@ -94,6 +94,7 @@ extern PGDLLIMPORT XLogRecPtr XactLastCommitEnd;
extern bool reachedConsistency; extern bool reachedConsistency;
/* these variables are GUC parameters related to XLOG */ /* these variables are GUC parameters related to XLOG */
extern int wal_segment_size;
extern int min_wal_size_mb; extern int min_wal_size_mb;
extern int max_wal_size_mb; extern int max_wal_size_mb;
extern int wal_keep_segments; extern int wal_keep_segments;
......
...@@ -85,15 +85,27 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -85,15 +85,27 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define XLogPageHeaderSize(hdr) \ #define XLogPageHeaderSize(hdr) \
(((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD) (((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD)
/* /* wal_segment_size can range from 1MB to 1GB */
* The XLOG is split into WAL segments (physical files) of the size indicated #define WalSegMinSize 1024 * 1024
* by XLOG_SEG_SIZE. #define WalSegMaxSize 1024 * 1024 * 1024
*/ /* default number of min and max wal segments */
#define XLogSegSize ((uint32) XLOG_SEG_SIZE) #define DEFAULT_MIN_WAL_SEGS 5
#define XLogSegmentsPerXLogId (UINT64CONST(0x100000000) / XLOG_SEG_SIZE) #define DEFAULT_MAX_WAL_SEGS 64
/* check that the given size is a valid wal_segment_size */
#define IsPowerOf2(x) (x > 0 && ((x) & ((x)-1)) == 0)
#define IsValidWalSegSize(size) \
(IsPowerOf2(size) && \
((size) >= WalSegMinSize && (size) <= WalSegMaxSize))
#define XLogSegmentsPerXLogId(wal_segsz_bytes) \
(UINT64CONST(0x100000000) / (wal_segsz_bytes))
#define XLogSegNoOffsetToRecPtr(segno, offset, dest, wal_segsz_bytes) \
(dest) = (segno) * (wal_segsz_bytes) + (offset)
#define XLogSegNoOffsetToRecPtr(segno, offset, dest) \ #define XLogSegmentOffset(xlogptr, wal_segsz_bytes) \
(dest) = (segno) * XLOG_SEG_SIZE + (offset) ((xlogptr) & ((wal_segsz_bytes) - 1))
/* /*
* Compute a segment number from an XLogRecPtr. * Compute a segment number from an XLogRecPtr.
...@@ -103,11 +115,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -103,11 +115,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
* for deciding which segment to write given a pointer to a record end, * for deciding which segment to write given a pointer to a record end,
* for example. * for example.
*/ */
#define XLByteToSeg(xlrp, logSegNo) \ #define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes) \
logSegNo = (xlrp) / XLogSegSize logSegNo = (xlrp) / (wal_segsz_bytes)
#define XLByteToPrevSeg(xlrp, logSegNo) \ #define XLByteToPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \
logSegNo = ((xlrp) - 1) / XLogSegSize logSegNo = ((xlrp) - 1) / (wal_segsz_bytes)
/* /*
* Is an XLogRecPtr within a particular XLOG segment? * Is an XLogRecPtr within a particular XLOG segment?
...@@ -115,11 +127,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -115,11 +127,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
* For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg, * For XLByteInSeg, do the computation at face value. For XLByteInPrevSeg,
* a boundary byte is taken to be in the previous segment. * a boundary byte is taken to be in the previous segment.
*/ */
#define XLByteInSeg(xlrp, logSegNo) \ #define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes) \
(((xlrp) / XLogSegSize) == (logSegNo)) (((xlrp) / (wal_segsz_bytes)) == (logSegNo))
#define XLByteInPrevSeg(xlrp, logSegNo) \ #define XLByteInPrevSeg(xlrp, logSegNo, wal_segsz_bytes) \
((((xlrp) - 1) / XLogSegSize) == (logSegNo)) ((((xlrp) - 1) / (wal_segsz_bytes)) == (logSegNo))
/* Check if an XLogRecPtr value is in a plausible range */ /* Check if an XLogRecPtr value is in a plausible range */
#define XRecOffIsValid(xlrp) \ #define XRecOffIsValid(xlrp) \
...@@ -140,10 +152,10 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -140,10 +152,10 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
/* Length of XLog file name */ /* Length of XLog file name */
#define XLOG_FNAME_LEN 24 #define XLOG_FNAME_LEN 24
#define XLogFileName(fname, tli, logSegNo) \ #define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes) \
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \ (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId)) (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
#define XLogFileNameById(fname, tli, log, seg) \ #define XLogFileNameById(fname, tli, log, seg) \
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg) snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg)
...@@ -162,18 +174,18 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -162,18 +174,18 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0) strcmp((fname) + XLOG_FNAME_LEN, ".partial") == 0)
#define XLogFromFileName(fname, tli, logSegNo) \ #define XLogFromFileName(fname, tli, logSegNo, wal_segsz_bytes) \
do { \ do { \
uint32 log; \ uint32 log; \
uint32 seg; \ uint32 seg; \
sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \ sscanf(fname, "%08X%08X%08X", tli, &log, &seg); \
*logSegNo = (uint64) log * XLogSegmentsPerXLogId + seg; \ *logSegNo = (uint64) log * XLogSegmentsPerXLogId(wal_segsz_bytes) + seg; \
} while (0) } while (0)
#define XLogFilePath(path, tli, logSegNo) \ #define XLogFilePath(path, tli, logSegNo, wal_segsz_bytes) \
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \ (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId)) (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)))
#define TLHistoryFileName(fname, tli) \ #define TLHistoryFileName(fname, tli) \
snprintf(fname, MAXFNAMELEN, "%08X.history", tli) snprintf(fname, MAXFNAMELEN, "%08X.history", tli)
...@@ -189,20 +201,22 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; ...@@ -189,20 +201,22 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
#define StatusFilePath(path, xlog, suffix) \ #define StatusFilePath(path, xlog, suffix) \
snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix)
#define BackupHistoryFileName(fname, tli, logSegNo, offset) \ #define BackupHistoryFileName(fname, tli, logSegNo, startpoint, wal_segsz_bytes) \
snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \ (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset) (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) (XLogSegmentOffset(startpoint, wal_segsz_bytes)))
#define IsBackupHistoryFileName(fname) \ #define IsBackupHistoryFileName(fname) \
(strlen(fname) > XLOG_FNAME_LEN && \ (strlen(fname) > XLOG_FNAME_LEN && \
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \ strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0) strcmp((fname) + strlen(fname) - strlen(".backup"), ".backup") == 0)
#define BackupHistoryFilePath(path, tli, logSegNo, offset) \ #define BackupHistoryFilePath(path, tli, logSegNo, startpoint, wal_segsz_bytes) \
snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \ snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, \
(uint32) ((logSegNo) / XLogSegmentsPerXLogId), \ (uint32) ((logSegNo) / XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset) (uint32) ((logSegNo) % XLogSegmentsPerXLogId(wal_segsz_bytes)), \
(uint32) (XLogSegmentOffset((startpoint), wal_segsz_bytes)))
/* /*
* Information logged when we detect a change in one of the parameters * Information logged when we detect a change in one of the parameters
......
...@@ -73,6 +73,11 @@ struct XLogReaderState ...@@ -73,6 +73,11 @@ struct XLogReaderState
* ---------------------------------------- * ----------------------------------------
*/ */
/*
* Segment size of the to-be-parsed data (mandatory).
*/
int wal_segment_size;
/* /*
* Data input callback (mandatory). * Data input callback (mandatory).
* *
...@@ -189,7 +194,8 @@ struct XLogReaderState ...@@ -189,7 +194,8 @@ struct XLogReaderState
}; };
/* Get a new XLogReader */ /* Get a new XLogReader */
extern XLogReaderState *XLogReaderAllocate(XLogPageReadCB pagereadfunc, extern XLogReaderState *XLogReaderAllocate(int wal_segment_size,
XLogPageReadCB pagereadfunc,
void *private_data); void *private_data);
/* Free an XLogReader */ /* Free an XLogReader */
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
/* Version identifier for this pg_control format */ /* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1002 #define PG_CONTROL_VERSION 1003
/* Nonce key length, see below */ /* Nonce key length, see below */
#define MOCK_AUTH_NONCE_LEN 32 #define MOCK_AUTH_NONCE_LEN 32
......
...@@ -895,11 +895,6 @@ ...@@ -895,11 +895,6 @@
*/ */
#undef XLOG_BLCKSZ #undef XLOG_BLCKSZ
/* 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. */
#undef XLOG_SEG_SIZE
/* Number of bits in a file offset, on hosts where this is settable. */ /* Number of bits in a file offset, on hosts where this is settable. */
......
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
*------------------------------------------------------------------------ *------------------------------------------------------------------------
*/ */
/*
* This is default value for wal_segment_size to be used at intidb when run
* without --walsegsize option. Must be a valid segment size.
*/
#define DEFAULT_XLOG_SEG_SIZE (16*1024*1024)
/* /*
* Maximum length for identifiers (e.g. table names, column names, * Maximum length for identifiers (e.g. table names, column names,
* function names). Names actually are limited to one less byte than this, * function names). Names actually are limited to one less byte than this,
......
...@@ -179,8 +179,6 @@ s{PG_VERSION_STR "[^"]+"}{PG_VERSION_STR "PostgreSQL $self->{strver}$extraver, c ...@@ -179,8 +179,6 @@ s{PG_VERSION_STR "[^"]+"}{PG_VERSION_STR "PostgreSQL $self->{strver}$extraver, c
1024, "\n"; 1024, "\n";
print $o "#define XLOG_BLCKSZ ", print $o "#define XLOG_BLCKSZ ",
1024 * $self->{options}->{wal_blocksize}, "\n"; 1024 * $self->{options}->{wal_blocksize}, "\n";
print $o "#define XLOG_SEG_SIZE (", $self->{options}->{wal_segsize},
" * 1024 * 1024)\n";
if ($self->{options}->{float4byval}) if ($self->{options}->{float4byval})
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment