IvorySQL 贡献经历谈:如何参与内核研发?

IvorySQL 贡献经历谈:如何参与内核研发?

文一

2024-09-04 发布66 浏览 · 0 点赞 · 0 收藏

开源之夏是非常有意义的事情,它提供了一个平台以供我们参与到很多前沿的项目中去,本文将就如何参与到 IvorySQL 的内核研发中展开讨论,祝愿更多的人参与到 PostgreSQL 相关的数据库开发中,建立对于后端软件开发/数据库开发的一个了解。

什么是数据库内核研发?

建立对于数据库内核研发工作的基本理解,是我们参与类 PostgreSQL 数据库内核研发的基础,在这里,我们首先需要回顾后端开发的基本概念,参考下面的内容:

建立对后端开发的基本理解

后端开发可以理解为设计一种可以实现双向数据传输的软件,其中,被称为“服务端”的软件部分,负责在本地接受来自于外部用户/主机的连接,并根据某种设计好的协议,以及用户的某种指示(配置文件乃至于数据往往存储于某个本地的文件夹上面),实现与外部数据传输,如图所示:

server-intro

而在 PostgreSQL 中,postgres 即为服务端软件的代称,它依据放置于 “PGDATA” 目录中(专门用于存储配置文件及其数据的文件夹)的内容展开工作,如图:

postgres

