Make WAL segment size configurable at initdb time.
authorAndres Freund <andres@anarazel.de>
Wed, 20 Sep 2017 05:03:48 +0000 (22:03 -0700)
committerAndres Freund <andres@anarazel.de>
Wed, 20 Sep 2017 05:03:48 +0000 (22:03 -0700)
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

46 files changed:
configure
configure.in
contrib/pg_standby/pg_standby.c
doc/src/sgml/backup.sgml
doc/src/sgml/installation.sgml
doc/src/sgml/ref/initdb.sgml
doc/src/sgml/wal.sgml
src/backend/access/transam/twophase.c
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogarchive.c
src/backend/access/transam/xlogfuncs.c
src/backend/access/transam/xlogreader.c
src/backend/access/transam/xlogutils.c
src/backend/bootstrap/bootstrap.c
src/backend/postmaster/checkpointer.c
src/backend/replication/basebackup.c
src/backend/replication/logical/logical.c
src/backend/replication/logical/reorderbuffer.c
src/backend/replication/slot.c
src/backend/replication/walreceiver.c
src/backend/replication/walreceiverfuncs.c
src/backend/replication/walsender.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/pg_controldata.c
src/backend/utils/misc/postgresql.conf.sample
src/bin/initdb/initdb.c
src/bin/pg_basebackup/pg_basebackup.c
src/bin/pg_basebackup/pg_receivewal.c
src/bin/pg_basebackup/receivelog.c
src/bin/pg_basebackup/streamutil.c
src/bin/pg_basebackup/streamutil.h
src/bin/pg_controldata/pg_controldata.c
src/bin/pg_resetwal/pg_resetwal.c
src/bin/pg_rewind/parsexlog.c
src/bin/pg_rewind/pg_rewind.c
src/bin/pg_rewind/pg_rewind.h
src/bin/pg_test_fsync/pg_test_fsync.c
src/bin/pg_upgrade/test.sh
src/bin/pg_waldump/pg_waldump.c
src/include/access/xlog.h
src/include/access/xlog_internal.h
src/include/access/xlogreader.h
src/include/catalog/pg_control.h
src/include/pg_config.h.in
src/include/pg_config_manual.h
src/tools/msvc/Solution.pm

index 0d76e5ea42fbadd75d5f2076c51b21c4f20d90d6..5c38149a3df74a73dd2016d33ce2b9bcee23dde2 100755 (executable)
--- a/configure
+++ b/configure
@@ -821,7 +821,6 @@ enable_tap_tests
 with_blocksize
 with_segsize
 with_wal_blocksize
-with_wal_segsize
 with_CC
 enable_depend
 enable_cassert
@@ -1518,8 +1517,6 @@ Optional Packages:
   --with-segsize=SEGSIZE  set table segment size in GB [1]
   --with-wal-blocksize=BLOCKSIZE
                           set WAL block size in kB [8]
-  --with-wal-segsize=SEGSIZE
-                          set WAL segment size in MB [16]
   --with-CC=CMD           set compiler (deprecated)
   --with-icu              build with ICU support
   --with-tcl              build Tcl modules (PL/Tcl)
@@ -3733,57 +3730,6 @@ cat >>confdefs.h <<_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
 #
