openGauss数据库源码解析(三)| 公共组件源码解析(2)

2023年 11月 16日 24.6k 0

3.2 数据库初始化
数据库正常启动时需要指定数据目录,数据目录中包括了系统表的初始化数据。数据库初始化的过程会生成这些初始系统表数据文件,该过程由initdb和openGauss进程配合生成。initdb控制执行过程,创建目录和基本的配置文件;openGauss进程负责系统表的初始化。initdb通过PG_CMD_OPEN宏启动openGauss进程,同时打开一个管道流,然后通过解析系统表文件中的SQL命令,并把命令通过PG_CMD_PUTS宏的管道流发给openGauss进程,最后通过PG_CMD_CLOSE宏关闭管道流。PG_CMD_OPEN宏是系统函数popen的封装宏,PG_CMD_PUTS宏是系统函数fputs的封装宏,PG_CMD_CLOSE宏是系统函数pclose的封装宏。交互过程如图3-1所示。

图3-1 初始化交互过程图

initdb在创建template1模板数据库时,命令参数指定了“snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, “”%s" --boot -x1 %s %s", backend_exec, boot_options, talkargs);”,其中“–boot”表示openGauss进程以一个特殊的bootstrap模式运行。在其他初始化系统表时,initdb命令参数指定了“snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, “”%s" %s template1 >%s", backend_exec, backend_options, DEVNULL); ”,其中“static const char* backend_options = "–single "”表示openGauss进程以单用户模式运行。
下面以setup_schema函数为例详细介绍这个过程。相关代码如下:

{
PG_CMD_DECL;
char** line;
char** lines;
int nRet = 0;
char* buf_features = NULL;
fputs(_("creating information schema ... "), stdout);
(void)fflush(stdout);
lines = readfile(info_schema_file);
/*
* 使用-j 避免在information_schema.sql反斜杠处理
*/
nRet = snprintf_s(
cmd, sizeof(cmd), sizeof(cmd) - 1, ""%s" %s -j template1 >%s", backend_exec, backend_options, DEVNULL);
securec_check_ss_c(nRet, "", "");
PG_CMD_OPEN;
for (line = lines; *line != NULL; line++) {
PG_CMD_PUTS(*line);
FREE_AND_RESET(*line);
}
FREE_AND_RESET(lines);
PG_CMD_CLOSE;
nRet = snprintf_s(
cmd, sizeof(cmd), sizeof(cmd) - 1, ""%s" %s template1 >%s", backend_exec, backend_options, DEVNULL);
securec_check_ss_c(nRet, "", "");
PG_CMD_OPEN;
PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
" SET character_value = '%s' "
" WHERE implementation_info_name = 'DBMS VERSION';n",
infoversion);

buf_features = escape_quotes(features_file);
PG_CMD_PRINTF1("COPY information_schema.sql_features "
" (feature_id, feature_name, sub_feature_id, "
" sub_feature_name, is_supported, comments) "
" FROM E'%s';n",
buf_features);
FREE_AND_RESET(buf_features);
PG_CMD_CLOSE;
check_ok();
}

在这个函数中,PG_CMD_DECL是一个变量定义宏,通过语句“char cmd[MAXPGPATH]”和“FILE* cmdfd = NULL”定义了两个变量。这样的作用是代码格式统一、阅读方便。
语句“readfile(info_schema_file)”表示读取info_schema_file文件,这个文件中存放了系统表初始化的SQL命令。
语句“snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, “”%s" %s -j template1 >%s", backend_exec, backend_options, DEVNULL)”是格式化openGauss后台进程的命令。语句“PG_CMD_OPEN”是以popen的方式运行cmd命令,启动openGauss进程。
语句“for (line = lines; *line != NULL; line++)” 表示遍历info_schema_file文件中的每条SQL命令,宏PG_CMD_PUTS把每个SQL命令发送给openGauss进程执行。
整个文件执行完毕,调用宏PG_CMD_CLOSE停止进程,关闭管道。setup_schema函数的后面代码处理是类似的,只是SQL命令是函数内生成的,使用宏PG_CMD_PRINTF1写入管道,发给openGauss进程。
setup_sysviews、setup_dictionary、setup_privileges等其他系统对象初始化函数过程都是类似的,不再重复描述。
initdb的整个初始化过程如下。
(1) 对命令行参数进行解析。
(2) 查找openGauss程序,设置PGDATA、PGPATH等环境变量。设置数据库初始化原始文件,这些文件在shell命令make install执行安装后,默认都在“openGauss-server/dest/share/postgresql”目录下。
(3) 数据库本地初始化,locale默认初始化为en_US.UTF-8,数据库编码默认初始化为UTF8,文本搜索默认初始化为english。
(4) 检查数据库数据目录pg_data是否为空,是否需要创建,权限是否正确。
(5) 创建subdirs变量指定的子目录。
(6) 初始化conf配置文件。
(7) 创建template1数据库bootstrap_template1。这一步需要启动后台openGauss进程执行数据库的SQL语句,创建系统表。bootstrap_template1这个函数主要是读取bki文件中的SQL语句,发送到openGauss进程去执行,主要功能是创建系统表。SQL语句举例如下,其中语句create pg_type表示创建pg_type系统表,语句INSERT OID表示插入这个系统表的默认数据。这里的语法是专门为initdb定制的bootstrap解析语法,不是正式的SQL语法,语法文件也是单独的,可参照“openGauss-serversrcgausskernelbootstrap”目录下的bootscanner.l和bootparse.y文件。pg_type系统对象在initdb初始化中的bootstrap语法相关代码如下,在初始化时就是解析下面语法格式完成pg_type系统对象的创建:

(
typname = name ,
typnamespace = oid ,
typowner = oid ,
typlen = int2 ,
typbyval = bool ,
typtype = char ,
typcategory = char ,
typispreferred = bool ,
typisdefined = bool ,
typdelim = char ,
typrelid = oid ,
typelem = oid ,
typarray = oid ,
typinput = regproc ,
typoutput = regproc ,
typreceive = regproc ,
typsend = regproc ,
typmodin = regproc ,
typmodout = regproc ,
typanalyze = regproc ,
typalign = char ,
typstorage = char ,
typnotnull = bool ,
typbasetype = oid ,
typtypmod = int4 ,
typndims = int4 ,
typcollation = oid ,
typdefaultbin = pg_node_tree ,
typdefault = text ,
typacl = aclitem[]
)
INSERT OID = 16 ( bool 11 10 1 t b B t t 54 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 0 _null_ _null_ _null_ )
INSERT OID = 17 ( bytea 11 10 -1 f b U f t 54 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 0 _null_ _null_ _null_ )
...........
close pg_type

(8)使用setup_auth函数初始化pg_authid权限。该函数执行的SQL语句是在函数内静态定义“static const char* pg_authid_setup[]”。
(9)使用setup_depend函数创建系统表依赖关系。该函数执行的SQL语句是在函数内静态定义“static const char* pg_depend_setup[]”。
(10)使用load_plpgsql函数加载plpgsql扩展组件。该函数只执行一条SQL语句“CREATE EXTENSION plpgsql;”。
(11) 使用setup_sysviews函数创建系统视图。该函数会读取system_views.sql文件中的SQL语句,发送到openGauss去执行,主要功能是创建系统视图。
(12) 使用setup_perfviews函数创建性能视图。该函数会读取performance_views.sql文件中的SQL语句,发送到openGauss去执行,主要功能是创建性能视图。
(13) 使用setup_conversion函数创建编码转换。该函数会读取conversion_create.sql文件中的SQL语句,发送到openGauss去执行,主要功能是创建编码转换函数。
(14) 使用setup_dictionary函数创建词干数据字典。该函数会读取snowball_create.sql文件中的SQL语句,发送到openGauss去执行,主要功能是创建文本搜索函数。
(15) 使用setup_privileges函数设置权限。setup_privileges函数通过xstrdu复制SQL常量字符串到一个动态数组内,然后遍历执行指定的SQL语句。
(16) 使用load_supported_extension函数加载外表。该函数执行相应扩展组件的CREATE EXTENSION语句。
(17) 使用setup_update函数更新系统表。该函数执行语句COPY pg_cast_oid.txt到数据库中,主要功能是创建类型强制转换处理函数。
(18) 对template1进行垃圾数据清理,即执行三个SQL语句“ANALYZE;”、“VACUUM FULL;”、“VACUUM FREEZE;”。
(19) 创建template0数据库,即复制template1到template0。
(20) 创建默认数据库,即复制template1到默认数据库。
(21) 对template0、template1、默认数据库进行垃圾数据清理和事务ID冻结。

相关文章

在一台虚拟机上搭建MGR 9.0集群
众所周知的原因安装PMM2
唯一上榜!OceanBase入选 2023“科创中国”先导技术榜!
MySQL 删除数据表
利用 MySQL 克隆插件搭建主从
MySQL索引前缀长度超限怎么办?这种方法帮你搞定

发布评论