m6米乐安卓版下载-米乐app官网下载
4

postgresql 15源码浅析(1)—— postgres中的1号数据库 -m6米乐安卓版下载

夏克 2022-05-22
1492

在创建数据库集簇后,该集簇中默认会包含三个系统数据库template1、template0和postgres,其中template0和postgres都是在初始化过程中从template1复制出来的。这个理论大家想必不是那么陌生,但是template1又是从哪里来的呢?带着这个问题,下文将从代码的角度探究postgres中1号数据库的由来。

initdb代码位于postgres源码下src/bin/initdb/initdb.c中。


initdb主要功能是创建数据库集簇,包括:

  1. 创建数据库目录,及目录下一些必要的子目录,如base、global、pg_tblspc等,所有要创建的子目录保存在subdirs[]中。
static const char *const subdirs[] = { "global", "pg_wal/archive_status", "pg_commit_ts", "pg_dynshmem", "pg_notify", "pg_serial", "pg_snapshots", "pg_subtrans", "pg_twophase", "pg_multixact", "pg_multixact/members", "pg_multixact/offsets", "base", "base/1", "pg_replslot", "pg_tblspc", "pg_stat", "pg_stat_tmp", "pg_xact", "pg_logical", "pg_logical/snapshots", "pg_logical/mappings" };
  1. 测试当前服务器系统性能,由测试结果创建配置文件postgres.conf、pg_hba.conf、pg_ident.conf,并对其中定义的参数做一些设置。

分别通过set_null_conf、test_config_settings、setup_config,设置空的配置文件、测试系统配置、设置配置文件。

测试系统配置: 由大到小测试连接数和共享内存的大小。同时检查系统ipc的类型和时区。

通过postgres测试模式对系统参数进行检查,如大的参数检查不过依次减小配置进行重新测试,检查命令如下:

# 连接数检测 100 postgres --check -f -c log_checkpoints=false -c max_connections=100 -c shared_buffers=1000 -c dynamic_shared_memory_type=posix < "/dev/null" > "/dev/null" 2>&1 # 共享内存检测 128m postgres -check -f -c log_checkpoints=false -c max_connections=100 -c shared_buffers=16384 -c dynamic_shared_memory_type=posix < "/dev/null" > "/dev/null" 2>&1

注意: 这个检测只是针对初始化postgres基本的配置参数,实际生产应根据具体服务器的配置进行调整。此处可进行优化,根据检查实际物理内存大小进行自动配合。

设置配置文件:根据检测出的配置,替换模板的配置,模板文件放置在安装目录share子目录下:

frank@desktop-6nf3b9k:~/pgsql/share$ ll *.sample -rw-r--r-- 1 frank frank 4703 may 21 22:42 pg_hba.conf.sample -rw-r--r-- 1 frank frank 1636 may 21 22:42 pg_ident.conf.sample -rw-r--r-- 1 frank frank 604 may 21 22:42 pg_service.conf.sample -rw-r--r-- 1 frank frank 29431 may 21 22:42 postgresql.conf.sample -rw-r--r-- 1 frank frank 278 may 21 22:42 psqlrc.sample frank@desktop-6nf3b9k:~/pgsql/share$ pwd /home/frank/pgsql/share
  1. 在bootstrap模式下创建数据库template1,存放在数据目录的子目录base/1下,并通过复制template1来创建template0和postgres两个系统数据库。
/* bootstrap template1 */ bootstrap_template1(); // 创建template0 make_template0(cmdfd); // 创建postgrs make_postgres(cmdfd);

进程间通信

linux常用的进程间通信主要有共享内存、信号量、消息队列这几种,广义讲,夸主机的进程通信还可以使用socket,但postgres创建template1数据库和进行服务器配置检查使用的是管道的方式。

管道通信的代码:

/* * macros for running pipes to postgres */ #define pg_cmd_decl char cmd[maxpgpath]; file *cmdfd #define pg_cmd_open \ do { \ cmdfd = popen_check(cmd, "w"); \ if (cmdfd == null) \ exit(1); /* message already printed by popen_check */ \ } while (0) #define pg_cmd_close \ do { \ if (pclose_check(cmdfd)) \ exit(1); /* message already printed by pclose_check */ \ } while (0) #define pg_cmd_puts(line) \ do { \ if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \ output_failed = true, output_errno = errno; \ } while (0) #define pg_cmd_printf(fmt, ...) \ do { \ if (fprintf(cmdfd, fmt, __va_args__) < 0 || fflush(cmdfd) < 0) \ output_failed = true, output_errno = errno; \ } while (0)

步骤如下:

  1. 以bootstrap模式启动postgres进程并打开写管道:

启动命令:postgres --boot -x 16777216 -f -c log_checkpoints=false -d 5

  • –boot,以bootstrap模式启动,这个参数必须作为第一个参数。
  • 关闭fsync
  • -c 配置参数 不开启日志检查点
  • -d 开启debug日志,5是最高级别的debug日志
  • -x 设置wal文件大小,16m
  1. 将bki文件中的命令发送至postgres进程,完成对象的创建。

bki文件

这里先挖个坑吧,后续会详细学习一下bki的使用与执行过程。

bki文件在源码的postgres/src/backend/catalog目录下,安装完成后在share目录下。文件名为postgres.bki

语法与标准sql类似:

# postgresql 15 create pg_proc 1255 bootstrap rowtype_oid 81 ( oid = oid , proname = name , ...... prosrc = text force not null , probin = text , prosqlbody = pg_node_tree , proconfig = _text , proacl = _aclitem ) insert ( 1242 boolin 11 10 12 1 0 0 0 f f f t f i s 1 0 16 2275 _null_ _null_ _null_ _null_ _null_ boolin _null_ _null_ _null_ _null_ ) insert ( 1243 boolout 11 10 12 1 0 0 0 f f f t f i s 1 0 2275 16 _null_ _null_ _null_ _null_ _null_ boolout _null_ _null_ _null_ _null_ ) ......

创建template1和其中的系统表。

创建了如下的系统表(共64个):

frank@desktop-6nf3b9k:~/pgsql/share$ cat postgres.bki | grep "create pg_" create pg_proc 1255 bootstrap rowtype_oid 81 create pg_type 1247 bootstrap rowtype_oid 71 create pg_attribute 1249 bootstrap rowtype_oid 75 create pg_class 1259 bootstrap rowtype_oid 83 create pg_attrdef 2604 create pg_constraint 2606 create pg_inherits 2611 create pg_index 2610 create pg_operator 2617 create pg_opfamily 2753 create pg_opclass 2616 create pg_am 2601 create pg_amop 2602 create pg_amproc 2603 create pg_language 2612 create pg_largeobject_metadata 2995 create pg_largeobject 2613 create pg_aggregate 2600 create pg_statistic 2619 create pg_statistic_ext 3381 create pg_statistic_ext_data 3429 create pg_rewrite 2618 create pg_trigger 2620 create pg_event_trigger 3466 create pg_description 2609 create pg_cast 2605 create pg_enum 3501 create pg_namespace 2615 create pg_conversion 2607 create pg_depend 2608 create pg_database 1262 shared_relation rowtype_oid 1248 create pg_db_role_setting 2964 shared_relation create pg_tablespace 1213 shared_relation create pg_authid 1260 shared_relation rowtype_oid 2842 create pg_auth_members 1261 shared_relation rowtype_oid 2843 create pg_shdepend 1214 shared_relation create pg_shdescription 2396 shared_relation create pg_ts_config 3602 create pg_ts_config_map 3603 create pg_ts_dict 3600 create pg_ts_parser 3601 create pg_ts_template 3764 create pg_extension 3079 create pg_foreign_data_wrapper 2328 create pg_foreign_server 1417 create pg_user_mapping 1418 create pg_foreign_table 3118 create pg_policy 3256 create pg_replication_origin 6000 shared_relation create pg_default_acl 826 create pg_init_privs 3394 create pg_seclabel 3596 create pg_shseclabel 3592 shared_relation rowtype_oid 4066 create pg_collation 3456 create pg_parameter_acl 6243 shared_relation create pg_partitioned_table 3350 create pg_range 3541 create pg_transform 3576 create pg_sequence 2224 create pg_publication 6104 create pg_publication_namespace 6237 create pg_publication_rel 6106 create pg_subscription 6100 shared_relation rowtype_oid 6101 create pg_subscription_rel 6102
  • pg_xxx:对象名
  • 后面的 数字为 对象的oid
  • 如果声明了bootstrap,那么该表将只在磁盘上创建;不会向pg_classpg_attribute等表里面输入任何与该表相关的东西。因此这样的表将无法被普通的sql操作访问,直到那些记录被用硬办法(用insert命令)建立。 这个选项用于创建pg_class等表本身。
  • 如果声明了shared_relation,那么表就作为共享表创建。除非声明了without_oids,否则表将会有oid。表的行类型oid(pg_type的oid)可以有选择性地通过rowtype_oid子句指定。如果没有指定,会为之自产生一个oid(如果bootstrap被指定,则rowtype_oid是无效的,但不管怎样它还是被写在了文档中)。