index bdc41b071f1de2d46f874fa5491a22aebca84767..176b29a79205470b607d0b4022e6adc978c03b8d 100644 (file)
@@ -343,37 +343,6 @@ AC_DEFINE_UNQUOTED([XLOG_BLCKSZ], ${XLOG_BLCKSZ}, [
  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
 #
index d7fa2a80c69188086d6a07e7344dbdfc533c4f18..6aeca6e8f72acd35e763cc8a9001cc1848e01dcf 100644 (file)
@@ -36,6 +36,8 @@
 
 const char *progname;
 
+int                    WalSegSz = -1;
+
 /* Options and defaults */
 int                    sleeptime = 5;          /* amount of time to sleep between file checks */
 int                    waittime = -1;          /* how long we have been waiting, -1 no wait
@@ -100,6 +102,10 @@ int                        nextWALFileType;
 
 struct stat stat_buf;
 
+static bool SetWALFileNameForCleanup(void);
+static bool SetWALSegSize(void);
+
+
 /* =====================================================================
  *
  *               Customizable section
@@ -175,6 +181,35 @@ CustomizableNextWALFileReady(void)
 {
        if (stat(WALFilePath, &stat_buf) == 0)
        {
+               /*
+                * If we've not seen any WAL segments, we don't know the WAL segment
+                * size, which we need. If it looks like a WAL segment, determine size
+                * of segments for the cluster.
+                */
+               if (WalSegSz == -1 && IsXLogFileName(nextWALFileName))
+               {
+                       if (SetWALSegSize())
+                       {
+                               /*
+                                * Successfully determined WAL segment size. Can compute
+                                * cleanup cutoff now.
+                                */
+                               need_cleanup = SetWALFileNameForCleanup();
+                               if (debug)
+                               {
+                                       fprintf(stderr,
+                                                       _("WAL segment size:     %d \n"), WalSegSz);
+                                       fprintf(stderr, "Keep archive history: ");
+
+                                       if (need_cleanup)
+                                               fprintf(stderr, "%s and later\n",
+                                                               exclusiveCleanupFileName);
+                                       else
+                                               fprintf(stderr, "no cleanup required\n");
+                               }
+                       }
+               }
+
                /*
                 * If it's a backup file, return immediately. If it's a regular file
                 * return only if it's the right size already.
@@ -184,7 +219,7 @@ CustomizableNextWALFileReady(void)
                        nextWALFileType = XLOG_BACKUP_LABEL;
                        return true;
                }
-               else if (stat_buf.st_size == XLOG_SEG_SIZE)
+               else if (WalSegSz > 0 && stat_buf.st_size == WalSegSz)
                {
 #ifdef WIN32
 
@@ -204,7 +239,7 @@ CustomizableNextWALFileReady(void)
                /*
                 * 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)
                        {
@@ -218,8 +253,6 @@ CustomizableNextWALFileReady(void)
        return false;
 }
 
-#define MaxSegmentsPerLogFile ( 0xFFFFFFFF / XLOG_SEG_SIZE )
-
 static void
 CustomizableCleanupPriorWALFiles(void)
 {
@@ -315,6 +348,7 @@ SetWALFileNameForCleanup(void)
        uint32          log_diff = 0,
                                seg_diff = 0;
        bool            cleanup = false;
+       int                     max_segments_per_logfile = (0xFFFFFFFF / WalSegSz);
 
        if (restartWALFileName)
        {
@@ -336,12 +370,12 @@ SetWALFileNameForCleanup(void)
                sscanf(nextWALFileName, "%08X%08X%08X", &tli, &log, &seg);
                if (tli > 0 && seg > 0)
                {
-                       log_diff = keepfiles / MaxSegmentsPerLogFile;
-                       seg_diff = keepfiles % MaxSegmentsPerLogFile;
+                       log_diff = keepfiles / max_segments_per_logfile;
+                       seg_diff = keepfiles % max_segments_per_logfile;
                        if (seg_diff > seg)
                        {
                                log_diff++;
-                               seg = MaxSegmentsPerLogFile - (seg_diff - seg);
+                               seg = max_segments_per_logfile - (seg_diff - seg);
                        }
                        else
                                seg -= seg_diff;
@@ -364,6 +398,66 @@ SetWALFileNameForCleanup(void)
        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()
  *
@@ -708,8 +802,6 @@ main(int argc, char **argv)
 
        CustomizableInitialize();
 
-       need_cleanup = SetWALFileNameForCleanup();
-
        if (debug)
        {
                fprintf(stderr, "Trigger file:         %s\n", triggerPath ? triggerPath : "<not set>");
@@ -721,11 +813,6 @@ main(int argc, char **argv)
                fprintf(stderr, "Max wait interval:    %d %s\n",
                                maxwaittime, (maxwaittime > 0 ? "seconds" : "forever"));
                fprintf(stderr, "Command for restore:  %s\n", restoreCommand);
-               fprintf(stderr, "Keep archive history: ");
-               if (need_cleanup)
-                       fprintf(stderr, "%s and later\n", exclusiveCleanupFileName);
-               else
-                       fprintf(stderr, "no cleanup required\n");
                fflush(stderr);
        }
 
index 95aeb35507e08d8d7e733446fe3d996110cf206c..bd55e8bb775bec001893e9bcf346c75ea8cdc221 100644 (file)
@@ -562,7 +562,7 @@ tar -cf backup.tar /usr/local/pgsql/data
     produces an indefinitely long sequence of WAL records.  The system
     physically divides this sequence into WAL <firstterm>segment
     files</>, which are normally 16MB apiece (although the segment size
-    can be altered when building <productname>PostgreSQL</>).  The segment
+    can be altered during <application>initdb</>).  The segment
     files are given numeric names that reflect their position in the
     abstract WAL sequence.  When not using WAL archiving, the system
     normally creates just a few segment files and then
index b178d3074bb8aff3dbf97d6135fa6a6fe81040ff..a1bae951457e2c66bf40ed1eb731f8594c1258ff 100644 (file)
@@ -1058,20 +1058,6 @@ su - postgres
        </listitem>
       </varlistentry>
 
-      <varlistentry>
-       <term><option>--with-wal-segsize=<replaceable>SEGSIZE</replaceable></option></term>
-       <listitem>
-        <para>
-         Set the <firstterm>WAL segment size</>, in megabytes.  This is
-         the size of each individual file in the WAL log.  It may be useful
-         to adjust this size to control the granularity of WAL log shipping.
-         The default size is 16 megabytes.
-         The value must be a power of 2 between 1 and 1024 (megabytes).
-         Note that changing this value requires an initdb.
-        </para>
-       </listitem>
-      </varlistentry>
-
       <varlistentry>
        <term><option>--with-wal-blocksize=<replaceable>BLOCKSIZE</replaceable></option></term>
        <listitem>
index 6efb2e442d59c954c8a80149617c896c2933d2fb..732fecab8ecec159395f5900d176a5b7add03948 100644 (file)
@@ -316,6 +316,21 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
+       <term><option>--wal-segsize=<replaceable>SEGSIZE</replaceable></option></term>
+       <listitem>
+        <para>
+         Set the <firstterm>WAL segment size</>, in megabytes.  This is
+         the size of each individual file in the WAL log.  It may be useful
+         to adjust this size to control the granularity of WAL log shipping.
+         This option can only be set during initialization, and cannot be
+         changed later.
+         The default size is 16 megabytes.
+         The value must be a power of 2 between 1 and 1024 (megabytes).
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
       <term><option>-X <replaceable class="parameter">directory</replaceable></option></term>
       <term><option>--waldir=<replaceable class="parameter">directory</replaceable></option></term>
       <listitem>
index 940c37b21a30e86a70b15023d25639c947a113f3..ddcef5fbf53d21d5bc726d9f1041f9e66302f63a 100644 (file)
    <acronym>WAL</acronym> logs are stored in the directory
    <filename>pg_wal</filename> under the data directory, as a set of
    segment files, normally each 16 MB in size (but the size can be changed
-   by altering the <option>--with-wal-segsize</> configure option when
-   building the server).  Each segment is divided into pages, normally
-   8 kB each (this size can be changed via the <option>--with-wal-blocksize</>
-   configure option).  The log record headers are described in
-   <filename>access/xlogrecord.h</filename>; the record content is dependent
-   on the type of event that is being logged.  Segment files are given
-   ever-increasing numbers as names, starting at
+   by altering the <option>--wal-segsize</> initdb option).  Each segment is
+   divided into pages, normally 8 kB each (this size can be changed via the
+   <option>--with-wal-blocksize</> configure option).  The log record headers
+   are described in <filename>access/xlogrecord.h</filename>; the record
+   content is dependent on the type of event that is being logged.  Segment
+   files are given ever-increasing numbers as names, starting at
    <filename>000000010000000000000000</filename>.  The numbers do not wrap,
    but it will take a very, very long time to exhaust the
    available stock of numbers.
index ae832917ce2337cf9d6a9b160c2c4b2777967bfd..bfd800bc16b805f8417d272f6ca615a843a2ec64 100644 (file)
@@ -1299,7 +1299,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
        XLogReaderState *xlogreader;
        char       *errormsg;
 
-       xlogreader = XLogReaderAllocate(&read_local_xlog_page, NULL);
+       xlogreader = XLogReaderAllocate(wal_segment_size, &read_local_xlog_page,
+                                                                       NULL);
        if (!xlogreader)
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
index 96ebf32a58a5b0ae1ec169bd817b9075eabd80a1..051347163b53d48ae58d8b5d81fd4505be228940 100644 (file)
@@ -110,6 +110,8 @@ int                 wal_retrieve_retry_interval = 5000;
 bool           XLOG_DEBUG = false;
 #endif
 
+int                    wal_segment_size = DEFAULT_XLOG_SEG_SIZE;
+
 /*
  * Number of WAL insertion locks to use. A higher value allows more insertions
  * to happen concurrently, but adds some CPU overhead to flushing the WAL,
@@ -731,14 +733,16 @@ static ControlFileData *ControlFile = NULL;
        (((recptr) / XLOG_BLCKSZ) % (XLogCtl->XLogCacheBlck + 1))
 
 /*
- * These are the number of bytes in a WAL page and segment usable for WAL data.
+ * These are the number of bytes in a WAL page usable for WAL data.
  */
 #define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)
-#define UsableBytesInSegment ((XLOG_SEG_SIZE / XLOG_BLCKSZ) * UsableBytesInPage - (SizeOfXLogLongPHD - SizeOfXLogShortPHD))
 
 /* Convert min_wal_size_mb and max wal_size_mb to equivalent segment count */
-#define ConvertToXSegs(x)      \
-       (x / (XLOG_SEG_SIZE / (1024 * 1024)))
+#define ConvertToXSegs(x, segsize)     \
+       (x / ((segsize) / (1024 * 1024)))
+
+/* The number of bytes in a WAL segment usable for WAL data. */
+static int     UsableBytesInSegment;
 
 /*
  * Private, possibly out-of-date copy of shared LogwrtResult.
@@ -1137,7 +1141,9 @@ XLogInsertRecord(XLogRecData *rdata,
                        EndPos = StartPos + SizeOfXLogRecord;
                        if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
                        {
-                               if (EndPos % XLOG_SEG_SIZE == EndPos % XLOG_BLCKSZ)
+                               uint64          offset = XLogSegmentOffset(EndPos, wal_segment_size);
+
+                               if (offset == EndPos % XLOG_BLCKSZ)
                                        EndPos += SizeOfXLogLongPHD;
                                else
                                        EndPos += SizeOfXLogShortPHD;
@@ -1170,7 +1176,7 @@ XLogInsertRecord(XLogRecData *rdata,
                        appendBinaryStringInfo(&recordBuf, rdata->data, rdata->len);
 
                if (!debug_reader)
-                       debug_reader = XLogReaderAllocate(NULL, NULL);
+                       debug_reader = XLogReaderAllocate(wal_segment_size, NULL, NULL);
 
                if (!debug_reader)
                {
@@ -1296,7 +1302,7 @@ ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos, XLogRecPtr *PrevPtr)
        startbytepos = Insert->CurrBytePos;
 
        ptr = XLogBytePosToEndRecPtr(startbytepos);
-       if (ptr % XLOG_SEG_SIZE == 0)
+       if (XLogSegmentOffset(ptr, wal_segment_size) == 0)
        {
                SpinLockRelease(&Insert->insertpos_lck);
                *EndPos = *StartPos = ptr;
@@ -1309,8 +1315,8 @@ ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos, XLogRecPtr *PrevPtr)
        *StartPos = XLogBytePosToRecPtr(startbytepos);
        *EndPos = XLogBytePosToEndRecPtr(endbytepos);
 
-       segleft = XLOG_SEG_SIZE - ((*EndPos) % XLOG_SEG_SIZE);
-       if (segleft != XLOG_SEG_SIZE)
+       segleft = wal_segment_size - XLogSegmentOffset(*EndPos, wal_segment_size);
+       if (segleft != wal_segment_size)
        {
                /* consume the rest of the segment */
                *EndPos += segleft;
@@ -1323,7 +1329,7 @@ ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos, XLogRecPtr *PrevPtr)
 
        *PrevPtr = XLogBytePosToRecPtr(prevbytepos);
 
-       Assert((*EndPos) % XLOG_SEG_SIZE == 0);
+       Assert(XLogSegmentOffset(*EndPos, wal_segment_size) == 0);
        Assert(XLogRecPtrToBytePos(*EndPos) == endbytepos);
        Assert(XLogRecPtrToBytePos(*StartPos) == startbytepos);
        Assert(XLogRecPtrToBytePos(*PrevPtr) == prevbytepos);
@@ -1501,7 +1507,7 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
                        pagehdr->xlp_info |= XLP_FIRST_IS_CONTRECORD;
 
                        /* skip over the page header */
-                       if (CurrPos % XLogSegSize == 0)
+                       if (XLogSegmentOffset(CurrPos, wal_segment_size) == 0)
                        {
                                CurrPos += SizeOfXLogLongPHD;
                                currpos += SizeOfXLogLongPHD;
@@ -1532,16 +1538,16 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
         * allocated and zeroed in the WAL buffers so that when the caller (or
         * someone else) does XLogWrite(), it can really write out all the zeros.
         */
-       if (isLogSwitch && CurrPos % XLOG_SEG_SIZE != 0)
+       if (isLogSwitch && XLogSegmentOffset(CurrPos, wal_segment_size) != 0)
        {
                /* An xlog-switch record doesn't contain any data besides the header */
                Assert(write_len == SizeOfXLogRecord);
 
                /*
                 * We do this one page at a time, to make sure we don't deadlock
-                * against ourselves if wal_buffers < XLOG_SEG_SIZE.
+                * against ourselves if wal_buffers < wal_segment_size.
                 */
-               Assert(EndPos % XLogSegSize == 0);
+               Assert(XLogSegmentOffset(EndPos, wal_segment_size) == 0);
 
                /* Use up all the remaining space on the first page */
                CurrPos += freespace;
@@ -1866,10 +1872,10 @@ GetXLogBuffer(XLogRecPtr ptr)
                 * the page header.
                 */
                if (ptr % XLOG_BLCKSZ == SizeOfXLogShortPHD &&
-                       ptr % XLOG_SEG_SIZE > XLOG_BLCKSZ)
+                       XLogSegmentOffset(ptr, wal_segment_size) > XLOG_BLCKSZ)
                        initializedUpto = ptr - SizeOfXLogShortPHD;
                else if (ptr % XLOG_BLCKSZ == SizeOfXLogLongPHD &&
-                                ptr % XLOG_SEG_SIZE < XLOG_BLCKSZ)
+                                XLogSegmentOffset(ptr, wal_segment_size) < XLOG_BLCKSZ)
                        initializedUpto = ptr - SizeOfXLogLongPHD;
                else
                        initializedUpto = ptr;
@@ -1939,7 +1945,7 @@ XLogBytePosToRecPtr(uint64 bytepos)
                seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
        }
 
-       XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result);
+       XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result, wal_segment_size);
 
        return result;
 }
@@ -1985,7 +1991,7 @@ XLogBytePosToEndRecPtr(uint64 bytepos)
                        seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
        }
 
-       XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result);
+       XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result, wal_segment_size);
 
        return result;
 }
@@ -2001,9 +2007,9 @@ XLogRecPtrToBytePos(XLogRecPtr ptr)
        uint32          offset;
        uint64          result;
 
-       XLByteToSeg(ptr, fullsegs);
+       XLByteToSeg(ptr, fullsegs, wal_segment_size);
 
-       fullpages = (ptr % XLOG_SEG_SIZE) / XLOG_BLCKSZ;
+       fullpages = (XLogSegmentOffset(ptr, wal_segment_size)) / XLOG_BLCKSZ;
        offset = ptr % XLOG_BLCKSZ;
 
        if (fullpages == 0)
@@ -2168,12 +2174,12 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
                /*
                 * If first page of an XLOG segment file, make it a long header.
                 */
-               if ((NewPage->xlp_pageaddr % XLogSegSize) == 0)
+               if ((XLogSegmentOffset(NewPage->xlp_pageaddr, wal_segment_size)) == 0)
                {
                        XLogLongPageHeader NewLongPage = (XLogLongPageHeader) NewPage;
 
                        NewLongPage->xlp_sysid = ControlFile->system_identifier;
-                       NewLongPage->xlp_seg_size = XLogSegSize;
+                       NewLongPage->xlp_seg_size = wal_segment_size;
                        NewLongPage->xlp_xlog_blcksz = XLOG_BLCKSZ;
                        NewPage->xlp_info |= XLP_LONG_HEADER;
                }
@@ -2220,7 +2226,8 @@ CalculateCheckpointSegments(void)
         *        number of segments consumed between checkpoints.
         *-------
         */
-       target = (double) ConvertToXSegs(max_wal_size_mb) / (2.0 + CheckPointCompletionTarget);
+       target = (double) ConvertToXSegs(max_wal_size_mb, wal_segment_size) /
+               (2.0 + CheckPointCompletionTarget);
 
        /* round down */
        CheckPointSegments = (int) target;
@@ -2260,8 +2267,10 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr)
         * correspond to. Always recycle enough segments to meet the minimum, and
         * remove enough segments to stay below the maximum.
         */
-       minSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(min_wal_size_mb) - 1;
-       maxSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(max_wal_size_mb) - 1;
+       minSegNo = PriorRedoPtr / wal_segment_size +
+               ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1;
+       maxSegNo = PriorRedoPtr / wal_segment_size +
+               ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1;
 
        /*
         * Between those limits, recycle enough segments to get us through to the
@@ -2290,7 +2299,8 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr)
        /* add 10% for good measure. */
        distance *= 1.10;
 
-       recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) / XLOG_SEG_SIZE);
+       recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) /
+                                                                       wal_segment_size);
 
        if (recycleSegNo < minSegNo)
                recycleSegNo = minSegNo;
@@ -2314,7 +2324,7 @@ XLogCheckpointNeeded(XLogSegNo new_segno)
 {
        XLogSegNo       old_segno;
 
-       XLByteToSeg(RedoRecPtr, old_segno);
+       XLByteToSeg(RedoRecPtr, old_segno, wal_segment_size);
 
        if (new_segno >= old_segno + (uint64) (CheckPointSegments - 1))
                return true;
@@ -2392,7 +2402,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                LogwrtResult.Write = EndPtr;
                ispartialpage = WriteRqst.Write < LogwrtResult.Write;
 
-               if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+               if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                        wal_segment_size))
                {
                        /*
                         * Switch to new logfile segment.  We cannot have any pending
@@ -2401,7 +2412,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                        Assert(npages == 0);
                        if (openLogFile >= 0)
                                XLogFileClose();
-                       XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+                       XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                       wal_segment_size);
 
                        /* create/use new log file */
                        use_existent = true;
@@ -2412,7 +2424,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                /* Make sure we have the current logfile open */
                if (openLogFile < 0)
                {
-                       XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+                       XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                       wal_segment_size);
                        openLogFile = XLogFileOpen(openLogSegNo);
                        openLogOff = 0;
                }
@@ -2422,7 +2435,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                {
                        /* first of group */
                        startidx = curridx;
-                       startoffset = (LogwrtResult.Write - XLOG_BLCKSZ) % XLogSegSize;
+                       startoffset = XLogSegmentOffset(LogwrtResult.Write - XLOG_BLCKSZ,
+                                                                                       wal_segment_size);
                }
                npages++;
 
@@ -2435,7 +2449,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                last_iteration = WriteRqst.Write <= LogwrtResult.Write;
 
                finishing_seg = !ispartialpage &&
-                       (startoffset + npages * XLOG_BLCKSZ) >= XLogSegSize;
+                       (startoffset + npages * XLOG_BLCKSZ) >= wal_segment_size;
 
                if (last_iteration ||
                        curridx == XLogCtl->XLogCacheBlck ||
@@ -2562,11 +2576,13 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                        sync_method != SYNC_METHOD_OPEN_DSYNC)
                {
                        if (openLogFile >= 0 &&
-                               !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+                               !XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                                wal_segment_size))
                                XLogFileClose();
                        if (openLogFile < 0)
                        {
-                               XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo);
+                               XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                               wal_segment_size);
                                openLogFile = XLogFileOpen(openLogSegNo);
                                openLogOff = 0;
                        }
@@ -2982,7 +2998,8 @@ XLogBackgroundFlush(void)
        {
                if (openLogFile >= 0)
                {
-                       if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo))
+                       if (!XLByteInPrevSeg(LogwrtResult.Write, openLogSegNo,
+                                                                wal_segment_size))
                        {
                                XLogFileClose();
                        }
@@ -3161,7 +3178,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
        int                     fd;
        int                     nbytes;
 
-       XLogFilePath(path, ThisTimeLineID, logsegno);
+       XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size);
 
        /*
         * Try to use existent file (checkpoint maker may have created it already)
@@ -3215,7 +3232,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
         */
        zbuffer = (char *) MAXALIGN(zbuffer_raw);
        memset(zbuffer, 0, XLOG_BLCKSZ);
-       for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
+       for (nbytes = 0; nbytes < wal_segment_size; nbytes += XLOG_BLCKSZ)
        {
                errno = 0;
                pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_WRITE);
@@ -3332,7 +3349,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
        /*
         * Open the source file
         */
-       XLogFilePath(path, srcTLI, srcsegno);
+       XLogFilePath(path, srcTLI, srcsegno, wal_segment_size);
        srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
        if (srcfd < 0)
                ereport(ERROR,
@@ -3357,7 +3374,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
        /*
         * Do the data copying.
         */
-       for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))
+       for (nbytes = 0; nbytes < wal_segment_size; nbytes += sizeof(buffer))
        {
                int                     nread;
 
@@ -3467,7 +3484,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
        char            path[MAXPGPATH];
        struct stat stat_buf;
 
-       XLogFilePath(path, ThisTimeLineID, *segno);
+       XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size);
 
        /*
         * We want to be sure that only one process does this at a time.
@@ -3493,7 +3510,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
                                return false;
                        }
                        (*segno)++;
-                       XLogFilePath(path, ThisTimeLineID, *segno);
+                       XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size);
                }
        }
 
@@ -3524,7 +3541,7 @@ XLogFileOpen(XLogSegNo segno)
        char            path[MAXPGPATH];
        int                     fd;
 
-       XLogFilePath(path, ThisTimeLineID, segno);
+       XLogFilePath(path, ThisTimeLineID, segno, wal_segment_size);
 
        fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
                                           S_IRUSR | S_IWUSR);
@@ -3551,7 +3568,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
        char            path[MAXPGPATH];
        int                     fd;
 
-       XLogFileName(xlogfname, tli, segno);
+       XLogFileName(xlogfname, tli, segno, wal_segment_size);
 
        switch (source)
        {
@@ -3563,7 +3580,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 
                        restoredFromArchive = RestoreArchivedFile(path, xlogfname,
                                                                                                          "RECOVERYXLOG",
-                                                                                                         XLogSegSize,
+                                                                                                         wal_segment_size,
                                                                                                          InRedo);
                        if (!restoredFromArchive)
                                return -1;
@@ -3571,7 +3588,7 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 
                case XLOG_FROM_PG_WAL:
                case XLOG_FROM_STREAM:
-                       XLogFilePath(path, tli, segno);
+                       XLogFilePath(path, tli, segno, wal_segment_size);
                        restoredFromArchive = false;
                        break;
 
@@ -3690,7 +3707,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source)
        }
 
        /* Couldn't find it.  For simplicity, complain about front timeline */
-       XLogFilePath(path, recoveryTargetTLI, segno);
+       XLogFilePath(path, recoveryTargetTLI, segno, wal_segment_size);
        errno = ENOENT;
        ereport(emode,
                        (errcode_for_file_access(),
@@ -3741,9 +3758,11 @@ PreallocXlogFiles(XLogRecPtr endptr)
        XLogSegNo       _logSegNo;
        int                     lf;
        bool            use_existent;
+       uint64          offset;
 
-       XLByteToPrevSeg(endptr, _logSegNo);
-       if ((endptr - 1) % XLogSegSize >= (uint32) (0.75 * XLogSegSize))
+       XLByteToPrevSeg(endptr, _logSegNo, wal_segment_size);
+       offset = XLogSegmentOffset(endptr - 1, wal_segment_size);
+       if (offset >= (uint32) (0.75 * wal_segment_size))
        {
                _logSegNo++;
                use_existent = true;
@@ -3774,7 +3793,7 @@ CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
        {
                char            filename[MAXFNAMELEN];
 
-               XLogFileName(filename, tli, segno);
+               XLogFileName(filename, tli, segno, wal_segment_size);
                ereport(ERROR,
                                (errcode_for_file_access(),
                                 errmsg("requested WAL segment %s has already been removed",
@@ -3811,7 +3830,7 @@ UpdateLastRemovedPtr(char *filename)
        uint32          tli;
        XLogSegNo       segno;
 
-       XLogFromFileName(filename, &tli, &segno);
+       XLogFromFileName(filename, &tli, &segno, wal_segment_size);
 
        SpinLockAcquire(&XLogCtl->info_lck);
        if (segno > XLogCtl->lastRemovedSegNo)
@@ -3845,7 +3864,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
         * doesn't matter, we ignore that in the comparison. (During recovery,
         * ThisTimeLineID isn't set, so we can't use that.)
         */
-       XLogFileName(lastoff, 0, segno);
+       XLogFileName(lastoff, 0, segno, wal_segment_size);
 
        elog(DEBUG2, "attempting to remove WAL segments older than log file %s",
                 lastoff);
@@ -3906,7 +3925,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
        char            switchseg[MAXFNAMELEN];
        XLogSegNo       endLogSegNo;
 
-       XLByteToPrevSeg(switchpoint, endLogSegNo);
+       XLByteToPrevSeg(switchpoint, endLogSegNo, wal_segment_size);
 
        xldir = AllocateDir(XLOGDIR);
        if (xldir == NULL)
@@ -3918,7 +3937,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
        /*
         * Construct a filename of the last segment to be kept.
         */
-       XLogFileName(switchseg, newTLI, endLogSegNo);
+       XLogFileName(switchseg, newTLI, endLogSegNo, wal_segment_size);
 
        elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
                 switchseg);
@@ -3974,7 +3993,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
        /*
         * Initialize info about where to try to recycle to.
         */
-       XLByteToSeg(endptr, endlogSegNo);
+       XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
        if (PriorRedoPtr == InvalidXLogRecPtr)
                recycleSegNo = endlogSegNo + 10;
        else
@@ -4192,9 +4211,11 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
                        XLogSegNo       segno;
                        int32           offset;
 
-                       XLByteToSeg(xlogreader->latestPagePtr, segno);
-                       offset = xlogreader->latestPagePtr % XLogSegSize;
-                       XLogFileName(fname, xlogreader->readPageTLI, segno);
+                       XLByteToSeg(xlogreader->latestPagePtr, segno, wal_segment_size);
+                       offset = XLogSegmentOffset(xlogreader->latestPagePtr,
+                                                                          wal_segment_size);
+                       XLogFileName(fname, xlogreader->readPageTLI, segno,
+                                                wal_segment_size);
                        ereport(emode_for_corrupt_record(emode,
                                                                                         RecPtr ? RecPtr : EndRecPtr),
                                        (errmsg("unexpected timeline ID %u in log segment %s, offset %u",
@@ -4399,7 +4420,7 @@ WriteControlFile(void)
        ControlFile->blcksz = BLCKSZ;
        ControlFile->relseg_size = RELSEG_SIZE;
        ControlFile->xlog_blcksz = XLOG_BLCKSZ;
-       ControlFile->xlog_seg_size = XLOG_SEG_SIZE;
+       ControlFile->xlog_seg_size = wal_segment_size;
 
        ControlFile->nameDataLen = NAMEDATALEN;
        ControlFile->indexMaxKeys = INDEX_MAX_KEYS;
@@ -4467,6 +4488,7 @@ ReadControlFile(void)
 {
        pg_crc32c       crc;
        int                     fd;
+       static char wal_segsz_str[20];
 
        /*
         * Read data...
@@ -4569,13 +4591,6 @@ ReadControlFile(void)
                                                   " but the server was compiled with XLOG_BLCKSZ %d.",
                                                   ControlFile->xlog_blcksz, XLOG_BLCKSZ),
                                 errhint("It looks like you need to recompile or initdb.")));
-       if (ControlFile->xlog_seg_size != XLOG_SEG_SIZE)
-               ereport(FATAL,
-                               (errmsg("database files are incompatible with server"),
-                                errdetail("The database cluster was initialized with XLOG_SEG_SIZE %d,"
-                                                  " but the server was compiled with XLOG_SEG_SIZE %d.",
-                                                  ControlFile->xlog_seg_size, XLOG_SEG_SIZE),
-                                errhint("It looks like you need to recompile or initdb.")));
        if (ControlFile->nameDataLen != NAMEDATALEN)
                ereport(FATAL,
                                (errmsg("database files are incompatible with server"),
@@ -4637,6 +4652,32 @@ ReadControlFile(void)
                                 errhint("It looks like you need to recompile or initdb.")));
 #endif
 
+       wal_segment_size = ControlFile->xlog_seg_size;
+
+       if (!IsValidWalSegSize(wal_segment_size))
+               ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                               errmsg("WAL segment size must be a power of two between 1MB and 1GB, but the control file specifies %d bytes",
+                                                          wal_segment_size)));
+
+       snprintf(wal_segsz_str, sizeof(wal_segsz_str), "%d", wal_segment_size);
+       SetConfigOption("wal_segment_size", wal_segsz_str, PGC_INTERNAL,
+                                       PGC_S_OVERRIDE);
+
+       /* check and update variables dependent on wal_segment_size */
+       if (ConvertToXSegs(min_wal_size_mb, wal_segment_size) < 2)
+               ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                               errmsg("\"min_wal_size\" must be at least twice \"wal_segment_size\".")));
+
+       if (ConvertToXSegs(max_wal_size_mb, wal_segment_size) < 2)
+               ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                               errmsg("\"max_wal_size\" must be at least twice \"wal_segment_size\".")));
+
+       UsableBytesInSegment =
+               (wal_segment_size / XLOG_BLCKSZ * UsableBytesInPage) -
+               (SizeOfXLogLongPHD - SizeOfXLogShortPHD);
+
+       CalculateCheckpointSegments();
+
        /* Make the initdb settings visible as GUC variables, too */
        SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
                                        PGC_INTERNAL, PGC_S_OVERRIDE);
@@ -4757,8 +4798,8 @@ XLOGChooseNumBuffers(void)
        int                     xbuffers;
 
        xbuffers = NBuffers / 32;
-       if (xbuffers > XLOG_SEG_SIZE / XLOG_BLCKSZ)
-               xbuffers = XLOG_SEG_SIZE / XLOG_BLCKSZ;
+       if (xbuffers > (wal_segment_size / XLOG_BLCKSZ))
+               xbuffers = (wal_segment_size / XLOG_BLCKSZ);
        if (xbuffers < 8)
                xbuffers = 8;
        return xbuffers;
@@ -5034,7 +5075,7 @@ BootStrapXLOG(void)
         * segment with logid=0 logseg=1. The very first WAL segment, 0/0, is not
         * used, so that we can use 0/0 to mean "before any valid WAL segment".
         */
-       checkPoint.redo = XLogSegSize + SizeOfXLogLongPHD;
+       checkPoint.redo = wal_segment_size + SizeOfXLogLongPHD;
        checkPoint.ThisTimeLineID = ThisTimeLineID;
        checkPoint.PrevTimeLineID = ThisTimeLineID;
        checkPoint.fullPageWrites = fullPageWrites;
@@ -5065,10 +5106,10 @@ BootStrapXLOG(void)
        page->xlp_magic = XLOG_PAGE_MAGIC;
        page->xlp_info = XLP_LONG_HEADER;
        page->xlp_tli = ThisTimeLineID;
-       page->xlp_pageaddr = XLogSegSize;
+       page->xlp_pageaddr = wal_segment_size;
        longpage = (XLogLongPageHeader) page;
        longpage->xlp_sysid = sysidentifier;
-       longpage->xlp_seg_size = XLogSegSize;
+       longpage->xlp_seg_size = wal_segment_size;
        longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
 
        /* Insert the initial checkpoint record */
@@ -5550,8 +5591,8 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
         * they are the same, but if the switch happens exactly at a segment
         * boundary, startLogSegNo will be endLogSegNo + 1.
         */
-       XLByteToPrevSeg(endOfLog, endLogSegNo);
-       XLByteToSeg(endOfLog, startLogSegNo);
+       XLByteToPrevSeg(endOfLog, endLogSegNo, wal_segment_size);
+       XLByteToSeg(endOfLog, startLogSegNo, wal_segment_size);
 
        /*
         * Initialize the starting WAL segment for the new timeline. If the switch
@@ -5569,7 +5610,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
                 * avoid emplacing a bogus file.
                 */
                XLogFileCopy(endLogSegNo, endTLI, endLogSegNo,
-                                        endOfLog % XLOG_SEG_SIZE);
+                                        XLogSegmentOffset(endOfLog, wal_segment_size));
        }
        else
        {
@@ -5593,7 +5634,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
         * Let's just make real sure there are not .ready or .done flags posted
         * for the new segment.
         */
-       XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo);
+       XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo, wal_segment_size);
        XLogArchiveCleanup(xlogfname);
 
        /*
@@ -6390,7 +6431,7 @@ StartupXLOG(void)
 
        /* Set up XLOG reader facility */
        MemSet(&private, 0, sizeof(XLogPageReadPrivate));
-       xlogreader = XLogReaderAllocate(&XLogPageRead, &private);
+       xlogreader = XLogReaderAllocate(wal_segment_size, &XLogPageRead, &private);
        if (!xlogreader)
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
@@ -7523,7 +7564,7 @@ StartupXLOG(void)
                XLogRecPtr      pageBeginPtr;
 
                pageBeginPtr = EndOfLog - (EndOfLog % XLOG_BLCKSZ);
-               Assert(readOff == pageBeginPtr % XLogSegSize);
+               Assert(readOff == XLogSegmentOffset(pageBeginPtr, wal_segment_size));
 
                firstIdx = XLogRecPtrToBufIdx(EndOfLog);
 
@@ -7672,13 +7713,14 @@ StartupXLOG(void)
                 * restored from the archive to begin with, it's expected to have a
                 * .done file).
                 */
-               if (EndOfLog % XLOG_SEG_SIZE != 0 && XLogArchivingActive())
+               if (XLogSegmentOffset(EndOfLog, wal_segment_size) != 0 &&
+                       XLogArchivingActive())
                {
                        char            origfname[MAXFNAMELEN];
                        XLogSegNo       endLogSegNo;
 
-                       XLByteToPrevSeg(EndOfLog, endLogSegNo);
-                       XLogFileName(origfname, EndOfLogTLI, endLogSegNo);
+                       XLByteToPrevSeg(EndOfLog, endLogSegNo, wal_segment_size);
+                       XLogFileName(origfname, EndOfLogTLI, endLogSegNo, wal_segment_size);
 
                        if (!XLogArchiveIsReadyOrDone(origfname))
                        {
@@ -7686,7 +7728,7 @@ StartupXLOG(void)
                                char            partialfname[MAXFNAMELEN];
                                char            partialpath[MAXPGPATH];
 
-                               XLogFilePath(origpath, EndOfLogTLI, endLogSegNo);
+                               XLogFilePath(origpath, EndOfLogTLI, endLogSegNo, wal_segment_size);
                                snprintf(partialfname, MAXFNAMELEN, "%s.partial", origfname);
                                snprintf(partialpath, MAXPGPATH, "%s.partial", origpath);
 
@@ -8192,6 +8234,9 @@ InitXLOGAccess(void)
        ThisTimeLineID = XLogCtl->ThisTimeLineID;
        Assert(ThisTimeLineID != 0 || IsBootstrapProcessingMode());
 
+       /* set wal_segment_size */
+       wal_segment_size = ControlFile->xlog_seg_size;
+
        /* Use GetRedoRecPtr to copy the RedoRecPtr safely */
        (void) GetRedoRecPtr();
        /* Also update our copy of doPageWrites. */
@@ -8522,7 +8567,7 @@ UpdateCheckPointDistanceEstimate(uint64 nbytes)
         * more.
         *
         * When checkpoints are triggered by max_wal_size, this should converge to
-        * CheckpointSegments * XLOG_SEG_SIZE,
+        * CheckpointSegments * wal_segment_size,
         *
         * Note: This doesn't pay any attention to what caused the checkpoint.
         * Checkpoints triggered manually with CHECKPOINT command, or by e.g.
@@ -8721,7 +8766,7 @@ CreateCheckPoint(int flags)
        freespace = INSERT_FREESPACE(curInsert);
        if (freespace == 0)
        {
-               if (curInsert % XLogSegSize == 0)
+               if (XLogSegmentOffset(curInsert, wal_segment_size) == 0)
                        curInsert += SizeOfXLogLongPHD;
                else
                        curInsert += SizeOfXLogShortPHD;
@@ -8955,7 +9000,7 @@ CreateCheckPoint(int flags)
                /* Update the average distance between checkpoints. */
                UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
-               XLByteToSeg(PriorRedoPtr, _logSegNo);
+               XLByteToSeg(PriorRedoPtr, _logSegNo, wal_segment_size);
                KeepLogSeg(recptr, &_logSegNo);
                _logSegNo--;
                RemoveOldXlogFiles(_logSegNo, PriorRedoPtr, recptr);
@@ -9283,7 +9328,7 @@ CreateRestartPoint(int flags)
                /* Update the average distance between checkpoints/restartpoints. */
                UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
-               XLByteToSeg(PriorRedoPtr, _logSegNo);
+               XLByteToSeg(PriorRedoPtr, _logSegNo, wal_segment_size);
 
                /*
                 * Get the current end of xlog replayed or received, whichever is
@@ -9378,7 +9423,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
        XLogSegNo       segno;
        XLogRecPtr      keep;
 
-       XLByteToSeg(recptr, segno);
+       XLByteToSeg(recptr, segno, wal_segment_size);
        keep = XLogGetReplicationSlotMinimumLSN();
 
        /* compute limit for wal_keep_segments first */
@@ -9396,7 +9441,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
        {
                XLogSegNo       slotSegNo;
 
-               XLByteToSeg(keep, slotSegNo);
+               XLByteToSeg(keep, slotSegNo, wal_segment_size);
 
                if (slotSegNo <= 0)
                        segno = 1;
@@ -10179,7 +10224,7 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
 {
        char       *result = palloc(MAXFNAMELEN);
 
-       XLogFileName(result, tli, segno);
+       XLogFileName(result, tli, segno, wal_segment_size);
        return result;
 }
 
@@ -10433,8 +10478,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
                        WALInsertLockRelease();
                } while (!gotUniqueStartpoint);
 
-               XLByteToSeg(startpoint, _logSegNo);
-               XLogFileName(xlogfilename, starttli, _logSegNo);
+               XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
+               XLogFileName(xlogfilename, starttli, _logSegNo, wal_segment_size);
 
                /*
                 * Construct tablespace_map file
@@ -10985,8 +11030,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
                 */
                RequestXLogSwitch(false);
 
-               XLByteToPrevSeg(stoppoint, _logSegNo);
-               XLogFileName(stopxlogfilename, stoptli, _logSegNo);
+               XLByteToPrevSeg(stoppoint, _logSegNo, wal_segment_size);
+               XLogFileName(stopxlogfilename, stoptli, _logSegNo, wal_segment_size);
 
                /* Use the log timezone here, not the session timezone */
                stamp_time = (pg_time_t) time(NULL);
@@ -10997,9 +11042,9 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
                /*
                 * Write the backup history file
                 */
-               XLByteToSeg(startpoint, _logSegNo);
+               XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
                BackupHistoryFilePath(histfilepath, stoptli, _logSegNo,
-                                                         (uint32) (startpoint % XLogSegSize));
+                                                         startpoint, wal_segment_size);
                fp = AllocateFile(histfilepath, "w");
                if (!fp)
                        ereport(ERROR,
@@ -11053,12 +11098,12 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
                ((!backup_started_in_recovery && XLogArchivingActive()) ||
                 (backup_started_in_recovery && XLogArchivingAlways())))
        {
-               XLByteToPrevSeg(stoppoint, _logSegNo);
-               XLogFileName(lastxlogfilename, stoptli, _logSegNo);
+               XLByteToPrevSeg(stoppoint, _logSegNo, wal_segment_size);
+               XLogFileName(lastxlogfilename, stoptli, _logSegNo, wal_segment_size);
 
-               XLByteToSeg(startpoint, _logSegNo);
+               XLByteToSeg(startpoint, _logSegNo, wal_segment_size);
                BackupHistoryFileName(histfilename, stoptli, _logSegNo,
-                                                         (uint32) (startpoint % XLogSegSize));
+                                                         startpoint, wal_segment_size);
 
                seconds_before_warning = 60;
                waits = 0;
@@ -11501,14 +11546,15 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
        uint32          targetPageOff;
        XLogSegNo       targetSegNo PG_USED_FOR_ASSERTS_ONLY;
 
-       XLByteToSeg(targetPagePtr, targetSegNo);
-       targetPageOff = targetPagePtr % XLogSegSize;
+       XLByteToSeg(targetPagePtr, targetSegNo, wal_segment_size);
+       targetPageOff = XLogSegmentOffset(targetPagePtr, wal_segment_size);
 
        /*
         * See if we need to switch to a new segment because the requested record
         * is not in the currently open one.
         */
-       if (readFile >= 0 && !XLByteInSeg(targetPagePtr, readSegNo))
+       if (readFile >= 0 &&
+               !XLByteInSeg(targetPagePtr, readSegNo, wal_segment_size))
        {
                /*
                 * Request a restartpoint if we've replayed too much xlog since the
@@ -11529,7 +11575,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
                readSource = 0;
        }
 
-       XLByteToSeg(targetPagePtr, readSegNo);
+       XLByteToSeg(targetPagePtr, readSegNo, wal_segment_size);
 
 retry:
        /* See if we need to retrieve more data */
@@ -11569,7 +11615,8 @@ retry:
                if (((targetPagePtr) / XLOG_BLCKSZ) != (receivedUpto / XLOG_BLCKSZ))
                        readLen = XLOG_BLCKSZ;
                else
-                       readLen = receivedUpto % XLogSegSize - targetPageOff;
+                       readLen = XLogSegmentOffset(receivedUpto, wal_segment_size) -
+                               targetPageOff;
        }
        else
                readLen = XLOG_BLCKSZ;
@@ -11580,7 +11627,7 @@ retry:
        {
                char            fname[MAXFNAMELEN];
 
-               XLogFileName(fname, curFileTLI, readSegNo);
+               XLogFileName(fname, curFileTLI, readSegNo, wal_segment_size);
                ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
                                (errcode_for_file_access(),
                                 errmsg("could not seek in log segment %s to offset %u: %m",
@@ -11594,7 +11641,7 @@ retry:
                char            fname[MAXFNAMELEN];
 
                pgstat_report_wait_end();
-               XLogFileName(fname, curFileTLI, readSegNo);
+               XLogFileName(fname, curFileTLI, readSegNo, wal_segment_size);
                ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
                                (errcode_for_file_access(),
                                 errmsg("could not read from log segment %s, offset %u: %m",
index 7afb73579b009444f9b7df658645ea3f2cf5e5f5..c723c931d895aa93aefa4a5e31cd862348f5d13a 100644 (file)
@@ -134,13 +134,14 @@ RestoreArchivedFile(char *path, const char *xlogfname,
        if (cleanupEnabled)
        {
                GetOldestRestartPoint(&restartRedoPtr, &restartTli);
-               XLByteToSeg(restartRedoPtr, restartSegNo);
-               XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+               XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+               XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+                                        wal_segment_size);
                /* we shouldn't need anything earlier than last restart point */
                Assert(strcmp(lastRestartPointFname, xlogfname) <= 0);
        }
        else
-               XLogFileName(lastRestartPointFname, 0, 0L);
+               XLogFileName(lastRestartPointFname, 0, 0L, wal_segment_size);
 
        /*
         * construct the command to be executed
@@ -347,8 +348,9 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
         * archive, though there is no requirement to do so.
         */
        GetOldestRestartPoint(&restartRedoPtr, &restartTli);
-       XLByteToSeg(restartRedoPtr, restartSegNo);
-       XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
+       XLByteToSeg(restartRedoPtr, restartSegNo, wal_segment_size);
+       XLogFileName(lastRestartPointFname, restartTli, restartSegNo,
+                                wal_segment_size);
 
        /*
         * construct the command to be executed
@@ -547,7 +549,7 @@ XLogArchiveNotifySeg(XLogSegNo segno)
 {
        char            xlog[MAXFNAMELEN];
 
-       XLogFileName(xlog, ThisTimeLineID, segno);
+       XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size);
        XLogArchiveNotify(xlog);
 }
 
index f9b49ba49842db17497fc83292d8aa7a0fc16856..443ccd6411299a4b498b1f84611e3636f20e39f8 100644 (file)
@@ -489,8 +489,8 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
        /*
         * xlogfilename
         */
-       XLByteToPrevSeg(locationpoint, xlogsegno);
-       XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
+       XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
+       XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
 
        values[0] = CStringGetTextDatum(xlogfilename);
        isnull[0] = false;
@@ -498,7 +498,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
        /*
         * offset
         */
-       xrecoff = locationpoint % XLogSegSize;
+       xrecoff = XLogSegmentOffset(locationpoint, wal_segment_size);
 
        values[1] = UInt32GetDatum(xrecoff);
        isnull[1] = false;
@@ -530,8 +530,8 @@ pg_walfile_name(PG_FUNCTION_ARGS)
                                 errmsg("recovery is in progress"),
                                 errhint("pg_walfile_name() cannot be executed during recovery.")));
 
-       XLByteToPrevSeg(locationpoint, xlogsegno);
-       XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
+       XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size);
+       XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size);
 
        PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
 }
index 0781a7b9de926439c910dc2ce9a3d8df33264f15..b1f9b90c50f0dbb8adb27db38c306a09f00ec43c 100644 (file)
@@ -64,7 +64,8 @@ report_invalid_record(XLogReaderState *state, const char *fmt,...)
  * Returns NULL if the xlogreader couldn't be allocated.
  */
 XLogReaderState *
-XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
+XLogReaderAllocate(int wal_segment_size, XLogPageReadCB pagereadfunc,
+                                  void *private_data)
 {
        XLogReaderState *state;
 
@@ -91,6 +92,7 @@ XLogReaderAllocate(XLogPageReadCB pagereadfunc, void *private_data)
                return NULL;
        }
 
+       state->wal_segment_size = wal_segment_size;
        state->read_page = pagereadfunc;
        /* system_identifier initialized to zeroes above */
        state->private_data = private_data;
@@ -466,8 +468,8 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg)
                (record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH)
        {
                /* Pretend it extends to end of segment */
-               state->EndRecPtr += XLogSegSize - 1;
-               state->EndRecPtr -= state->EndRecPtr % XLogSegSize;
+               state->EndRecPtr += state->wal_segment_size - 1;
+               state->EndRecPtr -= XLogSegmentOffset(state->EndRecPtr, state->wal_segment_size);
        }
 
        if (DecodeXLogRecord(state, record, errormsg))
@@ -509,8 +511,8 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
 
        Assert((pageptr % XLOG_BLCKSZ) == 0);
 
-       XLByteToSeg(pageptr, targetSegNo);
-       targetPageOff = (pageptr % XLogSegSize);
+       XLByteToSeg(pageptr, targetSegNo, state->wal_segment_size);
+       targetPageOff = XLogSegmentOffset(pageptr, state->wal_segment_size);
 
        /* check whether we have all the requested data already */
        if (targetSegNo == state->readSegNo && targetPageOff == state->readOff &&
@@ -719,16 +721,16 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
 
        Assert((recptr % XLOG_BLCKSZ) == 0);
 
-       XLByteToSeg(recptr, segno);
-       offset = recptr % XLogSegSize;
+       XLByteToSeg(recptr, segno, state->wal_segment_size);
+       offset = XLogSegmentOffset(recptr, state->wal_segment_size);
 
-       XLogSegNoOffsetToRecPtr(segno, offset, recaddr);
+       XLogSegNoOffsetToRecPtr(segno, offset, recaddr, state->wal_segment_size);
 
        if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
        {
                char            fname[MAXFNAMELEN];
 
-               XLogFileName(fname, state->readPageTLI, segno);
+               XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
 
                report_invalid_record(state,
                                                          "invalid magic number %04X in log segment %s, offset %u",
@@ -742,7 +744,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
        {
                char            fname[MAXFNAMELEN];
 
-               XLogFileName(fname, state->readPageTLI, segno);
+               XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
 
                report_invalid_record(state,
                                                          "invalid info bits %04X in log segment %s, offset %u",
@@ -775,10 +777,10 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
                                                                  fhdrident_str, sysident_str);
                        return false;
                }
-               else if (longhdr->xlp_seg_size != XLogSegSize)
+               else if (longhdr->xlp_seg_size != state->wal_segment_size)
                {
                        report_invalid_record(state,
-                                                                 "WAL file is from different database system: incorrect XLOG_SEG_SIZE in page header");
+                                                                 "WAL file is from different database system: incorrect segment size in page header");
                        return false;
                }
                else if (longhdr->xlp_xlog_blcksz != XLOG_BLCKSZ)
@@ -792,7 +794,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
        {
                char            fname[MAXFNAMELEN];
 
-               XLogFileName(fname, state->readPageTLI, segno);
+               XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
 
                /* hmm, first page of file doesn't have a long header? */
                report_invalid_record(state,
@@ -807,7 +809,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
        {
                char            fname[MAXFNAMELEN];
 
-               XLogFileName(fname, state->readPageTLI, segno);
+               XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
 
                report_invalid_record(state,
                                                          "unexpected pageaddr %X/%X in log segment %s, offset %u",
@@ -832,7 +834,7 @@ ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr,
                {
                        char            fname[MAXFNAMELEN];
 
-                       XLogFileName(fname, state->readPageTLI, segno);
+                       XLogFileName(fname, state->readPageTLI, segno, state->wal_segment_size);
 
                        report_invalid_record(state,
                                                                  "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u",
index bbae733d658be6ebed17ff8e0e844a069ccf35ea..b11c94c9b6846751296d4faa34e563f5c90685b1 100644 (file)
@@ -654,7 +654,8 @@ XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
  * frontend).  Probably these should be merged at some point.
  */
 static void
-XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
+XLogRead(char *buf, int segsize, TimeLineID tli, XLogRecPtr startptr,
+                Size count)
 {
        char       *p;
        XLogRecPtr      recptr;
@@ -666,6 +667,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
        static TimeLineID sendTLI = 0;
        static uint32 sendOff = 0;
 
+       Assert(segsize == wal_segment_size);
+
        p = buf;
        recptr = startptr;
        nbytes = count;
@@ -676,10 +679,10 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
                int                     segbytes;
                int                     readbytes;
 
-               startoff = recptr % XLogSegSize;
+               startoff = XLogSegmentOffset(recptr, segsize);
 
                /* Do we need to switch to a different xlog segment? */
-               if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo) ||
+               if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo, segsize) ||
                        sendTLI != tli)
                {
                        char            path[MAXPGPATH];
@@ -687,9 +690,9 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
                        if (sendFile >= 0)
                                close(sendFile);
 
-                       XLByteToSeg(recptr, sendSegNo);
+                       XLByteToSeg(recptr, sendSegNo, segsize);
 
-                       XLogFilePath(path, tli, sendSegNo);
+                       XLogFilePath(path, tli, sendSegNo, segsize);
 
                        sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
 
@@ -717,7 +720,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
                        {
                                char            path[MAXPGPATH];
 
-                               XLogFilePath(path, tli, sendSegNo);
+                               XLogFilePath(path, tli, sendSegNo, segsize);
 
                                ereport(ERROR,
                                                (errcode_for_file_access(),
@@ -728,8 +731,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
                }
 
                /* How many bytes are within this segment? */
-               if (nbytes > (XLogSegSize - startoff))
-                       segbytes = XLogSegSize - startoff;
+               if (nbytes > (segsize - startoff))
+                       segbytes = segsize - startoff;
                else
                        segbytes = nbytes;
 
@@ -740,7 +743,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
                {
                        char            path[MAXPGPATH];
 
-                       XLogFilePath(path, tli, sendSegNo);
+                       XLogFilePath(path, tli, sendSegNo, segsize);
 
                        ereport(ERROR,
                                        (errcode_for_file_access(),
@@ -798,7 +801,8 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
 void
 XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
 {
-       const XLogRecPtr lastReadPage = state->readSegNo * XLogSegSize + state->readOff;
+       const XLogRecPtr lastReadPage = state->readSegNo *
+               state->wal_segment_size + state->readOff;
 
        Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
        Assert(wantLength <= XLOG_BLCKSZ);
@@ -842,7 +846,8 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
        if (state->currTLIValidUntil != InvalidXLogRecPtr &&
                state->currTLI != ThisTimeLineID &&
                state->currTLI != 0 &&
-               (wantPage + wantLength) / XLogSegSize < state->currTLIValidUntil / XLogSegSize)
+               ((wantPage + wantLength) / state->wal_segment_size) <
+               (state->currTLIValidUntil / state->wal_segment_size))
                return;
 
        /*
@@ -864,9 +869,11 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
                 */
                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
@@ -1014,7 +1021,8 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
         * as 'count', read the whole page anyway. It's guaranteed to be
         * zero-padded up to the page boundary if it's incomplete.
         */
-       XLogRead(cur_page, *pageTLI, targetPagePtr, XLOG_BLCKSZ);
+       XLogRead(cur_page, state->wal_segment_size, *pageTLI, targetPagePtr,
+                        XLOG_BLCKSZ);
 
        /* number of valid bytes in the buffer */
        return count;
index 0453fd4ac1036fe857b41f09a7b0d0db1058c9bd..b14e6f79244bd21e7cd7a98ed336c92374b413c0 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "access/htup_details.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/index.h"
 #include "catalog/pg_collation.h"
@@ -222,7 +223,7 @@ AuxiliaryProcessMain(int argc, char *argv[])
        /* If no -x argument, we are a CheckerProcess */
        MyAuxProcType = CheckerProcess;
 
-       while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
+       while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:X:-:")) != -1)
        {
                switch (flag)
                {
@@ -257,6 +258,18 @@ AuxiliaryProcessMain(int argc, char *argv[])
                        case 'x':
                                MyAuxProcType = atoi(optarg);
                                break;
+                       case 'X':
+                               {
+                                       int                     WalSegSz = strtoul(optarg, NULL, 0);
+
+                                       if (!IsValidWalSegSize(WalSegSz))
+                                               ereport(ERROR,
+                                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                                errmsg("-X requires a power of 2 value between 1MB and 1GB")));
+                                       SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL,
+                                                                       PGC_S_OVERRIDE);
+                               }
+                               break;
                        case 'c':
                        case '-':
                                {
index e48ebd557ffb2b1571d61f44d9295b4d9f0234f3..7e0af10c4dc48dfa5521091c4d0532c1c9760b4c 100644 (file)
@@ -624,7 +624,7 @@ CheckArchiveTimeout(void)
                         * If the returned pointer points exactly to a segment boundary,
                         * assume nothing happened.
                         */
-                       if ((switchpoint % XLogSegSize) != 0)
+                       if (XLogSegmentOffset(switchpoint, wal_segment_size) != 0)
                                elog(DEBUG1, "write-ahead log switch forced (archive_timeout=%d)",
                                         XLogArchiveTimeout);
                }
@@ -782,7 +782,8 @@ IsCheckpointOnSchedule(double progress)
                recptr = GetXLogReplayRecPtr(NULL);
        else
                recptr = GetInsertRecPtr();
-       elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) / XLogSegSize) / CheckPointSegments;
+       elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) /
+                                        wal_segment_size) / CheckPointSegments;
 
        if (progress < elapsed_xlogs)
        {
index 12a16bd773d9525de914c2ea39c8fba2af9c3caa..c3b9bddc8fe7592d01f1f61883b3e577e4047baa 100644 (file)
@@ -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
                 * including them.
                 */
-               XLByteToSeg(startptr, startsegno);
-               XLogFileName(firstoff, ThisTimeLineID, startsegno);
-               XLByteToPrevSeg(endptr, endsegno);
-               XLogFileName(lastoff, ThisTimeLineID, endsegno);
+               XLByteToSeg(startptr, startsegno, wal_segment_size);
+               XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+               XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+               XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
 
                dir = AllocateDir("pg_wal");
                if (!dir)
@@ -415,12 +415,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                 * Sanity check: the first and last segment should cover startptr and
                 * endptr, with no gaps in between.
                 */
-               XLogFromFileName(walFiles[0], &tli, &segno);
+               XLogFromFileName(walFiles[0], &tli, &segno, wal_segment_size);
                if (segno != startsegno)
                {
                        char            startfname[MAXFNAMELEN];
 
-                       XLogFileName(startfname, ThisTimeLineID, startsegno);
+                       XLogFileName(startfname, ThisTimeLineID, startsegno,
+                                                wal_segment_size);
                        ereport(ERROR,
                                        (errmsg("could not find WAL file \"%s\"", startfname)));
                }
@@ -429,12 +430,13 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        XLogSegNo       currsegno = segno;
                        XLogSegNo       nextsegno = segno + 1;
 
-                       XLogFromFileName(walFiles[i], &tli, &segno);
+                       XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
                        if (!(nextsegno == segno || currsegno == segno))
                        {
                                char            nextfname[MAXFNAMELEN];
 
-                               XLogFileName(nextfname, ThisTimeLineID, nextsegno);
+                               XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+                                                        wal_segment_size);
                                ereport(ERROR,
                                                (errmsg("could not find WAL file \"%s\"", nextfname)));
                        }
@@ -443,7 +445,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                {
                        char            endfname[MAXFNAMELEN];
 
-                       XLogFileName(endfname, ThisTimeLineID, endsegno);
+                       XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
                        ereport(ERROR,
                                        (errmsg("could not find WAL file \"%s\"", endfname)));
                }
@@ -457,7 +459,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        pgoff_t         len = 0;
 
                        snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFiles[i]);
-                       XLogFromFileName(walFiles[i], &tli, &segno);
+                       XLogFromFileName(walFiles[i], &tli, &segno, wal_segment_size);
 
                        fp = AllocateFile(pathbuf, "rb");
                        if (fp == NULL)
@@ -479,7 +481,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                                                (errcode_for_file_access(),
                                                 errmsg("could not stat file \"%s\": %m",
                                                                pathbuf)));
-                       if (statbuf.st_size != XLogSegSize)
+                       if (statbuf.st_size != wal_segment_size)
                        {
                                CheckXLogRemoved(segno, tli);
                                ereport(ERROR,
@@ -490,7 +492,9 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                        /* send the WAL file itself */
                        _tarWriteHeader(pathbuf, NULL, &statbuf, false);
 
-                       while ((cnt = fread(buf, 1, Min(sizeof(buf), XLogSegSize - len), fp)) > 0)
+                       while ((cnt = fread(buf, 1,
+                                                               Min(sizeof(buf), wal_segment_size - len),
+                                                               fp)) > 0)
                        {
                                CheckXLogRemoved(segno, tli);
                                /* Send the chunk as a CopyData message */
@@ -501,11 +505,11 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                                len += cnt;
                                throttle(cnt);
 
-                               if (len == XLogSegSize)
+                               if (len == wal_segment_size)
                                        break;
                        }
 
-                       if (len != XLogSegSize)
+                       if (len != wal_segment_size)
                        {
                                CheckXLogRemoved(segno, tli);
                                ereport(ERROR,
@@ -513,7 +517,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
                                                 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);
 
index efb9785f25e5fc23f2c5149dee9e617706400e94..bca585fc27c36d32710cf8867528dad4334a5ad3 100644 (file)
@@ -163,7 +163,7 @@ StartupDecodingContext(List *output_plugin_options,
 
        ctx->slot = slot;
 
-       ctx->reader = XLogReaderAllocate(read_page, ctx);
+       ctx->reader = XLogReaderAllocate(wal_segment_size, read_page, ctx);
        if (!ctx->reader)
                ereport(ERROR,
                                (errcode(ERRCODE_OUT_OF_MEMORY),
index 657bafae579fc9b1085b2070a1c8cbde04dc15f9..68766d522d5b78e1085dfc708e3d3ae566319ec2 100644 (file)
@@ -2083,15 +2083,16 @@ ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
                 * store in segment in which it belongs by start lsn, don't split over
                 * multiple segments tho
                 */
-               if (fd == -1 || !XLByteInSeg(change->lsn, curOpenSegNo))
+               if (fd == -1 ||
+                       !XLByteInSeg(change->lsn, curOpenSegNo, wal_segment_size))
                {
                        XLogRecPtr      recptr;
 
                        if (fd != -1)
                                CloseTransientFile(fd);
 
-                       XLByteToSeg(change->lsn, curOpenSegNo);
-                       XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr);
+                       XLByteToSeg(change->lsn, curOpenSegNo, wal_segment_size);
+                       XLogSegNoOffsetToRecPtr(curOpenSegNo, 0, recptr, wal_segment_size);
 
                        /*
                         * No need to care about TLIs here, only used during a single run,
@@ -2319,7 +2320,7 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
        txn->nentries_mem = 0;
        Assert(dlist_is_empty(&txn->changes));
 
-       XLByteToSeg(txn->final_lsn, last_segno);
+       XLByteToSeg(txn->final_lsn, last_segno, wal_segment_size);
 
        while (restored < max_changes_in_memory && *segno <= last_segno)
        {
@@ -2334,11 +2335,11 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
                        /* first time in */
                        if (*segno == 0)
                        {
-                               XLByteToSeg(txn->first_lsn, *segno);
+                               XLByteToSeg(txn->first_lsn, *segno, wal_segment_size);
                        }
 
                        Assert(*segno != 0 || dlist_is_empty(&txn->changes));
-                       XLogSegNoOffsetToRecPtr(*segno, 0, recptr);
+                       XLogSegNoOffsetToRecPtr(*segno, 0, recptr, wal_segment_size);
 
                        /*
                         * No need to care about TLIs here, only used during a single run,
@@ -2575,8 +2576,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
        Assert(txn->first_lsn != InvalidXLogRecPtr);
        Assert(txn->final_lsn != InvalidXLogRecPtr);
 
-       XLByteToSeg(txn->first_lsn, first);
-       XLByteToSeg(txn->final_lsn, last);
+       XLByteToSeg(txn->first_lsn, first, wal_segment_size);
+       XLByteToSeg(txn->final_lsn, last, wal_segment_size);
 
        /* iterate over all possible filenames, and delete them */
        for (cur = first; cur <= last; cur++)
@@ -2584,7 +2585,7 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
                char            path[MAXPGPATH];
                XLogRecPtr      recptr;
 
-               XLogSegNoOffsetToRecPtr(cur, 0, recptr);
+               XLogSegNoOffsetToRecPtr(cur, 0, recptr, wal_segment_size);
 
                sprintf(path, "pg_replslot/%s/xid-%u-lsn-%X-%X.snap",
                                NameStr(MyReplicationSlot->data.name), txn->xid,
index a8a16f55e98747b61a480f1bfd307cb0f2f34b36..23de2577effb682d9af38abc4a3bb933f8173f99 100644 (file)
@@ -1039,7 +1039,7 @@ ReplicationSlotReserveWal(void)
                 * the new restart_lsn above, so normally we should never need to loop
                 * more than twice.
                 */
-               XLByteToSeg(slot->data.restart_lsn, segno);
+               XLByteToSeg(slot->data.restart_lsn, segno, wal_segment_size);
                if (XLogGetLastRemovedSegno() < segno)
                        break;
        }
index ea9d21a46b396cb6dd4da7443d6df73a23fa6eaa..3474514adcca9ff410616cb16410bdf6e5a1766c 100644 (file)
@@ -613,7 +613,7 @@ WalReceiverMain(void)
                         * Create .done file forcibly to prevent the streamed segment from
                         * being archived later.
                         */
-                       XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+                       XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
                        if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
                                XLogArchiveForceDone(xlogfname);
                        else
@@ -943,7 +943,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
        {
                int                     segbytes;
 
-               if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo))
+               if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
                {
                        bool            use_existent;
 
@@ -972,7 +972,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                                 * Create .done file forcibly to prevent the streamed segment
                                 * from being archived later.
                                 */
-                               XLogFileName(xlogfname, recvFileTLI, recvSegNo);
+                               XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
                                if (XLogArchiveMode != ARCHIVE_MODE_ALWAYS)
                                        XLogArchiveForceDone(xlogfname);
                                else
@@ -981,7 +981,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                        recvFile = -1;
 
                        /* Create/use new log file */
-                       XLByteToSeg(recptr, recvSegNo);
+                       XLByteToSeg(recptr, recvSegNo, wal_segment_size);
                        use_existent = true;
                        recvFile = XLogFileInit(recvSegNo, &use_existent, true);
                        recvFileTLI = ThisTimeLineID;
@@ -989,10 +989,10 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                }
 
                /* Calculate the start offset of the received logs */
-               startoff = recptr % XLogSegSize;
+               startoff = XLogSegmentOffset(recptr, wal_segment_size);
 
-               if (startoff + nbytes > XLogSegSize)
-                       segbytes = XLogSegSize - startoff;
+               if (startoff + nbytes > wal_segment_size)
+                       segbytes = wal_segment_size - startoff;
                else
                        segbytes = nbytes;
 
index 8ed7254b5c60af486ffd3e1ca1ac58dbf45bab83..78f8693ece719facd78906d8e109a7cd8e3a4f60 100644 (file)
@@ -233,8 +233,8 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
         * being created by XLOG streaming, which might cause trouble later on if
         * the segment is e.g archived.
         */
-       if (recptr % XLogSegSize != 0)
-               recptr -= recptr % XLogSegSize;
+       if (XLogSegmentOffset(recptr, wal_segment_size) != 0)
+               recptr -= XLogSegmentOffset(recptr, wal_segment_size);
 
        SpinLockAcquire(&walrcv->mutex);
 
index 1fbe8ed71b05d5c2f22a607e7e26ada5b70e977e..56999e931577d852d