📄 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, shutdown, and periodic checkpoints. 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-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.347.2.2 2004/02/23 20:46:16 tgl Exp $ * * NOTES * * Initialization: * The Postmaster sets up a few shared memory data structures * for the backends. It should at the very least initialize the * lock manager. * * 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. * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <signal.h>#include <sys/wait.h>#include <ctype.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/socket.h>#include <errno.h>#include <fcntl.h>#include <time.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_RENDEZVOUS#include <DNSServiceDiscovery/DNSServiceDiscovery.h>#endif#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 "storage/fd.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "storage/pmsignal.h"#include "storage/proc.h"#include "access/xlog.h"#include "tcop/tcopprot.h"#include "utils/guc.h"#include "utils/memutils.h"#include "utils/ps_status.h"#include "bootstrap/bootstrap.h"#include "pgstat.h"#define INVALID_SOCK (-1)#ifdef HAVE_SIGPROCMASKsigset_t UnBlockSig, BlockSig, AuthBlockSig;#elseint UnBlockSig, BlockSig, AuthBlockSig;#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. */typedef struct bkend{ pid_t pid; /* process id of backend */ long cancel_key; /* cancel key for cancels for this backend */} Backend;static Dllist *BackendList;/* The socket number we are listening for connections on */int PostPortNumber;char *UnixSocketDir;char *VirtualHost;/* * MaxBackends is the limit on the number of backends we can start. * Note that a larger MaxBackends value will increase the size of the * shared memory area as well as cause the postmaster to grab more * kernel semaphores, even if you never actually use that many * backends. */int MaxBackends;/* * 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;static char *progname = (char *) NULL;/* The socket(s) we're listening to. */#define MAXLISTEN 10static int ListenSocket[MAXLISTEN];/* Used to reduce macros tests */#ifdef EXEC_BACKENDconst bool ExecBackend = true;#elseconst bool ExecBackend = false;#endif/* * 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 NetServer = false; /* listen on TCP/IP */bool EnableSSL = false;bool SilentMode = false; /* silent mode (-S) */int PreAuthDelay = 0;int AuthenticationTimeout = 60;int CheckPointTimeout = 300;int CheckPointWarning = 30;time_t LastSignalledCheckpoint = 0;bool log_hostname; /* for ps display */bool LogSourcePort;bool Log_connections = false;bool Db_user_namespace = false;char *rendezvous_name;/* For FNCTL_NONBLOCK */#if defined(WIN32) || defined(__BEOS__)long ioctlsocket_ret = 1;#endif/* list of library:init-function to be preloaded */char *preload_libraries_string = NULL;/* Startup/shutdown state */static pid_t StartupPID = 0, ShutdownPID = 0, CheckPointPID = 0;static time_t checkpointed = 0;#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;static int debug_flag = 0;extern char *optarg;extern int optind, opterr;#ifdef HAVE_INT_OPTRESETextern int optreset;#endif/* * postmaster.c - function prototypes */static void pmdaemonize(int argc, char *argv[]);static Port *ConnCreate(int serverFd);static void ConnFree(Port *port);static void reset_shared(unsigned short 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 CleanupProc(int pid, int exitstatus);static void LogChildExit(int lev, const char *procname, int pid, int exitstatus);static int BackendFork(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);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);static void SignalChildren(int signal);static int CountChildren(void);static bool CreateOptsFile(int argc, char *argv[]);static pid_t SSDataBase(int xlop);static voidpostmaster_error(const char *fmt,...)/* This lets gcc check the format string for consistency. */__attribute__((format(printf, 1, 2)));#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN)static voidcheckDataDir(const char *checkdir){ char path[MAXPGPATH]; FILE *fp; struct stat stat_buf; if (checkdir == NULL) { fprintf(stderr, gettext("%s does not know where to find the database system data.\n" "You must specify the directory that contains the database system\n" "either by specifying the -D invocation option or by setting the\n" "PGDATA environment variable.\n"), progname); ExitPostmaster(2); } if (stat(checkdir, &stat_buf) == -1) { if (errno == ENOENT) ereport(FATAL, (errcode_for_file_access(), errmsg("data directory \"%s\" does not exist", checkdir))); else ereport(FATAL, (errcode_for_file_access(), errmsg("could not read permissions of directory \"%s\": %m", checkdir))); } /* * Check if the directory has group or world access. If so, reject. * * XXX temporarily suppress check when on Windows, because there may not * be proper support for Unix-y file permissions. Need to think of a * reasonable check to apply on Windows. */#if !defined(__CYGWIN__) && !defined(WIN32) if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("data directory \"%s\" has group or world access", checkdir), errdetail("Permissions should be u=rwx (0700).")));#endif /* Look for PG_VERSION before looking for pg_control */ ValidatePgVersion(checkdir); snprintf(path, sizeof(path), "%s/global/pg_control", checkdir); fp = AllocateFile(path, PG_BINARY_R); if (fp == NULL) { fprintf(stderr, gettext("%s: could not find the database system\n" "Expected to find it in the directory \"%s\",\n" "but could not open file \"%s\": %s\n"), progname, checkdir, path, strerror(errno)); ExitPostmaster(2); } FreeFile(fp);}#ifdef USE_RENDEZVOUS/* reg_reply -- empty callback function for DNSServiceRegistrationCreate() */static voidreg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context){}#endifintPostmasterMain(int argc, char *argv[]){ int opt; int status; char original_extraoptions[MAXPGPATH]; char *potential_DataDir = NULL; int i; *original_extraoptions = '\0'; progname = argv[0]; 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); } } /* * for security, no dir or file created can be group or other * accessible */ umask((mode_t) 0077); MyProcPid = getpid(); /* * 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); /* * Options setup */ InitializeGUCOptions(); potential_DataDir = getenv("PGDATA"); /* default value */ 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 postmaster_error("assert checking is not compiled in");#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': potential_DataDir = optarg; break; case 'd': { /* Turn on debugging for the postmaster. */ char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1); sprintf(debugstr, "debug%s", optarg); SetConfigOption("log_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV); pfree(debugstr); debug_flag = atoi(optarg); break; } case 'F': SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV); break; case 'h': SetConfigOption("virtual_host", optarg, PGC_POSTMASTER, PGC_S_ARGV); break; case 'i': SetConfigOption("tcpip_socket", "true", 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': /* Multiplexed backends no longer supported. */ break; case 'M': /* * ignore this flag. This may be passed in because the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -