Skip to content

Commit 30aeda4

Browse files
committed
Include the first valid listen address in pg_ctl to improve server start
"wait" detection and add postmaster start time to help determine if the postmaster is actually using the specified data directory.
1 parent 39c8dd6 commit 30aeda4

File tree

7 files changed

+121
-62
lines changed

7 files changed

+121
-62
lines changed

doc/src/sgml/storage.sgml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ last started with</entry>
117117
<row>
118118
<entry><filename>postmaster.pid</></entry>
119119
<entry>A lock file recording the current postmaster process id (PID),
120-
cluster data directory, port number, Unix domain socket directory,
121-
and shared memory segment ID</entry>
120+
postmaster start time, cluster data directory, port number, user-specified
121+
Unix domain socket directory, first valid listen_address host, and
122+
shared memory segment ID</entry>
122123
</row>
123124

124125
</tbody>

src/backend/port/ipc_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ on_exit_reset(void)
104104
}
105105

106106
void
107-
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
107+
AddToLockFile(int target_line, const char *str)
108108
{
109109
}
110110

src/backend/port/sysv_shmem.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,17 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
198198
/* Register on-exit routine to detach new segment before deleting */
199199
on_shmem_exit(IpcMemoryDetach, PointerGetDatum(memAddress));
200200

201-
/* Record key and ID in lockfile for data directory. */
202-
RecordSharedMemoryInLockFile((unsigned long) memKey,
203-
(unsigned long) shmid);
201+
/*
202+
* Append record key and ID in lockfile for data directory. Format
203+
* to try to keep it the same length.
204+
*/
205+
{
206+
char line[32];
207+
208+
sprintf(line, "%9lu %9lu\n", (unsigned long) memKey,
209+
(unsigned long) shmid);
210+
AddToLockFile(LOCK_FILE_LINES, line);
211+
}
204212

205213
return memAddress;
206214
}

src/backend/postmaster/postmaster.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,8 @@ PostmasterMain(int argc, char *argv[])
483483
int status;
484484
char *userDoption = NULL;
485485
int i;
486-
486+
bool connection_line_output = false;
487+
487488
MyProcPid = PostmasterPid = getpid();
488489

489490
MyStartTime = time(NULL);
@@ -860,10 +861,22 @@ PostmasterMain(int argc, char *argv[])
860861
UnixSocketDir,
861862
ListenSocket, MAXLISTEN);
862863
else
864+
{
863865
status = StreamServerPort(AF_UNSPEC, curhost,
864866
(unsigned short) PostPortNumber,
865867
UnixSocketDir,
866868
ListenSocket, MAXLISTEN);
869+
/* must supply a valid listen_address for PQping() */
870+
if (!connection_line_output)
871+
{
872+
char line[MAXPGPATH + 2];
873+
874+
sprintf(line, "%s\n", curhost);
875+
AddToLockFile(LOCK_FILE_LINES - 1, line);
876+
connection_line_output = true;
877+
}
878+
}
879+
867880
if (status == STATUS_OK)
868881
success++;
869882
else
@@ -880,6 +893,10 @@ PostmasterMain(int argc, char *argv[])
880893
pfree(rawstring);
881894
}
882895

896+
/* Supply an empty listen_address line for PQping() */
897+
if (!connection_line_output)
898+
AddToLockFile(LOCK_FILE_LINES - 1, "\n");
899+
883900
#ifdef USE_BONJOUR
884901
/* Register for Bonjour only if we opened TCP socket(s) */
885902
if (enable_bonjour && ListenSocket[0] != PGINVALID_SOCKET)

src/backend/utils/init/miscinit.c

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,20 @@
4646

4747

4848
#define DIRECTORY_LOCK_FILE "postmaster.pid"
49-
49+
/*
50+
* The lock file contents are:
51+
*
52+
* line #
53+
* 1 pid
54+
* 2 postmaster start time
55+
* 3 data directory
56+
* 4 port #
57+
* 5 user-specified socket directory
58+
* (the lines below are added later)
59+
* 6 first valid listen_address
60+
* 7 shared memory key
61+
*/
62+
5063
ProcessingMode Mode = InitProcessing;
5164

5265
/* Note: we rely on this to initialize as zeroes */
@@ -678,7 +691,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
678691
bool isDDLock, const char *refName)
679692
{
680693
int fd;
681-
char buffer[MAXPGPATH * 2 + 256];
694+
char buffer[MAXPGPATH * 3 + 256];
682695
int ntries;
683696
int len;
684697
int encoded_pid;
@@ -845,11 +858,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
845858
if (isDDLock)
846859
{
847860
char *ptr = buffer;
848-
unsigned long id1,
849-
id2;
861+
unsigned long id1, id2;
850862
int lineno;
851863

852-
for (lineno = 1; lineno <= 4; lineno++)
864+
for (lineno = 1; lineno <= LOCK_FILE_LINES - 1; lineno++)
853865
{
854866
if ((ptr = strchr(ptr, '\n')) == NULL)
855867
{
@@ -893,9 +905,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
893905
/*
894906
* Successfully created the file, now fill it.
895907
*/
896-
snprintf(buffer, sizeof(buffer), "%d\n%s\n%d\n%s\n",
908+
snprintf(buffer, sizeof(buffer), "%d\n%ld\n%s\n%d\n%s\n",
897909
amPostmaster ? (int) my_pid : -((int) my_pid),
898-
DataDir, PostPortNumber, UnixSocketDir);
910+
(long) MyStartTime, DataDir, PostPortNumber,
911+
UnixSocketDir);
899912
errno = 0;
900913
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
901914
{
@@ -1004,24 +1017,19 @@ TouchSocketLockFile(void)
10041017
}
10051018
}
10061019

1020+
10071021
/*
1008-
* Append information about a shared memory segment to the data directory
1009-
* lock file.
1010-
*
1011-
* This may be called multiple times in the life of a postmaster, if we
1012-
* delete and recreate shmem due to backend crash. Therefore, be prepared
1013-
* to overwrite existing information. (As of 7.1, a postmaster only creates
1014-
* one shm seg at a time; but for the purposes here, if we did have more than
1015-
* one then any one of them would do anyway.)
1022+
* Add lines to the data directory lock file. This erases all following
1023+
* lines, but that is OK because lines are added in order.
10161024
*/
10171025
void
1018-
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
1026+
AddToLockFile(int target_line, const char *str)
10191027
{
10201028
int fd;
10211029
int len;
10221030
int lineno;
10231031
char *ptr;
1024-
char buffer[MAXPGPATH * 2 + 256];
1032+
char buffer[MAXPGPATH * 3 + 256];
10251033

10261034
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
10271035
if (fd < 0)
@@ -1048,7 +1056,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
10481056
* Skip over first four lines (PID, pgdata, portnum, socketdir).
10491057
*/
10501058
ptr = buffer;
1051-
for (lineno = 1; lineno <= 4; lineno++)
1059+
for (lineno = 1; lineno < target_line; lineno++)
10521060
{
10531061
if ((ptr = strchr(ptr, '\n')) == NULL)
10541062
{
@@ -1059,11 +1067,7 @@ RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
10591067
ptr++;
10601068
}
10611069

1062-
/*
1063-
* Append key information. Format to try to keep it the same length
1064-
* always (trailing junk won't hurt, but might confuse humans).
1065-
*/
1066-
sprintf(ptr, "%9lu %9lu\n", id1, id2);
1070+
strlcat(buffer, str, sizeof(buffer));
10671071

10681072
/*
10691073
* And rewrite the data. Since we write in a single kernel call, this

src/bin/pg_ctl/pg_ctl.c

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <locale.h>
2424
#include <signal.h>
25+
#include <stdlib.h>
2526
#include <sys/types.h>
2627
#include <sys/stat.h>
2728
#include <unistd.h>
@@ -138,6 +139,7 @@ static void read_post_opts(void);
138139

139140
static PGPing test_postmaster_connection(bool);
140141
static bool postmaster_is_alive(pid_t pid);
142+
static time_t start_time;
141143

142144
static char postopts_file[MAXPGPATH];
143145
static char pid_file[MAXPGPATH];
@@ -404,13 +406,13 @@ static PGPing
404406
test_postmaster_connection(bool do_checkpoint)
405407
{
406408
int portnum = 0;
407-
char socket_dir[MAXPGPATH];
409+
char host_str[MAXPGPATH];
408410
char connstr[MAXPGPATH + 256];
409411
PGPing ret = PQPING_OK; /* assume success for wait == zero */
410412
char **optlines;
411413
int i;
412414

413-
socket_dir[0] = '\0';
415+
host_str[0] = '\0';
414416
connstr[0] = '\0';
415417

416418
for (i = 0; i < wait_seconds; i++)
@@ -425,21 +427,25 @@ test_postmaster_connection(bool do_checkpoint)
425427
* 0 lock file created but status not written
426428
* 2 pre-9.1 server, shared memory not created
427429
* 3 pre-9.1 server, shared memory created
428-
* 4 9.1+ server, shared memory not created
429-
* 5 9.1+ server, shared memory created
430+
* 5 9.1+ server, listen host not created
431+
* 6 9.1+ server, shared memory not created
432+
* 7 9.1+ server, shared memory created
430433
*
431434
* For pre-9.1 Unix servers, we grab the port number from the
432435
* shmem key (first value on line 3). Pre-9.1 Win32 has no
433-
* written shmem key, so we fail. 9.1+ writes both the port
434-
* number and socket address in the file for us to use.
436+
* written shmem key, so we fail. 9.1+ writes connection
437+
* information in the file for us to use.
435438
* (PG_VERSION could also have told us the major version.)
436439
*/
437440

438441
/* Try to read a completed postmaster.pid file */
439442
if ((optlines = readfile(pid_file)) != NULL &&
440443
optlines[0] != NULL &&
441444
optlines[1] != NULL &&
442-
optlines[2] != NULL)
445+
optlines[2] != NULL &&
446+
/* pre-9.1 server or listen_address line is present? */
447+
(optlines[3] == NULL ||
448+
optlines[5] != NULL))
443449
{
444450
/* A 3-line file? */
445451
if (optlines[3] == NULL)
@@ -459,41 +465,63 @@ test_postmaster_connection(bool do_checkpoint)
459465
return PQPING_NO_ATTEMPT;
460466
}
461467
}
462-
else /* 9.1+ server */
468+
else
463469
{
464-
portnum = atoi(optlines[2]);
465-
466-
/* Get socket directory, if specified. */
467-
if (optlines[3][0] != '\n')
470+
/*
471+
* Easy check to see if we are looking at the right
472+
* data directory: Is the postmaster older than this
473+
* execution of pg_ctl? Subtract 2 seconds to account
474+
* for possible clock skew between pg_ctl and the
475+
* postmaster.
476+
*/
477+
if (atol(optlines[1]) < start_time - 2)
468478
{
469-
/*
470-
* While unix_socket_directory can accept relative
471-
* directories, libpq's host must have a leading slash
472-
* to indicate a socket directory.
473-
*/
474-
if (optlines[3][0] != '/')
475-
{
476-
write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
477-
progname);
478-
return PQPING_NO_ATTEMPT;
479-
}
480-
strlcpy(socket_dir, optlines[3], MAXPGPATH);
481-
/* remove newline */
482-
if (strchr(socket_dir, '\n') != NULL)
483-
*strchr(socket_dir, '\n') = '\0';
479+
write_stderr(_("%s: this data directory is running an older postmaster\n"),
480+
progname);
481+
return PQPING_NO_ATTEMPT;
484482
}
485-
}
483+
484+
portnum = atoi(optlines[3]);
486485

486+
/*
487+
* Determine the proper host string to use.
488+
*/
489+
#ifdef HAVE_UNIX_SOCKETS
490+
/*
491+
* Use socket directory, if specified. We assume if we
492+
* have unix sockets, the server does too because we
493+
* just started the postmaster.
494+
*/
495+
/*
496+
* While unix_socket_directory can accept relative
497+
* directories, libpq's host must have a leading slash
498+
* to indicate a socket directory.
499+
*/
500+
if (optlines[4][0] != '\n' && optlines[4][0] != '/')
501+
{
502+
write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
503+
progname);
504+
return PQPING_NO_ATTEMPT;
505+
}
506+
strlcpy(host_str, optlines[4], sizeof(host_str));
507+
#else
508+
strlcpy(host_str, optlines[5], sizeof(host_str));
509+
#endif
510+
/* remove newline */
511+
if (strchr(host_str, '\n') != NULL)
512+
*strchr(host_str, '\n') = '\0';
513+
}
514+
487515
/*
488516
* We need to set connect_timeout otherwise on Windows the
489517
* Service Control Manager (SCM) will probably timeout first.
490518
*/
491519
snprintf(connstr, sizeof(connstr),
492520
"dbname=postgres port=%d connect_timeout=5", portnum);
493521

494-
if (socket_dir[0] != '\0')
522+
if (host_str[0] != '\0')
495523
snprintf(connstr + strlen(connstr), sizeof(connstr) - strlen(connstr),
496-
" host='%s'", socket_dir);
524+
" host='%s'", host_str);
497525
}
498526
}
499527

@@ -1756,6 +1784,7 @@ main(int argc, char **argv)
17561784

17571785
progname = get_progname(argv[0]);
17581786
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
1787+
start_time = time(NULL);
17591788

17601789
/*
17611790
* save argv[0] so do_start() can look for the postmaster if necessary. we

src/include/miscadmin.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,11 @@ extern PGDLLIMPORT bool process_shared_preload_libraries_in_progress;
348348
extern char *shared_preload_libraries_string;
349349
extern char *local_preload_libraries_string;
350350

351+
#define LOCK_FILE_LINES 7
351352
extern void CreateDataDirLockFile(bool amPostmaster);
352353
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
353354
extern void TouchSocketLockFile(void);
354-
extern void RecordSharedMemoryInLockFile(unsigned long id1,
355-
unsigned long id2);
355+
extern void AddToLockFile(int target_line, const char *str);
356356
extern void ValidatePgVersion(const char *path);
357357
extern void process_shared_preload_libraries(void);
358358
extern void process_local_preload_libraries(void);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy