📄 postmaster.c
字号:
/*------------------------------------------------------------------------- * * postmaster.c * This program acts as a clearing house for requests to the * POSTGRES system. Frontend programs send a startup message * to the Postmaster and the postmaster uses the info in the * message to setup a backend process. * * The postmaster also manages system-wide operations such as * startup and shutdown. The postmaster itself doesn't do those * operations, mind you --- it just forks off a subprocess to do them * at the right times. It also takes care of resetting the system * if a backend crashes. * * The postmaster process creates the shared memory and semaphore * pools during startup, but as a rule does not touch them itself. * In particular, it is not a member of the PGPROC array of backends * and so it cannot participate in lock-manager operations. Keeping * the postmaster away from shared memory operations makes it simpler * and more reliable. The postmaster is almost always able to recover * from crashes of individual backends by resetting shared memory; * if it did much with shared memory then it would be prone to crashing * along with the backends. * * When a request message is received, we now fork() immediately. * The child process performs authentication of the request, and * then becomes a backend if successful. This allows the auth code * to be written in a simple single-threaded style (as opposed to the * crufty "poor man's multitasking" code that used to be needed). * More importantly, it ensures that blockages in non-multithreaded * libraries like SSL or PAM cannot cause denial of service to other * clients. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.475.2.5 2006/05/19 15:15:38 alvherre Exp $ * * NOTES * * Initialization: * The Postmaster sets up shared memory data structures * for the backends. * * Synchronization: * The Postmaster shares memory with the backends but should avoid * touching shared memory, so as not to become stuck if a crashing * backend screws up locks or shared memory. Likewise, the Postmaster * should never block on messages from frontend clients. * * Garbage Collection: * The Postmaster cleans up after backends if they have an emergency * exit and/or core dump. * * Error Reporting: * Use write_stderr() only for reporting "interactive" errors * (essentially, bogus arguments on the command line). Once the * postmaster is launched, use ereport(). In particular, don't use * write_stderr() for anything that occurs after pmdaemonize. * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <signal.h>#include <time.h>#include <sys/wait.h>#include <ctype.h>#include <sys/stat.h>#include <sys/socket.h>#include <fcntl.h>#include <sys/param.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <limits.h>#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#ifdef USE_BONJOUR#include <DNSServiceDiscovery/DNSServiceDiscovery.h>#endif#include "access/xlog.h"#include "bootstrap/bootstrap.h"#include "catalog/pg_control.h"#include "catalog/pg_database.h"#include "commands/async.h"#include "lib/dllist.h"#include "libpq/auth.h"#include "libpq/crypt.h"#include "libpq/libpq.h"#include "libpq/pqcomm.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "nodes/nodes.h"#include "pgstat.h"#include "postmaster/autovacuum.h"#include "postmaster/fork_process.h"#include "postmaster/pgarch.h"#include "postmaster/postmaster.h"#include "postmaster/syslogger.h"#include "storage/bufmgr.h"#include "storage/fd.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "storage/pmsignal.h"#include "storage/proc.h"#include "tcop/tcopprot.h"#include "utils/builtins.h"#include "utils/datetime.h"#include "utils/guc.h"#include "utils/memutils.h"#include "utils/ps_status.h"#ifdef EXEC_BACKEND#include "storage/spin.h"#endif/* * List of active backends (or child processes anyway; we don't actually * know whether a given child has become a backend or is still in the * authorization phase). This is used mainly to keep track of how many * children we have and send them appropriate signals when necessary. * * "Special" children such as the startup and bgwriter tasks are not in * this list. */typedef struct bkend{ pid_t pid; /* process id of backend */ long cancel_key; /* cancel key for cancels for this backend */} Backend;static Dllist *BackendList;#ifdef EXEC_BACKEND/* * Number of entries in the backend table. Twice the number of backends, * plus four other subprocesses (stats, bgwriter, autovac, logger). */#define NUM_BACKENDARRAY_ELEMS (2*MaxBackends + 4)static Backend *ShmemBackendArray;#endif/* The socket number we are listening for connections on */int PostPortNumber;char *UnixSocketDir;char *ListenAddresses;/* * ReservedBackends is the number of backends reserved for superuser use. * This number is taken out of the pool size given by MaxBackends so * number of backend slots available to non-superusers is * (MaxBackends - ReservedBackends). Note what this really means is * "if there are <= ReservedBackends connections available, only superusers * can make new connections" --- pre-existing superuser connections don't * count against the limit. */int ReservedBackends;/* The socket(s) we're listening to. */#define MAXLISTEN 64static int ListenSocket[MAXLISTEN];/* * Set by the -o option */static char ExtraOptions[MAXPGPATH];/* * These globals control the behavior of the postmaster in case some * backend dumps core. Normally, it kills all peers of the dead backend * and reinitializes shared memory. By specifying -s or -n, we can have * the postmaster stop (rather than kill) peers and not reinitialize * shared data structures. */static bool Reinit = true;static int SendStop = false;/* still more option variables */bool EnableSSL = false;bool SilentMode = false; /* silent mode (-S) */int PreAuthDelay = 0;int AuthenticationTimeout = 60;bool log_hostname; /* for ps display and logging */bool Log_connections = false;bool Db_user_namespace = false;char *bonjour_name;/* list of library:init-function to be preloaded */char *preload_libraries_string = NULL;/* PIDs of special child processes; 0 when not running */static pid_t StartupPID = 0, BgWriterPID = 0, AutoVacPID = 0, PgArchPID = 0, PgStatPID = 0, SysLoggerPID = 0;/* Startup/shutdown state */#define NoShutdown 0#define SmartShutdown 1#define FastShutdown 2static int Shutdown = NoShutdown;static bool FatalError = false; /* T if recovering from backend crash */bool ClientAuthInProgress = false; /* T during new-client * authentication *//* * State for assigning random salts and cancel keys. * Also, the global MyCancelKey passes the cancel key assigned to a given * backend from the postmaster to that backend (via fork). */static unsigned int random_seed = 0;extern char *optarg;extern int optind, opterr;#ifdef HAVE_INT_OPTRESETextern int optreset;#endif/* * postmaster.c - function prototypes */static void checkDataDir(void);#ifdef USE_BONJOURstatic void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context);#endifstatic void pmdaemonize(void);static Port *ConnCreate(int serverFd);static void ConnFree(Port *port);static void reset_shared(int port);static void SIGHUP_handler(SIGNAL_ARGS);static void pmdie(SIGNAL_ARGS);static void reaper(SIGNAL_ARGS);static void sigusr1_handler(SIGNAL_ARGS);static void dummy_handler(SIGNAL_ARGS);static void CleanupBackend(int pid, int exitstatus);static void HandleChildCrash(int pid, int exitstatus, const char *procname);static void LogChildExit(int lev, const char *procname, int pid, int exitstatus);static int BackendRun(Port *port);static void ExitPostmaster(int status);static void usage(const char *);static int ServerLoop(void);static int BackendStartup(Port *port);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);static enum CAC_state canAcceptConnections(void);static long PostmasterRandom(void);static void RandomSalt(char *cryptSalt, char *md5Salt);static void SignalChildren(int signal);static int CountChildren(void);static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);static pid_t StartChildProcess(int xlop);#ifdef EXEC_BACKEND#ifdef WIN32static void win32_AddChild(pid_t pid, HANDLE handle);static void win32_RemoveChild(pid_t pid);static pid_t win32_waitpid(int *exitstatus);static DWORD WINAPI win32_sigchld_waiter(LPVOID param);static pid_t *win32_childPIDArray;static HANDLE *win32_childHNDArray;static unsigned long win32_numChildren = 0;HANDLE PostmasterHandle;#endifstatic pid_t backend_forkexec(Port *port);static pid_t internal_forkexec(int argc, char *argv[], Port *port);/* Type for a socket that can be inherited to a client process */#ifdef WIN32typedef struct{ SOCKET origsocket; /* Original socket value, or -1 if not a * socket */ WSAPROTOCOL_INFO wsainfo;} InheritableSocket;#elsetypedef int InheritableSocket;#endiftypedef struct LWLock LWLock; /* ugly kluge *//* * Structure contains all variables passed to exec:ed backends */typedef struct{ Port port; InheritableSocket portsocket; char DataDir[MAXPGPATH]; int ListenSocket[MAXLISTEN]; long MyCancelKey; unsigned long UsedShmemSegID; void *UsedShmemSegAddr; slock_t *ShmemLock; slock_t *ShmemIndexLock; VariableCache ShmemVariableCache; void *ShmemIndexAlloc; Backend *ShmemBackendArray; LWLock *LWLockArray; slock_t *ProcStructLock; InheritableSocket pgStatSock; InheritableSocket pgStatPipe0; InheritableSocket pgStatPipe1; pid_t PostmasterPid; TimestampTz PgStartTime;#ifdef WIN32 HANDLE PostmasterHandle; HANDLE initial_signal_pipe; HANDLE syslogPipe[2];#else int syslogPipe[2];#endif char my_exec_path[MAXPGPATH]; char pkglib_path[MAXPGPATH]; char ExtraOptions[MAXPGPATH]; char lc_collate[LOCALE_NAME_BUFLEN]; char lc_ctype[LOCALE_NAME_BUFLEN];} BackendParameters;static void read_backend_variables(char *id, Port *port);static void restore_backend_variables(BackendParameters * param, Port *port);#ifndef WIN32static bool save_backend_variables(BackendParameters * param, Port *port);#elsestatic bool save_backend_variables(BackendParameters * param, Port *port, HANDLE childProcess, pid_t childPid);#endifstatic void ShmemBackendArrayAdd(Backend *bn);static void ShmemBackendArrayRemove(pid_t pid);#endif /* EXEC_BACKEND */#define StartupDataBase() StartChildProcess(BS_XLOG_STARTUP)#define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)/* * Postmaster main entry point */intPostmasterMain(int argc, char *argv[]){ int opt; int status; char *userDoption = NULL; int i; MyProcPid = PostmasterPid = getpid(); IsPostmasterEnvironment = true; /* * Catch standard options before doing much else. This even works on * systems without getopt_long. */ if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { usage(progname); ExitPostmaster(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("postmaster (PostgreSQL) " PG_VERSION); ExitPostmaster(0); } }#ifdef WIN32 /* Start our win32 signal implementation */ pgwin32_signal_initialize();#endif /* * for security, no dir or file created can be group or other accessible */ umask((mode_t) 0077); /* * Fire up essential subsystems: memory management */ MemoryContextInit(); /* * By default, palloc() requests in the postmaster will be allocated in * the PostmasterContext, which is space that can be recycled by backends. * Allocated data that needs to be available to backends should be * allocated in TopMemoryContext. */ PostmasterContext = AllocSetContextCreate(TopMemoryContext, "Postmaster", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(PostmasterContext); IgnoreSystemIndexes(false); if (find_my_exec(argv[0], my_exec_path) < 0) elog(FATAL, "%s: could not locate my own executable path", argv[0]); get_pkglib_path(my_exec_path, pkglib_path); /* * Options setup */ InitializeGUCOptions(); opterr = 1; while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1) { switch (opt) { case 'A':#ifdef USE_ASSERT_CHECKING SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);#else write_stderr("%s: assert checking is not compiled in\n", progname);#endif break; case 'a': /* Can no longer set authentication method. */ break; case 'B': SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'b': /* Can no longer set the backend executable file to use. */ break; case 'D': userDoption = optarg; break; case 'd': set_debug_options(atoi(optarg), PGC_POSTMASTER, PGC_S_ARGV); break; case 'F': SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV); break; case 'h': SetConfigOption("listen_addresses", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'i': SetConfigOption("listen_addresses", "*", PGC_POSTMASTER, PGC_S_ARGV); break; case 'k': SetConfigOption("unix_socket_directory", optarg, PGC_POSTMASTER, PGC_S_ARGV); break;#ifdef USE_SSL case 'l': SetConfigOption("ssl", "true", PGC_POSTMASTER, PGC_S_ARGV); break;#endif case 'm':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -