OpenGauss线程管理-主线程-Postmaster(1)
主线程postmaster负责内存、全局信息、信号、线程池等的初始化,用来创建其他子线程,OpenGauss是单进程多线程,在程序启动时,一个进程被操作系统创建,同时主线程立刻运行。
主线程运行时可以用来接收前端的命令,对命令做出处理,还会对子线程进行监视,在子线程出现问题时会对子线程进行管理,保证数据库正常的运行。
主线程是和后端共享的内存,但它不会碰共享内存,避免崩溃、卡住。
PostmasterMain函数
openGauss-server\src\gausskernel\process\postmaster\postmaster.cpp
- 初始化postmaster配置参数
- 初始化审计模块
- 建立输入socket监听
- 建立共享内存和信号量池
- 初始化postmaster信号管理
- 初始化宕机监听
- 初始化统计数据收集子系统
- 初始化工作负载管理器
- 初始化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 */
}