summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2016-09-20 12:04:41 -0400
committerRobert Haas <rhaas@postgresql.org>2016-09-20 12:12:36 -0400
commitc23b2523d3fcc09524e6720d7c2558ba1ee6c239 (patch)
tree4e59a440f14fd04508bbaaacc6274bbd063184d1
parent476945c451d675cc31cd89bce202b775cef45a8e (diff)
Retry DSM control segment creation if Windows indicates access denied.
Otherwise, attempts to run multiple postmasters running on the same machine may fail, because Windows sometimes returns ERROR_ACCESS_DENIED rather than ERROR_ALREADY_EXISTS when there is an existing segment. Hitting this bug is much more likely because of another defect not fixed by this patch, namely that dsm_postmaster_startup() uses random() which returns the same value every time. But that's not a reason not to fix this. Kyotaro Horiguchi and Amit Kapila, reviewed by Michael Paquier Discussion: <CAA4eK1JyNdMeF-dgrpHozDecpDfsRZUtpCi+1AbtuEkfG3YooQ@mail.gmail.com>
-rw-r--r--src/backend/storage/ipc/dsm_impl.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index 35969c4501d..ff72d045ea5 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -671,6 +671,7 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size,
{
DWORD size_high;
DWORD size_low;
+ DWORD errcode;
/* Shifts >= the width of the type are undefined. */
#ifdef _WIN64
@@ -686,27 +687,31 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size,
size_high, /* Upper 32 bits of size */
size_low, /* Lower 32 bits of size */
name);
+
+ errcode = GetLastError();
+ if (errcode == ERROR_ALREADY_EXISTS || errcode == ERROR_ACCESS_DENIED)
+ {
+ /*
+ * On Windows, when the segment already exists, a handle for the
+ * existing segment is returned. We must close it before
+ * returning. However, if the existing segment is created by a
+ * service, then it returns ERROR_ACCESS_DENIED. We don't do
+ * _dosmaperr here, so errno won't be modified.
+ */
+ if (hmap)
+ CloseHandle(hmap);
+ return false;
+ }
+
if (!hmap)
{
- _dosmaperr(GetLastError());
+ _dosmaperr(errcode);
ereport(elevel,
(errcode_for_dynamic_shared_memory(),
errmsg("could not create shared memory segment \"%s\": %m",
name)));
return false;
}
- _dosmaperr(GetLastError());
- if (errno == EEXIST)
- {
- /*
- * On Windows, when the segment already exists, a handle for the
- * existing segment is returned. We must close it before
- * returning. We don't do _dosmaperr here, so errno won't be
- * modified.
- */
- CloseHandle(hmap);
- return false;
- }
}
else
{