openGauss源码解析(26)

openGauss源码解析:第3章公共组件源码解析(2)

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函数为例详细介绍这个过程。相关代码如下:

static void setup_schema(void)

{

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, "\0", "\0");

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, "\0", "\0");

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-server\src\gausskernel\bootstrap”目录下的bootscanner.l和bootparse.y文件。pg_type系统对象在initdb初始化中的bootstrap语法相关代码如下,在初始化时就是解析下面语法格式完成pg_type系统对象的创建:

create pg_type 1247 bootstrap rowtype_oid 71

(

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 \054 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 \054 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冻结。
posted @ 2024-04-29 15:32  openGauss-bot  阅读(30)  评论(0编辑  收藏  举报