aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/storage/ipc/dsm.c31
-rw-r--r--src/include/storage/dsm.h4
-rw-r--r--src/test/modules/test_shm_mq/setup.c2
3 files changed, 33 insertions, 4 deletions
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index 983d0fa744f..d2b231f7895 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -454,9 +454,9 @@ dsm_set_control_handle(dsm_handle h)
* Create a new dynamic shared memory segment.
*/
dsm_segment *
-dsm_create(Size size)
+dsm_create(Size size, int flags)
{
- dsm_segment *seg = dsm_create_descriptor();
+ dsm_segment *seg;
uint32 i;
uint32 nitems;
@@ -466,6 +466,21 @@ dsm_create(Size size)
if (!dsm_init_done)
dsm_backend_startup();
+ /*
+ * If we've been instructed to return NULL when it's not possible to
+ * register another segment, check whether we seem to be at the limit.
+ * This allows us to avoid the overhead of creating a new segment only to
+ * immediately destroy it again. Since we don't take the lock here, the
+ * value we read might be slightly stale, but the remote possibility of
+ * an unnecessary failure here shouldn't trouble anyone too much.
+ */
+ if ((flags & DSM_CREATE_NULL_IF_MAXSEGMENTS) != 0
+ && dsm_control->nitems >= dsm_control->maxitems)
+ return NULL;
+
+ /* Create a new segment descriptor. */
+ seg = dsm_create_descriptor();
+
/* Loop until we find an unused segment identifier. */
for (;;)
{
@@ -496,9 +511,21 @@ dsm_create(Size size)
/* Verify that we can support an additional mapping. */
if (nitems >= dsm_control->maxitems)
+ {
+ if ((flags & DSM_CREATE_NULL_IF_MAXSEGMENTS) != 0)
+ {
+ dsm_impl_op(DSM_OP_DESTROY, seg->handle, 0, &seg->impl_private,
+ &seg->mapped_address, &seg->mapped_size, WARNING);
+ if (seg->resowner != NULL)
+ ResourceOwnerForgetDSM(seg->resowner, seg);
+ dlist_delete(&seg->node);
+ pfree(seg);
+ return NULL;
+ }
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("too many dynamic shared memory segments")));
+ }
/* Enter the handle into a new array slot. */
dsm_control->item[nitems].handle = seg->handle;
diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h
index 2bf12ce5313..beee105a6bd 100644
--- a/src/include/storage/dsm.h
+++ b/src/include/storage/dsm.h
@@ -17,6 +17,8 @@
typedef struct dsm_segment dsm_segment;
+#define DSM_CREATE_NULL_IF_MAXSEGMENTS 0x0001
+
/* Startup and shutdown functions. */
struct PGShmemHeader; /* avoid including pg_shmem.h */
extern void dsm_cleanup_using_control_segment(dsm_handle old_control_handle);
@@ -29,7 +31,7 @@ extern void dsm_set_control_handle(dsm_handle h);
#endif
/* Functions that create, update, or remove mappings. */
-extern dsm_segment *dsm_create(Size size);
+extern dsm_segment *dsm_create(Size size, int flags);
extern dsm_segment *dsm_attach(dsm_handle h);
extern void *dsm_resize(dsm_segment *seg, Size size);
extern void *dsm_remap(dsm_segment *seg);
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 195099095de..7f2f5fd3ff7 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -125,7 +125,7 @@ setup_dynamic_shared_memory(int64 queue_size, int nworkers,
segsize = shm_toc_estimate(&e);
/* Create the shared memory segment and establish a table of contents. */
- seg = dsm_create(shm_toc_estimate(&e));
+ seg = dsm_create(shm_toc_estimate(&e), 0);
toc = shm_toc_create(PG_TEST_SHM_MQ_MAGIC, dsm_segment_address(seg),
segsize);