On 29/08/2023 09:21, Heikki Linnakangas wrote:
Thinking about this some more, the ListenSockets array is a bit silly anyway. We fill the array starting from index 0, always append to the end, and never remove entries from it. It would seem more straightforward to keep track of the used size of the array. Currently we always loop through the unused parts too, and e.g. ConfigurePostmasterWaitSet() needs to walk the array to count how many elements are in use.
Like this. -- Heikki Linnakangas Neon (https://neon.tech)
From 796280f07dd5dbf50897c9895715ab5e2dbf187b Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas <heikki.linnakan...@iki.fi> Date: Tue, 29 Aug 2023 09:53:08 +0300 Subject: [PATCH 1/1] Refactor ListenSocket array. 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. --- src/backend/libpq/pqcomm.c | 18 +++---- src/backend/postmaster/postmaster.c | 76 +++++++++++------------------ src/include/libpq/libpq.h | 2 +- 3 files changed, 36 insertions(+), 60 deletions(-) diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 8d217b0645..48ae7704fb 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -311,8 +311,9 @@ 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. The + * current size of the array is *NumListenSockets, it is updated to reflect + * the opened sockets. MaxListen is the allocated size of the array. * * RETURNS: STATUS_OK or STATUS_ERROR */ @@ -320,7 +321,7 @@ socket_close(int code, Datum arg) 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++; } diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index d7bfb28ff3..2659329b82 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -226,7 +226,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; @@ -587,7 +588,6 @@ PostmasterMain(int argc, char *argv[]) int status; char *userDoption = NULL; bool listen_addr_saved = false; - int i; char *output_config_variable = NULL; InitProcessGlobals(); @@ -1141,17 +1141,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 */ @@ -1186,7 +1175,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; @@ -1215,12 +1210,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) { @@ -1248,7 +1247,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; @@ -1312,7 +1311,9 @@ PostmasterMain(int argc, char *argv[]) status = StreamServerPort(AF_UNIX, NULL, (unsigned short) PostPortNumber, socketdir, - ListenSocket, MAXLISTEN); + ListenSockets, + &NumListenSockets, + MAXLISTEN); if (status == STATUS_OK) { @@ -1338,7 +1339,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"))); @@ -1486,14 +1487,8 @@ 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]); /* * Next, remove any filesystem entries for Unix sockets. To avoid race @@ -1694,29 +1689,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, + 1 + (accept_connections ? NumListenSockets : 0)); 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); } } @@ -2578,14 +2563,9 @@ 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; #endif /* diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index 50fc781f47..a6104d8cd0 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -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); -- 2.39.2