Retry DSM control segment creation if Windows indicates access denied.
authorRobert Haas <[email protected]>
Tue, 20 Sep 2016 16:04:41 +0000 (12:04 -0400)
committerRobert Haas <[email protected]>
Tue, 20 Sep 2016 16:04:41 +0000 (12:04 -0400)
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>

src/backend/storage/ipc/dsm_impl.c

index 99051f02c8c7c4dc6162bfff2ea1a54978e834ed..7122c4abe000368b7827c2fa963d068eba9f4db0 100644 (file)
@@ -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
    {