温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PostgreSQL中PostgresMain函数的实现逻辑是什么

发布时间:2021-11-11 11:48:22 来源:亿速云 阅读:232 作者:iii 栏目:关系型数据库

本篇内容主要讲解“PostgreSQL中PostgresMain函数的实现逻辑是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中PostgresMain函数的实现逻辑是什么”吧!

一、源码解读

PostgresMain函数

/* ----------------------------------------------------------------  * PostgresMain  *     postgres main loop -- all backends, interactive or otherwise start here  *  * argc/argv are the command line arguments to be used.  (When being forked  * by the postmaster, these are not the original argv array of the process.)  * dbname is the name of the database to connect to, or NULL if the database  * name should be extracted from the command line arguments or defaulted.  * username is the PostgreSQL user name to be used for the session.  * ----------------------------------------------------------------  */ /* 输入:     argc/argv-Main函数的输入参数     dbname-数据库名称     username-用户名 输出:     无 */ void PostgresMain(int argc, char *argv[],              const char *dbname,              const char *username) {     int         firstchar;//临时变量,读取输入的Command     StringInfoData input_message;//字符串增强结构体     sigjmp_buf  local_sigjmp_buf;//系统变量     volatile bool send_ready_for_query = true;//     bool        disable_idle_in_transaction_timeout = false;     /* Initialize startup process environment if necessary. */     if (!IsUnderPostmaster//未初始化?initialized for the bootstrap/standalone case         InitStandaloneProcess(argv[0]);//初始化进程     SetProcessingMode(InitProcessing);//设置进程状态为InitProcessing     /*      * Set default values for command-line options.      */     if (!IsUnderPostmaster)         InitializeGUCOptions();//初始化GUC参数,GUC=Grand Unified Configuration     /*      * Parse command-line options.      */     process_postgres_switches(argc, argv, PGC_POSTMASTER, &dbname);//解析输入参数     /* Must have gotten a database name, or have a default (the username) */     if (dbname == NULL)//输入的dbname为空     {         dbname = username;//设置为用户名         if (dbname == NULL)//如仍为空,报错             ereport(FATAL,                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),                      errmsg("%s: no database nor user name specified",                             progname)));     }     /* Acquire configuration parameters, unless inherited from postmaster */     if (!IsUnderPostmaster)     {         if (!SelectConfigFiles(userDoption, progname))//读取配置文件conf/hba文件&定位数据目录             proc_exit(1);     }     /*      * Set up signal handlers and masks.      *      * Note that postmaster blocked all signals before forking child process,      * so there is no race condition whereby we might receive a signal before      * we have set up the handler.      *      * Also note: it's best not to use any signals that are SIG_IGNored in the      * postmaster.  If such a signal arrives before we are able to change the      * handler to non-SIG_IGN, it'll get dropped.  Instead, make a dummy      * handler in the postmaster to reserve the signal. (Of course, this isn't      * an issue for signals that are locally generated, such as SIGALRM and      * SIGPIPE.)      */     if (am_walsender)//wal sender进程?         WalSndSignals();//如果是,则调用WalSndSignals     else//不是wal sender进程     {         pqsignal(SIGHUP, PostgresSigHupHandler);    /* set flag to read config                                                      * file */         pqsignal(SIGINT, StatementCancelHandler);   /* cancel current query */         pqsignal(SIGTERM, die); /* cancel current query and exit */         /*          * In a standalone backend, SIGQUIT can be generated from the keyboard          * easily, while SIGTERM cannot, so we make both signals do die()          * rather than quickdie().          */         if (IsUnderPostmaster)             pqsignal(SIGQUIT, quickdie);    /* hard crash time */         else             pqsignal(SIGQUIT, die); /* cancel current query and exit */         InitializeTimeouts();   /* establishes SIGALRM handler */         /*          * Ignore failure to write to frontend. Note: if frontend closes          * connection, we will notice it and exit cleanly when control next          * returns to outer loop.  This seems safer than forcing exit in the          * midst of output during who-knows-what operation...          */         pqsignal(SIGPIPE, SIG_IGN);         pqsignal(SIGUSR1, procsignal_sigusr1_handler);         pqsignal(SIGUSR2, SIG_IGN);         pqsignal(SIGFPE, FloatExceptionHandler);         /*          * Reset some signals that are accepted by postmaster but not by          * backend          */         pqsignal(SIGCHLD, SIG_DFL); /* system() requires this on some                                      * platforms */     }     pqinitmask();//Initialize BlockSig, UnBlockSig, and StartupBlockSig.     if (IsUnderPostmaster)     {         /* We allow SIGQUIT (quickdie) at all times */         sigdelset(&BlockSig, SIGQUIT);     }     PG_SETMASK(&BlockSig);      /* block everything except SIGQUIT */     if (!IsUnderPostmaster)     {         /*          * Validate we have been given a reasonable-looking DataDir (if under          * postmaster, assume postmaster did this already).          */         checkDataDir();//确认数据库路径OK,使用stat命令         /* Change into DataDir (if under postmaster, was done already) */         ChangeToDataDir();//切换至数据库路径,使用chdir命令         /*          * Create lockfile for data directory.          */         CreateDataDirLockFile(false);//创建锁定文件,CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir);         /* read control file (error checking and contains config ) */         LocalProcessControlFile(false);//Read the control file, set respective GUCs.         /* Initialize MaxBackends (if under postmaster, was done already) */         InitializeMaxBackends();//Initialize MaxBackends value from config options.     }     /* Early initialization */     BaseInit();//基础的初始化     /*      * Create a per-backend PGPROC struct in shared memory, except in the      * EXEC_BACKEND case where this was done in SubPostmasterMain. We must do      * this before we can use LWLocks (and in the EXEC_BACKEND case we already      * had to do some stuff with LWLocks).      */ // initialize a per-process data structure for this backend #ifdef EXEC_BACKEND     if (!IsUnderPostmaster)         InitProcess(); #else     InitProcess(); #endif     /* We need to allow SIGINT, etc during the initial transaction */     PG_SETMASK(&UnBlockSig);     /*      * General initialization.      *      * NOTE: if you are tempted to add code in this vicinity, consider putting      * it inside InitPostgres() instead.  In particular, anything that      * involves database access should be there, not here.      */     InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, false);//Initialize POSTGRES     /*      * If the PostmasterContext is still around, recycle the space; we don't      * need it anymore after InitPostgres completes.  Note this does not trash      * *MyProcPort, because ConnCreate() allocated that space with malloc()      * ... else we'd need to copy the Port data first.  Also, subsidiary data      * such as the username isn't lost either; see ProcessStartupPacket().      */     if (PostmasterContext)     {         MemoryContextDelete(PostmasterContext);         PostmasterContext = NULL;     }     SetProcessingMode(NormalProcessing);//完成初始化后,设置进程模式为NormalProcessing     /*      * Now all GUC states are fully set up.  Report them to client if      * appropriate.      */     BeginReportingGUCOptions();//Report GUC     /*      * Also set up handler to log session end; we have to wait till now to be      * sure Log_disconnections has its final value.      */     if (IsUnderPostmaster && Log_disconnections)         on_proc_exit(log_disconnections, 0);//this function adds a callback function to the list of functions invoked by proc_exit()     /* Perform initialization specific to a WAL sender process. */     if (am_walsender)         InitWalSender();//初始化 WAL sender process     /*      * process any libraries that should be preloaded at backend start (this      * likewise can't be done until GUC settings are complete)      */     process_session_preload_libraries();//加载LIB     /*      * Send this backend's cancellation info to the frontend.      */     if (whereToSendOutput == DestRemote)     {         StringInfoData buf;         pq_beginmessage(&buf, 'K');         pq_sendint32(&buf, (int32) MyProcPid);         pq_sendint32(&buf, (int32) MyCancelKey);         pq_endmessage(&buf);         /* Need not flush since ReadyForQuery will do it. */     }     /* Welcome banner for standalone case */     if (whereToSendOutput == DestDebug)         printf("\nPostgreSQL stand-alone backend %s\n", PG_VERSION);     /*      * Create the memory context we will use in the main loop.      *      * MessageContext is reset once per iteration of the main loop, ie, upon      * completion of processing of each command message from the client.      */     //初始化内存上下文:MessageContext     MessageContext = AllocSetContextCreate(TopMemoryContext,                                            "MessageContext",                                            ALLOCSET_DEFAULT_SIZES);     /*      * Create memory context and buffer used for RowDescription messages. As      * SendRowDescriptionMessage(), via exec_describe_statement_message(), is      * frequently executed for ever single statement, we don't want to      * allocate a separate buffer every time.      */     //TODO 传输RowDescription messages?     row_description_context = AllocSetContextCreate(TopMemoryContext,                                                     "RowDescriptionContext",                                                     ALLOCSET_DEFAULT_SIZES);     MemoryContextSwitchTo(row_description_context);     initStringInfo(&row_description_buf);     MemoryContextSwitchTo(TopMemoryContext);     /*      * Remember stand-alone backend startup time      */     if (!IsUnderPostmaster)         PgStartTime = GetCurrentTimestamp();//记录启动时间     /*      * POSTGRES main processing loop begins here      *      * If an exception is encountered, processing resumes here so we abort the      * current transaction and start a new one.      *      * You might wonder why this isn't coded as an infinite loop around a      * PG_TRY construct.  The reason is that this is the bottom of the      * exception stack, and so with PG_TRY there would be no exception handler      * in force at all during the CATCH part.  By leaving the outermost setjmp      * always active, we have at least some chance of recovering from an error      * during error recovery.  (If we get into an infinite loop thereby, it      * will soon be stopped by overflow of elog.c's internal state stack.)      *      * Note that we use sigsetjmp(..., 1), so that this function's signal mask      * (to wit, UnBlockSig) will be restored when longjmp'ing to here.  This      * is essential in case we longjmp'd out of a signal handler on a platform      * where that leaves the signal blocked.  It's not redundant with the      * unblock in AbortTransaction() because the latter is only called if we      * were inside a transaction.      */     if (sigsetjmp(local_sigjmp_buf, 1) != 0)//     {         /*          * NOTE: if you are tempted to add more code in this if-block,          * consider the high probability that it should be in          * AbortTransaction() instead.  The only stuff done directly here          * should be stuff that is guaranteed to apply *only* for outer-level          * error recovery, such as adjusting the FE/BE protocol status.          */         /* Since not using PG_TRY, must reset error stack by hand */         error_context_stack = NULL;         /* Prevent interrupts while cleaning up */         HOLD_INTERRUPTS();         /*          * Forget any pending QueryCancel request, since we're returning to          * the idle loop anyway, and cancel any active timeout requests.  (In          * future we might want to allow some timeout requests to survive, but          * at minimum it'd be necessary to do reschedule_timeouts(), in case          * we got here because of a query cancel interrupting the SIGALRM          * interrupt handler.)  Note in particular that we must clear the          * statement and lock timeout indicators, to prevent any future plain          * query cancels from being misreported as timeouts in case we're          * forgetting a timeout cancel.          */         disable_all_timeouts(false);         QueryCancelPending = false; /* second to avoid race condition */         stmt_timeout_active = false;         /* Not reading from the client anymore. */         DoingCommandRead = false;         /* Make sure libpq is in a good state */         pq_comm_reset();         /* Report the error to the client and/or server log */         EmitErrorReport();         /*          * Make sure debug_query_string gets reset before we possibly clobber          * the storage it points at.          */         debug_query_string = NULL;         /*          * Abort the current transaction in order to recover.          */         AbortCurrentTransaction();         if (am_walsender)             WalSndErrorCleanup();         PortalErrorCleanup();         SPICleanup();         /*          * We can't release replication slots inside AbortTransaction() as we          * need to be able to start and abort transactions while having a slot          * acquired. But we never need to hold them across top level errors,          * so releasing here is fine. There's another cleanup in ProcKill()          * ensuring we'll correctly cleanup on FATAL errors as well.          */         if (MyReplicationSlot != NULL)             ReplicationSlotRelease();         /* We also want to cleanup temporary slots on error. */         ReplicationSlotCleanup();         jit_reset_after_error();         /*          * Now return to normal top-level context and clear ErrorContext for          * next time.          */         MemoryContextSwitchTo(TopMemoryContext);         FlushErrorState();         /*          * If we were handling an extended-query-protocol message, initiate          * skip till next Sync.  This also causes us not to issue          * ReadyForQuery (until we get Sync).          */         if (doing_extended_query_message)             ignore_till_sync = true;         /* We don't have a transaction command open anymore */         xact_started = false;         /*          * If an error occurred while we were reading a message from the          * client, we have potentially lost track of where the previous          * message ends and the next one begins.  Even though we have          * otherwise recovered from the error, we cannot safely read any more          * messages from the client, so there isn't much we can do with the          * connection anymore.          */         if (pq_is_reading_msg())             ereport(FATAL,                     (errcode(ERRCODE_PROTOCOL_VIOLATION),                      errmsg("terminating connection because protocol synchronization was lost")));         /* Now we can allow interrupts again */         RESUME_INTERRUPTS();     }     /* We can now handle ereport(ERROR) */     PG_exception_stack = &local_sigjmp_buf;     if (!ignore_till_sync)         send_ready_for_query = true;    /* initially, or after error */     /*      * Non-error queries loop here.      */     for (;;)//主循环     {         /*          * At top of loop, reset extended-query-message flag, so that any          * errors encountered in "idle" state don't provoke skip.          */         doing_extended_query_message = false;         /*          * Release storage left over from prior query cycle, and create a new          * query input buffer in the cleared MessageContext.          */         MemoryContextSwitchTo(MessageContext);//切换至MessageContext         MemoryContextResetAndDeleteChildren(MessageContext);         initStringInfo(&input_message);//初始化输入的信息         /*          * Also consider releasing our catalog snapshot if any, so that it's          * not preventing advance of global xmin while we wait for the client.          */         InvalidateCatalogSnapshotConditionally();         /*          * (1) If we've reached idle state, tell the frontend we're ready for          * a new query.          *          * Note: this includes fflush()'ing the last of the prior output.          *          * This is also a good time to send collected statistics to the          * collector, and to update the PS stats display.  We avoid doing          * those every time through the message loop because it'd slow down          * processing of batched messages, and because we don't want to report          * uncommitted updates (that confuses autovacuum).  The notification          * processor wants a call too, if we are not in a transaction block.          */         if (send_ready_for_query)//I am ready!         {             if (IsAbortedTransactionBlockState())             {                 set_ps_display("idle in transaction (aborted)", false);                 pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL);                 /* Start the idle-in-transaction timer */                 if (IdleInTransactionSessionTimeout > 0)                 {                     disable_idle_in_transaction_timeout = true;                     enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,                                          IdleInTransactionSessionTimeout);                 }             }             else if (IsTransactionOrTransactionBlock())             {                 set_ps_display("idle in transaction", false);                 pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL);                 /* Start the idle-in-transaction timer */                 if (IdleInTransactionSessionTimeout > 0)                 {                     disable_idle_in_transaction_timeout = true;                     enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,                                          IdleInTransactionSessionTimeout);                 }             }             else             {                 ProcessCompletedNotifies();                 pgstat_report_stat(false);                 set_ps_display("idle", false);                 pgstat_report_activity(STATE_IDLE, NULL);             }             ReadyForQuery(whereToSendOutput);             send_ready_for_query = false;         }         /*          * (2) Allow asynchronous signals to be executed immediately if they          * come in while we are waiting for client input. (This must be          * conditional since we don't want, say, reads on behalf of COPY FROM          * STDIN doing the same thing.)          */         DoingCommandRead = true;         /*          * (3) read a command (loop blocks here)          */         firstchar = ReadCommand(&input_message);//读取命令         /*          * (4) disable async signal conditions again.          *          * Query cancel is supposed to be a no-op when there is no query in          * progress, so if a query cancel arrived while we were idle, just          * reset QueryCancelPending. ProcessInterrupts() has that effect when          * it's called when DoingCommandRead is set, so check for interrupts          * before resetting DoingCommandRead.          */         CHECK_FOR_INTERRUPTS();         DoingCommandRead = false;         /*          * (5) turn off the idle-in-transaction timeout          */         if (disable_idle_in_transaction_timeout)         {             disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false);             disable_idle_in_transaction_timeout = false;         }         /*          * (6) check for any other interesting events that happened while we          * slept.          */         if (ConfigReloadPending)         {             ConfigReloadPending = false;             ProcessConfigFile(PGC_SIGHUP);         }         /*          * (7) process the command.  But ignore it if we're skipping till          * Sync.          */         if (ignore_till_sync && firstchar != EOF)             continue;         switch (firstchar)         {             case 'Q':           /* simple query */                 {                     const char *query_string;                     /* Set statement_timestamp() */                     SetCurrentStatementStartTimestamp();                     query_string = pq_getmsgstring(&input_message);//SQL语句                     pq_getmsgend(&input_message);                     if (am_walsender)                     {                         if (!exec_replication_command(query_string))                             exec_simple_query(query_string);                     }                     else                         exec_simple_query(query_string);//执行SQL语句                     send_ready_for_query = true;                 }                 break;             case 'P':           /* parse */                 {                     const char *stmt_name;                     const char *query_string;                     int         numParams;                     Oid        *paramTypes = NULL;                     forbidden_in_wal_sender(firstchar);                     /* Set statement_timestamp() */                     SetCurrentStatementStartTimestamp();                     stmt_name = pq_getmsgstring(&input_message);                     query_string = pq_getmsgstring(&input_message);                     numParams = pq_getmsgint(&input_message, 2);                     if (numParams > 0)                     {                         int         i;                         paramTypes = (Oid *) palloc(numParams * sizeof(Oid));                         for (i = 0; i < numParams; i++)                             paramTypes[i] = pq_getmsgint(&input_message, 4);                     }                     pq_getmsgend(&input_message);                     exec_parse_message(query_string, stmt_name,                                        paramTypes, numParams);                 }                 break;             case 'B':           /* bind */                 forbidden_in_wal_sender(firstchar);                 /* Set statement_timestamp() */                 SetCurrentStatementStartTimestamp();                 /*                  * this message is complex enough that it seems best to put                  * the field extraction out-of-line                  */                 exec_bind_message(&input_message);                 break;             case 'E':           /* execute */                 {                     const char *portal_name;                     int         max_rows;                     forbidden_in_wal_sender(firstchar);                     /* Set statement_timestamp() */                     SetCurrentStatementStartTimestamp();                     portal_name = pq_getmsgstring(&input_message);                     max_rows = pq_getmsgint(&input_message, 4);                     pq_getmsgend(&input_message);                     exec_execute_message(portal_name, max_rows);                 }                 break;             case 'F':           /* fastpath function call */                 forbidden_in_wal_sender(firstchar);                 /* Set statement_timestamp() */                 SetCurrentStatementStartTimestamp();                 /* Report query to various monitoring facilities. */                 pgstat_report_activity(STATE_FASTPATH, NULL);                 set_ps_display("<FASTPATH>", false);                 /* start an xact for this function invocation */                 start_xact_command();                 /*                  * Note: we may at this point be inside an aborted                  * transaction.  We can't throw error for that until we've                  * finished reading the function-call message, so                  * HandleFunctionRequest() must check for it after doing so.                  * Be careful not to do anything that assumes we're inside a                  * valid transaction here.                  */                 /* switch back to message context */                 MemoryContextSwitchTo(MessageContext);                 HandleFunctionRequest(&input_message);                 /* commit the function-invocation transaction */                 finish_xact_command();                 send_ready_for_query = true;                 break;             case 'C':           /* close */                 {                     int         close_type;                     const char *close_target;                     forbidden_in_wal_sender(firstchar);                     close_type = pq_getmsgbyte(&input_message);                     close_target = pq_getmsgstring(&input_message);                     pq_getmsgend(&input_message);                     switch (close_type)                     {                         case 'S':                             if (close_target[0] != '\0')                                 DropPreparedStatement(close_target, false);                             else                             {                                 /* special-case the unnamed statement */                                 drop_unnamed_stmt();                             }                             break;                         case 'P':                             {                                 Portal      portal;                                 portal = GetPortalByName(close_target);                                 if (PortalIsValid(portal))                                     PortalDrop(portal, false);                             }                             break;                         default:                             ereport(ERROR,                                     (errcode(ERRCODE_PROTOCOL_VIOLATION),                                      errmsg("invalid CLOSE message subtype %d",                                             close_type)));                             break;                     }                     if (whereToSendOutput == DestRemote)                         pq_putemptymessage('3');    /* CloseComplete */                 }                 break;             case 'D':           /* describe */                 {                     int         describe_type;                     const char *describe_target;                     forbidden_in_wal_sender(firstchar);                     /* Set statement_timestamp() (needed for xact) */                     SetCurrentStatementStartTimestamp();                     describe_type = pq_getmsgbyte(&input_message);                     describe_target = pq_getmsgstring(&input_message);                     pq_getmsgend(&input_message);                     switch (describe_type)                     {                         case 'S':                             exec_describe_statement_message(describe_target);                             break;                         case 'P':                             exec_describe_portal_message(describe_target);                             break;                         default:                             ereport(ERROR,                                     (errcode(ERRCODE_PROTOCOL_VIOLATION),                                      errmsg("invalid DESCRIBE message subtype %d",                                             describe_type)));                             break;                     }                 }                 break;             case 'H':           /* flush */                 pq_getmsgend(&input_message);                 if (whereToSendOutput == DestRemote)                     pq_flush();                 break;             case 'S':           /* sync */                 pq_getmsgend(&input_message);                 finish_xact_command();                 send_ready_for_query = true;                 break;                 /*                  * 'X' means that the frontend is closing down the socket. EOF                  * means unexpected loss of frontend connection. Either way,                  * perform normal shutdown.                  */             case 'X':             case EOF:                 /*                  * Reset whereToSendOutput to prevent ereport from attempting                  * to send any more messages to client.                  */                 if (whereToSendOutput == DestRemote)                     whereToSendOutput = DestNone;                 /*                  * NOTE: if you are tempted to add more code here, DON'T!                  * Whatever you had in mind to do should be set up as an                  * on_proc_exit or on_shmem_exit callback, instead. Otherwise                  * it will fail to be called during other backend-shutdown                  * scenarios.                  */                 proc_exit(0);             case 'd':           /* copy data */             case 'c':           /* copy done */             case 'f':           /* copy fail */                 /*                  * Accept but ignore these messages, per protocol spec; we                  * probably got here because a COPY failed, and the frontend                  * is still sending data.                  */                 break;             default:                 ereport(FATAL,                         (errcode(ERRCODE_PROTOCOL_VIOLATION),                          errmsg("invalid frontend message type %d",                                 firstchar)));         }     }                           /* end of input-reading loop */ }

二、基础信息

PostgresMain函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、StringInfoData

 /*-------------------------   * StringInfoData holds information about an extensible string.   *      data    is the current buffer for the string (allocated with palloc).   *      len     is the current string length.  There is guaranteed to be   *              a terminating '\0' at data[len], although this is not very   *              useful when the string holds binary data rather than text.   *      maxlen  is the allocated size in bytes of 'data', i.e. the maximum   *              string size (including the terminating '\0' char) that we can   *              currently store in 'data' without having to reallocate   *              more space.  We must always have maxlen > len.   *      cursor  is initialized to zero by makeStringInfo or initStringInfo,   *              but is not otherwise touched by the stringinfo.c routines.   *              Some routines use it to scan through a StringInfo.   *-------------------------   */  typedef struct StringInfoData  {      char       *data;      int         len;      int         maxlen;      int         cursor;  } StringInfoData;    typedef StringInfoData *StringInfo;

2、宏定义

  #ifndef WIN32  #define PG_SETMASK(mask)    sigprocmask(SIG_SETMASK, mask, NULL)  #else  /* Emulate POSIX sigset_t APIs on Windows */  typedef int sigset_t;    extern int  pqsigsetmask(int mask);    #define PG_SETMASK(mask)        pqsigsetmask(*(mask))  #define sigemptyset(set)        (*(set) = 0)  #define sigfillset(set)         (*(set) = ~0)  #define sigaddset(set, signum)  (*(set) |= (sigmask(signum)))  #define sigdelset(set, signum)  (*(set) &= ~(sigmask(signum)))  #endif                          /* WIN32 */

3、全局变量

/*   * IsPostmasterEnvironment is true in a postmaster process and any postmaster   * child process; it is false in a standalone process (bootstrap or   * standalone backend).  IsUnderPostmaster is true in postmaster child   * processes.  Note that "child process" includes all children, not only   * regular backends.  These should be set correctly as early as possible   * in the execution of a process, so that error handling will do the right   * things if an error should occur during process initialization.   *   * These are initialized for the bootstrap/standalone case.   */  bool        IsPostmasterEnvironment = false;  bool        IsUnderPostmaster = false;  bool        IsBinaryUpgrade = false;  bool IsBackgroundWorker = false;  bool am_walsender = false; /* Am I a walsender process? */

依赖的函数
1、InitStandaloneProcess

 /*   * Initialize the basic environment for a standalone process.   *   * argv0 has to be suitable to find the program's executable.   */  void  InitStandaloneProcess(const char *argv0)  {      Assert(!IsPostmasterEnvironment);        MyProcPid = getpid();       /* reset MyProcPid */        MyStartTime = time(NULL);   /* set our start time in case we call elog */        /* Initialize process-local latch support */      InitializeLatchSupport();      MyLatch = &LocalLatchData;      InitLatch(MyLatch);        /* Compute paths, no postmaster to inherit from */      if (my_exec_path[0] == '\0')      {          if (find_my_exec(argv0, my_exec_path) < 0)              elog(FATAL, "%s: could not locate my own executable path",                   argv0);      }        if (pkglib_path[0] == '\0')          get_pkglib_path(my_exec_path, pkglib_path);  }

2、InitializeGUCOptions

 /*   * Initialize GUC options during program startup.   *   * Note that we cannot read the config file yet, since we have not yet   * processed command-line switches.   */  void  InitializeGUCOptions(void)  {      int         i;        /*       * Before log_line_prefix could possibly receive a nonempty setting, make       * sure that timezone processing is minimally alive (see elog.c).       */      pg_timezone_initialize();        /*       * Build sorted array of all GUC variables.       */      build_guc_variables();        /*       * Load all variables with their compiled-in defaults, and initialize       * status fields as needed.       */      for (i = 0; i < num_guc_variables; i++)      {          InitializeOneGUCOption(guc_variables[i]);      }        guc_dirty = false;        reporting_enabled = false;        /*       * Prevent any attempt to override the transaction modes from       * non-interactive sources.       */      SetConfigOption("transaction_isolation", "default",                      PGC_POSTMASTER, PGC_S_OVERRIDE);      SetConfigOption("transaction_read_only", "no",                      PGC_POSTMASTER, PGC_S_OVERRIDE);      SetConfigOption("transaction_deferrable", "no",                      PGC_POSTMASTER, PGC_S_OVERRIDE);        /*       * For historical reasons, some GUC parameters can receive defaults from       * environment variables.  Process those settings.       */      InitializeGUCOptionsFromEnvironment();  }

3、process_postgres_switches

 /* ----------------------------------------------------------------   * process_postgres_switches   *     Parse command line arguments for PostgresMain   *   * This is called twice, once for the "secure" options coming from the   * postmaster or command line, and once for the "insecure" options coming   * from the client's startup packet.  The latter have the same syntax but   * may be restricted in what they can do.   *   * argv[0] is ignored in either case (it's assumed to be the program name).   *   * ctx is PGC_POSTMASTER for secure options, PGC_BACKEND for insecure options   * coming from the client, or PGC_SU_BACKEND for insecure options coming from   * a superuser client.   *   * If a database name is present in the command line arguments, it's   * returned into *dbname (this is allowed only if *dbname is initially NULL).   * ----------------------------------------------------------------   */  void  process_postgres_switches(int argc, char *argv[], GucContext ctx,                            const char **dbname)  {      bool        secure = (ctx == PGC_POSTMASTER);      int         errs = 0;      GucSource   gucsource;      int         flag;        if (secure)      {          gucsource = PGC_S_ARGV; /* switches came from command line */            /* Ignore the initial --single argument, if present */          if (argc > 1 && strcmp(argv[1], "--single") == 0)          {              argv++;              argc--;          }      }      else      {          gucsource = PGC_S_CLIENT;   /* switches came from client */      }    #ifdef HAVE_INT_OPTERR        /*       * Turn this off because it's either printed to stderr and not the log       * where we'd want it, or argv[0] is now "--single", which would make for       * a weird error message.  We print our own error message below.       */      opterr = 0;  #endif        /*       * Parse command-line options.  CAUTION: keep this in sync with       * postmaster/postmaster.c (the option sets should not conflict) and with       * the common help() function in main/main.c.       */      while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:-:")) != -1)      {          switch (flag)          {              case 'B':                  SetConfigOption("shared_buffers", optarg, ctx, gucsource);                  break;                case 'b':                  /* Undocumented flag used for binary upgrades */                  if (secure)                      IsBinaryUpgrade = true;                  break;                case 'C':                  /* ignored for consistency with the postmaster */                  break;                case 'D':                  if (secure)                      userDoption = strdup(optarg);                  break;                case 'd':                  set_debug_options(atoi(optarg), ctx, gucsource);                  break;                case 'E':                  if (secure)                      EchoQuery = true;                  break;                case 'e':                  SetConfigOption("datestyle", "euro", ctx, gucsource);                  break;                case 'F':                  SetConfigOption("fsync", "false", ctx, gucsource);                  break;                case 'f':                  if (!set_plan_disabling_options(optarg, ctx, gucsource))                      errs++;                  break;                case 'h':                  SetConfigOption("listen_addresses", optarg, ctx, gucsource);                  break;                case 'i':                  SetConfigOption("listen_addresses", "*", ctx, gucsource);                  break;                case 'j':                  if (secure)                      UseSemiNewlineNewline = true;                  break;                case 'k':                  SetConfigOption("unix_socket_directories", optarg, ctx, gucsource);                  break;                case 'l':                  SetConfigOption("ssl", "true", ctx, gucsource);                  break;                case 'N':                  SetConfigOption("max_connections", optarg, ctx, gucsource);                  break;                case 'n':                  /* ignored for consistency with postmaster */                  break;                case 'O':                  SetConfigOption("allow_system_table_mods", "true", ctx, gucsource);                  break;                case 'o':                  errs++;                  break;                case 'P':                  SetConfigOption("ignore_system_indexes", "true", ctx, gucsource);                  break;                case 'p':                  SetConfigOption("port", optarg, ctx, gucsource);                  break;                case 'r':                  /* send output (stdout and stderr) to the given file */                  if (secure)                      strlcpy(OutputFileName, optarg, MAXPGPATH);                  break;                case 'S':                  SetConfigOption("work_mem", optarg, ctx, gucsource);                  break;                case 's':                  SetConfigOption("log_statement_stats", "true", ctx, gucsource);                  break;                case 'T':                  /* ignored for consistency with the postmaster */                  break;                case 't':                  {                      const char *tmp = get_stats_option_name(optarg);                        if (tmp)                          SetConfigOption(tmp, "true", ctx, gucsource);                      else                          errs++;                      break;                  }                case 'v':                    /*                   * -v is no longer used in normal operation, since                   * FrontendProtocol is already set before we get here. We keep                   * the switch only for possible use in standalone operation,                   * in case we ever support using normal FE/BE protocol with a                   * standalone backend.                   */                  if (secure)                      FrontendProtocol = (ProtocolVersion) atoi(optarg);                  break;                case 'W':                  SetConfigOption("post_auth_delay", optarg, ctx, gucsource);                  break;                case 'c':              case '-':                  {                      char       *name,                                 *value;                        ParseLongOption(optarg, &name, &value);                      if (!value)                      {                          if (flag == '-')                              ereport(ERROR,                                      (errcode(ERRCODE_SYNTAX_ERROR),                                       errmsg("--%s requires a value",                                              optarg)));                          else                              ereport(ERROR,                                      (errcode(ERRCODE_SYNTAX_ERROR),                                       errmsg("-c %s requires a value",                                              optarg)));                      }                      SetConfigOption(name, value, ctx, gucsource);                      free(name);                      if (value)                          free(value);                      break;                  }                default:                  errs++;                  break;          }            if (errs)              break;      }        /*       * Optional database name should be there only if *dbname is NULL.       */      if (!errs && dbname && *dbname == NULL && argc - optind >= 1)          *dbname = strdup(argv[optind++]);        if (errs || argc != optind)      {          if (errs)              optind--;           /* complain about the previous argument */            /* spell the error message a bit differently depending on context */          if (IsUnderPostmaster)              ereport(FATAL,                      (errcode(ERRCODE_SYNTAX_ERROR),                       errmsg("invalid command-line argument for server process: %s", argv[optind]),                       errhint("Try \"%s --help\" for more information.", progname)));          else              ereport(FATAL,                      (errcode(ERRCODE_SYNTAX_ERROR),                       errmsg("%s: invalid command-line argument: %s",                              progname, argv[optind]),                       errhint("Try \"%s --help\" for more information.", progname)));      }        /*       * Reset getopt(3) library so that it will work correctly in subprocesses       * or when this function is called a second time with another array.       */      optind = 1;  #ifdef HAVE_INT_OPTRESET      optreset = 1;               /* some systems need this too */  #endif  }

4、SelectConfigFiles

 /*   * Select the configuration files and data directory to be used, and   * do the initial read of postgresql.conf.   *   * This is called after processing command-line switches.   *      userDoption is the -D switch value if any (NULL if unspecified).   *      progname is just for use in error messages.   *   * Returns true on success; on failure, prints a suitable error message   * to stderr and returns false.   */  bool  SelectConfigFiles(const char *userDoption, const char *progname)  {      char       *configdir;      char       *fname;      struct stat stat_buf;        /* configdir is -D option, or $PGDATA if no -D */      if (userDoption)          configdir = make_absolute_path(userDoption);      else          configdir = make_absolute_path(getenv("PGDATA"));        if (configdir && stat(configdir, &stat_buf) != 0)      {          write_stderr("%s: could not access directory \"%s\": %s\n",                       progname,                       configdir,                       strerror(errno));          if (errno == ENOENT)              write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n");          return false;      }        /*       * Find the configuration file: if config_file was specified on the       * command line, use it, else use configdir/postgresql.conf.  In any case       * ensure the result is an absolute path, so that it will be interpreted       * the same way by future backends.       */      if (ConfigFileName)          fname = make_absolute_path(ConfigFileName);      else if (configdir)      {          fname = guc_malloc(FATAL,                             strlen(configdir) + strlen(CONFIG_FILENAME) + 2);          sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);      }      else      {          write_stderr("%s does not know where to find the server configuration file.\n"                       "You must specify the --config-file or -D invocation "                       "option or set the PGDATA environment variable.\n",                       progname);          return false;      }        /*       * Set the ConfigFileName GUC variable to its final value, ensuring that       * it can't be overridden later.       */      SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);      free(fname);        /*       * Now read the config file for the first time.       */      if (stat(ConfigFileName, &stat_buf) != 0)      {          write_stderr("%s: could not access the server configuration file \"%s\": %s\n",                       progname, ConfigFileName, strerror(errno));          free(configdir);          return false;      }        /*       * Read the configuration file for the first time.  This time only the       * data_directory parameter is picked up to determine the data directory,       * so that we can read the PG_AUTOCONF_FILENAME file next time.       */      ProcessConfigFile(PGC_POSTMASTER);        /*       * If the data_directory GUC variable has been set, use that as DataDir;       * otherwise use configdir if set; else punt.       *       * Note: SetDataDir will copy and absolute-ize its argument, so we don't       * have to.       */      if (data_directory)          SetDataDir(data_directory);      else if (configdir)          SetDataDir(configdir);      else      {          write_stderr("%s does not know where to find the database system data.\n"                       "This can be specified as \"data_directory\" in \"%s\", "                       "or by the -D invocation option, or by the "                       "PGDATA environment variable.\n",                       progname, ConfigFileName);          return false;      }        /*       * Reflect the final DataDir value back into the data_directory GUC var.       * (If you are wondering why we don't just make them a single variable,       * it's because the EXEC_BACKEND case needs DataDir to be transmitted to       * child backends specially.  XXX is that still true?  Given that we now       * chdir to DataDir, EXEC_BACKEND can read the config file without knowing       * DataDir in advance.)       */      SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);        /*       * Now read the config file a second time, allowing any settings in the       * PG_AUTOCONF_FILENAME file to take effect.  (This is pretty ugly, but       * since we have to determine the DataDir before we can find the autoconf       * file, the alternatives seem worse.)       */      ProcessConfigFile(PGC_POSTMASTER);        /*       * If timezone_abbreviations wasn't set in the configuration file, install       * the default value.  We do it this way because we can't safely install a       * "real" value until my_exec_path is set, which may not have happened       * when InitializeGUCOptions runs, so the bootstrap default value cannot       * be the real desired default.       */      pg_timezone_abbrev_initialize();        /*       * Figure out where pg_hba.conf is, and make sure the path is absolute.       */      if (HbaFileName)          fname = make_absolute_path(HbaFileName);      else if (configdir)      {          fname = guc_malloc(FATAL,                             strlen(configdir) + strlen(HBA_FILENAME) + 2);          sprintf(fname, "%s/%s", configdir, HBA_FILENAME);      }      else      {          write_stderr("%s does not know where to find the \"hba\" configuration file.\n"                       "This can be specified as \"hba_file\" in \"%s\", "                       "or by the -D invocation option, or by the "                       "PGDATA environment variable.\n",                       progname, ConfigFileName);          return false;      }      SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);      free(fname);        /*       * Likewise for pg_ident.conf.       */      if (IdentFileName)          fname = make_absolute_path(IdentFileName);      else if (configdir)      {          fname = guc_malloc(FATAL,                             strlen(configdir) + strlen(IDENT_FILENAME) + 2);          sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);      }      else      {          write_stderr("%s does not know where to find the \"ident\" configuration file.\n"                       "This can be specified as \"ident_file\" in \"%s\", "                       "or by the -D invocation option, or by the "                       "PGDATA environment variable.\n",                       progname, ConfigFileName);          return false;      }      SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);      free(fname);        free(configdir);        return true;  }

