summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas2014-03-10 18:04:47 +0000
committerRobert Haas2014-03-10 18:04:47 +0000
commit8722017bbcbc95e311bbaa6d21cd028e296e5e35 (patch)
tree3fe4426fd8888edcde9360f553f2c290c2bb1dd8
parent5a991ef8692ed0d170b44958a81a6bd70e90585c (diff)
Allow dynamic shared memory segments to be kept until shutdown.
Amit Kapila, reviewed by Kyotaro Horiguchi, with some further changes by me.
-rw-r--r--src/backend/storage/ipc/dsm.c27
-rw-r--r--src/backend/storage/ipc/dsm_impl.c45
-rw-r--r--src/include/storage/dsm.h1
-rw-r--r--src/include/storage/dsm_impl.h3
4 files changed, 75 insertions, 1 deletions
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index 31e592e06e7..232c099c18a 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -886,6 +886,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.
*/
dsm_segment *
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index a8d8a64afbd..745ff23a8d8 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 46d3cbdd8ab..03dd7679ffd 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 f2d0c64fc05..fda551489f7 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 */