摘要

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

initdb源码概览

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.con、pghba.conf、pgident.conf,并对其中定义的参数做一些设置。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AaJe9Edk-1653222953327)(4)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-REcWIswe-1653222953327)(5)]

通过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);

创建template1

进程间统信

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和其中的系统表。

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

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库

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",

创建postgres库

/** 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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTWt60Ft-1653222953328)(images/rWhdF7BY_QHh9K8Sb4WeBR-ZUasYGP25sN_uEs1JQHA.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ixTqlkAk-1653222953329)(images/Y0cAvE8gnzbPTCGL_wz3-15zTcSZ6vRZzFa9f2_QGT8.png)]

结束

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

备注

本期挖的坑,后续填上。

理解bki 2022-05-22

postgresql 15源码浅析(1)—— postgres中的1号数据库相关推荐

  1. 13个Vue3中的全局API的源码浅析汇总整理

    前言 不知不觉vue-next的版本已经来到了3.1.2,最近对照着源码学习vue3的全局Api,边学习边整理了下来,希望可以和大家一起进步. 我们以官方定义.用法.源码浅析三个维度来一起看看它们.下 ...

  2. hive 强转为string_String 源码浅析————终结篇

    写在前面 说说这几天看源码的感受吧,其实 jdk 中的源码设计是最值得进阶学习的地方.我们在对 api 较为熟悉之后,完全可以去尝试阅读一些 jdk 源码,打开 jdk 源码后,如果你英文能力稍微过得 ...

  3. Koa洋葱圈模型源码浅析(`await next()`为什么能够形成洋葱圈模型?)

    Koa洋葱圈模型源码浅析 写在前面 什么是中间件? 为什么要使用中间件? auth中间件源码 Koa源码浅析 我们先来康一张gif图片 我们的探索流程图 listen函数 callback函数 cre ...

  4. Android应用进程间通信之Messenger信使使用及源码浅析

    转载: http://blog.csdn.net/yanbober 1 背景 这个知识点是个low货,刚开始其实想在之前一篇文章<Android异步消息处理机制详解及源码分析>一文中作为一 ...

  5. libevent源码浅析: http库

     libevent自带了一个http库,用它可以很简单的实现一个http服务器,本文非常简单地分析之.evhttp evhttp库有几个主要的结构体,它们之间的联系非常龌龊: 其中,结构体even ...

  6. hashmap允许null键和值吗_hashMap底层源码浅析

    来源:https://blog.csdn.net/qq_35824590/article/details/111769203 hashmap是我们经常使用的一个工具类.那么知道它的一些原理和特性吗? ...

  7. Android Loader机制全面详解及源码浅析

    原文出处:csdn@工匠若水,http://blog.csdn.net/yanbober/article/details/48861457 一.概述 在Android中任何耗时的操作都不能放在UI主线 ...

  8. 内核启动流程分析(四)源码浅析

    目录 kernel(四)源码浅析 建立工程 启动简析 head.s 入口点 查询处理器 查询机器ID 启动MMU 其他操作 start_kernel 处理命令行 分区 kernel(四)源码浅析 建立 ...

  9. harbor登录验证_Harbor 源码浅析

    Harbor 源码浅析​www.qikqiak.com Harbor 是一个CNCF基金会托管的开源的可信的云原生docker registry项目,可以用于存储.签名.扫描镜像内容,Harbor 通 ...

最新文章

  1. 【CocoaPods】CocoaPods:Objective-C依赖库管理(XCode 4.6)
  2. Openfire 源码部署
  3. 第六周项目三-IP地址类
  4. 人工智能算法--KNN算法(C++实现)
  5. JavaScipt30(第三个案例)(主要知识点:css变量)
  6. varnish介绍以及虚拟机的封装
  7. 为旧版代码创建存根–测试技术6
  8. 测试需要了解的技术之基础篇四__UI自动化测试体系
  9. 爆红的变老神器 FaceApp,夹杂着安全隐患?
  10. xps数据怎么导出为txt_如何处理XPS原始数据
  11. 敏感词过滤golang
  12. VS2017透明背景和皮肤设置
  13. Linux上获取软件程序包
  14. 小程序如何引导添加个人微信号
  15. Windows操作系统查看电脑开关机记录
  16. KDL学习之路01:KDL(Kinematics and Dynamics Library)入门学习
  17. python之API接口调用
  18. 入职华为云计算工程师值得嘛?
  19. css 父级设置了padding,但是子元素还是会超过padding解决方案
  20. Go语言读取文件的常用方式

热门文章

  1. 软件架构设计之理论篇
  2. Linux 中重启php命令
  3. python中deepcopy函数_python中copy()和deepcopy()详解
  4. js 闭包传参_JavaScript 闭包的应用
  5. 推广APP 不用明星代言还能怎么做?
  6. ajax省市线三级联动
  7. 在IDEA中设置依赖调用公共模块代码
  8. 【今日开播】第十二届蓝桥杯决赛特训营开播啦!国赛冲冲冲!
  9. 【日常代码记录】如何实现一个beancopier的工具类?
  10. BR/EDR 测试模式