Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)