📄 postmaster.c
字号:
while (offset < len) { char *nameptr = ((char *) buf) + offset; int32 valoffset; char *valptr; if (*nameptr == '\0') break; /* found packet terminator */ valoffset = offset + strlen(nameptr) + 1; if (valoffset >= len) break; /* missing value, will complain below */ valptr = ((char *) buf) + valoffset; if (strcmp(nameptr, "database") == 0) port->database_name = pstrdup(valptr); else if (strcmp(nameptr, "user") == 0) port->user_name = pstrdup(valptr); else if (strcmp(nameptr, "options") == 0) port->cmdline_options = pstrdup(valptr); else { /* Assume it's a generic GUC option */ port->guc_options = lappend(port->guc_options, pstrdup(nameptr)); port->guc_options = lappend(port->guc_options, pstrdup(valptr)); } offset = valoffset + strlen(valptr) + 1; } /* * If we didn't find a packet terminator exactly at the end of the * given packet length, complain. */ if (offset != len - 1) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid startup packet layout: expected terminator as last byte"))); } else { /* * Get the parameters from the old-style, fixed-width-fields startup * packet as C strings. The packet destination was cleared first so a * short packet has zeros silently added. We have to be prepared to * truncate the pstrdup result for oversize fields, though. */ StartupPacket *packet = (StartupPacket *) buf; port->database_name = pstrdup(packet->database); if (strlen(port->database_name) > sizeof(packet->database)) port->database_name[sizeof(packet->database)] = '\0'; port->user_name = pstrdup(packet->user); if (strlen(port->user_name) > sizeof(packet->user)) port->user_name[sizeof(packet->user)] = '\0'; port->cmdline_options = pstrdup(packet->options); if (strlen(port->cmdline_options) > sizeof(packet->options)) port->cmdline_options[sizeof(packet->options)] = '\0'; port->guc_options = NIL; } /* Check a user name was given. */ if (port->user_name == NULL || port->user_name[0] == '\0') ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("no PostgreSQL user name specified in startup packet"))); /* The database defaults to the user name. */ if (port->database_name == NULL || port->database_name[0] == '\0') port->database_name = pstrdup(port->user_name); if (Db_user_namespace) { /* * If user@, it is a global user, remove '@'. We only want to do this * if there is an '@' at the end and no earlier in the user string or * they may fake as a local user of another database attaching to this * database. */ if (strchr(port->user_name, '@') == port->user_name + strlen(port->user_name) - 1) *strchr(port->user_name, '@') = '\0'; else { /* Append '@' and dbname */ char *db_user; db_user = palloc(strlen(port->user_name) + strlen(port->database_name) + 2); sprintf(db_user, "%s@%s", port->user_name, port->database_name); port->user_name = db_user; } } /* * Truncate given database and user names to length of a Postgres name. * This avoids lookup failures when overlength names are given. */ if (strlen(port->database_name) >= NAMEDATALEN) port->database_name[NAMEDATALEN - 1] = '\0'; if (strlen(port->user_name) >= NAMEDATALEN) port->user_name[NAMEDATALEN - 1] = '\0'; /* * Done putting stuff in TopMemoryContext. */ MemoryContextSwitchTo(oldcontext); /* * 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.) */ switch (port->canAcceptConnections) { case CAC_STARTUP: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is starting up"))); break; case CAC_SHUTDOWN: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is shutting down"))); break; case CAC_RECOVERY: ereport(FATAL, (errcode(ERRCODE_CANNOT_CONNECT_NOW), errmsg("the database system is in recovery mode"))); break; case CAC_TOOMANY: ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("sorry, too many clients already"))); break; case CAC_OK: default: break; } return STATUS_OK;}/* * The client has sent a cancel request packet, not a normal * start-a-new-connection packet. Perform the necessary processing. * Nothing is sent back to the client. */static voidprocessCancelRequest(Port *port, void *pkt){ CancelRequestPacket *canc = (CancelRequestPacket *) pkt; int backendPID; long cancelAuthCode; Backend *bp;#ifndef EXEC_BACKEND Dlelem *curr;#else int i;#endif backendPID = (int) ntohl(canc->backendPID); cancelAuthCode = (long) ntohl(canc->cancelAuthCode); /* * See if we have a matching backend. In the EXEC_BACKEND case, we can no * longer access the postmaster's own backend list, and must rely on the * duplicate array in shared memory. */#ifndef EXEC_BACKEND for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) { bp = (Backend *) DLE_VAL(curr);#else for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++) { bp = (Backend *) &ShmemBackendArray[i];#endif if (bp->pid == backendPID) { if (bp->cancel_key == cancelAuthCode) { /* Found a match; signal that backend to cancel current op */ ereport(DEBUG2, (errmsg_internal("processing cancel request: sending SIGINT to process %d", backendPID))); kill(bp->pid, SIGINT); } else /* Right PID, wrong key: no way, Jose */ ereport(DEBUG2, (errmsg_internal("bad key in cancel request for process %d", backendPID))); return; } } /* No matching backend */ ereport(DEBUG2, (errmsg_internal("bad pid in cancel request for process %d", backendPID)));}/* * canAcceptConnections --- check to see if database state allows connections. */static enum CAC_statecanAcceptConnections(void){ /* Can't start backends when in startup/shutdown/recovery state. */ if (Shutdown > NoShutdown) return CAC_SHUTDOWN; if (StartupPID) return CAC_STARTUP; if (FatalError) return CAC_RECOVERY; /* * Don't start too many children. * * We allow more connections than we can have backends here because some * might still be authenticating; they might fail auth, or some existing * backend might exit before the auth cycle is completed. The exact * MaxBackends limit is enforced when a new backend tries to join the * shared-inval backend array. */ if (CountChildren() >= 2 * MaxBackends) return CAC_TOOMANY; return CAC_OK;}/* * ConnCreate -- create a local connection data structure */static Port *ConnCreate(int serverFd){ Port *port; if (!(port = (Port *) calloc(1, sizeof(Port)))) { ereport(LOG, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); ExitPostmaster(1); } if (StreamConnection(serverFd, port) != STATUS_OK) { StreamClose(port->sock); ConnFree(port); port = NULL; } else { /* * Precompute password salt values to use for this connection. It's * slightly annoying to do this long in advance of knowing whether * we'll need 'em or not, but we must do the random() calls before we * fork, not after. Else the postmaster's random sequence won't get * advanced, and all backends would end up using the same salt... */ RandomSalt(port->cryptSalt, port->md5Salt); } return port;}/* * ConnFree -- free a local connection data structure */static voidConnFree(Port *conn){#ifdef USE_SSL secure_close(conn);#endif free(conn);}/* * ClosePostmasterPorts -- close all the postmaster's open sockets * * This is called during child process startup to release file descriptors * that are not needed by that child process. The postmaster still has * them open, of course. * * Note: we pass am_syslogger as a boolean because we don't want to set * the global variable yet when this is called. */voidClosePostmasterPorts(bool am_syslogger){ int i; /* Close the listen sockets */ for (i = 0; i < MAXLISTEN; i++) { if (ListenSocket[i] != -1) { StreamClose(ListenSocket[i]); ListenSocket[i] = -1; } } /* If using syslogger, close the read side of the pipe */ if (!am_syslogger) {#ifndef WIN32 if (syslogPipe[0] >= 0) close(syslogPipe[0]); syslogPipe[0] = -1;#else if (syslogPipe[0]) CloseHandle(syslogPipe[0]); syslogPipe[0] = 0;#endif }}/* * reset_shared -- reset shared memory and semaphores */static voidreset_shared(int port){ /* * Create or re-create shared memory and semaphores. * * Note: in each "cycle of life" we will normally assign the same IPC keys * (if using SysV shmem and/or semas), since the port number is used to * determine IPC keys. This helps ensure that we will clean up dead IPC * objects if the postmaster crashes and is restarted. */ CreateSharedMemoryAndSemaphores(false, port);}/* * SIGHUP -- reread config files, and tell children to do same */static voidSIGHUP_handler(SIGNAL_ARGS){ int save_errno = errno; PG_SETMASK(&BlockSig); if (Shutdown <= SmartShutdown) { ereport(LOG, (errmsg("received SIGHUP, reloading configuration files"))); ProcessConfigFile(PGC_SIGHUP); SignalChildren(SIGHUP); if (BgWriterPID != 0) kill(BgWriterPID, SIGHUP); if (AutoVacPID != 0) kill(AutoVacPID, SIGHUP); if (PgArchPID != 0) kill(PgArchPID, SIGHUP); if (SysLoggerPID != 0) kill(SysLoggerPID, SIGHUP); /* PgStatPID does not currently need SIGHUP */ /* Reload authentication config files too */ load_hba(); load_ident();#ifdef EXEC_BACKEND /* Update the starting-point file for future children */ write_nondefault_variables(PGC_SIGHUP);#endif } PG_SETMASK(&UnBlockSig); errno = save_errno;}/* * pmdie -- signal handler for processing various postmaster signals. */static voidpmdie(SIGNAL_ARGS){ int save_errno = errno; PG_SETMASK(&BlockSig); ereport(DEBUG2, (errmsg_internal("postmaster received signal %d", postgres_signal_arg))); switch (postgres_signal_arg) { case SIGTERM: /* * Smart Shutdown: * * Wait for children to end their work, then shut down. */ if (Shutdown >= SmartShutdown) break; Shutdown = SmartShutdown; ereport(LOG, (errmsg("received smart shutdown request"))); /* * We won't wait out an autovacuum iteration ... */ if (AutoVacPID != 0) { /* Use statement cancel to shut it down */ kill(AutoVacPID, SIGINT); break; /* let reaper() handle this */ } if (DLGetHead(BackendList)) break; /* let reaper() handle this */ /* * No children left. Begin shutdown of data base system. */ if (StartupPID != 0 || FatalError) break; /* let reaper() handle this */ /* Start the bgwriter if not running */ if (BgWriterPID == 0) BgWriterPID = StartBackgroundWriter(); /* And tell it to shut down */ if (BgWriterPID != 0) kill(BgWriterPID, SIGUSR2); /* Tell pgarch to shut down too; nothing left for it to do */ if (PgArchPID != 0) kill(PgArchPID, SIGQUIT); /* Tell pgstat to shut down too; nothing left for it to do */ if (PgStatPID != 0) kill(PgStatPID, SIGQUIT); break; case SIGINT: /* * Fast Shutdown: * * Abort all children with SIGTERM (rollback active transactions * and exit) and shut down when they are gone. */ if (Shutdown >= FastShutdown) break; Shutdown = FastShutdown; ereport(LOG, (errmsg("received fast shutdown request"))); if (DLGetHead(BackendList) || AutoVacPID != 0) { if (!FatalError) { ereport(LOG, (errmsg("aborting any active transactions"))); SignalChildren(SIGTERM); if (AutoVacPID != 0) kill(AutoVacPID, SIGTERM); /* reaper() does the rest */ } break; } /* * No children left. Begin shutdown of data base system. * * Note: if we previously got SIGTERM then we may send SIGUSR2 to * the bgwriter a second time here. This should be harmless. */ if (StartupPID != 0 || FatalError) break; /* let reaper() handle this */ /* Start the bgwriter if not running */ if (BgWriterPID == 0) BgWriterPID = StartBackgroundWriter(); /* And tell it to shut down */ if (BgWriterPID != 0) kill(BgWriterPID, SIGUSR2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -