On Mon, May 14, 2007 at 09:34:05AM -0400, Andrew Dunstan wrote:
> 
> 
> Magnus Hagander wrote:
> >On Mon, May 14, 2007 at 09:02:10AM -0400, Tom Lane wrote:
> >  
> >>Magnus Hagander <[EMAIL PROTECTED]> writes:
> >>    
> >>>If all we want to do is add a check that prevents two servers to start on
> >>>the same port, we could do that trivially in a win32 specific way (since
> >>>we'll never have unix sockets there). Just create an object in the global
> >>>namespace named postgresql.interlock.<portnumber> or such a thing.
> >>>      
> >>Does it go away automatically on postmaster crash?
> >>    
> >
> >Yes.
> >
> >
> >  
> 
> Then I think it's worth adding, and I'd argue that as a low risk safety 
> measure we should allow it to sneak into 8.3. I'm assuming the code 
> involved will be quite small.

Yes, see attached.

BTW, did you mean 8.2? One typical case where this could happen is in an
upgrade scenario, I think...

//Magnus

Index: src/backend/libpq/pqcomm.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/libpq/pqcomm.c,v
retrieving revision 1.191
diff -c -r1.191 pqcomm.c
*** src/backend/libpq/pqcomm.c  3 Mar 2007 19:32:54 -0000       1.191
--- src/backend/libpq/pqcomm.c  14 May 2007 13:52:05 -0000
***************
*** 261,266 ****
--- 261,291 ----
                snprintf(portNumberStr, sizeof(portNumberStr), "%d", 
portNumber);
                service = portNumberStr;
        }
+ #ifdef WIN32
+       /* Win32 doesn't have Unix sockets, but will allow multiple processes
+        * to listen on the same port. This interlock is to prevent that.
+        */
+       {
+               char mutexName[64];
+               HANDLE mutex;
+ 
+               sprintf(mutexName,"postgresql.interlock.%i", portNumber);
+               mutex = CreateMutex(NULL, FALSE, mutexName);
+               if (mutex == NULL)
+                       ereport(FATAL,
+                                       (errmsg_internal("could not create 
interlocking mutex: %li",
+                                       GetLastError())));
+ 
+               if (GetLastError() == ERROR_ALREADY_EXISTS)
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_LOCK_FILE_EXISTS),
+                                        errmsg("interlock mutex \"%s\" already 
exists", mutexName),
+                                        errhint("Is another postgres listening 
on port %i", portNumber)));
+ 
+               /* Intentionally leak the handle until process exit, so the 
mutex
+                * isn't freed. It will be automatically freed when the process 
exits. */
+       }
+ #endif
  
        ret = pg_getaddrinfo_all(hostName, service, &hint, &addrs);
        if (ret || !addrs)
---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Reply via email to