postgresql从入门到菜鸟(十二)initdb流程分析-初期化集簇(下)

上篇文章分析到使用引导模式创建了template0,下面继续分析

到了这里引导模式的工作基本就结束了,下面开始使用postgres的单用户模式对template1创建系统表,视图,依赖,以及扩展插件的安装等一列操作。

首先是通过setup_auth()设置search_path和exit_on_error,下面的代码本来是放在setup_auth()中执行,但是新版本中被提出来了。

	//这里第一个参数给的是postgres,第二个参数给的是-single -F -O -c search_path=pg_catalog -c exit_on_error=true
	//这里把exit_on_error设为true之后,任何错误将中止当前会话。默认是false,只有 FATAL 错误(致命)将中止会话。
	snprintf(cmd, sizeof(cmd),
		 "\"%s\" %s template1 >%s",
	     backend_exec, backend_options,
	     DEVNULL);

然后是通过setup_depend()设置依赖关系,其实就是更新pg_depend和pg_shdepend表

static void
setup_depend(FILE *cmdfd)
{
	const char *const *line;
	static const char *const pg_depend_setup[] = {
		……
		//删除pg_depend和pg_shdepend表中的数据并清理
		//pg_depend和pg_shdepend表之前通过postgres.bki创建
		"DELETE FROM pg_depend;\n\n",
		"VACUUM pg_depend;\n\n",
		"DELETE FROM pg_shdepend;\n\n",
		"VACUUM pg_shdepend;\n\n",
		
		//向pg_depend表中填充数据
		"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
		" FROM pg_class;\n\n",
		"INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
		" FROM pg_proc;\n\n",
		……
		NULL
	};
	
	//逐行执行
	for (line = pg_depend_setup; *line != NULL; line++)
		PG_CMD_PUTS(*line);
}

通过setup_sysviews()创建系统视图

static void
setup_sysviews(FILE *cmdfd)
{
	char	  **line;
	char	  **sysviews_setup;
	//这里其实就是读取了system_views.sql文件,然后逐行执行
	sysviews_setup = readfile(system_views_file);

	for (line = sysviews_setup; *line != NULL; line++)
	{
		PG_CMD_PUTS(*line);
		free(*line);
	}

	free(sysviews_setup);
}

通过setup_description()创建pg_description和pg_shdescription表,也就是描述表

static void
setup_description(FILE *cmdfd)
{
	//创建临时表tmp_pg_description
	PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
				"	objoid oid, "
				"	classname name, "
				"	objsubid int4, "
				"	description text) WITHOUT OIDS;\n\n");

	//把postgres.description文件中的内容copy到tmp_pg_description表
	PG_CMD_PRINTF1("COPY tmp_pg_description FROM E'%s';\n\n",
				   escape_quotes(desc_file));

	//把tmp_pg_description表中的数据插入到pg_description表
	PG_CMD_PUTS("INSERT INTO pg_description "
				" SELECT t.objoid, c.oid, t.objsubid, t.description "
				"  FROM tmp_pg_description t, pg_class c "
				"    WHERE c.relname = t.classname;\n\n");

	//后面pg_shdescription表也是同理,这里不再分析
	……

	PG_CMD_PUTS("DROP TABLE tmp_pg_description;\n\n");
	PG_CMD_PUTS("DROP TABLE tmp_pg_shdescription;\n\n");
}

通过setup_collation()创建pg_collation表,也就是排序规则表

static void
setup_collation(FILE *cmdfd)
{
	//直接向pg_collation表插入数据
	PG_CMD_PRINTF3("INSERT INTO pg_collation (collname, collnamespace, collowner, collprovider, collencoding, collcollate, collctype) VALUES ('ucs_basic', 'pg_catalog'::regnamespace, %u, '%c', %d, 'C', 'C');\n\n",
				   BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);

	PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
}

通过setup_conversion()创建表pg_conversion,也就是编码转换表

static void
setup_conversion(FILE *cmdfd)
{
	char	  **line;
	char	  **conv_lines;
	
	//这里其实就是读取了conversion_create.sql文件,然后逐行执行
	conv_lines = readfile(conversion_file);
	for (line = conv_lines; *line != NULL; line++)
	{
		if (strstr(*line, "DROP CONVERSION") != *line)
			PG_CMD_PUTS(*line);
		free(*line);
	}

	free(conv_lines);
}

通过 setup_dictionary()创建一些额外的目录

static void
setup_dictionary(FILE *cmdfd)
{
	char	  **line;
	char	  **conv_lines;

	//这里其实就是读取了\src\backend\catalog\snowball_create.sql文件,然后逐行执行
	conv_lines = readfile(dictionary_file);
	for (line = conv_lines; *line != NULL; line++)
	{
		PG_CMD_PUTS(*line);
		free(*line);
	}

	free(conv_lines);
}

通过setup_privileges()设置权限

//函数比较长这里就不贴了,内容是一些修改权限的sql文
setup_privileges()

通过setup_schema()创建info_schema

static void
setup_schema(FILE *cmdfd)
{
	char	  **line;
	char	  **lines;

	lines = readfile(info_schema_file);
	//这里读取了information_schema.sql文件
	for (line = lines; *line != NULL; line++)
	{
		PG_CMD_PUTS(*line);
		free(*line);
	}

	free(lines);

	//这里更新了一下sql_implementation_info表中的character_value字段
	PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
				   "  SET character_value = '%s' "
				   "  WHERE implementation_info_name = 'DBMS VERSION';\n\n",
				   infoversion);

	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\n",
				   escape_quotes(features_file));
}

添加plpgsql扩展

static void
load_plpgsql(FILE *cmdfd)
{
	PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n");
}

对template1进行清理

//这个函数其实就是对template1分别执行以下命令
//ANALYZE:收集template1的统计信息
//VACUUM FULL:完全清理template1
//VACUUM FREEZE:选择激进的元组“冻结”
vacuum_db();

到了这里template1就算是完工了,下面需要把template1 COPY一份 成为template0

/*
 * copy template1 to template0
 * 代码就不分析了,注释已经写的很明白了
 */
make_template0()

然后再把template1 COPY一份 成为postgres

/*
 * copy template1 to postgres
 */
static void
make_postgres(FILE *cmdfd)
{
	const char *const * line;
	//这里还会顺带把postgres数据库设置为默认连接数据库
	static const char *const postgres_setup[] = {
		"CREATE DATABASE postgres;\n\n",
		"COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n",
		NULL
	};

	for (line = postgres_setup; *line; line++)
		PG_CMD_PUTS(*line);
}

到了这里,初期化基本就结束了,剩下来还有一些收尾工作,比如数据同步

//这里其实就是是否等待数据同步到磁盘,默认是开启的,可以在initdb时通过-N关闭
if (do_sync)
	fsync_pgdata();
else
	printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));

最后就是向用户返回成功信息了

printf(_("\nSuccess. You can now start the database server using:\n\n"
			 "    %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"),
	   QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
		   QUOTE_PATH, pgdata_native, QUOTE_PATH);

initdb流程分析结束

你可能感兴趣的:(postgresql)