searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

PostgreSQL 的 Hook 技术在内核代码的加载过程

2024-06-07 09:50:34
15
0

       在前面的博文中提到,可以利用 PostgreSQL 的 Hook 技术,来定制化数据库行为。其原理就是利用全局的函数指针,来判断PG中预制的各种HOOK是否为空, 如果不为空,则指向用户自定义的HOOK函数(注册用户的自定义 hook)。现在我们来具体看一下 postgres 中 hook 的实现机制。

  1. PG 通过全局指针函数(global pointer),来判断PG中预制的各种HOOK是否为空, 如果不为空,则指向用户自定义的HOOK函数(注册用户的自定义 hook)。
  2. 如果参数shared_preload_library 中包含多个插件,并且存在多个插件都修改同一个HOOK的情况,那么会把previous hook 保存记录下来, 如果 previous hook 不为空,会在自己开发中的HOOK中调用previous hook, 从而避免了后面的HOOK覆盖掉之前HOOK的逻辑,类似于 HOOK 链的设计。
  3. 当PG启动的时候,会调用方法__PG__init()来加载shared library 的 *.so 文件:
  4. 当PG关系实例的时候, 会调用方法__PG___finit()来关闭掉shared library 中加载的插件。

PG 预制HOOK的种类:

  • General Hooks
  • Security Hooks
  • Function Manager Hooks
  • Planner Hooks
  • Executor Hooks
  • PL/pgsql Hooks
  • ...

 

例如常用的pg_stat_statements和auto_explain,安装插件时,第一步就需要先修改 postgres.conf 中的参数 shared_preload_libraries,启动的时候加载2个插件:pg_stat_statements 和 auto_explain:

shared_preload_libraries='pg_stat_statements,auto_explain'

在 src/backend/postmaster/postmaster.c 中,主流程  PostmasterMain 中,调用 process_shared_preload_libraries()

可以看到 libraries 是值 是我们的GUC 的shared_preload_libraries值:是一个字符串形式,这个字符串就是我们配置文件中的那一串。

load_libraries 会把字符串按照逗号拆分放入 elemlist, 进行循环加载调用函数 load_file。

其中 internal_load_library 这个函数是实际的加载链接文件的入口;

调用底层 操作系统OS 函数 dlopen 打开动态链接文件

通过dlsym 调用动态加载文件中的 PG_MODULE_MAGIC 判断插件程序的兼容性。

如果存在不兼容的情况,则会调用dlclose(file_scanner->handle); 卸载动态库。

验证完插件的兼容性之后,会调用插件中的初始化函数 _PG_init(void)

在pg_stat_statements.c 文件中, 初始化函数 _PG_init(void) 完成了:

  1. EnableQueryId 设置SQL 的query ID
  2. DefineCustomIntVariable,DefineCustomEnumVariable,DefineCustomBoolVariable 设置用户自己定义的GUC变量
  3. install hook – 加载钩子函数

可以看到在HOOK的实现上,如果预制的HOOK已经被加载,则是 优先执行之前的PREVIOUS hook。

这样才能保证插件彼此时间不存在互相覆盖的现象。

 

以上就是 Postgres hook 在内核的加载过程。

 

 
0条评论
0 / 1000
张****豪
2文章数
0粉丝数
张****豪
2 文章 | 0 粉丝
张****豪
2文章数
0粉丝数
张****豪
2 文章 | 0 粉丝
原创

PostgreSQL 的 Hook 技术在内核代码的加载过程

2024-06-07 09:50:34
15
0

       在前面的博文中提到,可以利用 PostgreSQL 的 Hook 技术,来定制化数据库行为。其原理就是利用全局的函数指针,来判断PG中预制的各种HOOK是否为空, 如果不为空,则指向用户自定义的HOOK函数(注册用户的自定义 hook)。现在我们来具体看一下 postgres 中 hook 的实现机制。

  1. PG 通过全局指针函数(global pointer),来判断PG中预制的各种HOOK是否为空, 如果不为空,则指向用户自定义的HOOK函数(注册用户的自定义 hook)。
  2. 如果参数shared_preload_library 中包含多个插件,并且存在多个插件都修改同一个HOOK的情况,那么会把previous hook 保存记录下来, 如果 previous hook 不为空,会在自己开发中的HOOK中调用previous hook, 从而避免了后面的HOOK覆盖掉之前HOOK的逻辑,类似于 HOOK 链的设计。
  3. 当PG启动的时候,会调用方法__PG__init()来加载shared library 的 *.so 文件:
  4. 当PG关系实例的时候, 会调用方法__PG___finit()来关闭掉shared library 中加载的插件。

PG 预制HOOK的种类:

  • General Hooks
  • Security Hooks
  • Function Manager Hooks
  • Planner Hooks
  • Executor Hooks
  • PL/pgsql Hooks
  • ...

 

例如常用的pg_stat_statements和auto_explain,安装插件时,第一步就需要先修改 postgres.conf 中的参数 shared_preload_libraries,启动的时候加载2个插件:pg_stat_statements 和 auto_explain:

shared_preload_libraries='pg_stat_statements,auto_explain'

在 src/backend/postmaster/postmaster.c 中,主流程  PostmasterMain 中,调用 process_shared_preload_libraries()

可以看到 libraries 是值 是我们的GUC 的shared_preload_libraries值:是一个字符串形式,这个字符串就是我们配置文件中的那一串。

load_libraries 会把字符串按照逗号拆分放入 elemlist, 进行循环加载调用函数 load_file。

其中 internal_load_library 这个函数是实际的加载链接文件的入口;

调用底层 操作系统OS 函数 dlopen 打开动态链接文件

通过dlsym 调用动态加载文件中的 PG_MODULE_MAGIC 判断插件程序的兼容性。

如果存在不兼容的情况,则会调用dlclose(file_scanner->handle); 卸载动态库。

验证完插件的兼容性之后,会调用插件中的初始化函数 _PG_init(void)

在pg_stat_statements.c 文件中, 初始化函数 _PG_init(void) 完成了:

  1. EnableQueryId 设置SQL 的query ID
  2. DefineCustomIntVariable,DefineCustomEnumVariable,DefineCustomBoolVariable 设置用户自己定义的GUC变量
  3. install hook – 加载钩子函数

可以看到在HOOK的实现上,如果预制的HOOK已经被加载,则是 优先执行之前的PREVIOUS hook。

这样才能保证插件彼此时间不存在互相覆盖的现象。

 

以上就是 Postgres hook 在内核的加载过程。

 

 
文章来自个人专栏
数据库内核
2 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0