From ba9da88207d02f0173ec0cf4f698cf49b6926229 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Wed, 19 Jun 2019 12:43:09 +1200
Subject: [PATCH] Add dynamic_shared_memory_segments_per_backend GUC.

In some scenarios (probably mostly testing for now) it is possible
to run out of DSM segment slots, because we have a hardcoded
allowance of 2 per backend.  Make that into a GUC so that users
who run into problems have some room to move.

Also make dsa.c ramp up its segment sizes more aggressively, so that
fewer slots are needed.

Remove an outdated comment about expect segment and slot sizes.

Author: Thomas Munro (based on a suggestion from Andres Freund)
---
 doc/src/sgml/config.sgml                      | 17 +++++++++++++++++
 src/backend/storage/ipc/dsm.c                 |  8 +-------
 src/backend/storage/ipc/dsm_impl.c            |  1 +
 src/backend/utils/misc/guc.c                  | 12 ++++++++++++
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/backend/utils/mmgr/dsa.c                  |  2 +-
 src/include/storage/dsm_impl.h                |  3 ++-
 7 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 84341a30e5..3e8fab263f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1786,6 +1786,23 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-dynamic-shared-memory-segments-per-backend" xreflabel="dynamic_shared_memory_segments_per_backend">
+      <term><varname>dynamic_shared_memory_segments_per_backend</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>dynamic_shared_memory_segments_per_backend</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Limits the total number of dynamic shared memory segments the
+        server can create.  The system-wide limit is 64 + 
+        (<varname>max_connections</varname> *
+        <varname>dynamic_shared_memory_segments_per_backend</varname>) before
+        an error is raised.  The default value is <literal>2</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
      </sect2>
 
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index 142293fd2c..42948791e6 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -45,13 +45,7 @@
 
 #define PG_DYNSHMEM_CONTROL_MAGIC		0x9a503d32
 
-/*
- * There's no point in getting too cheap here, because the minimum allocation
- * is one OS page, which is probably at least 4KB and could easily be as high
- * as 64KB.  Each currently sizeof(dsm_control_item), currently 8 bytes.
- */
 #define PG_DYNSHMEM_FIXED_SLOTS			64
-#define PG_DYNSHMEM_SLOTS_PER_BACKEND	2
 
 #define INVALID_CONTROL_SLOT		((uint32) -1)
 
@@ -161,7 +155,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
 
 	/* Determine size for new control segment. */
 	maxitems = PG_DYNSHMEM_FIXED_SLOTS
-		+ PG_DYNSHMEM_SLOTS_PER_BACKEND * MaxBackends;
+		+ dynamic_shared_memory_segments_per_backend * MaxBackends;
 	elog(DEBUG2, "dynamic shared memory system will support %u segments",
 		 maxitems);
 	segsize = dsm_control_bytes_needed(maxitems);
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index d32996b6fc..a15409538c 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -112,6 +112,7 @@ const struct config_enum_entry dynamic_shared_memory_options[] = {
 
 /* Implementation selector. */
 int			dynamic_shared_memory_type;
+int			dynamic_shared_memory_segments_per_backend;
 
 /* Size of buffer to be used for zero-filling. */
 #define ZBUFFER_SIZE				8192
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1208eb9a68..293f8d11a5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3197,6 +3197,18 @@ static struct config_int ConfigureNamesInt[] =
 		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
 	},
 
+	{
+		{"dynamic_shared_memory_segments_per_backend", PGC_POSTMASTER,
+			RESOURCES_MEM,
+			gettext_noop("Sets the number of DSM segments that can be created."),
+			NULL
+		},
+		&dynamic_shared_memory_segments_per_backend,
+		2, 1, 256,
+		NULL, NULL, NULL
+	},
+
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 5ee5e09ddf..d069712caf 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -144,6 +144,7 @@
 					#   windows
 					#   mmap
 					# (change requires restart)
+#dynamic_shared_memory_segments_per_backend = 2
 
 # - Disk -
 
diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c
index 4b826cdaa5..d8d36bf46c 100644
--- a/src/backend/utils/mmgr/dsa.c
+++ b/src/backend/utils/mmgr/dsa.c
@@ -74,7 +74,7 @@
  * dsm.c's limits on total number of segments), or limiting the total size
  * an area can manage when using small pointers.
  */
-#define DSA_NUM_SEGMENTS_AT_EACH_SIZE 4
+#define DSA_NUM_SEGMENTS_AT_EACH_SIZE 2
 
 /*
  * The number of bits used to represent the offset part of a dsa_pointer.
diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h
index 1dc557b791..fb116ce208 100644
--- a/src/include/storage/dsm_impl.h
+++ b/src/include/storage/dsm_impl.h
@@ -38,8 +38,9 @@
 #define USE_DSM_MMAP
 #endif
 
-/* GUC. */
+/* GUCs. */
 extern int	dynamic_shared_memory_type;
+extern int	dynamic_shared_memory_segments_per_backend;
 
 /*
  * Directory for on-disk state.
-- 
2.21.0