5、pqinitmask

 /*   * Initialize BlockSig, UnBlockSig, and StartupBlockSig.   *   * BlockSig is the set of signals to block when we are trying to block   * signals.  This includes all signals we normally expect to get, but NOT   * signals that should never be turned off.   *   * StartupBlockSig is the set of signals to block during startup packet   * collection; it's essentially BlockSig minus SIGTERM, SIGQUIT, SIGALRM.   *   * UnBlockSig is the set of signals to block when we don't want to block   * signals (is this ever nonzero??)   */  void  pqinitmask(void)  {      sigemptyset(&UnBlockSig);        /* First set all signals, then clear some. */      sigfillset(&BlockSig);      sigfillset(&StartupBlockSig);        /*       * Unmark those signals that should never be blocked. Some of these signal       * names don't exist on all platforms.  Most do, but might as well ifdef       * them all for consistency...       */  #ifdef SIGTRAP      sigdelset(&BlockSig, SIGTRAP);      sigdelset(&StartupBlockSig, SIGTRAP);  #endif  #ifdef SIGABRT      sigdelset(&BlockSig, SIGABRT);      sigdelset(&StartupBlockSig, SIGABRT);  #endif  #ifdef SIGILL      sigdelset(&BlockSig, SIGILL);      sigdelset(&StartupBlockSig, SIGILL);  #endif  #ifdef SIGFPE      sigdelset(&BlockSig, SIGFPE);      sigdelset(&StartupBlockSig, SIGFPE);  #endif  #ifdef SIGSEGV      sigdelset(&BlockSig, SIGSEGV);      sigdelset(&StartupBlockSig, SIGSEGV);  #endif  #ifdef SIGBUS      sigdelset(&BlockSig, SIGBUS);      sigdelset(&StartupBlockSig, SIGBUS);  #endif  #ifdef SIGSYS      sigdelset(&BlockSig, SIGSYS);      sigdelset(&StartupBlockSig, SIGSYS);  #endif  #ifdef SIGCONT      sigdelset(&BlockSig, SIGCONT);      sigdelset(&StartupBlockSig, SIGCONT);  #endif    /* Signals unique to startup */  #ifdef SIGQUIT      sigdelset(&StartupBlockSig, SIGQUIT);  #endif  #ifdef SIGTERM      sigdelset(&StartupBlockSig, SIGTERM);  #endif  #ifdef SIGALRM      sigdelset(&StartupBlockSig, SIGALRM);  #endif  }

6、BaseInit

 /*   * Early initialization of a backend (either standalone or under postmaster).   * This happens even before InitPostgres.   *   * This is separate from InitPostgres because it is also called by auxiliary   * processes, such as the background writer process, which may not call   * InitPostgres at all.   */  void  BaseInit(void)  {      /*       * Attach to shared memory and semaphores, and initialize our       * input/output/debugging file descriptors.       */      InitCommunication();      DebugFileOpen();        /* Do local initialization of file, storage and buffer managers */      InitFileAccess();      smgrinit();      InitBufferPoolAccess();  }

7、InitProcess

 /*   * InitProcess -- initialize a per-process data structure for this backend   */  void  InitProcess(void)  {      PGPROC     *volatile *procgloballist;        /*       * ProcGlobal should be set up already (if we are a backend, we inherit       * this by fork() or EXEC_BACKEND mechanism from the postmaster).       */      if (ProcGlobal == NULL)          elog(PANIC, "proc header uninitialized");        if (MyProc != NULL)          elog(ERROR, "you already exist");        /* Decide which list should supply our PGPROC. */      if (IsAnyAutoVacuumProcess())          procgloballist = &ProcGlobal->autovacFreeProcs;      else if (IsBackgroundWorker)          procgloballist = &ProcGlobal->bgworkerFreeProcs;      else          procgloballist = &ProcGlobal->freeProcs;        /*       * Try to get a proc struct from the appropriate free list.  If this       * fails, we must be out of PGPROC structures (not to mention semaphores).       *       * While we are holding the ProcStructLock, also copy the current shared       * estimate of spins_per_delay to local storage.       */      SpinLockAcquire(ProcStructLock);        set_spins_per_delay(ProcGlobal->spins_per_delay);        MyProc = *procgloballist;        if (MyProc != NULL)      {          *procgloballist = (PGPROC *) MyProc->links.next;          SpinLockRelease(ProcStructLock);      }      else      {          /*           * If we reach here, all the PGPROCs are in use.  This is one of the           * possible places to detect "too many backends", so give the standard           * error message.  XXX do we need to give a different failure message           * in the autovacuum case?           */          SpinLockRelease(ProcStructLock);          ereport(FATAL,                  (errcode(ERRCODE_TOO_MANY_CONNECTIONS),                   errmsg("sorry, too many clients already")));      }      MyPgXact = &ProcGlobal->allPgXact[MyProc->pgprocno];        /*       * Cross-check that the PGPROC is of the type we expect; if this were not       * the case, it would get returned to the wrong list.       */      Assert(MyProc->procgloballist == procgloballist);        /*       * Now that we have a PGPROC, mark ourselves as an active postmaster       * child; this is so that the postmaster can detect it if we exit without       * cleaning up.  (XXX autovac launcher currently doesn't participate in       * this; it probably should.)       */      if (IsUnderPostmaster && !IsAutoVacuumLauncherProcess())          MarkPostmasterChildActive();        /*       * Initialize all fields of MyProc, except for those previously       * initialized by InitProcGlobal.       */      SHMQueueElemInit(&(MyProc->links));      MyProc->waitStatus = STATUS_OK;      MyProc->lxid = InvalidLocalTransactionId;      MyProc->fpVXIDLock = false;      MyProc->fpLocalTransactionId = InvalidLocalTransactionId;      MyPgXact->xid = InvalidTransactionId;      MyPgXact->xmin = InvalidTransactionId;      MyProc->pid = MyProcPid;      /* backendId, databaseId and roleId will be filled in later */      MyProc->backendId = InvalidBackendId;      MyProc->databaseId = InvalidOid;      MyProc->roleId = InvalidOid;      MyProc->isBackgroundWorker = IsBackgroundWorker;      MyPgXact->delayChkpt = false;      MyPgXact->vacuumFlags = 0;      /* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */      if (IsAutoVacuumWorkerProcess())          MyPgXact->vacuumFlags |= PROC_IS_AUTOVACUUM;      MyProc->lwWaiting = false;      MyProc->lwWaitMode = 0;      MyProc->waitLock = NULL;      MyProc->waitProcLock = NULL;  #ifdef USE_ASSERT_CHECKING      {          int         i;            /* Last process should have released all locks. */          for (i = 0; i < NUM_LOCK_PARTITIONS; i++)              Assert(SHMQueueEmpty(&(MyProc->myProcLocks[i])));      }  #endif      MyProc->recoveryConflictPending = false;        /* Initialize fields for sync rep */      MyProc->waitLSN = 0;      MyProc->syncRepState = SYNC_REP_NOT_WAITING;      SHMQueueElemInit(&(MyProc->syncRepLinks));        /* Initialize fields for group XID clearing. */      MyProc->procArrayGroupMember = false;      MyProc->procArrayGroupMemberXid = InvalidTransactionId;      pg_atomic_init_u32(&MyProc->procArrayGroupNext, INVALID_PGPROCNO);        /* Check that group locking fields are in a proper initial state. */      Assert(MyProc->lockGroupLeader == NULL);      Assert(dlist_is_empty(&MyProc->lockGroupMembers));        /* Initialize wait event information. */      MyProc->wait_event_info = 0;        /* Initialize fields for group transaction status update. */      MyProc->clogGroupMember = false;      MyProc->clogGroupMemberXid = InvalidTransactionId;      MyProc->clogGroupMemberXidStatus = TRANSACTION_STATUS_IN_PROGRESS;      MyProc->clogGroupMemberPage = -1;      MyProc->clogGroupMemberLsn = InvalidXLogRecPtr;      pg_atomic_init_u32(&MyProc->clogGroupNext, INVALID_PGPROCNO);        /*       * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch       * on it.  That allows us to repoint the process latch, which so far       * points to process local one, to the shared one.       */      OwnLatch(&MyProc->procLatch);      SwitchToSharedLatch();        /*       * We might be reusing a semaphore that belonged to a failed process. So       * be careful and reinitialize its value here.  (This is not strictly       * necessary anymore, but seems like a good idea for cleanliness.)       */      PGSemaphoreReset(MyProc->sem);        /*       * Arrange to clean up at backend exit.       */      on_shmem_exit(ProcKill, 0);        /*       * Now that we have a PGPROC, we could try to acquire locks, so initialize       * local state needed for LWLocks, and the deadlock checker.       */      InitLWLockAccess();      InitDeadLockChecking();  }

8、InitPostgres

 /* --------------------------------   * InitPostgres   *      Initialize POSTGRES.   *   * The database can be specified by name, using the in_dbname parameter, or by   * OID, using the dboid parameter.  In the latter case, the actual database   * name can be returned to the caller in out_dbname.  If out_dbname isn't   * NULL, it must point to a buffer of size NAMEDATALEN.   *   * Similarly, the username can be passed by name, using the username parameter,   * or by OID using the useroid parameter.   *   * In bootstrap mode no parameters are used.  The autovacuum launcher process   * doesn't use any parameters either, because it only goes far enough to be   * able to read pg_database; it doesn't connect to any particular database.   * In walsender mode only username is used.   *   * As of PostgreSQL 8.2, we expect InitProcess() was already called, so we   * already have a PGPROC struct ... but it's not completely filled in yet.   *   * Note:   *      Be very careful with the order of calls in the InitPostgres function.   * --------------------------------   */  void  InitPostgres(const char *in_dbname, Oid dboid, const char *username,               Oid useroid, char *out_dbname, bool override_allow_connections)  {      bool        bootstrap = IsBootstrapProcessingMode();      bool        am_superuser;      char       *fullpath;      char        dbname[NAMEDATALEN];        elog(DEBUG3, "InitPostgres");        /*       * Add my PGPROC struct to the ProcArray.       *       * Once I have done this, I am visible to other backends!       */      InitProcessPhase2();        /*       * Initialize my entry in the shared-invalidation manager's array of       * per-backend data.       *       * Sets up MyBackendId, a unique backend identifier.       */      MyBackendId = InvalidBackendId;        SharedInvalBackendInit(false);        if (MyBackendId > MaxBackends || MyBackendId <= 0)          elog(FATAL, "bad backend ID: %d", MyBackendId);        /* Now that we have a BackendId, we can participate in ProcSignal */      ProcSignalInit(MyBackendId);        /*       * Also set up timeout handlers needed for backend operation.  We need       * these in every case except bootstrap.       */      if (!bootstrap)      {          RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLockAlert);          RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler);          RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler);          RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,                          IdleInTransactionSessionTimeoutHandler);      }        /*       * bufmgr needs another initialization call too       */      InitBufferPoolBackend();        /*       * Initialize local process's access to XLOG.       */      if (IsUnderPostmaster)      {          /*           * The postmaster already started the XLOG machinery, but we need to           * call InitXLOGAccess(), if the system isn't in hot-standby mode.           * This is handled by calling RecoveryInProgress and ignoring the           * result.           */          (void) RecoveryInProgress();      }      else      {          /*           * We are either a bootstrap process or a standalone backend. Either           * way, start up the XLOG machinery, and register to have it closed           * down at exit.           *           * We don't yet have an aux-process resource owner, but StartupXLOG           * and ShutdownXLOG will need one.  Hence, create said resource owner           * (and register a callback to clean it up after ShutdownXLOG runs).           */          CreateAuxProcessResourceOwner();            StartupXLOG();          /* Release (and warn about) any buffer pins leaked in StartupXLOG */          ReleaseAuxProcessResources(true);          /* Reset CurrentResourceOwner to nothing for the moment */          CurrentResourceOwner = NULL;            on_shmem_exit(ShutdownXLOG, 0);      }        /*       * Initialize the relation cache and the system catalog caches.  Note that       * no catalog access happens here; we only set up the hashtable structure.       * We must do this before starting a transaction because transaction abort       * would try to touch these hashtables.       */      RelationCacheInitialize();      InitCatalogCache();      InitPlanCache();        /* Initialize portal manager */      EnablePortalManager();        /* Initialize stats collection --- must happen before first xact */      if (!bootstrap)          pgstat_initialize();        /*       * Load relcache entries for the shared system catalogs.  This must create       * at least entries for pg_database and catalogs used for authentication.       */      RelationCacheInitializePhase2();        /*       * Set up process-exit callback to do pre-shutdown cleanup.  This is the       * first before_shmem_exit callback we register; thus, this will be the       * last thing we do before low-level modules like the buffer manager begin       * to close down.  We need to have this in place before we begin our first       * transaction --- if we fail during the initialization transaction, as is       * entirely possible, we need the AbortTransaction call to clean up.       */      before_shmem_exit(ShutdownPostgres, 0);        /* The autovacuum launcher is done here */      if (IsAutoVacuumLauncherProcess())      {          /* report this backend in the PgBackendStatus array */          pgstat_bestart();            return;      }        /*       * Start a new transaction here before first access to db, and get a       * snapshot.  We don't have a use for the snapshot itself, but we're       * interested in the secondary effect that it sets RecentGlobalXmin. (This       * is critical for anything that reads heap pages, because HOT may decide       * to prune them even if the process doesn't attempt to modify any       * tuples.)       */      if (!bootstrap)      {          /* statement_timestamp must be set for timeouts to work correctly */          SetCurrentStatementStartTimestamp();          StartTransactionCommand();            /*           * transaction_isolation will have been set to the default by the           * above.  If the default is "serializable", and we are in hot           * standby, we will fail if we don't change it to something lower.           * Fortunately, "read committed" is plenty good enough.           */          XactIsoLevel = XACT_READ_COMMITTED;            (void) GetTransactionSnapshot();      }        /*       * Perform client authentication if necessary, then figure out our       * postgres user ID, and see if we are a superuser.       *       * In standalone mode and in autovacuum worker processes, we use a fixed       * ID, otherwise we figure it out from the authenticated user name.       */      if (bootstrap || IsAutoVacuumWorkerProcess())      {          InitializeSessionUserIdStandalone();          am_superuser = true;      }      else if (!IsUnderPostmaster)      {          InitializeSessionUserIdStandalone();          am_superuser = true;          if (!ThereIsAtLeastOneRole())              ereport(WARNING,                      (errcode(ERRCODE_UNDEFINED_OBJECT),                       errmsg("no roles are defined in this database system"),                       errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.",                               username != NULL ? username : "postgres")));      }      else if (IsBackgroundWorker)      {          if (username == NULL && !OidIsValid(useroid))          {              InitializeSessionUserIdStandalone();              am_superuser = true;          }          else          {              InitializeSessionUserId(username, useroid);              am_superuser = superuser();          }      }      else      {          /* normal multiuser case */          Assert(MyProcPort != NULL);          PerformAuthentication(MyProcPort);          InitializeSessionUserId(username, useroid);          am_superuser = superuser();      }        /*       * If we're trying to shut down, only superusers can connect, and new       * replication connections are not allowed.       */      if ((!am_superuser || am_walsender) &&          MyProcPort != NULL &&          MyProcPort->canAcceptConnections == CAC_WAITBACKUP)      {          if (am_walsender)              ereport(FATAL,                      (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                       errmsg("new replication connections are not allowed during database shutdown")));          else              ereport(FATAL,                      (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                       errmsg("must be superuser to connect during database shutdown")));      }        /*       * Binary upgrades only allowed super-user connections       */      if (IsBinaryUpgrade && !am_superuser)      {          ereport(FATAL,                  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                   errmsg("must be superuser to connect in binary upgrade mode")));      }        /*       * The last few connection slots are reserved for superusers.  Although       * replication connections currently require superuser privileges, we       * don't allow them to consume the reserved slots, which are intended for       * interactive use.       */      if ((!am_superuser || am_walsender) &&          ReservedBackends > 0 &&          !HaveNFreeProcs(ReservedBackends))          ereport(FATAL,                  (errcode(ERRCODE_TOO_MANY_CONNECTIONS),                   errmsg("remaining connection slots are reserved for non-replication superuser connections")));        /* Check replication permissions needed for walsender processes. */      if (am_walsender)      {          Assert(!bootstrap);            if (!superuser() && !has_rolreplication(GetUserId()))              ereport(FATAL,                      (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),                       errmsg("must be superuser or replication role to start walsender")));      }        /*       * If this is a plain walsender only supporting physical replication, we       * don't want to connect to any particular database. Just finish the       * backend startup by processing any options from the startup packet, and       * we're done.       */      if (am_walsender && !am_db_walsender)      {          /* process any options passed in the startup packet */          if (MyProcPort != NULL)              process_startup_options(MyProcPort, am_superuser);            /* Apply PostAuthDelay as soon as we've read all options */          if (PostAuthDelay > 0)              pg_usleep(PostAuthDelay * 1000000L);            /* initialize client encoding */          InitializeClientEncoding();            /* report this backend in the PgBackendStatus array */          pgstat_bestart();            /* close the transaction we started above */          CommitTransactionCommand();            return;      }        /*       * Set up the global variables holding database id and default tablespace.       * But note we won't actually try to touch the database just yet.       *       * We take a shortcut in the bootstrap case, otherwise we have to look up       * the db's entry in pg_database.       */      if (bootstrap)      {          MyDatabaseId = TemplateDbOid;          MyDatabaseTableSpace = DEFAULTTABLESPACE_OID;      }      else if (in_dbname != NULL)      {          HeapTuple   tuple;          Form_pg_database dbform;            tuple = GetDatabaseTuple(in_dbname);          if (!HeapTupleIsValid(tuple))              ereport(FATAL,                      (errcode(ERRCODE_UNDEFINED_DATABASE),                       errmsg("database \"%s\" does not exist", in_dbname)));          dbform = (Form_pg_database) GETSTRUCT(tuple);          MyDatabaseId = HeapTupleGetOid(tuple);          MyDatabaseTableSpace = dbform->dattablespace;          /* take database name from the caller, just for paranoia */          strlcpy(dbname, in_dbname, sizeof(dbname));      }      else if (OidIsValid(dboid))      {          /* caller specified database by OID */          HeapTuple   tuple;          Form_pg_database dbform;            tuple = GetDatabaseTupleByOid(dboid);          if (!HeapTupleIsValid(tuple))              ereport(FATAL,                      (errcode(ERRCODE_UNDEFINED_DATABASE),                       errmsg("database %u does not exist", dboid)));          dbform = (Form_pg_database) GETSTRUCT(tuple);          MyDatabaseId = HeapTupleGetOid(tuple);          MyDatabaseTableSpace = dbform->dattablespace;          Assert(MyDatabaseId == dboid);          strlcpy(dbname, NameStr(dbform->datname), sizeof(dbname));          /* pass the database name back to the caller */          if (out_dbname)              strcpy(out_dbname, dbname);      }      else      {          /*           * If this is a background worker not bound to any particular           * database, we're done now.  Everything that follows only makes sense           * if we are bound to a specific database.  We do need to close the           * transaction we started before returning.           */          if (!bootstrap)          {              pgstat_bestart();              CommitTransactionCommand();          }          return;      }        /*       * Now, take a writer's lock on the database we are trying to connect to.       * If there is a concurrently running DROP DATABASE on that database, this       * will block us until it finishes (and has committed its update of       * pg_database).       *       * Note that the lock is not held long, only until the end of this startup       * transaction.  This is OK since we will advertise our use of the       * database in the ProcArray before dropping the lock (in fact, that's the       * next thing to do).  Anyone trying a DROP DATABASE after this point will       * see us in the array once they have the lock.  Ordering is important for       * this because we don't want to advertise ourselves as being in this       * database until we have the lock; otherwise we create what amounts to a       * deadlock with CountOtherDBBackends().       *       * Note: use of RowExclusiveLock here is reasonable because we envision       * our session as being a concurrent writer of the database.  If we had a       * way of declaring a session as being guaranteed-read-only, we could use       * AccessShareLock for such sessions and thereby not conflict against       * CREATE DATABASE.       */      if (!bootstrap)          LockSharedObject(DatabaseRelationId, MyDatabaseId, 0,                           RowExclusiveLock);        /*       * Now we can mark our PGPROC entry with the database ID.       *       * We assume this is an atomic store so no lock is needed; though actually       * things would work fine even if it weren't atomic.  Anyone searching the       * ProcArray for this database's ID should hold the database lock, so they       * would not be executing concurrently with this store.  A process looking       * for another database's ID could in theory see a chance match if it read       * a partially-updated databaseId value; but as long as all such searches       * wait and retry, as in CountOtherDBBackends(), they will certainly see       * the correct value on their next try.       */      MyProc->databaseId = MyDatabaseId;        /*       * We established a catalog snapshot while reading pg_authid and/or       * pg_database; but until we have set up MyDatabaseId, we won't react to       * incoming sinval messages for unshared catalogs, so we won't realize it       * if the snapshot has been invalidated.  Assume it's no good anymore.       */      InvalidateCatalogSnapshot();        /*       * Recheck pg_database to make sure the target database hasn't gone away.       * If there was a concurrent DROP DATABASE, this ensures we will die       * cleanly without creating a mess.       */      if (!bootstrap)      {          HeapTuple   tuple;            tuple = GetDatabaseTuple(dbname);          if (!HeapTupleIsValid(tuple) ||              MyDatabaseId != HeapTupleGetOid(tuple) ||              MyDatabaseTableSpace != ((Form_pg_database) GETSTRUCT(tuple))->dattablespace)              ereport(FATAL,                      (errcode(ERRCODE_UNDEFINED_DATABASE),                       errmsg("database \"%s\" does not exist", dbname),                       errdetail("It seems to have just been dropped or renamed.")));      }        /*       * Now we should be able to access the database directory safely. Verify       * it's there and looks reasonable.       */      fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);        if (!bootstrap)      {          if (access(fullpath, F_OK) == -1)          {              if (errno == ENOENT)                  ereport(FATAL,                          (errcode(ERRCODE_UNDEFINED_DATABASE),                           errmsg("database \"%s\" does not exist",                                  dbname),                           errdetail("The database subdirectory \"%s\" is missing.",                                     fullpath)));              else                  ereport(FATAL,                          (errcode_for_file_access(),                           errmsg("could not access directory \"%s\": %m",                                  fullpath)));          }            ValidatePgVersion(fullpath);      }        SetDatabasePath(fullpath);        /*       * It's now possible to do real access to the system catalogs.       *       * Load relcache entries for the system catalogs.  This must create at       * least the minimum set of "nailed-in" cache entries.       */      RelationCacheInitializePhase3();        /* set up ACL framework (so CheckMyDatabase can check permissions) */      initialize_acl();        /*       * Re-read the pg_database row for our database, check permissions and set       * up database-specific GUC settings.  We can't do this until all the       * database-access infrastructure is up.  (Also, it wants to know if the       * user is a superuser, so the above stuff has to happen first.)       */      if (!bootstrap)          CheckMyDatabase(dbname, am_superuser, override_allow_connections);        /*       * Now process any command-line switches and any additional GUC variable       * settings passed in the startup packet.   We couldn't do this before       * because we didn't know if client is a superuser.       */      if (MyProcPort != NULL)          process_startup_options(MyProcPort, am_superuser);        /* Process pg_db_role_setting options */      process_settings(MyDatabaseId, GetSessionUserId());        /* Apply PostAuthDelay as soon as we've read all options */      if (PostAuthDelay > 0)          pg_usleep(PostAuthDelay * 1000000L);        /*       * Initialize various default states that can't be set up until we've       * selected the active user and gotten the right GUC settings.       */        /* set default namespace search path */      InitializeSearchPath();        /* initialize client encoding */      InitializeClientEncoding();        /* Initialize this backend's session state. */      InitializeSession();        /* report this backend in the PgBackendStatus array */      if (!bootstrap)          pgstat_bestart();        /* close the transaction we started above */      if (!bootstrap)          CommitTransactionCommand();  }

三、跟踪分析

插入测试数据:

testdb=# -- 获取pid testdb=# select pg_backend_pid();  pg_backend_pid  ----------------            1893 (1 row) testdb=# -- 插入1行 testdb=# insert into t_insert values(23,'I am PostgresMain','I am PostgresMain','I am PostgresMain'); testdb=# -- 插入1行                          insert into t_insert values(23,'I am PostgresMain','I am PostgresMain','I am PostgresMain'); (挂起)

启动gdb,跟踪调试:

[root@localhost ~]# gdb -p 1893 GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7 Copyright (C) 2013 Free Software Foundation, Inc. ... #断点设置在循环中 (gdb) b postgres.c:4013 Breakpoint 1 at 0x850d26: file postgres.c, line 4013. ... (gdb) p input_message $7 = {data = 0x1508ef0 "insert into t_insert values(23,'I am PostgresMain','I am PostgresMain','I am PostgresMain');", len = 93, maxlen = 1024, cursor = 0} (gdb) n ... 4135            switch (firstchar) (gdb)  4142                        SetCurrentStatementStartTimestamp(); (gdb) p firstchar $8 = 81 ... (gdb) finish Run till exit from #0  PostgresMain (argc=1, argv=0x1532aa8, dbname=0x1532990 "testdb", username=0x1532978 "xdb") at postgres.c:4020 #DONE!

