开发者学堂课程【PolarDB for PostgreSQL 入门:《如何参与贡献 PolarDB for PG 开源》】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/813/detail/13921
《如何参与贡献PolarDB for PG开源》
内容介绍:
一、背景
二、开发环境搭建
三、开发规范
四、开发示例
一、背景
首先设计开源是什么?由于最近的开源项目越来越多,开源也越来越热,这个原因每个人都有自己的看法。
在这里是认为随着软件行业的发展,无论是软件的消费端还是生产端,都有对软件产品的需求。而软件的消费端就是所谓的用户,用户希望软件产品是长久的产品,不会因为各种原因导致软件停止服务或是没有人去维护,同时保证软件能够提供后续功能的一些支持。
作为软件开发人员,从软件生产端来说是要开发出一些更新更炫的一些功能进而可以快速的分享给大家。开源就是给他们提供一个非常好的二创,一个好的开源项目是离不开大家的支持和共享,以及一个好的开源管理。
作为开源的参与者如何能快速高效的参与进来,并开发出符合开源标准的高质量代码。所以这里主要讲解如何进行PolarDB for PG 的快速搭建,以及阿里云的行业规范,最后会演示一下如何快速参与到共享中去。
二、开发环境搭建
作为开发人员,最想拥有的就是一个适合自己的开发环境。就像一个砍树的人人,他需要一个坏的斧头一样。可以使其快速的投入到工作中,而不是被一些繁杂的问题所影响。欲要善其事必先利其器。开源环境搭建会分为俩部分,一部分是系统环境搭建
(1)系统环境搭建:
这里以 centos 为例,虽然在开源项目里已经提供了刀客版本的快速部署,还是要知道具体里面是做了哪些内容。作为开发人员,可能需要对里面的内容做一些开发与维护,这就需要知道里面具体都是做了写什么,由于这次项目是基于PG 的,对于以前参与过 PG 的开发的,了解 PG 是基于 C 语言开发的,所以这里面需要编译一些 c 语言的开发环境和依赖库,同时为了方便后期的代码调式,代码编写,也是要安装一些其他的工具。
比如说 gate,它实际上是一个代码编写工具,是可以快速的获取一个代码;还有 GDB 用来调式 debug;还有 wem可以进行快速的编辑;以及 sh 服务等,这个服务肯定是在集群部署中会用到;安装 PolarDB 的一些依赖,这邪恶依赖确保了后续代码开发的保障,后期开发过程中需要开发新的语法或是对现有语法的修改,肯定是要安装这些依赖,因为这个语法编辑器正是基于这个功能开发的。
系统环境搭建
系统环境:
yum install gcc-c++ libstdc++ libstdc++-devel binutils -y
yum intall glibc glibc- devel glibc-all-langpacks -y
yum insatll - -enablerepoe=* -y which sudo passwd wget gdb git vim oess-sever openssh-clients
PolarDB 依赖 :
yum install --enablerepo=' -y bison flex libzstd-devel libzstd zstd cmake openss-devel\
prolobul-devel readline-devel libxml2-devel libxslt-devel zlib-develbzip2-devel\
lz4-devel snappy-devel python-devel perl perl-devel per-libintl per-lPC-Run\
per-Time-HiRes per-Test-Simple per-ExtUtilis-Embed per-ExtUtils-MakeMaker\
per-Text-Unidecode
(2)源代码的获取
源代码一般是托管在 guihub 上的,可以简单通过git的管理工具,可以快速的获取信息代码。同时也可以时刻浏览开源GitHub 的地址,浏览开源的最新动态,讨论一些新的功能。
Git 命令:
gitclone https://github.com/alibaba/PolarDB-for-PostgreSQL.git
(3)源码编译
/bulid.sh debug configure&make&make istall这个默认安装在了$HOME /polardb/polardbhome
cd $CODEHOME
./configure CFLAGS=*-O0" -enable-debug -enable-tap-tests --with-python -prefix=目录
cd $CODEHOME/srcbackend/polar_dma/libconsensus/polar_wrapper && ./build -sh -r debug
cd $CODEHOME && make-sj && make istll//编译 polardb 并安装
cd $CODEHOME/contrib && make -sj &&make Install //编译插件井安装
拿到代码讨论之后,就要进行编译。前面是讲过很多依赖了,所以这里会顺利很多。
这里会提供一个 build.sh 的快速编译的脚本。通过这个脚本可以快速的实现编译安装,他的默认编译位置是在
HOME/polardb/polarhome cd ¥ CODEHOME 下的子目录中,这个脚本做了三件事,一是 configure,是用来检测依赖环境,生成 makepale,之后就是一些 make 进行编译。对于开发人员来讲,受控的就是一些编译软件的安装步骤。手动进行编译的环境是对开发有一定的要求和修改,这里会提供一些手动编译的过程。通过 configure 命令来指定几个参数来 configure,这里面的内容像“-O0”可以阻止编译器不要优化代码,这样可以在 debug 过程当中得到有效的信息。enable 的 debug 实际上实在内部的编译命令上加了一些参数,比如-g 参数,以便于可以在 debug过程中提供代码详细的文字信息。
Enable -tap-test 实际上是一个基于 polar 的测试框架,产品在测试中分为俩部分,一部分是有内核功能的测试,还有一部分是可以认为是周边的一些工具、插件的测试。部分工具、插件采用的是基于 polar 的测试框架去支持,这方便后期的框架测试。还有一部分是基于 python 的支持,是由于是用 python 语言开发的。
最后是 prefix 这个参数指定了默认的安装目录,如果按照上面 build.sh
来去编译安装指定的目录,这个需要根据自身的开发管理来指定所用目录,之后就是编译 DMA 一个高可用的功能,在这个目录进行编译即可,回到主目录 polardb 安装编译。最后回到主目录来进行所有插件的编译安装。目前为止,是可以基本了解简单的开发环境,可以进行代码的编辑,代码的 debug 调试编译等工作都是可以在上面运行的。部分同学有自己的集成开发环境,大家可以根据自己来安装相应的环境,比如 eclipes 、source-set、wirecode等。
(4)测试
在拿到一个编译环境之后想要快速的验证这个产品是不是好用或是快速 知道产品的功能,实际上就是提供一个测试框架。通过 make check 这几个命令比如 makecheck 、make checkworld、make checkdma、make check-world-dma。
这些命令可以快速完成对环境内核功能的验证,包括周边工具的测试验证。比如 makecheckworld在 刚才的五个目录下,这个过程中不仅包含了提供的 make check world,它主要是测试内核功能。之前都有提到过,测试功能分为内核功能和测试周边的工具、插件。这个 make checkworld 可以测试所有make check 的模块上,它通过这个模式就可以包括了核心功能测试。执行一个 make check world 的时间会花费很长,但它会全面测试。在这个版本中,提供了make check-dma,之前讲过这个是支持 dma 高可用的一个版本。这种高可用是一种集群,采用 make check world这个单个节点的测试。这里会用来测试是不是高可用集群的版本。这个 make checkworld 和 make check world-dma 是差不多的功能,只不过这个每次测试都是在集群中测试,而不是一个单个节点的测试
三、开发规范
开发规范对平时我们有重要的作用,但对于我们平时对开发规范的关注并不多。但作为开源项目来讲,开发规范特别重要。这些年 pg 社区发展非常快,每年都有很多的发布,实际上就是通过一些标准的开发规范、制度,集齐全世界各国的开发制度优选开发人员,协同开发并写出高质量的代码。所以开发规范就好比一个在开源项目的一个标准,那么大家就有了标准的共同语言,是一个项目能否良好持续发展的关键。实际上 polar 依然坚持这套标准。
,这里会简单介绍一些基本规范,这样会帮助大家开发出一些高质量,符合国际标准的代码,可以为了之后的发展提供一些好的支撑。
(1)C 语言格式规定
大部分语言都是 C 语言开发的,所以 C 语言就是最基础的规范。首先就是缩进,在过去的时间中可能会被告知不要使用tab 键,但在 pg 中是要求使用 tab 键的,并且使用4个子表符。大家使用是要符合这个标准,所有都是要符合这个标准的。之后就是布局,就是所谓的大括号的放置,是要求遵循 BSD 习惯的。
特别地,if、while、switch 等受控块的花括号都是要独自占据一行的。限制行长度,这样的80列窗口中代码也是可读的。也不是不能超过80行有一些 every maysige,为了80行进行任意一行的切断,实际上就会影响可读性。
目的是保证可读性的情况下保持80列的限制。不使用c++风格的注释(//注释),严格的 ANSI C 编译器不接受这样的注释。出自相同的原因,不适用 c++扩展,例如在块中声明新变量。
比如说 for 语句在控制块里会有一个变量i,这里是不允许的,要把声明变量i放到控制块后面。多行注释中需要使用这样的风格
/*
*注释文本从这里开始
*继续到这里
*/
(2)如何报错
这里说明一下报错信息,作为开发人员来讲,输入认知信息是和用户交流的重要手段。如果输出的正确认知信息在软件开发手段中尤其重要,这是告诉用户我们是一个专业的软件开发人员。如果写的信息是 se,软件可能在客户那里无论是不是有一个优秀的算法,或是一个优秀的功能,只要写的功能不够好,那么从用户的角度上来讲,合格软件产品就是一个不够专业的软件,所以说往往忽略的问题可能是一个重要的东西。这里讲的报错信息主要通过俩个方面来实现的,是 ereport 和 elog。
Ereport(ERROR,(errcode(ERRCORE_DIVISION_BY_ZERO),errmsg(“division by zero”)));
A.严重级别//DEBUG...ERROR,FATAL,PANC,随着级别越来越高,严重级别对于用户来说也是越来越高。也可以通过文件配置设置输出什么信息。如果严重级别没有设置,或是设置 error 会更高,那么 ereport 会终止用户的定义类型,并且不会返回到严重者,如果低于 error,ereport 会正常返回。
B.错误代码,一般由五个字符组成,数字和大写字母组成表示多重错误和警告的代码。是分层次的,前俩位表示错误的分类,后三位表示分类的子类。代码五个0表示成功的状态,这个可以快速的定义问题的类型,知道大概debug的方向在哪里。如果没有写错误表示或是别的就会以一个更高的错误标识来记录这个 error,如果错误级别是worry就会默认是 worry;如果是 notice 及以下的话,实际上就会使用 errorcode,这是在没有设置 errcode 的情况下默认的。有时不用 errcode 是一个很方便的地方,但当考虑不用时一定要清楚不用的原因是什么。
C.错误信息 errmmsg 是要提供报错的主体信息,这就提到 ereport 是一个符合函数,实际上需要多都是复合函数。这些复合函数可以写在官网上去查看。
Elog(level,”format string”,...);
等效于 ereport(level,(errmsg_internal(“format string”,...)));是一种旧有的模式,可以看到它提供了 level,但没有提供 errcode,严重级别就会提供默认的 errcode。它的消息通过 errmsg 去传递,这和刚才讲到的 errmsg是不一样的。
Errmsg 可以通过地域设置成不一样的,比如英语翻译成汉语,实际上这种语言就不会受翻译的限制,这样就可以原模原样打印出来,而为什么需要保留旧的模式因为它本身足够简洁,在有些内部的错误它是被用户受出来的,它是用户感兴趣的一些错误,这些错误可以用简洁的模式进行打印,这种模式是非常方便的,这才得到了保留。
(3)错误消息如何撰写
1.消息的构成:主要分为三部分,是要简单概要的介绍错误的部分。后期这个概要不能够表达出具体的错误,就可以添加 detail 信息,把具体的细节打印出来。如果提出来一些特殊的修复建议,可以进行一些文件的修改,比如一些文件不见了就可以进行文件的添加
1. Primary: could not create shared memory segment: %m
2. Detall: Failed syscall was shmget(key=%d, size=%u, 0%o).
3. Hint: the addendum
2.引号:
(1).在引用时,英语文本应该使用双引号
(2)总是用引号界定文件名、用户提供的标识符以及其他可能包含词的变量。不要用它们来标记不会包含词的变量.因为有些对象再插入的过程中会存在歧义的,如果加的话,可以避免歧义。
3.语法和标点:
(1)主要错误消息:第-个字母不要大写.不要用一个句点结束一个消息。甚至不要考虑用一个感叹号结束一个消息
(2)详细和提示消息:使用完整的句子,并且每一个都用句点结束。 对句子的第一个词进行首字母大写. 如果后面跟着另一个句子,在句号后面放两个空格。这些具体的建议实际上是为了更好的使用,对于用户来讲有些信息可以更好更方便的插入到各种各样的上下文中。通常来讲,一般不是一个完整的语法句子,如果是一个长句子,尽量拆分成一个主要消息和详细部分,不过详细部分通常会很长,需要一个包括句子,为了一致即使是一个句子也要保证完整的风格。
4.大写和小写:
(1)对消息使用小写形式,包括一个主要错误消息的第一个字母。 如果 SQL 命令或者关键词出现在消息中,请为它们使用大写.
5.避免被动态:
使用主动语态。在有主语时使用完整句子(“A could not doB" ) .如果主语是程序本身,使用没有主语的电报风格。但不要为程序使用“I”.程序不是人不用假装。
6.现在时和过去时:
如果一次尝试做某事失败但是可能在下一次成功(也许在修复某个问题之后) ,则使用过去时。如果失败必定是持久的,请使用现在时,如下有何区别:
could not open file "%s": %m 和 cannot open file“%s"前一个表示打开文件失败,会给出一个具体的原因,比如文件满了或是磁盘不存在,这样会更合适,因为下一回可能文件就不满了。后一个是这个程序所以提到的功能更本就不存在或是概念上就不可能,在这种情况下,这个错误会无限存在。这样做是因为,普通用户是没有能力从消息的时长上去得出重要的结论,但是由于语言提供正确的语法,所以就要正确的使用。
7.对象类型:
在引用一个对象的名称时,说明该对象的类型。否则没有人会了解“foo bar.baz"具体是什么
8.组装错误信息:
当一个消息包括在别处产生的文本时,这样将它嵌入 could not open file %s: %m.
消息应该总是说明为什么错误会发生的原因。如果没有已知原因,你最好修复代码,例如
BAD: could not open file %s,这种没有给原因就不确定是怎样产生的
BETTER: could not open file %s (I/0 failure)
不要在消息中写函数名.在开发过程中会经常用到日志名,这个实际上对用户来讲是没有任何作用的,他不会清楚里面的,需要把函数名保持在 debug 阶段最后还是要把函数名提交写成一个合规的错误消息。
避免缩略语。例如"can't" ,请使用"cannot"
避免使用 Unable Bad llegal Unknown unable 更接近于被动语态,会酌情使用 cannot;比如 bad result,实际上很难从错误信息上知道是什么东西;llegal 是表示错误的违法信息,最好是携程 envalue,说明为什么无效就更好;unknown 是尝试避免,如果不知道相应是什么应该使用 recognize 这种没有识别,相当于是一个更好的选择。
BAD: unknown node type
BETTER: unrecognized node type: 42
Find 还是 Exists,使用算法器查找或是失败了就用 find;如果是已知的资源位置但程序无法找到它,那么就要用exists
(4)其他编码习惯
1.宏和内联函数:
带有参数的宏以及 static inline 函数都可能被使用,但当使用宏时,有多次计算的风险,则推荐使用后者。其他情况只能使用宏,或者至少说使用宏更容易。
信号处理函数:这个很重要的代码,除特殊代码外,信号处理不好就会导致信息混乱。
除特殊安排的代码之外,在信号处理器中只应该调用对异步信号安全的函数.比如在处理信息的时候操控锁,这个锁是在外部调用的已经锁上了,此时在信号处理中去处理这个锁就会带来大家知道的结果。
在大部分情况下,信号处理器应该只提示个信号已经到达,并且使用一个 latch唤醒运行在处理器之外的代码。这样一个处理器的例子如下:
static void handle_ sighup(SIGNAL_ ARGS)
{
int save_ errno = errno;
got_ SIGHUP = true;
SetLatch(MyLatch);
errno = save_ errno;
}
其他编码习惯
3.调用函数指针:
显示调用函数指针。如果函数指针是一个简单的变量 ,在调用指向的函数时显式地对其解除引用会更好,例如:
("emit log hook) (edata); (虽然 emit log. hook(edata)还会有效)
(5)其他语言编码规范
Http://google.github.io/styleguide/pyguide.html
https://github.com/qolang/go/wiki/CodeReviewComments
Httpt://google github.io/styleguide/shellguide.html
四、开发示例
这里举一个例子来简单告诉如何快速加入开源的项目中,这里进入之后可以看到已经把之前要克隆的代码克隆好了,输入语句$git log,可以看到已经更新到最新的位置信息了。
这里已经提供了一个 docke r的快速启动方式,通过则会个方式来 build 出一个 docker 的版本,通过这个命令来去dockerfile,用社区版的来去 bulid。之后就可以看到 build 生成好的 image,通过 image 来启动这个集群,之后就可以使用了。
完成之后需要把这些停止下来,去启动我们的集群,通过 exec 命令来发现集群。进去之后会发现代码和clone一样的。可以查看一些文件内容,输入 vi bulid.sh,可以看进去没有语法报量。
之后用 vim 语句登进去可以查看语法报量,看出来文件是没有这个的,就需要在安装一个
安装就会发现一个问题,它本身没有安装是不是可以让社区版本的去提供一个,这样在下次使用就不必在安装,这也就是共性开源好的地方,安装后输入语句,vim build.sh
就可以查看语法报量,如下图。
这就可以作为代码提交到开源社区里,比如这就可以直接来道 docker 的目录下,打开 dockerfile 就可以看到如下图。
就可以在里面进行以下安装,加入 vim,之后在原页面上去验证是否可以,下图就显示的是可以的,之后就可以了。
之后重新进来之后查看是否可以直接进入 vim build.sh,进入成功就说明代码是可以进行提交的。
现在就需要 git branch fix...dockerfile,就可以 git checkout fix_dockerfile,如下图
之后就可以看到是不是会有一个更改文件,添加以下更改意识,比如说是
Support vim 新的版本,如下图。
之后把文件加进来,在输入语句 git commit -m “support vim in docker”,最后在 git log 就可以看到提交后的源代码,如下图。
如何把提交的推到社区呢?就要把提交前的,输入语句,git checkout master、git bra、git branch,如下图,需要重启代码。
之后要切换回我们的源文件,还要输入语句,git rebase master 去提交,这里可以使用自己账户的名字,这样就会把代码提交到社区,之后就会直接从社区来进去即可。
可以在 github 网站上建立一个 procast,就可以看到 dockerfile,之后描述一下提交,描述内容为 support vim in docker,最后就是点击提交。把代码快速提交到 master 里面,这就是真个代码的提交以及修改流程。以下就是命令的分级区域和层次,可以参考以下。
giclone http://github.com/alibaba/PolarDB-for-PostgreSQL.git
docker build -t polardb-for-postgresql -f ./docker/Dockerfile
docker run --name polardb -d polardb-for-postgresql:latest
docker exec -it polardb /bin/bash