diff options
Diffstat (limited to 'src/backend/storage/ipc/dsm.c')
-rw-r--r-- | src/backend/storage/ipc/dsm.c | 31 |
1 files changed, 29 insertions, 2 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; |