将template1插入至pg_database

open pg_database insert ( 1 template1 10 encoding locale_provider t t -1 0 1 1663 lc_collate lc_ctype icu_locale _null_ _null_ ) close pg_database

把1号数据库设为创建数据库的默认模板

create pg_shdescription 2396 shared_relation ( objoid = oid , classoid = oid , description = text force not null ) open pg_shdescription insert ( 1 1262 'default template for new databases' ) close pg_shdescription

在pg_namespace中插入3个模式。

create pg_namespace 2615 ( oid = oid , nspname = name , nspowner = oid , nspacl = _aclitem ) open pg_namespace insert ( 11 pg_catalog 10 _null_ ) insert ( 99 pg_toast 10 _null_ ) insert ( 2200 public 6171 _null_ ) close pg_namespace

postgres支持的3种内置pl语言

create pg_language 2612 ( oid = oid , lanname = name , lanowner = oid , lanispl = bool , lanpltrusted = bool , lanplcallfoid = oid , laninline = oid , lanvalidator = oid , lanacl = _aclitem ) open pg_language insert ( 12 internal 10 f f 0 0 2246 _null_ ) insert ( 13 c 10 f f 0 0 2247 _null_ ) insert ( 14 sql 10 f t 0 0 2248 _null_ ) close pg_language

两个默认的表空间

create pg_tablespace 1213 shared_relation ( oid = oid , spcname = name , spcowner = oid , spcacl = _aclitem , spcoptions = _text ) open pg_tablespace insert ( 1663 pg_default 10 _null_ _null_ ) insert ( 1664 pg_global 10 _null_ _null_ ) close pg_tablespace
oid 对象
1 template1
10 postgres
6171 pg_database_owner
2200 public
11 pg_catalog
99 pg_toast
1262 pg_database
pg_namespace insert ( 2200 public 6171 _null_ )

根据oid可以看到,public模式在postgres 15中的owner是6171,即pg_database_owner,这是15的新特新。

template0是使用标准sql进行创建的。

"create database template0 is_template = true allow_connections = false" " oid = " cppasstring2(template0dboid) " strategy = file_copy;\n\n",
  • is_template = true:template0是个模板库。
  • allow_connections = false :不允许客户端链接
  • #define template0dboid 4 宏定义了template0的oid
  • strategy = file_copy :通过文件copy的方式创建。

对template1和template0的datcollversion进行设置

/* * template0 shouldn't have any collation-dependent objects, so unset * the collation version. this disables collation version checks when * making a new database from it. */ "update pg_database set datcollversion = null where datname = 'template0';\n\n", /* * while we are here, do set the collation version on template1. */ "update pg_database set datcollversion = pg_database_collation_actual_version(oid) where datname = 'template1';\n\n",

回收权限

/* * explicitly revoke public create-schema and create-temp-table * privileges in template1 and template0; else the latter would be on * by default */ "revoke create,temporary on database template1 from public;\n\n", "revoke create,temporary on database template0 from public;\n\n",

添加注释

"comment on database template0 is 'unmodifiable empty database';\n\n",

去死皮^_^

/* * finally vacuum to clean up dead rows in pg_database */ "vacuum pg_database;\n\n",
/* * copy template1 to postgres */ static void make_postgres(file *cmdfd) { const char *const *line; /* * just as we did for template0, and for the same reasons, assign a fixed * oid to postgres and select the file_copy strategy. */ static const char *const postgres_setup[] = { "create database postgres oid = " cppasstring2(postgresdboid) " strategy = file_copy;\n\n", "comment on database postgres is 'default administrative connection database';\n\n", null }; for (line = postgres_setup; *line; line ) pg_cmd_puts(*line); }

可以看到postgres就是对template1的直接复制。

其oid为5

可以看到在执行完initdb后,base目录下共有3个子目录,分别是1,4,5

本文通过源码分析了template1、template0和postgres的创建过程,也是initdb进程的运行过程。希望能从底层逻辑来理解postgres的一些特性,更有助于对postgres运行逻辑的深入理解,希望对大家有所帮助。

本期挖的坑,后续填上。

待填的坑 挖坑时间
理解bki 2022-05-22
最后修改时间:2022-05-23 09:20:33
「喜欢文章,快来给作者赞赏墨值吧」
1人已赞赏
【米乐app官网下载的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

网站地图