From: Robert Haas Date: Mon, 10 Mar 2014 18:04:47 +0000 (-0400) Subject: Allow dynamic shared memory segments to be kept until shutdown. X-Git-Tag: REL9_4_BETA1~354 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8722017bbcbc95e311bbaa6d21cd028e296e5e35;p=postgresql Allow dynamic shared memory segments to be kept until shutdown. Amit Kapila, reviewed by Kyotaro Horiguchi, with some further changes by me. --- diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c index 31e592e06e..232c099c18 100644 --- a/src/backend/storage/ipc/dsm.c +++ b/src/backend/storage/ipc/dsm.c @@ -885,6 +885,33 @@ dsm_keep_mapping(dsm_segment *seg) } } +/* + * Keep a dynamic shared memory segment until postmaster shutdown. + * + * This function should not be called more than once per segment; + * on Windows, doing so will create unnecessary handles which will + * consume system resources to no benefit. + * + * Note that this function does not arrange for the current process to + * keep the segment mapped indefinitely; if that behavior is desired, + * dsm_keep_mapping() should be used from each process that needs to + * retain the mapping. + */ +void +dsm_keep_segment(dsm_segment *seg) +{ + /* + * Bump reference count for this segment in shared memory. This will + * ensure that even if there is no session which is attached to this + * segment, it will remain until postmaster shutdown. + */ + LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); + dsm_control->item[seg->control_slot].refcnt++; + LWLockRelease(DynamicSharedMemoryControlLock); + + dsm_impl_keep_segment(seg->handle, seg->impl_private); +} + /* * Find an existing mapping for a shared memory segment, if there is one. */ diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index a8d8a64afb..745ff23a8d 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -67,6 +67,7 @@ #include "storage/fd.h" #include "utils/guc.h" #include "utils/memutils.h" +#include "postmaster/postmaster.h" #ifdef USE_DSM_POSIX static bool dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, @@ -113,6 +114,8 @@ int dynamic_shared_memory_type; /* Size of buffer to be used for zero-filling. */ #define ZBUFFER_SIZE 8192 +#define SEGMENT_NAME_PREFIX "Global/PostgreSQL" + /*------ * Perform a low-level shared memory operation in a platform-specific way, * as dictated by the selected implementation. Each implementation is @@ -635,7 +638,7 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, * convention similar to main shared memory. We can change here once * issue mentioned in GetSharedMemName is resolved. */ - snprintf(name, 64, "Global/PostgreSQL.%u", handle); + snprintf(name, 64, "%s.%u", SEGMENT_NAME_PREFIX, handle); /* * Handle teardown cases. Since Windows automatically destroys the object @@ -982,6 +985,46 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, } #endif +/* + * Implementation-specific actions that must be performed when a segment + * is to be preserved until postmaster shutdown. + * + * Except on Windows, we don't need to do anything at all. But since Windows + * cleans up segments automatically when no references remain, we duplicate + * the segment handle into the postmaster process. The postmaster needn't + * do anything to receive the handle; Windows transfers it automatically. + */ +void +dsm_impl_keep_segment(dsm_handle handle, void *impl_private) +{ + switch (dynamic_shared_memory_type) + { +#ifdef USE_DSM_WINDOWS + case DSM_IMPL_WINDOWS: + { + HANDLE hmap; + + if (!DuplicateHandle(GetCurrentProcess(), impl_private, + PostmasterHandle, &hmap, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + char name[64]; + + snprintf(name, 64, "%s.%u", SEGMENT_NAME_PREFIX, handle); + _dosmaperr(GetLastError()); + ereport(ERROR, + (errcode_for_dynamic_shared_memory(), + errmsg("could not duplicate handle for \"%s\": %m", + name))); + } + break; + } +#endif + default: + break; + } +} + static int errcode_for_dynamic_shared_memory() { diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h index 46d3cbdd8a..03dd7679ff 100644 --- a/src/include/storage/dsm.h +++ b/src/include/storage/dsm.h @@ -30,6 +30,7 @@ extern void dsm_detach(dsm_segment *seg); /* Resource management functions. */ extern void dsm_keep_mapping(dsm_segment *seg); +extern void dsm_keep_segment(dsm_segment *seg); extern dsm_segment *dsm_find_mapping(dsm_handle h); /* Informational functions. */ diff --git a/src/include/storage/dsm_impl.h b/src/include/storage/dsm_impl.h index f2d0c64fc0..fda551489f 100644 --- a/src/include/storage/dsm_impl.h +++ b/src/include/storage/dsm_impl.h @@ -72,4 +72,7 @@ extern bool dsm_impl_op(dsm_op op, dsm_handle handle, Size request_size, /* Some implementations cannot resize segments. Can this one? */ extern bool dsm_impl_can_resize(void); +/* Implementation-dependent actions required to keep segment until shudown. */ +extern void dsm_impl_keep_segment(dsm_handle handle, void *impl_private); + #endif /* DSM_IMPL_H */