v20260407-0003-Various-adjustments-to-resizable-shmem-acc.nocfbot.patch
application/octet-stream
Filename: v20260407-0003-Various-adjustments-to-resizable-shmem-acc.nocfbot.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v20260407-0003
Subject: Various adjustments to resizable shmem accounting
| File | + | − |
|---|---|---|
| src/backend/storage/ipc/shmem.c | 63 | 48 |
| src/include/storage/shmem.h | 12 | 8 |
From 62d7a2a841494c12d1814eae5ab5788dfeb9d5c1 Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Tue, 7 Apr 2026 20:59:36 +0200
Subject: [PATCH v20260407 3/4] Various adjustments to resizable shmem
accounting
Instead of continuously falling back onto .size when .maximum_size
is 0, update the copied(!) options' .maximum_size with the value
of .size. This saves a compare operation per SHMEM_REQUEST_SPACE_SIZE()
evaluation, and simplifies which field to access for bound checks.
Similarly, .minimum_size is updated with an input of 0 meaning to
default to .size. A substitute Zero value of SHMEM_RESIZE_TO_ZERO
is used to allow users to resize the segment's memory usage to zero
bytes used.
It also reorders and deduplicates some error condition checks.
---
src/backend/storage/ipc/shmem.c | 111 ++++++++++++++++++--------------
src/include/storage/shmem.h | 20 +++---
2 files changed, 75 insertions(+), 56 deletions(-)
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 61808c7a8e5..12de6344cac 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -108,14 +108,19 @@
* In order to allocate resizable shared memory structures, set
* ShmemRequestStructOpts::maximum_size to the maximum size that the structure
* can grow to. The address space for the maximum size will be reserved at
- * startup, but memory is allocated or freed as the structure grows or shrinks
- * respectively. ShmemRequestStructOpts::size should be set to the initial size
- * of the structure, which is the amount of memory allocated at the startup.
- * Optionally, ShmemRequestStructOpts::minimum_size can be set to the minimum
- * size that the structure can shrink to. After startup, the structure can be
- * resized by calling ShmemResizeStruct() by passing it the ShmemStructDesc for
- * the structure and the new size. ShmemResizeStruct() enforces that the new
- * size is within [minimum_size, maximum_size].
+ * startup, whilst the backing memory is allocated or freed as the structure
+ * grows or shrinks respectively. ShmemRequestStructOpts::size should be set
+ * to the initial size of the structure at startup. Optionally,
+ * ShmemRequestStructOpts::minimum_size can be set to the minimum size that
+ * the structure can shrink to. A sentinel value of SHMEM_RESIZE_TO_ZERO can
+ * be used used to indicate the struct can scale its memory usage down to 0
+ * bytes; the natural 0 is assumed to be uninitialized and so will cause the
+ * minimum size to default to the value of ShmemRequestStructOpts::size, like
+ * ShmemRequestStructOpts::maximum_size.
+ * After startup, the structure can be resized by calling ShmemResizeStruct()
+ * by passing it the ShmemStructDesc for the structure and the new size.
+ * ShmemResizeStruct() enforces that the new size is within
+ * [minimum_size, maximum_size].
*
* While resizable structures can be created after the startup, the memory
* available for them is quite limited.
@@ -192,8 +197,7 @@ typedef struct
* resizable shmem, the maximum_size is ensured to be 0 i.e. all the structures
* are treated as fixed-size structures.
*/
-#define SHMEM_REQUEST_SPACE_SIZE(request) \
- ((request)->options->maximum_size > 0 ? (request)->options->maximum_size : (request)->options->size)
+#define SHMEM_REQUEST_SPACE_SIZE(request) ((request)->options->maximum_size)
static List *pending_shmem_requests;
@@ -371,70 +375,81 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
{
ShmemRequest *request;
+ /* Check that we're in the right state */
+ if (shmem_request_state != SRS_REQUESTING)
+ elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
+
/* Check the options */
if (options->name == NULL)
elog(ERROR, "shared memory request is missing 'name' option");
+ /*
+ * Sanitize the options input by populating min/max with their actual values.
+ *
+ * Note that minimum_size's zero-initialized value "not specified" conflicts
+ * with a natural value for "resize to zero", so "resize to zero" has its own
+ * sentinel value with SHMEM_RESIZE_TO_ZERO.
+ */
+ if (options->maximum_size == 0)
+ {
+ options->maximum_size = options->size;
+ Assert(options->minimum_size == 0);
+ }
+
+ if (options->minimum_size == 0)
+ options->minimum_size = options->size;
+ else if (options->minimum_size == SHMEM_RESIZE_TO_ZERO)
+ options->minimum_size = 0;
+
+ /* resizing shmem segment */
+ if (options->maximum_size != options->minimum_size)
+ {
#ifndef HAVE_RESIZABLE_SHMEM
- if (options->maximum_size > 0)
elog(ERROR, "resizable shared memory is not supported on this platform");
#else
- if (options->maximum_size > 0 && shared_memory_type != SHMEM_TYPE_MMAP)
- elog(ERROR, "resizable shared memory requires shared_memory_type = mmap");
+ if (shared_memory_type != SHMEM_TYPE_MMAP)
+ elog(ERROR, "resizable shared memory requires shared_memory_type = mmap");
#endif
-
- if (IsUnderPostmaster)
- {
- if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
- elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
- options->size, options->name);
- if (options->minimum_size < 0 && options->minimum_size != SHMEM_ATTACH_UNKNOWN_SIZE)
- elog(ERROR, "invalid minimum_size %zd for shared memory request for \"%s\"",
- options->minimum_size, options->name);
- if (options->maximum_size < 0 && options->maximum_size != SHMEM_ATTACH_UNKNOWN_SIZE)
- elog(ERROR, "invalid maximum_size %zd for shared memory request for \"%s\"",
- options->maximum_size, options->name);
}
- else
+
+ if (!IsUnderPostmaster)
{
if (options->size == SHMEM_ATTACH_UNKNOWN_SIZE)
elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
- if (options->size <= 0)
- elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
- options->size, options->name);
if (options->minimum_size == SHMEM_ATTACH_UNKNOWN_SIZE)
elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
- if (options->minimum_size < 0)
- elog(ERROR, "invalid minimum_size %zd for shared memory request for \"%s\"",
- options->minimum_size, options->name);
if (options->maximum_size == SHMEM_ATTACH_UNKNOWN_SIZE)
elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
- if (options->maximum_size < 0)
- elog(ERROR, "invalid maximum_size %zd for shared memory request for \"%s\"",
- options->maximum_size, options->name);
}
+ if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
+ elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
+ options->size, options->name);
+ if (options->minimum_size < 0 && options->minimum_size != SHMEM_ATTACH_UNKNOWN_SIZE)
+ elog(ERROR, "invalid minimum_size %zd for shared memory request for \"%s\"",
+ options->minimum_size, options->name);
+ if (options->maximum_size < 0 && options->maximum_size != SHMEM_ATTACH_UNKNOWN_SIZE)
+ elog(ERROR, "invalid maximum_size %zd for shared memory request for \"%s\"",
+ options->maximum_size, options->name);
+
if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
options->alignment, options->name);
- if (options->minimum_size > 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE &&
- options->minimum_size > options->size)
- elog(ERROR, "resizable shared memory structure \"%s\" should have minimum size (%zd) less than or equal to size (%zd)",
- options->name, options->minimum_size, options->size);
-
- if (options->maximum_size > 0 && options->size > options->maximum_size)
- elog(ERROR, "resizable shared memory structure \"%s\" should have maximum size (%zd) greater than size (%zd)",
- options->name, options->maximum_size, options->size);
-
- if (options->minimum_size > 0 && options->maximum_size > 0 &&
+ if (options->minimum_size != SHMEM_ATTACH_UNKNOWN_SIZE && options->maximum_size != SHMEM_ATTACH_UNKNOWN_SIZE &&
options->minimum_size > options->maximum_size)
elog(ERROR, "resizable shared memory structure \"%s\" should have minimum size (%zd) less than or equal to maximum size (%zd)",
options->name, options->minimum_size, options->maximum_size);
- /* Check that we're in the right state */
- if (shmem_request_state != SRS_REQUESTING)
- elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
+ if (options->minimum_size != SHMEM_ATTACH_UNKNOWN_SIZE && options->size != SHMEM_ATTACH_UNKNOWN_SIZE &&
+ options->minimum_size > options->size)
+ elog(ERROR, "resizable shared memory structure \"%s\" should have minimum size (%zd) less than or equal to size (%zd)",
+ options->name, options->minimum_size, options->size);
+
+ if (options->maximum_size != SHMEM_ATTACH_UNKNOWN_SIZE && options->size != SHMEM_ATTACH_UNKNOWN_SIZE &&
+ options->size > options->maximum_size)
+ elog(ERROR, "resizable shared memory structure \"%s\" should have size (%zd) less than or equal to maximum size (%zd)",
+ options->name, options->size, options->maximum_size);
/* Check that it's not already registered in this process */
foreach_ptr(ShmemRequest, existing, pending_shmem_requests)
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index f8ddb0dd7c0..2682704b3ef 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -58,18 +58,21 @@ typedef struct ShmemStructOpts
size_t alignment;
/*
- * Minimum size this structure can shrink to. Should be set to 0 for
- * fixed-size structures.
+ * Minimum size this structure can shrink to.
+ * When initialized to 0, it defaults to the value of the .size field; use
+ * SHMEM_RESIZE_TO_ZERO instead if you want your shmem allocation to be
+ * able to shrink to 'no memory usage'.
*/
ssize_t minimum_size;
/*
- * Maximum size this structure can grow upto in future. The memory is not
- * allocated right away but the corresponding address space is reserved so
- * that memory can be mapped to it when the structure grows. Typically
- * should be used for large resizable structures which need several pages
- * worth of contiguous memory. Should be set to 0 for fixed-size
- * structures.
+ * Maximum size this structure can grow up to in the future. The memory not
+ * required for .size is not allocated right away, but the corresponding
+ * address space is reserved so that memory can be mapped to it when the
+ * structure grows. Typically, this should be used for large resizable
+ * structures which need several pages worth of contiguous memory.
+ *
+ * When set to 0, it defaults to the value of the .size field.
*/
ssize_t maximum_size;
@@ -83,6 +86,7 @@ typedef struct ShmemStructOpts
} ShmemStructOpts;
#define SHMEM_ATTACH_UNKNOWN_SIZE (-1)
+#define SHMEM_RESIZE_TO_ZERO (-2)
/*
* Options for ShmemRequestHash()
--
2.50.1 (Apple Git-155)