Refactor ListenSocket array.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 5 Oct 2023 12:05:25 +0000 (15:05 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 5 Oct 2023 12:05:25 +0000 (15:05 +0300)
Keep track of the used size of the array. That avoids looping through
the whole array in a few places. It doesn't matter from a performance
point of view since the array is small anyway, but this feels less
surprising and is a little less code. Now that we have an explicit
NumListenSockets variable that is statically initialized to 0, we
don't need the loop to initialize the array.

Allocate the array in PostmasterContext. The array isn't needed in
child processes, so this allows reusing that memory. We could easily
make the array resizable now, but we haven't heard any complaints
about the current 64 sockets limit.

Discussion: https://www.postgresql.org/message-id/7bb7ad65-a018-2419-742f-fa5fd877d338@iki.fi

src/backend/libpq/pqcomm.c
src/backend/postmaster/postmaster.c
src/include/libpq/libpq.h

index 8d217b06455d405094bb28310dc0fd45b5153503..522584e5978a15d617dc8428a839b5c49864d6df 100644 (file)
@@ -311,16 +311,17 @@ socket_close(int code, Datum arg)
  * specified.  For TCP ports, hostName is either NULL for all interfaces or
  * the interface to listen on, and unixSocketDir is ignored (can be NULL).
  *
- * Successfully opened sockets are added to the ListenSocket[] array (of
- * length MaxListen), at the first position that isn't PGINVALID_SOCKET.
+ * Successfully opened sockets are appended to the ListenSockets[] array.  On
+ * entry, *NumListenSockets holds the number of elements currently in the
+ * array, and it is updated to reflect the opened sockets.  MaxListen is the
+ * allocated size of the array.
  *
  * RETURNS: STATUS_OK or STATUS_ERROR
  */
-
 int
 StreamServerPort(int family, const char *hostName, unsigned short portNumber,
                                 const char *unixSocketDir,
-                                pgsocket ListenSocket[], int MaxListen)
+                                pgsocket ListenSockets[], int *NumListenSockets, int MaxListen)
 {
        pgsocket        fd;
        int                     err;
@@ -335,7 +336,6 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
        struct addrinfo *addrs = NULL,
                           *addr;
        struct addrinfo hint;
-       int                     listen_index = 0;
        int                     added = 0;
        char            unixSocketPath[MAXPGPATH];
 #if !defined(WIN32) || defined(IPV6_V6ONLY)
@@ -401,12 +401,7 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
                }
 
                /* See if there is still room to add 1 more socket. */
-               for (; listen_index < MaxListen; listen_index++)
-               {
-                       if (ListenSocket[listen_index] == PGINVALID_SOCKET)
-                               break;
-               }
-               if (listen_index >= MaxListen)
+               if (*NumListenSockets == MaxListen)
                {
                        ereport(LOG,
                                        (errmsg("could not bind to all requested addresses: MAXLISTEN (%d) exceeded",
@@ -573,7 +568,8 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
                                        (errmsg("listening on %s address \"%s\", port %d",
                                                        familyDesc, addrDesc, (int) portNumber)));
 
-               ListenSocket[listen_index] = fd;
+               ListenSockets[*NumListenSockets] = fd;
+               (*NumListenSockets)++;
                added++;
        }
 
index 54e9bfb8c487ad00cf9528517e66c3927f5ae3b1..0d876c61fd70d7bd6e80c3902f6e65605acf07ad 100644 (file)
@@ -227,7 +227,8 @@ int                 ReservedConnections;
 
 /* The socket(s) we're listening to. */
 #define MAXLISTEN      64
-static pgsocket ListenSocket[MAXLISTEN];
+static int     NumListenSockets = 0;
+static pgsocket *ListenSockets = NULL;
 
 /* still more option variables */
 bool           EnableSSL = false;
@@ -588,7 +589,6 @@ PostmasterMain(int argc, char *argv[])
        int                     status;
        char       *userDoption = NULL;
        bool            listen_addr_saved = false;
-       int                     i;
        char       *output_config_variable = NULL;
 
        InitProcessGlobals();
@@ -1142,17 +1142,6 @@ PostmasterMain(int argc, char *argv[])
                                 errmsg("could not remove file \"%s\": %m",
                                                LOG_METAINFO_DATAFILE)));
 
-       /*
-        * Initialize input sockets.
-        *
-        * Mark them all closed, and set up an on_proc_exit function that's
-        * charged with closing the sockets again at postmaster shutdown.
-        */
-       for (i = 0; i < MAXLISTEN; i++)
-               ListenSocket[i] = PGINVALID_SOCKET;
-
-       on_proc_exit(CloseServerPorts, 0);
-
        /*
         * If enabled, start up syslogger collection subprocess
         */
@@ -1187,7 +1176,13 @@ PostmasterMain(int argc, char *argv[])
 
        /*
         * Establish input sockets.
+        *
+        * First set up an on_proc_exit function that's charged with closing the
+        * sockets again at postmaster shutdown.
         */
+       ListenSockets = palloc(MAXLISTEN * sizeof(pgsocket));
+       on_proc_exit(CloseServerPorts, 0);
+
        if (ListenAddresses)
        {
                char       *rawstring;
@@ -1216,12 +1211,16 @@ PostmasterMain(int argc, char *argv[])
                                status = StreamServerPort(AF_UNSPEC, NULL,
                                                                                  (unsigned short) PostPortNumber,
                                                                                  NULL,
-                                                                                 ListenSocket, MAXLISTEN);
+                                                                                 ListenSockets,
+                                                                                 &NumListenSockets,
+                                                                                 MAXLISTEN);
                        else
                                status = StreamServerPort(AF_UNSPEC, curhost,
                                                                                  (unsigned short) PostPortNumber,
                                                                                  NULL,
-                                                                                 ListenSocket, MAXLISTEN);
+                                                                                 ListenSockets,
+                                                                                 &NumListenSockets,
+                                                                                 MAXLISTEN);
 
                        if (status == STATUS_OK)
                        {
@@ -1249,7 +1248,7 @@ PostmasterMain(int argc, char *argv[])
 
 #ifdef USE_BONJOUR
        /* Register for Bonjour only if we opened TCP socket(s) */
-       if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET)
+       if (enable_bonjour && NumListenSockets > 0)
        {
                DNSServiceErrorType err;
 
@@ -1313,7 +1312,9 @@ PostmasterMain(int argc, char *argv[])
                        status = StreamServerPort(AF_UNIX, NULL,
                                                                          (unsigned short) PostPortNumber,
                                                                          socketdir,
-                                                                         ListenSocket, MAXLISTEN);
+                                                                         ListenSockets,
+                                                                         &NumListenSockets,
+                                                                         MAXLISTEN);
 
                        if (status == STATUS_OK)
                        {
@@ -1339,7 +1340,7 @@ PostmasterMain(int argc, char *argv[])
        /*
         * check that we have some socket to listen on
         */
-       if (ListenSocket[0] == PGINVALID_SOCKET)
+       if (NumListenSockets == 0)
                ereport(FATAL,
                                (errmsg("no socket created for listening")));
 
@@ -1487,14 +1488,9 @@ CloseServerPorts(int status, Datum arg)
         * before we remove the postmaster.pid lockfile; otherwise there's a race
         * condition if a new postmaster wants to re-use the TCP port number.
         */
-       for (i = 0; i < MAXLISTEN; i++)
-       {
-               if (ListenSocket[i] != PGINVALID_SOCKET)
-               {
-                       StreamClose(ListenSocket[i]);
-                       ListenSocket[i] = PGINVALID_SOCKET;
-               }
-       }
+       for (i = 0; i < NumListenSockets; i++)
+               StreamClose(ListenSockets[i]);
+       NumListenSockets = 0;
 
        /*
         * Next, remove any filesystem entries for Unix sockets.  To avoid race
@@ -1695,29 +1691,19 @@ DetermineSleepTime(void)
 static void
 ConfigurePostmasterWaitSet(bool accept_connections)
 {
-       int                     nsockets;
-
        if (pm_wait_set)
                FreeWaitEventSet(pm_wait_set);
        pm_wait_set = NULL;
 
-       /* How many server sockets do we need to wait for? */
-       nsockets = 0;
-       if (accept_connections)
-       {
-               while (nsockets < MAXLISTEN &&
-                          ListenSocket[nsockets] != PGINVALID_SOCKET)
-                       ++nsockets;
-       }
-
-       pm_wait_set = CreateWaitEventSet(CurrentMemoryContext, 1 + nsockets);
+       pm_wait_set = CreateWaitEventSet(CurrentMemoryContext,
+                                                                        accept_connections ? (1 + NumListenSockets) : 1);
        AddWaitEventToSet(pm_wait_set, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch,
                                          NULL);
 
        if (accept_connections)
        {
-               for (int i = 0; i < nsockets; i++)
-                       AddWaitEventToSet(pm_wait_set, WL_SOCKET_ACCEPT, ListenSocket[i],
+               for (int i = 0; i < NumListenSockets; i++)
+                       AddWaitEventToSet(pm_wait_set, WL_SOCKET_ACCEPT, ListenSockets[i],
                                                          NULL, NULL);
        }
 }
@@ -2579,14 +2565,11 @@ ClosePostmasterPorts(bool am_syslogger)
         * EXEC_BACKEND mode.
         */
 #ifndef EXEC_BACKEND
-       for (int i = 0; i < MAXLISTEN; i++)
-       {
-               if (ListenSocket[i] != PGINVALID_SOCKET)
-               {
-                       StreamClose(ListenSocket[i]);
-                       ListenSocket[i] = PGINVALID_SOCKET;
-               }
-       }
+       for (int i = 0; i < NumListenSockets; i++)
+               StreamClose(ListenSockets[i]);
+       NumListenSockets = 0;
+       pfree(ListenSockets);
+       ListenSockets = NULL;
 #endif
 
        /*
index 50fc781f471f3e4d271b186bab82dd81779e6b8a..a6104d8cd02bbdc6c8d471c05145797d41fbb619 100644 (file)
@@ -66,7 +66,7 @@ extern PGDLLIMPORT WaitEventSet *FeBeWaitSet;
 
 extern int     StreamServerPort(int family, const char *hostName,
                                                         unsigned short portNumber, const char *unixSocketDir,
-                                                        pgsocket ListenSocket[], int MaxListen);
+                                                        pgsocket ListenSocket[], int *NumListenSockets, int MaxListen);
 extern int     StreamConnection(pgsocket server_fd, Port *port);
 extern void StreamClose(pgsocket sock);
 extern void TouchSocketFiles(void);