aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/postmaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r--src/backend/postmaster/postmaster.c236
1 files changed, 121 insertions, 115 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 9fa4ebb3689..80ff7bac3ea 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.194 2000/11/28 23:27:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.195 2000/11/29 20:59:52 tgl Exp $
*
* NOTES
*
@@ -104,8 +104,6 @@ typedef struct bkend
long cancel_key; /* cancel key for cancels for this backend */
} Backend;
-Port *MyBackendPort = NULL;
-
/* list of active backends. For garbage collection only now. */
static Dllist *BackendList;
@@ -114,8 +112,8 @@ static Dllist *PortList;
/* The socket number we are listening for connections on */
int PostPortNumber;
-char * UnixSocketDir;
-char * Virtual_host;
+char *UnixSocketDir;
+char *VirtualHost;
/*
* MaxBackends is the actual limit on the number of backends we will
@@ -216,6 +214,7 @@ static int BackendStartup(Port *port);
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
static int initMasks(fd_set *rmask, fd_set *wmask);
+static char *canAcceptConnections(void);
static long PostmasterRandom(void);
static void RandomSalt(char *salt);
static void SignalChildren(SIGNAL_ARGS);
@@ -252,7 +251,7 @@ checkDataDir(const char *checkdir)
"database system either by specifying the -D invocation "
"option or by setting the PGDATA environment variable.\n\n",
progname);
- exit(2);
+ ExitPostmaster(2);
}
snprintf(path, sizeof(path), "%s%cglobal%cpg_control",
@@ -265,7 +264,7 @@ checkDataDir(const char *checkdir)
"\n\tExpected to find it in the PGDATA directory \"%s\","
"\n\tbut unable to open file \"%s\": %s\n\n",
progname, checkdir, path, strerror(errno));
- exit(2);
+ ExitPostmaster(2);
}
FreeFile(fp);
@@ -299,12 +298,12 @@ PostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--help")==0 || strcmp(argv[1], "-?")==0)
{
usage(progname);
- exit(0);
+ ExitPostmaster(0);
}
if (strcmp(argv[1], "--version")==0 || strcmp(argv[1], "-V")==0)
{
puts("postmaster (PostgreSQL) " PG_VERSION);
- exit(0);
+ ExitPostmaster(0);
}
}
@@ -367,7 +366,7 @@ PostmasterMain(int argc, char *argv[])
case '?':
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -378,7 +377,7 @@ PostmasterMain(int argc, char *argv[])
{
fprintf(stderr, "%s: invalid argument -- %s\n", progname, argv[optind]);
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
checkDataDir(potential_DataDir); /* issues error messages */
@@ -427,7 +426,7 @@ PostmasterMain(int argc, char *argv[])
enableFsync = false;
break;
case 'h':
- Virtual_host = optarg;
+ VirtualHost = optarg;
break;
case 'i':
NetServer = true;
@@ -525,7 +524,7 @@ PostmasterMain(int argc, char *argv[])
default:
/* shouldn't get here */
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -542,7 +541,7 @@ PostmasterMain(int argc, char *argv[])
*/
fprintf(stderr, "%s: The number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16.\n",
progname);
- exit(1);
+ ExitPostmaster(1);
}
if (DebugLvl > 2)
@@ -559,6 +558,27 @@ PostmasterMain(int argc, char *argv[])
}
/*
+ * Fork away from controlling terminal, if -S specified.
+ *
+ * Must do this before we grab any interlock files, else the interlocks
+ * will show the wrong PID.
+ */
+ if (SilentMode)
+ pmdaemonize(argc, argv);
+
+ /*
+ * Create lockfile for data directory.
+ *
+ * We want to do this before we try to grab the input sockets, because
+ * the data directory interlock is more reliable than the socket-file
+ * interlock (thanks to whoever decided to put socket files in /tmp :-().
+ * For the same reason, it's best to grab the TCP socket before the
+ * Unix socket.
+ */
+ if (! CreateDataDirLockFile(DataDir, true))
+ ExitPostmaster(1);
+
+ /*
* Establish input sockets.
*/
#ifdef USE_SSL
@@ -566,7 +586,7 @@ PostmasterMain(int argc, char *argv[])
{
fprintf(stderr, "%s: For SSL, TCP/IP connections must be enabled. See -? for help.\n",
progname);
- exit(1);
+ ExitPostmaster(1);
}
if (EnableSSL)
InitSSL();
@@ -574,7 +594,7 @@ PostmasterMain(int argc, char *argv[])
if (NetServer)
{
- status = StreamServerPort(AF_INET, Virtual_host,
+ status = StreamServerPort(AF_INET, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
&ServerSock_INET);
if (status != STATUS_OK)
@@ -586,7 +606,7 @@ PostmasterMain(int argc, char *argv[])
}
#ifdef HAVE_UNIX_SOCKETS
- status = StreamServerPort(AF_UNIX, Virtual_host,
+ status = StreamServerPort(AF_UNIX, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
&ServerSock_UNIX);
if (status != STATUS_OK)
@@ -599,7 +619,9 @@ PostmasterMain(int argc, char *argv[])
XLOGPathInit();
- /* set up shared memory and semaphores */
+ /*
+ * Set up shared memory and semaphores.
+ */
reset_shared(PostPortNumber);
/*
@@ -609,35 +631,12 @@ PostmasterMain(int argc, char *argv[])
BackendList = DLNewList();
PortList = DLNewList();
- if (SilentMode)
- pmdaemonize(argc, argv);
- else
- {
-
- /*
- * create pid file. if the file has already existed, exits.
- */
- SetPidFname(DataDir);
- if (SetPidFile(getpid()) == 0)
- {
- if (!CreateOptsFile(argc, argv))
- {
- UnlinkPidFile();
- ExitPostmaster(1);
- return 0; /* not reached */
- }
- }
- else
- {
- ExitPostmaster(1);
- return 0; /* not reached */
- }
-
- /*
- * register clean up proc
- */
- on_proc_exit(UnlinkPidFile, 0);
- }
+ /*
+ * Record postmaster options. We delay this till now to avoid recording
+ * bogus options (eg, NBuffers too high for available memory).
+ */
+ if (!CreateOptsFile(argc, argv))
+ ExitPostmaster(1);
/*
* Set up signal handlers for the postmaster process.
@@ -658,11 +657,18 @@ PostmasterMain(int argc, char *argv[])
pqsignal(SIGTTOU, SIG_IGN); /* ignored */
pqsignal(SIGWINCH, dumpstatus); /* dump port status */
+ /*
+ * We're ready to rock and roll...
+ */
StartupPID = StartupDataBase();
status = ServerLoop();
+ /*
+ * ServerLoop probably shouldn't ever return, but if it does, close down.
+ */
ExitPostmaster(status != STATUS_OK);
+
return 0; /* not reached */
}
@@ -672,8 +678,6 @@ pmdaemonize(int argc, char *argv[])
int i;
pid_t pid;
- SetPidFname(DataDir);
-
pid = fork();
if (pid == -1)
{
@@ -683,36 +687,8 @@ pmdaemonize(int argc, char *argv[])
}
else if (pid)
{ /* parent */
-
- /*
- * create pid file. if the file has already existed, exits.
- */
- if (SetPidFile(pid) == 0)
- {
- if (!CreateOptsFile(argc, argv))
- {
-
- /*
- * Failed to create opts file. kill the child and exit
- * now.
- */
- UnlinkPidFile();
- kill(pid, SIGTERM);
- ExitPostmaster(1);
- return; /* not reached */
- }
- _exit(0);
- }
- else
- {
-
- /*
- * Failed to create pid file. kill the child and exit now.
- */
- kill(pid, SIGTERM);
- ExitPostmaster(1);
- return; /* not reached */
- }
+ /* Parent should just exit, without doing any atexit cleanup */
+ _exit(0);
}
/* GH: If there's no setsid(), we hopefully don't need silent mode.
@@ -723,7 +699,7 @@ pmdaemonize(int argc, char *argv[])
{
fprintf(stderr, "%s: ", progname);
perror("cannot disassociate from controlling TTY");
- exit(1);
+ ExitPostmaster(1);
}
#endif
i = open(NULL_DEV, O_RDWR | PG_BINARY);
@@ -731,11 +707,6 @@ pmdaemonize(int argc, char *argv[])
dup2(i, 1);
dup2(i, 2);
close(i);
-
- /*
- * register clean up proc
- */
- on_proc_exit(UnlinkPidFile, 0);
}
@@ -960,24 +931,19 @@ ServerLoop(void)
if (status == STATUS_OK && port->pktInfo.state == Idle)
{
-
/*
- * Can't start backend if max backend count is exceeded.
+ * Can we accept a connection now?
*
- * The same when data base is in startup/shutdown mode.
+ * Even though readStartupPacket() already checked,
+ * we have to check again in case conditions changed
+ * while negotiating authentication.
*/
- if (Shutdown > NoShutdown)
- PacketSendError(&port->pktInfo,
- "The Data Base System is shutting down");
- else if (StartupPID)
- PacketSendError(&port->pktInfo,
- "The Data Base System is starting up");
- else if (FatalError)
- PacketSendError(&port->pktInfo,
- "The Data Base System is in recovery mode");
- else if (CountChildren() >= MaxBackends)
- PacketSendError(&port->pktInfo,
- "Sorry, too many clients already");
+ char *rejectMsg = canAcceptConnections();
+
+ if (rejectMsg != NULL)
+ {
+ PacketSendError(&port->pktInfo, rejectMsg);
+ }
else
{
@@ -1066,6 +1032,7 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
{
Port *port;
StartupPacket *si;
+ char *rejectMsg;
port = (Port *) arg;
si = (StartupPacket *) pkt;
@@ -1158,6 +1125,19 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
return STATUS_OK; /* don't close the connection yet */
}
+ /*
+ * If we're going to reject the connection due to database state,
+ * say so now instead of wasting cycles on an authentication exchange.
+ * (This also allows a pg_ping utility to be written.)
+ */
+ rejectMsg = canAcceptConnections();
+
+ if (rejectMsg != NULL)
+ {
+ PacketSendError(&port->pktInfo, rejectMsg);
+ return STATUS_OK; /* don't close the connection yet */
+ }
+
/* Start the authentication itself. */
be_recvauth(port);
@@ -1226,6 +1206,28 @@ processCancelRequest(Port *port, PacketLen len, void *pkt)
return STATUS_ERROR;
}
+/*
+ * canAcceptConnections --- check to see if database state allows connections.
+ *
+ * If we are open for business, return NULL, otherwise return an error message
+ * string suitable for rejecting a connection request.
+ */
+static char *
+canAcceptConnections(void)
+{
+ /* Can't start backends when in startup/shutdown/recovery state. */
+ if (Shutdown > NoShutdown)
+ return "The Data Base System is shutting down";
+ if (StartupPID)
+ return "The Data Base System is starting up";
+ if (FatalError)
+ return "The Data Base System is in recovery mode";
+ /* Can't start backend if max backend count is exceeded. */
+ if (CountChildren() >= MaxBackends)
+ return "Sorry, too many clients already";
+
+ return NULL;
+}
/*
* ConnCreate -- create a local connection data structure
@@ -1423,7 +1425,7 @@ pmdie(SIGNAL_ARGS)
}
/* exit postmaster */
- proc_exit(0);
+ ExitPostmaster(0);
}
/*
@@ -1465,9 +1467,9 @@ reaper(SIGNAL_ARGS)
{
fprintf(stderr, "Shutdown failed - abort\n");
fflush(stderr);
- proc_exit(1);
+ ExitPostmaster(1);
}
- proc_exit(0);
+ ExitPostmaster(0);
}
if (StartupPID > 0)
{
@@ -1477,7 +1479,7 @@ reaper(SIGNAL_ARGS)
{
fprintf(stderr, "Startup failed - abort\n");
fflush(stderr);
- proc_exit(1);
+ ExitPostmaster(1);
}
StartupPID = 0;
FatalError = false;
@@ -1507,7 +1509,7 @@ reaper(SIGNAL_ARGS)
{
/*
- * Wait for all children exit then StartupDataBase.
+ * Wait for all children exit, then reset shmem and StartupDataBase.
*/
if (DLGetHead(BackendList))
return;
@@ -1518,8 +1520,10 @@ reaper(SIGNAL_ARGS)
"Reinitializing shared memory and semaphores\n",
ctime(&tnow));
fflush(stderr);
+
shmem_exit(0);
reset_shared(PostPortNumber);
+
StartupPID = StartupDataBase();
return;
}
@@ -1744,10 +1748,10 @@ BackendStartup(Port *port)
{
fprintf(stderr, "%s child[%d]: BackendStartup: backend startup failed\n",
progname, (int) getpid());
- exit(1);
+ ExitPostmaster(1);
}
else
- exit(0);
+ ExitPostmaster(0);
}
/* in parent */
@@ -1943,9 +1947,9 @@ DoBackend(Port *port)
/*
* Release postmaster's working memory context so that backend can
- * recycle the space. Note we couldn't do it earlier than here,
- * because port pointer is pointing into that space! But now we
- * have copied all the interesting info into safe local storage.
+ * recycle the space. Note this does not trash *MyProcPort, because
+ * ConnCreate() allocated that space with malloc() ... else we'd need
+ * to copy the Port data here.
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextDelete(PostmasterContext);
@@ -1968,6 +1972,8 @@ DoBackend(Port *port)
/*
* ExitPostmaster -- cleanup
+ *
+ * Do NOT call exit() directly --- always go through here!
*/
static void
ExitPostmaster(int status)
@@ -2099,24 +2105,24 @@ InitSSL(void)
if (!SSL_context)
{
fprintf(stderr, "Failed to create SSL context: %s\n", ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir);
if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
{
fprintf(stderr, "Failed to load server certificate (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir);
if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
{
fprintf(stderr, "Failed to load private key file (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
if (!SSL_CTX_check_private_key(SSL_context))
{
fprintf(stderr, "Check of private key failed: %s\n", ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -2178,7 +2184,7 @@ SSDataBase(int xlop)
PG_SETMASK(&BlockSig);
BootstrapMain(ac, av);
- exit(0);
+ ExitPostmaster(0);
}
/* in parent */