Commit 84b1c63a authored by Thomas Munro's avatar Thomas Munro

Preallocate some DSM space at startup.

Create an optional region in the main shared memory segment that can be
used to acquire and release "fast" DSM segments, and can benefit from
huge pages allocated at cluster startup time, if configured.  Fall back
to the existing mechanisms when that space is full.  The size is
controlled by a new GUC min_dynamic_shared_memory, defaulting to 0.

Main region DSM segments initially contain whatever garbage the memory
held last time they were used, rather than zeroes.  That change revealed
that DSA areas failed to initialize themselves correctly in memory that
wasn't zeroed first, so fix that problem.

Discussion: https://postgr.es/m/CA%2BhUKGLAE2QBv-WgGp%2BD9P_J-%3Dyne3zof9nfMaqq1h3EGHFXYQ%40mail.gmail.com
parent 7b1110d2
......@@ -1906,6 +1906,30 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
<varlistentry id="guc-min-dynamic-shared-memory" xreflabel="min_dynamic_shared_memory">
<term><varname>min_dynamic_shared_memory</varname> (<type>integer</type>)
<indexterm>
<primary><varname>min_dynamic_shared_memory</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Specifies the amount of memory that should be allocated at server
startup time for use by parallel queries. When this memory region is
insufficient or exhausted by concurrent queries, new parallel queries
try to allocate extra shared memory temporarily from the operating
system using the method configured with
<varname>dynamic_shared_memory_type</varname>, which may be slower due
to memory management overheads. Memory that is allocated at startup
time with <varname>min_dynamic_shared_memory</varname> is affected by
the <varname>huge_pages</varname> setting on operating systems where
that is supported, and may be more likely to benefit from larger pages
on operating systems where that is managed automatically.
The default value is <literal>0</literal> (none).
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
......
This diff is collapsed.
......@@ -113,6 +113,9 @@ const struct config_enum_entry dynamic_shared_memory_options[] = {
/* Implementation selector. */
int dynamic_shared_memory_type;
/* Amount of space reserved for DSM segments in the main area. */
int min_dynamic_shared_memory;
/* Size of buffer to be used for zero-filling. */
#define ZBUFFER_SIZE 8192
......
......@@ -120,6 +120,7 @@ CreateSharedMemoryAndSemaphores(void)
size = add_size(size, SpinlockSemaSize());
size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
sizeof(ShmemIndexEnt)));
size = add_size(size, dsm_estimate_size());
size = add_size(size, BufferShmemSize());
size = add_size(size, LockShmemSize());
size = add_size(size, PredicateLockShmemSize());
......@@ -209,6 +210,8 @@ CreateSharedMemoryAndSemaphores(void)
*/
InitShmemIndex();
dsm_shmem_init();
/*
* Set up xlog, clog, and buffers
*/
......
......@@ -2231,6 +2231,17 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
{
{"min_dynamic_shared_memory", PGC_POSTMASTER, RESOURCES_MEM,
gettext_noop("Amount of dynamic shared memory reserved at startup."),
NULL,
GUC_UNIT_MB
},
&min_dynamic_shared_memory,
0, 0, Min(INT_MAX, SIZE_MAX / 1024 / 1024),
NULL, NULL, NULL
},
/*
* We sometimes multiply the number of shared buffers by two without
* checking for overflow, so we mustn't allow more than INT_MAX / 2.
......
......@@ -148,6 +148,7 @@
# windows
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
# - Disk -
......
......@@ -1223,6 +1223,7 @@ create_internal(void *place, size_t size,
* space.
*/
control = (dsa_area_control *) place;
memset(place, 0, sizeof(*control));
control->segment_header.magic =
DSA_SEGMENT_HEADER_MAGIC ^ control_handle ^ 0;
control->segment_header.next = DSA_SEGMENT_INDEX_NONE;
......@@ -1233,14 +1234,10 @@ create_internal(void *place, size_t size,
control->handle = control_handle;
control->max_total_segment_size = (size_t) -1;
control->total_segment_size = size;
memset(&control->segment_handles[0], 0,
sizeof(dsm_handle) * DSA_MAX_SEGMENTS);
control->segment_handles[0] = control_handle;
for (i = 0; i < DSA_NUM_SEGMENT_BINS; ++i)
control->segment_bins[i] = DSA_SEGMENT_INDEX_NONE;
control->high_segment_index = 0;
control->refcnt = 1;
control->freed_segment_counter = 0;
control->lwlock_tranche_id = tranche_id;
/*
......
......@@ -29,6 +29,9 @@ extern void dsm_postmaster_startup(struct PGShmemHeader *);
extern void dsm_backend_shutdown(void);
extern void dsm_detach_all(void);
extern size_t dsm_estimate_size(void);
extern void dsm_shmem_init(void);
#ifdef EXEC_BACKEND
extern void dsm_set_control_handle(dsm_handle h);
#endif
......
......@@ -40,6 +40,7 @@
/* GUC. */
extern int dynamic_shared_memory_type;
extern int min_dynamic_shared_memory;
/*
* Directory for on-disk state.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment