OpenGauss线程管理-主线程-Postmaster(1)

OpenGauss线程管理-主线程-Postmaster(1)

主线程postmaster负责内存、全局信息、信号、线程池等的初始化,用来创建其他子线程,OpenGauss是单进程多线程,在程序启动时,一个进程被操作系统创建,同时主线程立刻运行。
主线程运行时可以用来接收前端的命令,对命令做出处理,还会对子线程进行监视,在子线程出现问题时会对子线程进行管理,保证数据库正常的运行。
主线程是和后端共享的内存,但它不会碰共享内存,避免崩溃、卡住。

PostmasterMain函数

openGauss-server\src\gausskernel\process\postmaster\postmaster.cpp

  1. 初始化postmaster配置参数
  2. 初始化审计模块
  3. 建立输入socket监听
  4. 建立共享内存和信号量池
  5. 初始化postmaster信号管理
  6. 初始化宕机监听
  7. 初始化统计数据收集子系统
  8. 初始化工作负载管理器
  9. 初始化unique sql资源
 int PostmasterMain(int argc, char* argv[])
{
    int opt;
    int status = STATUS_OK;
    char* output_config_variable = NULL;
    char* userDoption = NULL;
    bool listen_addr_saved = false;
    int use_pooler_port = -1;
    int i;
    OptParseContext optCtxt;
    errno_t rc = 0;
    Port port;

    t_thrd.proc_cxt.MyProcPid = PostmasterPid = gs_thread_self();//设置线程号相关的全局变量MyProcPid、PostmasterPid、MyProgName

    t_thrd.proc_cxt.MyStartTime = time(NULL);

    IsPostmasterEnvironment = true;//设置程序运行环境相关的全局变量IsPostmasterEnvironment

    t_thrd.proc_cxt.MyProgName = "gaussmaster";

	/*
     * 为了安全起见,创建的目录或文件不能被group或其他方式访问
     */
    umask(S_IRWXG | S_IRWXO);

    /*
     * 启动基本子系统:内存管理
     */

    /*
     * 默认情况下,postmaster中的 palloc()请求将在 t_thrd.mem_cxt 中分配. 
     * postmaster_mem_cxt 是后端可以回收的空间。 需要提供给后端的已分配数据
     * 应在 t_thrd.top_mem_cxt 中分配。
     */
    t_thrd.mem_cxt.postmaster_mem_cxt = AllocSetContextCreate(t_thrd.top_mem_cxt,
        "Postmaster",
        ALLOCSET_DEFAULT_MINSIZE,
        ALLOCSET_DEFAULT_INITSIZE,
        ALLOCSET_DEFAULT_MAXSIZE);
    MemoryContextSwitchTo(t_thrd.mem_cxt.postmaster_mem_cxt);

    /*
     * 初始化版本信息
     */
    initialize_feature_flags();

#ifndef ENABLE_LITE_MODE
    /*
     * @OBS
     * 创建一个线程之间共享的全局 OBS CA 对象
     */
    initOBSCacheObject();

    S3_init();
#endif

    /* 为minizip libs设置内存管理器 */
    pm_set_unzip_memfuncs();

    /* 为 cJSON 设置内存管理器 */
    cJSON_Hooks hooks = {cJSON_internal_malloc, cJSON_internal_free};
    cJSON_InitHooks(&hooks);

#ifdef ENABLE_LLVM_COMPILE
    /*
     * 准备编译环境。
     */
    CodeGenProcessInitialize();
#endif

    /* 初始化安装文件的路径 */
    getInstallationPaths(argv[0]);//设置my_exec_path

    /*
     * 选项设置(根据各个GUC参数的默认值生成GUC参数的全局变量数组,
     * 还有统一管理GUC参数的全局变量,并设置与操作系统环境相关的GUC参数)
     */
    InitializeGUCOptions();

    /*
     *初始化cb_for_getlc的回调函数类型
     */
    SetcbForGetLCName(GetLogicClusterForAlarm);

    optCtxt.opterr = 1;

    /*
     * 分析命令行选项。	注意:要与 tcop/postgres.c(选项集不应冲突)
     * 以及 main/main.c中的 common help() 函数保持同步。
     */
    initOptParseContext(&optCtxt);
    //如果在启动gaussdb时使用了非默认的GUC参数,则加载到上一步中创建的全局变量中
    while ((opt = getopt_r(argc, argv, "A:B:bc:C:D:d:EeFf:h:ijk:lM:N:nOo:Pp:Rr:S:sTt:u:W:g:X:-:", &optCtxt)) != -1) {
        switch (opt) {
            case 'A':
                SetConfigOption("debug_assertions", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'B':
                SetConfigOption("shared_buffers", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'b':
                /* 用于二进制升级的未记录标志 */
                u_sess->proc_cxt.IsBinaryUpgrade = true;
                break;

            case 'C':
                output_config_variable = optCtxt.optarg;
                break;

            case 'D':
                userDoption = optCtxt.optarg;
                break;

            case 'd':
                set_debug_options(atoi(optCtxt.optarg), PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'E':
                SetConfigOption("log_statement", "all", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'e':
                SetConfigOption("datestyle", "euro", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'F':
                SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'f':
                if (!set_plan_disabling_options(optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV)) {
                    write_stderr("%s: invalid argument for option -f: \"%s\"\n", progname, optCtxt.optarg);
                    ExitPostmaster(1);
                }

                break;
            case 'g':
                SetConfigOption("xlog_file_path", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;
            case 'h':
                SetConfigOption("listen_addresses", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'i':
                SetConfigOption("listen_addresses", "*", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'j':
                /* 仅由交互式后端使用 */
                break;

            case 'k':
                SetConfigOption("unix_socket_directory", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'l':
                SetConfigOption("ssl", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'M':
                if (0 == strncmp(optCtxt.optarg, "primary", strlen("primary")) &&
                    '\0' == optCtxt.optarg[strlen("primary")]) {
                    t_thrd.xlog_cxt.server_mode = PRIMARY_MODE;
                } else if (0 == strncmp(optCtxt.optarg, "standby", strlen("standby")) &&
                           '\0' == optCtxt.optarg[strlen("standby")]) {
                    t_thrd.xlog_cxt.server_mode = STANDBY_MODE;
                } else if (0 == strncmp(optCtxt.optarg, "pending", strlen("pending")) &&
                           '\0' == optCtxt.optarg[strlen("pending")]) {
                    t_thrd.xlog_cxt.server_mode = PENDING_MODE;
                } else if (0 == strncmp(optCtxt.optarg, "normal", strlen("normal")) &&
                           '\0' == optCtxt.optarg[strlen("normal")]) {
                    t_thrd.xlog_cxt.server_mode = NORMAL_MODE;
                } else if (0 == strncmp(optCtxt.optarg, "cascade_standby", strlen("cascade_standby")) &&
                           '\0' == optCtxt.optarg[strlen("cascade_standby")]) {
                    t_thrd.xlog_cxt.server_mode = STANDBY_MODE;
                    t_thrd.xlog_cxt.is_cascade_standby = true;
                } else if (0 == strncmp(optCtxt.optarg, "hadr_main_standby", strlen("hadr_main_standby")) &&
                           '\0' == optCtxt.optarg[strlen("hadr_main_standby")]) {
                    t_thrd.xlog_cxt.server_mode = STANDBY_MODE;
                    t_thrd.xlog_cxt.is_hadr_main_standby = true;
                } else {
                    ereport(FATAL, (errmsg("the options of -M is not recognized")));
                }
                break;

            case 'N':
                SetConfigOption("max_connections", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'n':
                /* 异常退出后不要重新启动共享 */
                ereport(FATAL, (errmsg("the options of -n is deprecated")));
                break;

            case 'O':
                SetConfigOption("allow_system_table_mods", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'o':
                /* 在命令行上传递到后端的其他选项 */
                rc = snprintf_s(g_instance.ExtraOptions + strlen(g_instance.ExtraOptions),
                    sizeof(g_instance.ExtraOptions) - strlen(g_instance.ExtraOptions),
                    sizeof(g_instance.ExtraOptions) - strlen(g_instance.ExtraOptions) - 1,
                    " %s",
                    optCtxt.optarg);
                securec_check_ss(rc, "", "");
                break;

            case 'P':
                SetConfigOption("ignore_system_indexes", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'p':
                SetConfigOption("port", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;
#ifdef ENABLE_MULTIPLE_NODES
            case 'R':
                /* 指示运行为 xlogreiver。仅用于 -M 备用 */
                dummyStandbyMode = true;
                break;
#endif
            case 'r':
                /* 仅由单用户后端使用 */
                break;

            case 'S':
                SetConfigOption("work_mem", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 's':
                SetConfigOption("log_statement_stats", "true", PGC_POSTMASTER, PGC_S_ARGV);
                break;

            case 'T':

                /*
                 * 如果某些后端转储了核心,请将 SIGSTOP 而不是 SIGQUIT 发送到其所有对等端。 
                 * 这让post_hacker收集每个人的核心转储。
                 */
                ereport(FATAL, (errmsg("the options of -T is deprecated")));
                break;

            case 't': {
                const char* tmp = get_stats_option_name(optCtxt.optarg);

                if (tmp != NULL) {
                    SetConfigOption(tmp, "true", PGC_POSTMASTER, PGC_S_ARGV);
                } else {
                    write_stderr("%s: invalid argument for option -t: \"%s\"\n", progname, optCtxt.optarg);
                    ExitPostmaster(1);
                }

                break;
            }

            case 'u':
                /* 用于原位或在线升级的无归档版本 */
                errno = 0;
                pg_atomic_write_u32(&WorkingGrandVersionNum, (uint32)strtoul(optCtxt.optarg, NULL, 10));
                if (errno != 0 || pg_atomic_read_u32(&WorkingGrandVersionNum) > GRAND_VERSION_NUM) {
                    write_stderr("%s: invalid argument for option -u: \"%s\", GRAND_VERSION_NUM is %u\n",
                        progname,
                        optCtxt.optarg,
                        (uint32)GRAND_VERSION_NUM);
                    ExitPostmaster(1);
                } else if (pg_atomic_read_u32(&WorkingGrandVersionNum) == INPLACE_UPGRADE_PRECOMMIT_VERSION) {
                    pg_atomic_write_u32(&WorkingGrandVersionNum, GRAND_VERSION_NUM);
                    g_instance.comm_cxt.force_cal_space_info = true;
                }
                break;

            case 'W':
                SetConfigOption("post_auth_delay", optCtxt.optarg, PGC_POSTMASTER, PGC_S_ARGV);
                break;
            case 'X':
                /* 停止屏障 */
                if ((optCtxt.optarg != NULL) && (strlen(optCtxt.optarg) > 0)) {
                    if (strlen(optCtxt.optarg) > MAX_BARRIER_ID_LENGTH) {
                        ereport(FATAL, (errmsg("the options of -X is too long")));
                    }
                    rc = strncpy_s(g_instance.csn_barrier_cxt.stopBarrierId, MAX_BARRIER_ID_LENGTH,
                                   (char *)optCtxt.optarg, strlen(optCtxt.optarg));
                    securec_check(rc, "\0", "\0");
                    ereport(LOG, (errmsg("Set stop barrierID %s", g_instance.csn_barrier_cxt.stopBarrierId)));
                }
                break;
            case 'c':
            case '-': {
                char* name = NULL;
                char* value = NULL;

                ParseLongOption(optCtxt.optarg, &name, &value);

#ifndef ENABLE_MULTIPLE_NODES
                if (opt == '-' && (strcmp(name, "coordinator") == 0 || strcmp(name, "datanode") == 0)) {
                    ereport(FATAL,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("Single node mode: must start as single node (--single_node)\n")));
                }
#endif
                /* 正在激活协调器 */
                if (name != NULL && strcmp(name, "coordinator") == 0 && value == NULL)
                    g_instance.role = VCOORDINATOR;
                else if (name != NULL && strcmp(name, "datanode") == 0 && value == NULL)
                    g_instance.role = VDATANODE;
                /* 正在激活singleDN 模式 */
                else if (name != NULL && strcmp(name, "single_node") == 0 && value == NULL) {
                    g_instance.role = VSINGLENODE;
                    useLocalXid = true;
                } else if (name != NULL && strcmp(name, "restoremode") == 0 && value == NULL) {
                    /*
                     * 在恢复模式下,协调器和数据节点在内部都被视为数据节点
                     */
                    isRestoreMode = true;
                    g_instance.role = VDATANODE;
                } else if (name != NULL && 0 == strcmp(name, "fenced") && value == NULL)
                    FencedUDFMasterMode = true;
                else if (name != NULL && strlen(name) == SECURITY_MODE_NAME_LEN &&
                         strncmp(name, SECURITY_MODE_NAME, SECURITY_MODE_NAME_LEN) == 0 && value == NULL) {
                    /* 在安全模式下,打开安全策略 */
                    isSecurityMode = true;
                } else {
                    /* 默认大小写 */
                    if (value == NULL) {
                        if (opt == '-')
                            ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR), errmsg("--%s requires a value", optCtxt.optarg)));
                        else
                            ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR), errmsg("-c %s requires a value", optCtxt.optarg)));
                    }

                    SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
                }
                pfree(name);

                if (value != NULL) {
                    pfree(value);
                }

                break;
            }

            default:
                write_stderr("Try \"%s --help\" for more information.\n", progname);
                ExitPostmaster(1);
        }
    }
    /*
     * 找到正确的配置文件和数据目录,并首次读取postgresql.conf。
     */
#if ((defined ENABLE_PYTHON2) || (defined ENABLE_PYTHON3))
    if (!SelectConfigFiles(userDoption, progname))
        ExitPostmaster(1);

    if (strlen(GetConfigOption(const_cast<char*>("unix_socket_directory"), true, false)) != 0) {
        PythonFencedMasterModel = true;
        
        /* 禁用受防护 UDF 进程的 bbox */
        SetConfigOption("enable_bbox_dump", "false", PGC_POSTMASTER, PGC_S_ARGV);
    }
#else
    if (FencedUDFMasterMode) {
        /* 禁用受防护 UDF 进程的 bbox */
        SetConfigOption("enable_bbox_dump", "false", PGC_POSTMASTER, PGC_S_ARGV);
    } else if (!SelectConfigFiles(userDoption, progname)) {
        ExitPostmaster(1);
    }
#endif

    if ((g_instance.attr.attr_security.transparent_encrypted_string != NULL &&
         g_instance.attr.attr_security.transparent_encrypted_string[0] != '\0') &&
        (g_instance.attr.attr_common.transparent_encrypt_kms_url != NULL &&
         g_instance.attr.attr_common.transparent_encrypt_kms_url[0] != '\0') &&
        (g_instance.attr.attr_security.transparent_encrypt_kms_region != NULL &&
         g_instance.attr.attr_security.transparent_encrypt_kms_region[0] != '\0')) {
        isSecurityMode = true;
    }

    /*
     * 初始化Postmaster级别的 GUC 选项。
     *
     * 请注意,由于某些全局变量没有初始化,所以某些 guc 无法获得正确的值,
     * 例如single_node模式,因此需要此函数来初始化 Postmaster 级别的 guc。
     */
    InitializePostmasterGUC();

    t_thrd.myLogicTid = noProcLogicTid + POSTMASTER_LID;
    if (output_config_variable != NULL) {
        /*
         * 处理权限是因为用户在data dir中读取数据
         */
        puts(GetConfigOption(output_config_variable, false, false));
        ExitPostmaster(0);
    }

    InitializeNumLwLockPartitions();

    noProcLogicTid = GLOBAL_ALL_PROCS;

    if (FencedUDFMasterMode) {
        /* t_thrd.proc_cxt 必须设置DataDir */
        if (userDoption != NULL && userDoption[0] == '/') {
            if (chdir(userDoption) == -1)
                ExitPostmaster(1);
            SetDataDir(userDoption);
        } else {
            ExitPostmaster(1);
        }
        /*初始化除信号监视器之外的所有子线程的线程参数池 */
        gs_thread_args_pool_init(GLOBAL_ALL_PROCS + EXTERN_SLOTS_NUM, sizeof(BackendParameters));
        /* 初始化信号管理结构 */
        gs_signal_slots_init(GLOBAL_ALL_PROCS + EXTERN_SLOTS_NUM);
        gs_signal_startup_siginfo("PostmasterMain");

        gs_signal_monitor_startup();
        g_instance.attr.attr_common.Logging_collector = true;
        g_instance.global_sysdbcache.Init(INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
        CreateLocalSysDBCache();
        g_instance.pid_cxt.SysLoggerPID = SysLogger_Start();
        FencedUDFMasterMain(0, NULL);
        return 0;
    }

    /* 验证t_thrd.proc_cxt.DataDir看起来是合理的 (确保数据库安装成功及PGDATA目录有效)*/
    checkDataDir();

    /* 并将工作目录切换到其中 */
    ChangeToDataDir();
    /*
        * 检查无效的GUC设置组合。
        */
    CheckGUCConflicts();

    /* 设置并行恢复配置 */
    ConfigRecoveryParallelism();
    ProcessRedoCpuBindInfo();
    /*
        *如果速度快的话,其他一次性内部检查可在此处进行。
        *(在 postmaster.pid 创建之后,把一些缓慢的程序放下。)
        */
    if (!CheckDateTokenTables()) {
        write_stderr("%s: invalid datetoken tables, please fix\n", progname);
        ExitPostmaster(1);
    }

    initKnlRTOContext();

    /*
        * 现在我们已经完成了对 postmaster 参数的处理, 重置 getopt(3) 库,
        * 以便它将在子进程中正常工作。
        */
    optCtxt.optind = 1;
#ifdef HAVE_INT_OPTRESET
    optreset = 1; /* 有些系统也需要这个 */
#endif

    int rc1 = snprintf_s(
        gaussdb_state_file, sizeof(gaussdb_state_file), MAXPGPATH - 1, "%s/gaussdb.state", t_thrd.proc_cxt.DataDir);
    securec_check_intval(rc1, , -1);
    gaussdb_state_file[MAXPGPATH - 1] = '\0';
    if (!SetDBStateFileState(UNKNOWN_STATE, true)) {
        write_stderr("Failed to set gaussdb.state with UNKNOWN_STATE");
        ExitPostmaster(1);
    }

    if (g_instance.attr.attr_storage.dcf_attr.enable_dcf) {
        rc1 = snprintf_s(AddMemberFile, sizeof(AddMemberFile), MAXPGPATH - 1, "%s/addmember", t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        AddMemberFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(RemoveMemberFile, sizeof(RemoveMemberFile), MAXPGPATH - 1, "%s/removemember",
            t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        RemoveMemberFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(TimeoutFile, sizeof(TimeoutFile), MAXPGPATH - 1, "%s/timeout", t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        TimeoutFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(SwitchoverStatusFile, sizeof(SwitchoverStatusFile), MAXPGPATH - 1, "%s/switchoverstatus",
            t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        SwitchoverStatusFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(SetRunmodeStatusFile, sizeof(SetRunmodeStatusFile), MAXPGPATH - 1, "%s/setrunmodestatus",
            t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        SetRunmodeStatusFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(g_changeRoleStatusFile, sizeof(g_changeRoleStatusFile), MAXPGPATH - 1, "%s/changerolestatus",
            t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        g_changeRoleStatusFile[MAXPGPATH - 1] = '\0';

        rc1 =
            snprintf_s(ChangeRoleFile, sizeof(ChangeRoleFile), MAXPGPATH - 1, "%s/changerole", t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        ChangeRoleFile[MAXPGPATH - 1] = '\0';

        rc1 = snprintf_s(StartMinorityFile, sizeof(StartMinorityFile), MAXPGPATH - 1, "%s/startminority",
            t_thrd.proc_cxt.DataDir);
        securec_check_intval(rc1, , -1);
        StartMinorityFile[MAXPGPATH - 1] = '\0';
    }

    /* 用于调试:显示Postmaster环境 */
    {
        extern char** environ;
        char** p;

        ereport(DEBUG3, (errmsg_internal("%s: PostmasterMain: initial environment dump:", progname)));
        ereport(DEBUG3, (errmsg_internal("-----------------------------------------")));

        for (p = environ; *p; ++p)
            ereport(DEBUG3, (errmsg_internal("\t%s", *p)));

        ereport(DEBUG3, (errmsg_internal("-----------------------------------------")));
    }

    rc = memcpy_s(g_alarmComponentPath, MAXPGPATH - 1, Alarm_component, strlen(Alarm_component));
    securec_check_c(rc, "\0", "\0");
    g_alarmReportInterval = AlarmReportInterval;
    AlarmEnvInitialize();

    /*
        * 为数据目录创建lockfile。
        *
        *我们希望在尝试获取输入套接字之前执行此操作,因为数据目录互锁比套
        *接字文件联锁更可靠(感谢决定将套接字文件放入 /tmp :-( 的人。)
        *出于同样的原因,最好在Unix套接字之前获取TCP套接字。
        */
    CreateDataDirLockFile(true);

    /* 模块加载回调 */
    pgaudit_agent_init();
    auto_explain_init();
    ledger_hook_init();

    /*
        * 处理应在Postmaster启动时预加载的库
        */
    process_shared_preload_libraries();

    /*
        * 建立输入套接字。
        */
    for (i = 0; i < MAXLISTEN; i++)
        t_thrd.postmaster_cxt.ListenSocket[i] = PGINVALID_SOCKET;

    if (g_instance.attr.attr_network.ListenAddresses && !dummyStandbyMode) {
        char* rawstring = NULL;
        List* elemlist = NULL;
        ListCell* l = NULL;
        int success = 0;

        /*
            * 如果需要,启动 commproxy
            */
        if (CommProxyNeedSetup()) {
            CommProxyStartUp();
        }

        /* 需要g_instance.attr.attr_network.ListenAddresses的可修改副本 */
        rawstring = pstrdup(g_instance.attr.attr_network.ListenAddresses);

        /* 将字符串解析为标识符列表 */
        if (!SplitIdentifierString(rawstring, ',', &elemlist)) {
            /* 列表中的语法错误 */
            ereport(FATAL,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"listen_addresses\"")));
        }

        bool haswildcard = false;
        foreach (l, elemlist) {
            char* curhost = (char*)lfirst(l);
            if (strcmp(curhost, "*") == 0) {
                haswildcard = true;
                break;
            }
        }
        
        if (haswildcard == true) {
            char *wildcard = "*";
            elemlist = list_cell_clear(elemlist, (void *)wildcard, isNotWildcard);
        }

        foreach (l, elemlist) {
            char* curhost = (char*)lfirst(l);

            if (strcmp(curhost, "*") == 0)
                status = StreamServerPort(AF_UNSPEC,
                    NULL,
                    (unsigned short)g_instance.attr.attr_network.PostPortNumber,
                    g_instance.attr.attr_network.UnixSocketDir,
                    t_thrd.postmaster_cxt.ListenSocket,
                    MAXLISTEN,
                    true,
                    true,
                    false);
            else
                status = StreamServerPort(AF_UNSPEC,
                    curhost,
                    (unsigned short)g_instance.attr.attr_network.PostPortNumber,
                    g_instance.attr.attr_network.UnixSocketDir,
                    t_thrd.postmaster_cxt.ListenSocket,
                    MAXLISTEN,
                    true,
                    true,
                    false);

            if (status == STATUS_OK)
                success++;
            else {
                print_port_info();
                ereport(FATAL,
                    (errmsg("could not create listen socket for \"%s:%d\"",
                        curhost,
                        g_instance.attr.attr_network.PostPortNumber)));
            }

            /* 目前,我们不监听NORMAL_MODE下的 replconn 通道,因此需要pooler端口 */
            use_pooler_port = NeedPoolerPort(curhost);
            if (t_thrd.xlog_cxt.server_mode == NORMAL_MODE || use_pooler_port == -1) {
                /* 在 om 和其他维护工具中,pooler端口被硬连线为 gsql 端口加 1 */
                if (g_instance.attr.attr_network.PoolerPort != (g_instance.attr.attr_network.PostPortNumber + 1)) {
                    ereport(FATAL, (errmsg("pooler_port must equal to gsql listen port plus one!")));
                }

                if (strcmp(curhost, "*") == 0) {
                    status = StreamServerPort(AF_UNSPEC,
                        NULL,
                        (unsigned short)g_instance.attr.attr_network.PoolerPort,
                        g_instance.attr.attr_network.UnixSocketDir,
                        t_thrd.postmaster_cxt.ListenSocket,
                        MAXLISTEN,
                        false,
                        false,
                        false);
                } else {
                    status = StreamServerPort(AF_UNSPEC,
                        curhost,
                        (unsigned short)g_instance.attr.attr_network.PoolerPort,
                        g_instance.attr.attr_network.UnixSocketDir,
                        t_thrd.postmaster_cxt.ListenSocket,
                        MAXLISTEN,
                        false,
                        false,
                        false);
                }

                if (status != STATUS_OK)
                    ereport(FATAL,
                        (errmsg("could not create ha listen socket for \"%s:%d\"",
                            curhost,
                            g_instance.attr.attr_network.PoolerPort)));

                /*
                    * 记录第一个成功的主机addr,addr并不意味着锁定文件中的“localhost”。
                    * 内部维护工具,如 cm_agent 和 gs_ctl 将使用该主机来连接cn。
                    */
                if (!listen_addr_saved && !IsInplicitIp(curhost)) {
                    AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, curhost);
                    listen_addr_saved = true;
                }
            }
        }

        if (!success && list_length(elemlist))
            ereport(FATAL, (errmsg("could not create any TCP/IP sockets")));

        list_free_ext(elemlist);
        pfree(rawstring);
    }

    if (t_thrd.xlog_cxt.server_mode != NORMAL_MODE) {
        SetListenSocket(t_thrd.postmaster_cxt.ReplConnArray, &listen_addr_saved);
        ReportResumeAbnormalDataHAInstListeningSocket();
    }
    SetListenSocket(t_thrd.postmaster_cxt.CrossClusterReplConnArray, &listen_addr_saved);
    ReportResumeAbnormalDataHAInstListeningSocket();
#ifdef USE_BONJOUR

    /* 仅当我们打开了 TCP 套接字时才注册 Bonjour */
    if (g_instance.attr.attr_common.enable_bonjour && t_thrd.postmaster_cxt.ListenSocket[0] != PGINVALID_SOCKET) {
        DNSServiceErrorType err;

        /*
            *我们为interface_index传递 0 ,这将导致在所有“适用”接口上注册。 
            *从DNS-SD文档中并不完全清楚,如果我们只绑定到可用网络接口的子集,这是否合适。
            */
        err = DNSServiceRegister(&bonjour_sdref,
            0,
            0,
            g_instance.attr.attr_common.bonjour_name,
            "_postgresql._tcp.",
            NULL,
            NULL,
            htons(g_instance.attr.attr_network.PostPortNumber),
            0,
            NULL,
            NULL,
            NULL);

        if (err != kDNSServiceErr_NoError)
            ereport(LOG, (errmsg("DNSServiceRegister() failed: error code %ld", (long)err)));

        /*
            * 不必阅读 mDNS 守护程序的回复,并且我们希望当postmaster
            * 终止时套接字关闭,它将自动终止我们的注册。 所以这里没有什
            * 么可做的了。 但是,bonjour_sdref保留在周围,以便fork的子程序
            * 可以关闭其套接字的副本。
            */
    }

#endif

#ifdef HAVE_UNIX_SOCKETS
    if (!dummyStandbyMode) {
        /* unix socket for gsql port */
        status = StreamServerPort(AF_UNIX,
            NULL,
            (unsigned short)g_instance.attr.attr_network.PostPortNumber,
            g_instance.attr.attr_network.UnixSocketDir,
            t_thrd.postmaster_cxt.ListenSocket,
            MAXLISTEN,
            false,
            true,
            false);

        if (status != STATUS_OK)
            ereport(FATAL,
                (errmsg("could not create Unix-domain socket for \"%s:%d\"",
                    g_instance.attr.attr_network.UnixSocketDir,
                    g_instance.attr.attr_network.PostPortNumber)));

        /* unix socket for ha port */
        status = StreamServerPort(AF_UNIX,
            NULL,
            (unsigned short)g_instance.attr.attr_network.PoolerPort,
            g_instance.attr.attr_network.UnixSocketDir,
            t_thrd.postmaster_cxt.ListenSocket,
            MAXLISTEN,
            false,
            false,
            false);

        if (status != STATUS_OK)
            ereport(FATAL,
                (errmsg("could not create Unix-domain socket for \"%s:%d\"",
                    g_instance.attr.attr_network.UnixSocketDir,
                    g_instance.attr.attr_network.PoolerPort)));

        /*
            * 创建监听的 unix 域套接字以接收来自receiver_loop线程的gs_sock。
            * 注意:由于我们将在以后使用全局变量sock_path来初始化libcomm,
            * 因此此套接字必须是最后创建的unix域套接字。否则,sock_path将被其他路径替换。
            */
        if (g_instance.attr.attr_storage.comm_cn_dn_logic_conn && !isRestoreMode && !IS_SINGLE_NODE) {
            status = StreamServerPort(AF_UNIX,
                NULL,
                (unsigned short)g_instance.attr.attr_network.comm_sctp_port,
                g_instance.attr.attr_network.UnixSocketDir,
                t_thrd.postmaster_cxt.ListenSocket,
                MAXLISTEN,
                false,
                true,
                true);

            if (status != STATUS_OK)
                ereport(WARNING, (errmsg("could not create Unix-domain for comm  socket")));
        }
    }
#endif

    /*
        * 检查我们是否有一些套接字可以收听
        */
    if (t_thrd.postmaster_cxt.ListenSocket[0] == PGINVALID_SOCKET) {
        ereport(FATAL, (errmsg("no socket created for listening")));
    }

    /*
        * 设置一个on_proc_exit函数,该函数负责在postmaster关闭时再次关闭套接字。 
        * 您可能认为我们应该更早地执行此操作,但我们希望它在proc_exit回调删除
        * Unix套接字文件之前而不是之后运行。
        */
    on_proc_exit(CloseServerPorts, 0);

    /*
        * 如果没有有效的 TCP 端口,请编写一个空行进行监听,表示必须使用 Unix 套接字。 
        * 请注意,在有套接字支持它之前,不会将此行添加到锁定文件中。
        */
    if (!listen_addr_saved) {
        AddToDataDirLockFile(LOCK_FILE_LINE_LISTEN_ADDR, "");
        ereport(WARNING, (errmsg("No explicit IP is configured for listen_addresses GUC.")));
    }

    if (g_instance.attr.attr_common.enable_thread_pool) {
        /* 无需为虚拟备用节点启动线程池。 */
        if (!dummyStandbyMode) {
            g_threadPoolControler = (ThreadPoolControler*)
                New(INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR)) ThreadPoolControler();
            g_threadPoolControler->SetThreadPoolInfo();
        } else {
            g_instance.attr.attr_common.enable_thread_pool = false;
            g_threadPoolControler = NULL;
            AdjustThreadAffinity();
        }
    }

    /* 初始化 gstrace context */
    int errcode = gstrace_init(g_instance.attr.attr_network.PostPortNumber);
    if (errcode != 0) {
        ereport(LOG, (errmsg("gstrace initializes with failure. errno = %d.", errcode)));
    }

    InitGlobalBcm();

    /*
        * 设置共享内存和信号量。
        * (主要包括页面缓存池、各种锁缓存池、WAL日志缓存池、事务日志缓存池、
        * 事务(号)概况缓存池、各后台线程(锁使用)概况缓存池、各后台线程等
        * 待和运行状态缓存池、两阶段状态缓存池、检查点缓存池、WAL日志复制和接
        * 收缓存池、数据页复制和接收缓存池等。在后续阶段创建出的客户端后台线程
        * 以及各个辅助线程均使用该共享内存空间,不再单独开辟 )
        */
    reset_shared(g_instance.attr.attr_network.PostPortNumber);

    /* Alloc 数组进行后端记录 */
    BackendArrayAllocation();

    /* 初始化除信号监视器之外的所有子线程的线程参数池*/
    gs_thread_args_pool_init(GLOBAL_ALL_PROCS + EXTERN_SLOTS_NUM, sizeof(BackendParameters));
    // 1.初始化信号管理结构
    //
    gs_signal_slots_init(GLOBAL_ALL_PROCS + EXTERN_SLOTS_NUM);
    gs_signal_startup_siginfo("PostmasterMain");

    gs_signal_monitor_startup();

    /*
        * 估计可打开文件的数量。 这必须在设置信号量后发生,
        * 因为在某些平台上,信号量算作打开的文件。
        */
    SetHaShmemData();

    PMInitDBStateFile();

    set_max_safe_fds();

    /*
        * 设置堆栈深度检查的参考点。
        */
    set_stack_base();

    /*
        * 初始化活动后端的列表。
        */
    g_instance.backend_list = DLNewList();

    /*
        * 初始化管道(或 Windows 上的进程句柄),允许在postmaster死亡时从休眠状态中唤醒子线程。
        */
    InitPostmasterDeathWatchHandle();

#ifdef WIN32

    /*
        * 初始化用于提供已死子列表的 I/O 完成端口。
        */
    win32ChildQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);

    if (win32ChildQueue == NULL)
        ereport(FATAL, (errmsg("could not create I/O completion port for child queue")));

#endif

    /*
        * 记录postmaster选项。 我们将其推迟到现在,以避免记录虚假选项
        * (例如,NBuffers对于可用内存来说太高了)。
        */
    if (!CreateOptsFile(argc, (const char**)argv, (const char*)my_exec_path))
        ExitPostmaster(1);

#ifdef EXEC_BACKEND
    /* 写出供子进程使用的非默认 GUC 设置 */
    write_nondefault_variables(PGC_POSTMASTER);
#endif

#ifndef ENABLE_LITE_MODE
#if defined (ENABLE_MULTIPLE_NODES) || defined (ENABLE_PRIVATEGAUSS)
    /* init hotpatch */
    if (hotpatch_remove_signal_file(t_thrd.proc_cxt.DataDir) == HP_OK) {
        int ret;
        ret = hotpatch_init(t_thrd.proc_cxt.DataDir, (HOTPATCH_LOG_FUNC)gs_hotpatch_log_callback);
        if (ret != HP_OK) {
            write_stderr("hotpatch init failed ret is %d!\n", ret);
        }
    }
#endif
#endif
    /*
     * 如果需要,写入外部 PID 文件
     */
    if (g_instance.attr.attr_common.external_pid_file) {
        FILE* fpidfile = fopen(g_instance.attr.attr_common.external_pid_file, "w");

        if (fpidfile != NULL) {
            fprintf(fpidfile, "%lu\n", t_thrd.proc_cxt.MyProcPid);
            fclose(fpidfile);
            /* 在postmaster退出时,我们是否应该删除 pid 文件? */

            /* 使 PID 文件世界可读 */
            if (chmod(g_instance.attr.attr_common.external_pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0)
                write_stderr("%s: could not change permissions of external PID file \"%s\": %s\n",
                    progname,
                    g_instance.attr.attr_common.external_pid_file,
                    gs_strerror(errno));
        } else
            write_stderr("%s: could not write external PID file \"%s\": %s\n",
                progname,
                g_instance.attr.attr_common.external_pid_file,
                gs_strerror(errno));
    }

    /*
     * 为postmaster流程设置信号处理程序。
     * 注意:更改此列表时,请检查子进程的信号处理设置是否存在副作用。 
     * 请参阅 tcop/postgres.c、bootstrap/bootstrap.c、postmaster/bgwriter.c、
     * postmaster/walwriter.c、postmaster/autovacuum.c、postmaster/pgarch.c、
     * postmaster/pgstat.c、postmaster/syslogger.c 和 postmaster/checkpointer.c。
     */

    gs_signal_setmask(&t_thrd.libpq_cxt.BlockSig, NULL);
    gs_signal_block_sigusr2();

    (void)gspqsignal(SIGHUP, SIGHUP_handler); /* 重新读取配置文件并让做同样的事情 */
    (void)gspqsignal(SIGINT, pmdie);          /* send SIGTERM and shut down */
    (void)gspqsignal(SIGQUIT, pmdie);         /* send SIGQUIT and die */
    (void)gspqsignal(SIGTERM, pmdie);         /* wait for children and shut down */

    pqsignal(SIGALRM, SIG_IGN); /* ignored */
    pqsignal(SIGPIPE, SIG_IGN); /* ignored */
    pqsignal(SIGFPE, FloatExceptionHandler);

    (void)gspqsignal(SIGUSR1, sigusr1_handler); /* 来自子进程的消息*/
    (void)gspqsignal(SIGUSR2, dummy_handler);   /* unused, reserve for children */
    (void)gspqsignal(SIGCHLD, reaper);          /* handle child termination */
    (void)gspqsignal(SIGTTIN, SIG_IGN);         /* ignored */
    (void)gspqsignal(SIGTTOU, SIG_IGN);         /* ignored */

    /* 忽略 SIGXFSZ,以便 ulimit 冲突的工作方式类似于磁盘已满 */
#ifdef SIGXFSZ
    (void)gspqsignal(SIGXFSZ, SIG_IGN); /* ignored */
#endif

    /* 核心转储注入*/
    bbox_initialize();

    /*
     * 初始化stats收集子系统(这不会启动收集器进程!
     */
    pgstat_init();

    /* 初始化全局统计信息跟踪器 */
    GlobalStatsTrackerInit();

    /* 初始化工作负载管理器 */
    InitializeWorkloadManager();

    g_instance.global_sysdbcache.Init(INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
    CreateLocalSysDBCache();

    /* Init proc 的 subxid 缓存上下文, 父级是 g_instance.instance_context */
    ProcSubXidCacheContext = AllocSetContextCreate(g_instance.instance_context,
        "ProcSubXidCacheContext",
        ALLOCSET_DEFAULT_MINSIZE,
        ALLOCSET_DEFAULT_INITSIZE,
        ALLOCSET_DEFAULT_MAXSIZE,
        SHARED_CONTEXT);

    /*
     * 为流线程连接创建 StreamInfoContext,父级为 g_instance.instance_context。所有流线程将共享此上下文。
     */
    StreamInfoContext = AllocSetContextCreate(g_instance.instance_context,
        "StreamInfoContext",
        ALLOCSET_DEFAULT_MINSIZE,
        ALLOCSET_DEFAULT_INITSIZE,
        ALLOCSET_DEFAULT_MAXSIZE,
        SHARED_CONTEXT);
        
    /* 创建全局高速缓存上下文 */
    knl_g_cachemem_create();

    /* 创建节点组缓存哈希表 */
    ngroup_info_hash_create();
    /*初始化角色 ID 哈希表*/
    InitRoleIdHashTable();
    /* pcmap */
    RealInitialMMapLockArray();
    /* 初始化唯一的 sql */
    InitUniqueSQL();
    /* 初始化指数 */
    InitHypopg();
    InitAsp();
    /* 初始化 instr 用户 */
    InitInstrUser();
    /* 初始化 Opfusion 函数 id */
    InitOpfusionFunctionId();
    /* 初始化捕获视图 */
    init_capture_view();
    /* 初始化百分位数 */
    InitPercentile();
    /* 初始化动态语句跟踪控制*/
    InitTrackStmtControl();
    /* 初始化全局序列 */
    InitGlobalSeq();
#ifdef ENABLE_MULTIPLE_NODES
    /* 初始化压实 */
    CompactionProcess::init_instance();
    /*
     * 设置 TsStoreTagsCache
     */
    if (g_instance.attr.attr_common.enable_tsdb) {
        TagsCacheMgr::GetInstance().init();
        PartIdMgr::GetInstance().init();
        Tsdb::PartCacheMgr::GetInstance().init();
        InitExtensiblePlanMethodsHashTable();
    }
#endif

    /*
     * 如果启用,启动syslog日志收集子进程
     */
    g_instance.pid_cxt.SysLoggerPID = SysLogger_Start();

    if (IS_PGXC_DATANODE && !dummyStandbyMode && !isRestoreMode) {
        StreamObj::startUp();
        StreamNodeGroup::StartUp();
        pthread_mutex_init(&nodeDefCopyLock, NULL);
    }

    /* 初始化 usedDnSpace 哈希表*/
    InitDnHashTable();

    /*
     * 加载用于客户端身份验证的配置文件。在通信线程之前加载 pg_hba.conf。
     */
    int loadhbaCount = 0;
    while (!load_hba()) {
        check_old_hba(true);
        loadhbaCount++;
        if (loadhbaCount >= 3) {
            /*
             * 如果无法加载 HBA 文件,则继续操作是没有意义的,
             * 因为在这种情况下,无法连接到数据库。
             */
            ereport(FATAL, (errmsg("could not load pg_hba.conf")));
        }
        pg_usleep(200000L);  /* sleep 200ms for reload next time */
    }

    if (ENABLE_THREAD_POOL_DN_LOGICCONN) {
        InitCommLogicResource();
    }

    if ((!IS_SINGLE_NODE) &&
        ((IS_PGXC_DATANODE && !dummyStandbyMode && !isRestoreMode) ||
            (IS_PGXC_COORDINATOR && g_instance.attr.attr_storage.comm_cn_dn_logic_conn && !isRestoreMode))) {
        status = init_stream_comm();
        if (status != STATUS_OK)
            ereport(FATAL, (errmsg("Init libcomm for stream failed, maybe listen port already in use")));
    }
    if (g_instance.attr.attr_security.enable_tde) {
        /* 初始化云 KMS 消息实例*/
        TDE::CKMSMessage::get_instance().init();
        TDE::CKMSMessage::get_instance().load_user_info();
        /* 初始化 TDE 存储哈希表 */
        if (IS_PGXC_DATANODE) {
            TDE::TDEKeyStorage::get_instance().init();
            TDE::TDEBufferCache::get_instance().init();
        }
    }

#ifndef ENABLE_LITE_MODE
    if (g_instance.attr.attr_storage.enable_adio_function)
        AioResourceInitialize();
#endif

    /* 启动警报检查器线程。 */
    if (!dummyStandbyMode)
        g_instance.pid_cxt.AlarmCheckerPID = startAlarmChecker();

    /* 启动收割者后端线程,该线程始终处于活动状态。 */
    g_instance.pid_cxt.ReaperBackendPID = initialize_util_thread(REAPER);

    /*
     * 将 WhereToSendOutput 从 DestDebug(其起始状态)重置为 DestNone。
     * 这将阻止 ereport 向 stderr 发送日志消息,除非t_thrd.aes_cxt.Log_destination允许。 
     * 在postmaster完全启动之前,我们不会这样做,因为启动失败也可以报告给stderr。
     */
    t_thrd.postgres_cxt.whereToSendOutput = DestNone;

    /*
     * 初始化autovacum子系统(同样,尚未启动进程)
     */
    autovac_init();

    load_ident();

    /*
     * 删除旧的临时文件。	此时,此目录中不能运行其他 openGauss 进程,因此这应该是安全的。
     */
    RemovePgTempFiles();

    RemoveErrorCacheFiles();
    /*
     * 记住postmaster启动时间
     */
    t_thrd.time_cxt.pg_start_time = GetCurrentTimestamp();

    /* 节点统计验证时间戳 */
    gs_lock_test_and_set_64(&g_instance.stat_cxt.NodeStatResetTime, GetCurrentTimestamp());

    /* PostmasterRandom想要自己的拷贝 */
    gettimeofday(&t_thrd.postmaster_cxt.random_start_time, NULL);

    /*
     * We're ready to rock and roll...
     */
    ShareStorageInit();
    g_instance.pid_cxt.StartupPID = initialize_util_thread(STARTUP);
    Assert(g_instance.pid_cxt.StartupPID != 0);
    pmState = PM_STARTUP;

#ifdef ENABLE_MULTIPLE_NODES

    if (IS_PGXC_COORDINATOR) {
        MemoryContext oldcontext = MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));

        /*
         * 初始化数据节点连接池。pooler 线程不再存在,
         * StartPoolManager() 是 PoolManagerInit() 的别名。
         */
        StartPoolManager();

        MemoryContextSwitchTo(oldcontext);
    }

    load_searchserver_library();
#endif
    /* 
     * 保存DCF回调线程的后端变量,保存的后端变量将在DCF回调线程共享内存init函数中恢复。
     */
    if (g_instance.attr.attr_storage.dcf_attr.enable_dcf) {
        int ss_rc = memset_s(&port, sizeof(port), 0, sizeof(port));
        securec_check(ss_rc, "\0", "\0");
        port.sock = PGINVALID_SOCKET;
        BackendVariablesGlobal = static_cast<BackendParameters *>(palloc(sizeof(BackendParameters)));
        save_backend_variables(BackendVariablesGlobal, &port);
    }
    /* 如果从plpython fenced模式开始,我们只需以fenced模式启动 */
    if (PythonFencedMasterModel) {
        /*
         * 如果启用,启动syslog日志收集子进程
         */
        g_instance.attr.attr_common.Logging_collector = true;
        g_instance.pid_cxt.SysLoggerPID = SysLogger_Start();
        StartUDFMaster();
    }
    if (status == STATUS_OK)
        status = ServerLoop();

    /*
     * ServerLoop可能永远不应该返回,但如果返回,请关闭。
     */
    ExitPostmaster(status != STATUS_OK);

    return 0; /* not reached */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值