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.c286
1 files changed, 228 insertions, 58 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b17ade73761..f0560ce6f7e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.351 2003/12/01 22:15:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.352 2003/12/20 17:31:21 momjian Exp $
*
* NOTES
*
@@ -273,6 +273,7 @@ static void dummy_handler(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
+NON_EXEC_STATIC bool BackendInit(Port *port);
static int BackendFork(Port *port);
static void ExitPostmaster(int status);
static void usage(const char *);
@@ -282,10 +283,6 @@ static int ProcessStartupPacket(Port *port, bool SSLdone);
static void processCancelRequest(Port *port, void *pkt);
static int initMasks(fd_set *rmask);
static void report_fork_failure_to_client(Port *port, int errnum);
-enum CAC_state
-{
- CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY
-};
static enum CAC_state canAcceptConnections(void);
static long PostmasterRandom(void);
static void RandomSalt(char *cryptSalt, char *md5Salt);
@@ -298,6 +295,11 @@ postmaster_error(const char *fmt,...)
/* This lets gcc check the format string for consistency. */
__attribute__((format(printf, 1, 2)));
+#ifdef EXEC_BACKEND
+static void
+write_backend_variables(pid_t pid, Port *port);
+#endif
+
#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
@@ -1185,7 +1187,6 @@ initMasks(fd_set *rmask)
static int
ProcessStartupPacket(Port *port, bool SSLdone)
{
- enum CAC_state cac;
int32 len;
void *buf;
ProtocolVersion proto;
@@ -1244,7 +1245,11 @@ ProcessStartupPacket(Port *port, bool SSLdone)
if (proto == CANCEL_REQUEST_CODE)
{
+#ifdef EXEC_BACKEND
+ abort(); /* FIXME: [fork/exec] Whoops. Not handled... yet */
+#else
processCancelRequest(port, buf);
+#endif
return 127; /* XXX */
}
@@ -1435,9 +1440,7 @@ ProcessStartupPacket(Port *port, bool SSLdone)
* so now instead of wasting cycles on an authentication exchange.
* (This also allows a pg_ping utility to be written.)
*/
- cac = canAcceptConnections();
-
- switch (cac)
+ switch (port->canAcceptConnections)
{
case CAC_STARTUP:
ereport(FATAL,
@@ -1499,8 +1502,10 @@ processCancelRequest(Port *port, void *pkt)
backendPID)));
return;
}
- else if (ExecBackend)
+#ifdef EXEC_BACKEND
+ else
AttachSharedMemoryAndSemaphores();
+#endif
/* See if we have a matching backend */
@@ -2341,40 +2346,25 @@ split_opts(char **argv, int *argcp, char *s)
}
}
+
/*
- * BackendFork -- perform authentication, and if successful, set up the
- * backend's argument list and invoke backend main().
- *
- * This used to perform an execv() but we no longer exec the backend;
- * it's the same executable as the postmaster.
+ * BackendInit/Fork -- perform authentication [BackendInit], and if successful,
+ * set up the backend's argument list [BackendFork] and invoke
+ * backend main() [or exec in EXEC_BACKEND case]
*
* returns:
* Shouldn't return at all.
* If PostgresMain() fails, return status.
*/
-static int
-BackendFork(Port *port)
+NON_EXEC_STATIC bool
+BackendInit(Port *port)
{
- char **av;
- int maxac;
- int ac;
- char debugbuf[32];
- char protobuf[32];
-
-#ifdef EXEC_BACKEND
- char pbuf[NAMEDATALEN + 256];
-#endif
- int i;
int status;
struct timeval now;
struct timezone tz;
char remote_host[NI_MAXHOST];
char remote_port[NI_MAXSERV];
- /*
- * Let's clean up ourselves as the postmaster child
- */
-
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
ClientAuthInProgress = true; /* limit visibility of log messages */
@@ -2386,9 +2376,6 @@ BackendFork(Port *port)
* Signal handlers setting is moved to tcop/postgres...
*/
- /* Close the postmaster's other sockets */
- ClosePostmasterPorts(true);
-
/* Save port etc. for ps status */
MyProcPort = port;
@@ -2445,16 +2432,6 @@ BackendFork(Port *port)
}
/*
- * PreAuthDelay is a debugging aid for investigating problems in the
- * authentication cycle: it can be set in postgresql.conf to allow
- * time to attach to the newly-forked backend with a debugger. (See
- * also the -W backend switch, which we allow clients to pass through
- * PGOPTIONS, but it is not honored until after authentication.)
- */
- if (PreAuthDelay > 0)
- sleep(PreAuthDelay);
-
- /*
* Ready to begin client interaction. We will give up and exit(0)
* after a time delay, so that a broken client can't hog a connection
* indefinitely. PreAuthDelay doesn't count against the time limit.
@@ -2469,7 +2446,7 @@ BackendFork(Port *port)
status = ProcessStartupPacket(port, false);
if (status != STATUS_OK)
- return 0; /* cancel request processed, or error */
+ return false; /* cancel request processed, or error */
/*
* Now that we have the user and database name, we can set the process
@@ -2506,6 +2483,50 @@ BackendFork(Port *port)
gettimeofday(&now, &tz);
srandom((unsigned int) now.tv_usec);
+#ifdef EXEC_BACKEND
+ ClientAuthInProgress = false; /* client_min_messages is active
+ * now */
+#endif
+ return true;
+}
+
+
+static int
+BackendFork(Port *port)
+{
+ char **av;
+ int maxac;
+ int ac;
+ char debugbuf[32];
+#ifndef EXEC_BACKEND
+ char protobuf[32];
+#endif
+ int i;
+ char tmpExtraOptions[MAXPGPATH];
+
+ /*
+ * Let's clean up ourselves as the postmaster child, and
+ * close the postmaster's other sockets
+ */
+ ClosePostmasterPorts(true);
+
+ /*
+ * PreAuthDelay is a debugging aid for investigating problems in the
+ * authentication cycle: it can be set in postgresql.conf to allow
+ * time to attach to the newly-forked backend with a debugger. (See
+ * also the -W backend switch, which we allow clients to pass through
+ * PGOPTIONS, but it is not honored until after authentication.)
+ */
+ if (PreAuthDelay > 0)
+ sleep(PreAuthDelay);
+
+ port->canAcceptConnections = canAcceptConnections();
+
+#ifndef EXEC_BACKEND
+ if (!BackendInit(port))
+ return -1;
+#endif
+
/* ----------------
* Now, build the argv vector that will be given to PostgresMain.
*
@@ -2540,30 +2561,38 @@ BackendFork(Port *port)
/*
* Pass any backend switches specified with -o in the postmaster's own
- * command line. We assume these are secure. (It's OK to mangle
- * ExtraOptions since we are now in the child process; this won't
- * change the postmaster's copy.)
+ * command line. We assume these are secure.
+ * [Note: now makes a copy to protect against future fork/exec changes]
*/
- split_opts(av, &ac, ExtraOptions);
+ strcpy(tmpExtraOptions,ExtraOptions);
+ split_opts(av, &ac, tmpExtraOptions);
+#ifndef EXEC_BACKEND
/* Tell the backend what protocol the frontend is using. */
snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
av[ac++] = protobuf;
+#endif
/*
* Tell the backend it is being called from the postmaster, and which
* database to use. -p marks the end of secure switches.
*/
- av[ac++] = "-p";
#ifdef EXEC_BACKEND
- Assert(UsedShmemSegID != 0 && UsedShmemSegAddr != NULL);
- /* database name at the end because it might contain commas */
- snprintf(pbuf, sizeof(pbuf), "%d,%d,%lu,%p,%s",
- port->sock, canAcceptConnections(),
- UsedShmemSegID, UsedShmemSegAddr,
- port->database_name);
- av[ac++] = pbuf;
+ write_backend_variables(getpid(),port);
+
+ /* pass data dir before end of secure switches (-p) */
+ av[ac++] = "-D";
+ av[ac++] = DataDir;
+
+ /*
+ * This is totally bogus. We need to pass an arg to -p, but we'll
+ * actually get the dbname by ProcessStartupPacket in the exec'd
+ * process
+ */
+ av[ac++] = "-p";
+ av[ac++] = "FORK_EXEC";
#else
+ av[ac++] = "-p";
av[ac++] = port->database_name;
#endif
@@ -2571,6 +2600,10 @@ BackendFork(Port *port)
* Pass the (insecure) option switches from the connection request.
* (It's OK to mangle port->cmdline_options now.)
*/
+ /* FIXME: [fork/exec] Hmmm.. we won't see these until after we BackendInit.
+ * Should we add code to BackendInit to add these (somehow!) into
+ * the PostgresMain argument list in the EXEC_BACKEND case?
+ */
if (port->cmdline_options)
split_opts(av, &ac, port->cmdline_options);
@@ -2594,17 +2627,21 @@ BackendFork(Port *port)
*/
ereport(DEBUG3,
(errmsg_internal("%s child[%d]: starting with (",
- progname, MyProcPid)));
+ progname, getpid())));
for (i = 0; i < ac; ++i)
ereport(DEBUG3,
(errmsg_internal("\t%s", av[i])));
ereport(DEBUG3,
(errmsg_internal(")")));
+#ifdef EXEC_BACKEND
+ return execv(pg_pathname,av);
+#else
ClientAuthInProgress = false; /* client_min_messages is active
* now */
return (PostgresMain(ac, av, port->user_name));
+#endif
}
/*
@@ -3051,3 +3088,136 @@ postmaster_error(const char *fmt,...)
va_end(ap);
fprintf(stderr, "\n");
}
+
+
+#ifdef EXEC_BACKEND
+
+/*
+ * The following need to be available to the read/write_backend_variables
+ * functions
+ */
+extern XLogRecPtr RedoRecPtr;
+extern XLogwrtResult LogwrtResult;
+extern slock_t *ShmemLock;
+extern slock_t *ShmemIndexLock;
+extern void *ShmemIndexAlloc;
+typedef struct LWLock LWLock;
+extern LWLock *LWLockArray;
+extern slock_t *ProcStructLock;
+extern int pgStatSock;
+
+#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
+#define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp);
+#define get_tmp_backend_file_name(buf,id) \
+ do { \
+ Assert(DataDir); \
+ sprintf((buf), \
+ "%s/%s/%s.backend_var.%d", \
+ DataDir, \
+ PG_TEMP_FILES_DIR, \
+ PG_TEMP_FILE_PREFIX, \
+ (id)); \
+ } while (0)
+
+static void
+write_backend_variables(pid_t pid, Port *port)
+{
+ char filename[MAXPGPATH];
+ FILE *fp;
+ get_tmp_backend_file_name(filename,pid);
+
+ /* Open file */
+ fp = AllocateFile(filename, PG_BINARY_W);
+ if (!fp)
+ {
+ /* As per OpenTemporaryFile... */
+ char dirname[MAXPGPATH];
+ sprintf(dirname,"%s/%s",DataDir,PG_TEMP_FILES_DIR);
+ mkdir(dirname, S_IRWXU);
+
+ fp = AllocateFile(filename, PG_BINARY_W);
+ if (!fp)
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not write to file \"%s\": %m", filename)));
+ return;
+ }
+ }
+
+ /* Write vars */
+ write_var(port->sock,fp);
+ write_var(port->proto,fp);
+ write_var(port->laddr,fp);
+ write_var(port->raddr,fp);
+ write_var(port->canAcceptConnections,fp);
+ write_var(MyCancelKey,fp);
+
+ write_var(RedoRecPtr,fp);
+ write_var(LogwrtResult,fp);
+
+ write_var(UsedShmemSegID,fp);
+ write_var(UsedShmemSegAddr,fp);
+
+ write_var(ShmemLock,fp);
+ write_var(ShmemIndexLock,fp);
+ write_var(ShmemVariableCache,fp);
+ write_var(ShmemIndexAlloc,fp);
+
+ write_var(LWLockArray,fp);
+ write_var(ProcStructLock,fp);
+ write_var(pgStatSock,fp);
+
+ /* Release file */
+ FreeFile(fp);
+}
+
+void
+read_backend_variables(pid_t pid, Port *port)
+{
+ char filename[MAXPGPATH];
+ FILE *fp;
+ get_tmp_backend_file_name(filename,pid);
+
+ /* Open file */
+ fp = AllocateFile(filename, PG_BINARY_R);
+ if (!fp)
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read from backend_variables file \"%s\": %m", filename)));
+ return;
+ }
+
+ /* Read vars */
+ read_var(port->sock,fp);
+ read_var(port->proto,fp);
+ read_var(port->laddr,fp);
+ read_var(port->raddr,fp);
+ read_var(port->canAcceptConnections,fp);
+ read_var(MyCancelKey,fp);
+
+ read_var(RedoRecPtr,fp);
+ read_var(LogwrtResult,fp);
+
+ read_var(UsedShmemSegID,fp);
+ read_var(UsedShmemSegAddr,fp);
+
+ read_var(ShmemLock,fp);
+ read_var(ShmemIndexLock,fp);
+ read_var(ShmemVariableCache,fp);
+ read_var(ShmemIndexAlloc,fp);
+
+ read_var(LWLockArray,fp);
+ read_var(ProcStructLock,fp);
+ read_var(pgStatSock,fp);
+
+ /* Release file */
+ FreeFile(fp);
+ if (unlink(filename) != 0)
+ ereport(WARNING,
+ (errcode_for_file_access(),
+ errmsg("could not remove file \"%s\": %m", filename)));
+}
+
+#endif