diff options
-rw-r--r-- | src/backend/storage/ipc/dsm.c | 31 | ||||
-rw-r--r-- | src/include/storage/dsm.h | 4 | ||||
-rw-r--r-- | src/test/modules/test_shm_mq/setup.c | 2 |
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); |