使用gdb跟踪postgres进程启动过程:

[xdb@localhost ~]$ gdb postgres ... (gdb) set follow-fork-mode child  (gdb) start Temporary breakpoint 1 at 0x6f1735: file main.c, line 62. Starting program: /appdb/xdb/bin/postgres  [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe538) at main.c:62 62      bool        do_check_root = true; (gdb) b PostgresMain Breakpoint 2 at 0x8507bb: file postgres.c, line 3631. (gdb) del 1 No breakpoint number 1. ... (gdb) attach 3028 Attaching to program: /appdb/xdb/bin/postgres, process 3028 ... #连接DB [xdb@localhost ~]$ psql -d testdb #回到gdb #finish 直至进入postmaster.c中的PostgresMain  (gdb) finish Run till exit from #0  ServerLoop () at postmaster.c:1704 [New process 3042] [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". [Switching to Thread 0x7ffff7feb740 (LWP 3042)] Breakpoint 2, PostgresMain (argc=1, argv=0xf28ac8, dbname=0xf289b0 "testdb", username=0xf28998 "xdb") at postgres.c:3631 3631        volatile bool send_ready_for_query = true; (gdb) next 3632        bool        disable_idle_in_transaction_timeout = false; (gdb)  3635        if (!IsUnderPostmaster) (gdb) p IsUnderPostmaster $3 = true (gdb) p dbname $4 = 0xf289b0 "testdb" (gdb) p username $5 = 0xf28998 "xdb" ... 3845        MessageContext = AllocSetContextCreate(TopMemoryContext, (gdb)  3855        row_description_context = AllocSetContextCreate(TopMemoryContext, (gdb)  3858        MemoryContextSwitchTo(row_description_context); (gdb)  3859        initStringInfo(&row_description_buf); (gdb)  3860        MemoryContextSwitchTo(TopMemoryContext); (gdb)  3865        if (!IsUnderPostmaster) (gdb)  3890        if (sigsetjmp(local_sigjmp_buf, 1) != 0) (gdb) p *MessageContext $6 = {type = T_AllocSetContext, isReset = true, allowInCritSection = false, methods = 0xb8c720 <AllocSetMethods>, parent = 0xef9b90, firstchild = 0x0, prevchild = 0xf74c80, nextchild = 0xfabb50,    name = 0xb4e87c "MessageContext", ident = 0x0, reset_cbs = 0x0} ... (gdb) n 4090            DoingCommandRead = true; (gdb)  4095            firstchar = ReadCommand(&input_message); (gdb)  4106            CHECK_FOR_INTERRUPTS(); (gdb)  4107            DoingCommandRead = false; (gdb) p firstchar $8 = 81 (gdb) p input_message $9 = {data = 0xeff010 "insert into t_insert values(24,'I am PostgresMain','I am PostgresMain','I am PostgresMain');", len = 93, maxlen = 1024, cursor = 0} (gdb) n ... #DONE!

到此,相信大家对“PostgreSQL中PostgresMain函数的实现逻辑是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI