From b9a440ba4892f43e1f65c79c7b4da86d00053530 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Tue, 13 Mar 2018 23:37:28 +0000
Subject: [PATCH v2 3/4] Allow users to change the WAL segment size with
 pg_resetwal.

Like the '--wal-segsize' option in initdb, the new 's' option
accepts segment sizes in megabytes.  This patch also fixes a small
issue with the WAL starting address calculation that would cause
the WAL byte position to go backwards in some cases.

Note that some segment size changes will cause old WAL file names
to be reused.  The new documentation for '-s' contains a note
warning of this side effect and how to avoid it.
---
 doc/src/sgml/ref/pg_resetwal.sgml | 24 ++++++++++++++++++++++++
 src/bin/pg_resetwal/pg_resetwal.c | 25 ++++++++++++++++++++++---
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml
index 43b58a4..2bffb59 100644
--- a/doc/src/sgml/ref/pg_resetwal.sgml
+++ b/doc/src/sgml/ref/pg_resetwal.sgml
@@ -248,6 +248,30 @@ PostgreSQL documentation
    </varlistentry>
 
    <varlistentry>
+    <term><option>-s</option> <replaceable class="parameter">wal_segment_size</replaceable></term>
+    <listitem>
+     <para>
+      Manually set the WAL segment size (in megabytes).
+     </para>
+
+     <para>
+      The WAL segment size must be set to a power of 2 between 1 and 1024 (megabytes).
+     </para>
+
+     <note>
+      <para>
+       While <command>pg_resetwal</command> will set the WAL starting address
+       beyond the latest existing WAL segment file, some segment size changes
+       can cause previous WAL file names to be reused.  It is recommended to use
+       <option>-l</option> together with <option>-s</option> to manually set the
+       WAL starting address if WAL file name overlap will cause problems with
+       your archiving strategy.
+      </para>
+     </note>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><option>-x</option> <replaceable class="parameter">xid</replaceable></term>
     <listitem>
      <para>
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a5df0fe..604a8d2 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -118,7 +118,7 @@ main(int argc, char *argv[])
 	}
 
 
-	while ((c = getopt(argc, argv, "c:D:e:fl:m:no:O:x:")) != -1)
+	while ((c = getopt(argc, argv, "c:D:e:fl:m:no:O:x:s:")) != -1)
 	{
 		switch (c)
 		{
@@ -276,6 +276,15 @@ main(int argc, char *argv[])
 				log_fname = pg_strdup(optarg);
 				break;
 
+			case 's':
+				WalSegSz = strtol(optarg, &endptr, 10) * 1024 * 1024;
+				if (*endptr != '\0' || !IsValidWalSegSize(WalSegSz))
+				{
+					fprintf(stderr, _("%s: WAL segment size (-s) must be a power of 2 between 1 and 1024 (megabytes)\n"), progname);
+					exit(1);
+				}
+				break;
+
 			default:
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 				exit(1);
@@ -363,13 +372,16 @@ main(int argc, char *argv[])
 	 *
 	 * If the control file specifies the WAL segment size to be 0 bytes, guess
 	 * that it should be the default WAL segment size.
+	 *
+	 * If no new WAL segment size was set, use the control file value.
 	 */
 	if (ControlFile.xlog_seg_size == 0)
 	{
 		ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
 		walSegSizeChanged = true;
 	}
-	WalSegSz = ControlFile.xlog_seg_size;
+	if (WalSegSz == 0)
+		WalSegSz = ControlFile.xlog_seg_size;
 
 	if (log_fname != NULL)
 		XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
@@ -437,6 +449,12 @@ main(int argc, char *argv[])
 		ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
 	}
 
+	if (WalSegSz != ControlFile.xlog_seg_size)
+	{
+		ControlFile.xlog_seg_size = WalSegSz;
+		walSegSizeChanged = true;
+	}
+
 	if (minXlogSegNo > newXlogSegNo)
 		newXlogSegNo = minXlogSegNo;
 
@@ -1048,7 +1066,7 @@ FindEndOfXLOG(void)
 	 * are in virgin territory.
 	 */
 	xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
-	newXlogSegNo = (xlogbytepos + WalSegSz - 1) / WalSegSz;
+	newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
 	newXlogSegNo++;
 }
 
@@ -1276,6 +1294,7 @@ usage(void)
 	printf(_("  -n               no update, just show what would be done (for testing)\n"));
 	printf(_("  -o OID           set next OID\n"));
 	printf(_("  -O OFFSET        set next multitransaction offset\n"));
+	printf(_("  -s SIZE          set WAL segment size (in megabytes)\n"));
 	printf(_("  -V, --version    output version information, then exit\n"));
 	printf(_("  -x XID           set next transaction ID\n"));
 	printf(_("  -?, --help       show this help, then exit\n"));
-- 
2.7.3.AMZN