(-D 指示了 PostgreSQL 存储数据与存放目录的地址,而如何初始化这个目录呢?请使用 initdb 工具,方法是 initdb [你希望设定的 PGDATA 地址]

所依据的通信协议,可以参考 https://www.postgresql.org/docs/current/protocol.html 部分的文档(介绍 PostgreSQL 的数据包是如何组织的)。

而被称为“客户端”的软件部分,负责主动连接服务端,按照用户要求发送指令给服务端加以处理。

client

这种指令具体是什么,取决于服务端软件与客户端软件的设计乃至于其所处的领域,如在 Redis 中,倘若我们希望读写数据,只需要按照 Redis 对于键值对的管理方式,即可以解决问题,如图:

Redis-Command

而到了 PostgreSQL 之中,我们所需要做的事情,便在于按照 SQL 语言的模式,来处理问题,如图所示:

psql-command

(psql 便是 PostgreSQL 中的客户端,其使用 SQL 以及一些内建指令,展开同服务端的工作)

而后端开发,乃至于数据库内核的开发,实际上便是在服务端与客户端上面下功夫,针对某种类型的任务,展开某种改进。

在后端开发的基础上,建立对于数据库内核开发的理解

我们可以把数据库内核开发工作视作为一种定向的后端开发工作(后端开发还包含着游戏服务器设计,音视频服务器设计等),这是因为,它往往便是针对某一种类型数据的管理而展开设计的。

而在 PostgreSQL 中,我们关注的便是关系型数据(关系型数据便是一种以二维表格形式组织起来的数据),一切的工作,则围绕对于关系型数据的管理而展开,简单来说,具体的工作可以划分为如下的类别(这里,我们以 https://commitfest.postgresql.org/ 上面的分类作为阐述的依据):

我们可以把 Patch 理解为开源工作中常常听到的 Pr,代表对于某种功能的改进与完善

  1. 对于 PostgreSQL 内核工程中某种 Bug 的修复 这往往来自于各地用户通过 bug 邮件列表的反馈意见,牵涉到某种不正常的工作行为等,这些 Patch 便是对于这些不正常工作行为的修订
  2. 对于 PostgreSQL 客户端的某种改进 这种情况往往是为 PostgreSQL 增加某种客户端工具,或者是对既有的某种客户端工具的细节改进,如 PostgreSQL 17 引入的 pg_walsummary 便是打印了 PostgreSQL wal 目录中的 summary 部分信息,用以展现 wal 文件的概括情况(即修订了哪一些数据块等)
  3. 文档的完善与更新 文档可以帮助我们更好的理解软件的原理和使用,PostgreSQL 的文档在指导用户使用 PostgreSQL 的同时,往往还帮助用户去定制 PostgreSQL 以适应自身的场景。
  4. PostgreSQL 运维信息的管理 数据库的维护需要诸多指标作为参考的依据。
  5. 性能优化与改进
  6. 过程性语言 过程性语言即是向 PostgreSQL 引入外部拓展,以支持使用某种编程语言以处理关系型数据。
  7. 对某种模块的重构 重构即是在实现对原有模块兼容性的情况下,重新设计并编写某种模块,以便提升灵活性,或者是性能,或者是可读性。
  8. 流复制 流复制是 PostgreSQL 提供的多机集群方案,可以实现 PostgreSQL 自单节点向多节点的拓展部署。
  9. 安全性 如对于密码安全性的增强等。
  10. 服务端的改进 对于某种工作行为的改进
  11. SQL 指令 引入新的指令以兼容最新的 SQL 标准,或是拓展某种语法。
  12. 系统管理 与运维工作息息相关,即指导 PostgreSQL 的某种全局性行为。
  13. 测试工作 测试便是模拟某种环境下 PostgreSQL 的表现,形式也非常简单,便是预先构造一组输入,并且设计好预期的输出,倘若执行测试的输出与预期输出不相符合,则证明存在某种问题。
  14. 其它

在大致树立了总体的概念之后,我们便可以开始开始对 PostgreSQL 的工程布局做一个了解,这是我们开发内核的基础(我将以一个简单的 Patch 以及我对于 IvorySQL 的开发经历,阐述如何实际参与内核研发,真实难度其实是远远低于我们的想象的,哈哈哈哈)

简单的改进也是对内核研发的参与:以 Patch 'int4->bool test coverage' 为例

在 PostgreSQL 的 Commitfest 程序中罗列着许多的 Patch,他们都代表着一种对于内核某个模块的改进思路,理解这些 Patch 往往就意味着我们熟悉了 PostgreSQL 的某一种模块,乃至于某种对于软件的改进思路(所以如果你成功地熟悉了足够多的 Patch,你也就成为了一名优秀的 PostgreSQL 内核研发者,须知即使是到 PostgreSQL 17,总体的 Patch 都没有超过6万个,别被这个数字吓到,许多模块对应着十个乃至于数以百计的 Patch,因此当你熟悉了对应模块以后,你实际的 Patch 阅读量会比你统计的 Patch 阅读量高上许多,哈哈哈哈)

好的,言归正传,让我们开始阅读这个 Patch 有关的背景信息,乃至于作者所期待的改进。

PostgreSQL 的测试体系简介(回归测试简介)

软件的测试对于软件的工作正确性而言是非常重要的事情,而在 PostgreSQL 当中,测试工作可以简化为如下的流程:

test-intro

而对应到代码之中,则更是简单,参考下图:

make-check-1

(在 PostgreSQL 源代码文件夹中,通过 make check 执行测试操作)

make-check-2

(PostgreSQL 将会按照类别展开分组测试,测试需要涉及到内核工程中的各个重要模块,这样才可以最大避免地规避生产故障,ok 代表测试通过)

test-dir

(测试有关的源代码位于 src/test 目录之下,里面牵涉到的文件很多,但是核心的原理就是执行某些 SQL 代码,验证其预期的输出)

更为详细的内容,可以参考文档中 https://www.postgresql.org/docs/current/regress.html (回归测试)的部分

有了了解之后,开始分析 Patch

而我们将要分析的 Patch,则与作者的一则发现有关系:

patch-index-page

(Patch 在 Commitfest 页面上的主页信息,请参考 https://commitfest.postgresql.org/47/4789/)


作者邮件原文及其翻译

I was surprised to learn that 2 is a valid boolean (thanks Berge):

我非常惊讶地发现 2 (数字,译者注)也是一个有效的布尔值(感谢 Berge)

# select 2::boolean;
 bool
──────
 t

... while '2' is not:

... 同时我发现 '2' (字符串,译者注)不是有效的布尔值:

# select '2'::boolean;
ERROR:  22P02: invalid input syntax for type boolean: "2"
LINE 1: select '2'::boolean;
               ^
LOCATION:  boolin, bool.c:151

The first cast is the int4_bool function, but it isn't covered by the regression tests at all. The attached patch adds tests.

第一则转换应用到了 int4_bool 函数,但这这个函数并没有被回归测试所覆盖到。因此我所提交的 Patch 补充了相关的测试。

Christoph


而作者的 Patch 内容也非常简单,我们提取关键部分信息如下:

add-input

(增加了三条需要执行的 SQL 测试语句)

add-output

(以及三条语句所对应的期待输出)

而我们可以尝试执行其中的一条 SQL,可以发现这是一个简单的,但是长期以来被忽略的细节情况:

try-execute

而社区在接收到这则细节性改进的 Patch 之后,很快地给予了批复:

commit

(在2024年3月,该 Patch 合入 PostgreSQL 内核)

小结:内核研发实际上并不难

只需要我们保持着对于细节的注意力,小而稳健地推进,即可以慢慢成长为一名一流的 PostgreSQL 内核研发者。

而其它的诸多类 PostgreSQL,是针对某些特定的场景,对 PostgreSQL 做出的定向改进,我们不要将其看得那么难,而要将他们看成一件容易的事情(复杂的事情实际上是简单工作的不断组合)。

继续细化:如何参与 IvorySQL 贡献?

现在,我们已经理解了 PostgreSQL 内核研发是什么,以及如何研发 PostgreSQL 之后,理解参与针对某种场景定向优化的 PostgreSQL,也就不再算是一件非常困难的事情,继续参考下面的论述:

IvorySQL-Intro

(IvorySQL 是一款为增强 PostgreSQL Oracle 兼容性而二次开发的 PostgreSQL 数据库,在代码上始终跟踪着最新版本 PostgreSQL)

IvorySQL-Github

(而 IvorySQL 则托管于 Github 之上,因此希望参与贡献的话,提交 Issue 与 Pr 即可)

OSPP-2024-IvorySQL

(而在中国科学院与华为联合举办的 “开源之夏 2024” 中,我有幸成为中选的学生受邀参与到项目的开发之中,在这里非常感谢浪潮的任娇老师与牛世继老师)

而我所承担的项目职责,主要在于:

  1. 为 IvorySQL 增加新的 xml 函数
  2. 增强既有的 pg_get_functiondef 函数,增强其导出函数的能力
  3. 为他们编写对应的测试用例

而因为前面两篇所牵涉的具体原理已经在 [青年数据库学习会] 公众号上面发布,因此我并不会过多的讨论其细节,我们只需要了解的是,想要开发某种新的功能,或者是改进某种既有的功能,我们只需要了解其对应的模块的设计,原理以及对外接口,再融合我们自身的想法,即可以达成我们的目的。

以 xml 功能的增强为例,在我尝试向其加入 xmlisvalid 函数的时候,首先注意到的事情是:

  1. 既有的 xml 兼容函数都被设计于 ivorysql_ora 文件夹之中,而存放的地址,则位于 src/xml_functions 文件夹之下

xml_functions

换而言之,如果我需要加入新的 xml 兼容函数,就需要先从这里下功夫

  1. 因为 ivorysql_ora 是以拓展的形式涵盖于 PostgreSQL 整体的工程之中的,因此,我需要对 PostgreSQL CREATE EXTENSION 乃至于注册函数的 CREATE FUNCTION 有一个基本的了解

creare-extension

(PostgreSQL 文档中有关 CREATE EXTENSION 的部分信息)

  1. 之后,为了了解其实现目标,我需要查看 Oralce 对应的部分信息

Oracle-xmlisvalid

  1. 根据 libxml 库的既有函数,实现功能

xmlisvalid

(最后实现的关键代码其实非常少,但是它的难点就在于需要很多铺垫的知识)

  1. 编写测试用例

在这里一定一定要注重沟通,现在我所犯下的一个巨大错误就是闷头开发,不注重同导师交流,最后忽略了很多项目中的细节信息,导致即使在开源之夏申报成功后两周内就完成了功能开发,也没能将产出立刻合入到代码库之中。

reject

(两次遭到拒绝的 Pr 合入,因为我没能注重和导师沟通)

就以测试用例为案例,因为 IvorySQL 为了保持同 PostgreSQL 的兼容性,因此它设计了一个独立的为 Oracle 准备的 Oracle 兼容模式,而对应的测试也增添了 make oracle-check 选项,而我因为没有和导师沟通,忽略了这个事情,进而引入了很多不必要的沟通成本与误会,延缓了合入的效率,这点一定要引以为戒,不要单打独斗,一定要多和队友,导师,同行的朋友,以及跨领域的人多做交流,不然定然栽跟头。

言归正传,编写测试用例实际上和之前的 Patch 中的思路类似,就是引入一些范例的测试代码,同时给出输出的结果,然后放置于对应的测试用文件夹即可(这里又提到一个小细节,可以提供多个示范输出文件,这样只需要有一个符合,就可以通过测试,这非常适合于存在多种可能的正常输出的场景(IvorySQL 在 Oralce 模式与 PostgreSQL 模式下,同样的函数可能给出不一样的输出结果))

最终在于社区导师协调沟通以后,我的 Pr 顺利合入,由此也完成了 IvorySQL 的开源之夏工作任务,在这途中学习到了很多,尤其是严谨的软件开发精神。

reply

(对注释的把控都是很严格的,这有助于让我们编写出非常好的代码来,所以为什么要参与这种业界的前沿开源项目,正是因为在这途中可以学习到很多普通项目学习不到的东西)

写在最后

我们的“内核一周一审”栏目将会在每一周对某一个 PostgreSQL 的 Patch 展开解读,深刻挖掘其背后的原理,乃至于组织的思路,改进的思路等,期待这为各位投身于数据库内核开发带来更多有意义的借鉴与参考。

功夫全在于细节之处,而报团打堆才可以帮助我们更快的前进,期待更多的人投身于数据库领域之中,谢谢各位的支持。