From 12968cf4085409c50f70c6643d92befdb34008f6 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 19 Mar 2015 13:02:16 -0400 Subject: [PATCH] Add flags argument to dsm_create. Right now, there's only one flag, DSM_CREATE_NULL_IF_MAXSEGMENTS, which suppresses the error that would normally be thrown when the maximum number of segments already exists, instead returning NULL. It might be useful to add more flags in the future, such as one to ignore allocation errors, but I haven't done that here. --- src/backend/storage/ipc/dsm.c | 31 ++++++++++++++++++++++++++-- src/include/storage/dsm.h | 4 +++- 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 983d0fa744..d2b231f789 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 2bf12ce531..beee105a6b 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 195099095d..7f2f5fd3ff 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); -- 2.40.0