]> granicus.if.org Git - postgresql/commitdiff
Allow dynamic shared memory segments to be kept until shutdown.
authorRobert Haas <rhaas@postgresql.org>
Mon, 10 Mar 2014 18:04:47 +0000 (14:04 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 10 Mar 2014 18:04:47 +0000 (14:04 -0400)
Amit Kapila, reviewed by Kyotaro Horiguchi, with some further
changes by me.

src/backend/storage/ipc/dsm.c
src/backend/storage/ipc/dsm_impl.c
src/include/storage/dsm.h
src/include/storage/dsm_impl.h

index 31e592e06e7b74d1f5da052424110c9eb0fe3770..232c099c18acc88697f36664d268d8844d3659f8 100644 (file)
@@ -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.
  */
index a8d8a64afbd4c9dc4a505ae7603a71dee396cf59..745ff23a8d8c02a573984d755a723aa7fcd762f1 100644 (file)
@@ -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()
 {
index 46d3cbdd8ab6cd6ba576ef86b611025b8eec404d..03dd7679ffde8d4538a328408c38f470feecd9b2 100644 (file)
@@ -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. */
index f2d0c64fc05e4af02b63e5debd3c29ea51d947f0..fda551489f7aa41fc1a7a378661fbf4095d08b48 100644 (file)
@@ -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 */