diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c index 327d685..efbd2dd 100644 --- a/src/backend/storage/ipc/dsm.c +++ b/src/backend/storage/ipc/dsm.c @@ -886,6 +886,40 @@ dsm_keep_mapping(dsm_segment *seg) } /* + * Keep a dynamic shared memory segment until end of postmaster. + * + * This function should not be called more than once per segment, + * calling it more number of times will create unnecessary handles + * which will consume more memory for no good reason. Though this + * behaviour is specific to windows, there is no real benefit for + * calling it more than once on other platforms either. + * + * By default, segments are owned by the current resource owner, + * which typically means they stick around for the duration of the + * current query only. + */ +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 stay till postmaster lifetime. + */ + LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE); + dsm_control->item[seg->control_slot].refcnt++; + LWLockRelease(DynamicSharedMemoryControlLock); + + dsm_copy_impl_handle(seg->impl_private, seg->handle); + + if (seg->resowner != NULL) + { + ResourceOwnerForgetDSM(seg->resowner, seg); + seg->resowner = NULL; + } +} + +/* * Find an existing mapping for a shared memory segment, if there is one. */ dsm_segment * diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index a8d8a64..b6bc93a 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,48 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, } #endif +#ifdef WIN32 +/* + * The purpose of this function is to duplicate segment handle for + * postmaster process, as it automatically drops segment if all + * referring sessions end. Copying segment handle for postmaster + * process ensures that it will retain the segment for postmaster + * lifetime. This is a typical behavior for windows, other platforms + * don't need to make any such copy. + */ +void dsm_copy_impl_handle(void *impl_private, dsm_handle handle) +{ + 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 retain segment \"%s\" for postmaster lifetime: %m", + name))); + } +} +#else +/* + * For non-windows platform, this function is no-op. + */ +void dsm_copy_impl_handle(void *impl_private, dsm_handle handle) +{ + /* no-op */ +} + +#endif + static int errcode_for_dynamic_shared_memory() { diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h index 71901bf..16afef3 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 f2d0c64..bfed25d 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); +/* create a copy of implementation specific handle in postmaster process. */ +extern void dsm_copy_impl_handle(void *impl_private, dsm_handle handle); + #endif /* DSM_IMPL_H */