- 贡献于 Kudu
- Contributing Patches Using Gerrit ( 使用 Gerrit 贡献补丁 )
- Code Style ( 代码风格 )
- CMake Style Guide ( CMake 样式指南 )
- GFlags
- Testing ( 测试 )
- All new code should have tests. ( 所有新的代码都应该有测试。 )
- All bug fixes should have tests. ( 所有错误修复都应该有测试。 )
- Tests should run quickly (< 1s). ( 测试应该很快运行(<1s)。 )
- Tests which run a number of iterations of some task should use a
gflags
command-line argument for the number of iterations. ( 运行一些任务的迭代的测试应该使用 gflags 命令行参数来执行迭代次数。 ) - Commits which may affect performance should include before/after
perf-stat(1)
output. ( 可能影响性能的提交应包括在 perf-stat(1) 输出 之前/之后。 )
贡献于 Kudu
原文链接 : http://kudu.apache.org/docs/contributing.html
译文链接 : http://cwiki.apachecn.org/pages/viewpage.action?pageId=10813653
Contributing Patches Using Gerrit ( 使用 Gerrit 贡献补丁 )
Kudu 团队使用 Gerrit 进行代码审查,而不是 Github pull requests。通常,您从 Github pull ,但是 push 到 Gerrit , Gerrit 用于查看代码并将其合并到 Github 中。
有关使用 Gerrit 进行代码审查的概述,请参阅 Gerrit 教程。
Gerrit 的初始设置
- 使用您的 Github 用户名登录 Gerrit 。
- 前往 Setting 。在 Contact Information 页面上更新您的姓名和电子邮件地址,并上传 SSH 公钥。如果您不更新您的姓名,它将在 Gerrit 评论中显示为 “Anonymous Coward” 。
如果还没有这样做,请 clone the main Kudu repository 。默认情况下,main remote 称为 origin 。当你 fetch 或 pull ,你会从 origin 这样做。
git clone https://github.com/apache/kudu
切换到新的 kudu 目录。
添加 gerrit remote 。在以下命令中,用您的 Github 用户名替换 <username> 。
git remote add gerrit ssh://<username>@gerrit.cloudera.org:29418/kudu
运行以下命令来安装 Gerrit commit-msg hook 。使用以下命令,用您的 Github 用户名替换 <username> 。
gitdir=$(git rev-parse --git-dir); scp -p -P 29418 <username>@gerrit.cloudera.org:hooks/commit-msg ${gitdir}/hooks/
默认情况下,您已经设置了 Kudu 存储库使用 pull -rebase 。您可以使用以下两个命令,假设您至今已经检查过主机:
git config branch.autosetuprebase always
git config branch.master.rebase true
如果由于某种原因,您已经 checked out branches 而不是 master ,请在上面的第二个命令中替换 master 以获取 other branch names。
Submitting Patches ( 提交补丁 )
要提交修补程序,首先提交您的更改(如果可能,使用描述性多行提交消息),然后将请求 push 到 gerrit remote。例如,要将更改推送到 master 分支:
git push gerrit HEAD:refs/for/master --no-thin
或者将更改 push 到 gh-pages 分支 ( 更新网页 ):
git push gerrit HEAD:refs/for/gh-pages --no-thin
注意
在准备一个修补程序进行审查时,最好遵循通用 git 提交准则和良好做法。
注意
—no-thin 参数是防止 Gerrit 中的错误的解决方法。请参阅
注意
考虑为上述命令创建 Git 别名。 Gerrit 还包括一个名为 git-review 的命令行工具,您可能会发现有用。
Gerrit 会在您的提交消息中添加更改 ID ,并创建一个 Gerrit review ,其 URL 将作为推送回复的一部分发布。如果需要,您可以向 kudu-dev 邮件列表发送消息,解释补丁并请求 review 。
获得反馈后,您可以更改或修改您的提交(例如,使用像 git commit —amend 这样的命令),同时保留更改 ID 。将您的更改再次 push 给 Gerrit ,这将在 Gerrit 中创建一个新的修补程序,并通知所有审阅者有关更改。
当您的代码经过审查并准备合并到 Kudu 代码库后, Kudu 提交者将使用 Gerrit 进行合并。你可以丢弃你的 local branch 。
Abandoning a Review ( 放弃 review )
如果您的补丁不被接受或您决定从考虑中提取补丁,则可以使用 Gerrit UI 放弃补丁。它仍将在 Gerrit 的历史上展示,但不会被列为待审查。
Reviewing Patches In Gerrit ( 审查 Gerrit 中的补丁 )
您可以使用 Web UI 查看 Gerrit 中的统一或并行差异更改。要发表评论,请单击相关行号或突出显示该行的相关部分,然后键入 “c” 以显示注释框。要提交您的 review 和/或 您的 review status ,请转到评论的顶层,然后单击 Reply。您可以在此处添加其他顶级注释,然后提交。
要查看 Gerrit review 中的代码,请单击下载并将相关的 Git 命令粘贴到 Git 客户端。然后,您可以更新提交并推送 Gerrit 向审阅提交补丁,即使您不是原始审阅者。
Gerrit 允许您对 review 进行投票。在修补程序可以合并之前,需要至少提交一个提交者(除了提交者)之外的一个 +2 的投票。
Code Style ( 代码风格 )
熟悉这些准则,以便您的贡献能够快速轻松地进行审查和整合。
一般来说,Kudu 遵循 Google C++ Style Guide ,但有以下例外:
Notes on C++ 11 ( 关于 C++ 11 的注释 )
Kudu 使用 C ++ 11 。查看 C ++ 11 移动语义和 rvalue 引用的方便指南:https://www.chromium.org/rvalue-references 。
我们的目标是遵循大多数相同的指导原则,例如在可能的情况下迁移远离 foo.Pass() ,有利于 std :: move(foo)。
Limitations on boost Use ( boost 使用限制 )
在 kudu 代码库中不存在合适的替换的情况下,可以使用仅来自标头库的 boost 类。然而:
- 不要对标准 C ++ 库或 src/kudu/gutil/ 中存在等效功能的 boost 类引入依赖关系。例如,喜欢来自 gutil 的 strings :: Split() ,而不是 boost :: split 。
- 喜欢使用 boost 的功能而不是重新实现相同的功能,除非使用 boost 功能需要过度使用我们的风格指南不允许的 C ++ 功能。例如,boost :: spirit 非常基于模板元编程,不应该使用。
- 不要在 Kudu C ++ 客户端的任何公用头文件中使用 boost ,因为 boost 通常会破坏向后兼容性,并且在两个升级版本之间传递数据(一个由用户由 Kudu 导出)会导致严重的问题。
如果有任何提升功能引入新的依赖关系,最好发送电子邮件至 dev@kudu.apache.org 开始讨论。
Line length ( 线长 )
Kudu 团队允许每行 100 个字符的行长度,而不是 Google 的 80 标准。尽可能保持在 80 以下,但如果需要,您可以溢出到 100 个左右。
Pointers ( 指针 )
Smart Pointers and Singly-Owned Pointers ( 智能指针和单独指针 )
通常,大多数对象应该有明确的 “single-owner” 语义。大多数时候, singly-owned 的对象可以包装在 unique_ptr <> 中,确保在范围退出时删除,并防止意外复制。
如果对象是 singly owned 的,但是从多个位置引用,例如当已知指向对象至少与指针本身一样长时,将注释与将原始指针存储并存储的构造函数相关联,如在下面的例子中。
// 'blah' must remain valid for the lifetime of this class
MyClass(const Blah* blah) :
blah_(blah) {
}
注意
Kudu 代码库的较旧部分使用 gscoped_ptr 而不是 unique_ptr 。这些都是在 Kudu 采用 C ++ 11 之前进行的。新代码不应该使用 gscoped_ptr ,除非需要与现有代码进行接口。或者,考虑在您遇到这些问题时更新用法。
注意
严格禁止使用 std :: auto_ptr ,因为它的难度大且易出错的语义。此外, std :: auto_ptr 自 C ++ 11 被声明为不推荐使用。
Smart Pointers for Multiply-Owned Pointers ( 多指针指针的智能指针 ):
虽然 single ownership 是理想的,但有时候是不可能的,特别是当多个线程正在运行时,指针的生命周期没有明确定义。在这些情况下,您可以使用 std :: shared_ptr 或 Kudu 自己的 scoped_refptr 从 gutil/ref_counted.hpp 。这些机制中的每一个依赖于引用计数,以便在没有更多指针保留时自动删除指示。这两种类型的指针之间的关键区别是 scoped_refptr 要求对象扩展一个 RefCounted 基类,并将其引用计数存储在对象存储本身内,而 shared_ptr 在堆上维护单独的引用计数。
利弊是:
shared_ptr
- 可以与任何类型的对象一起使用,而不需要从特殊的基类派生对象
- 标准库的一部分,大多数 C ++ 开发人员熟悉
支持 weak_ptr 的用例:
- 当对象仅在存在的情况下需要被访问时才是临时所有权
- 打破 shared_ptr 的循环引用,如果由于聚合存在任何存在
- 您可以将 shared_ptr 转换为 weak_ptr 并返回
- 如果使用 std :: make_shared <>() 创建一个实例,则只能进行一次分配(因为 C ++ 11; Standard 中的非绑定的要求)
- 如果使用 shared_ptr <T> p(new T) 创建新对象需要两个分配(一个用于创建引用计数,另一个用于创建对象)
- 引用计数可能不在堆上的对象附近,因此在访问时可能会发生额外的高速缓存未命中
- shared_ptr 实例本身需要 16 个字节(指向 ref 计数的指针和指向对象的指针)
scoped_refptr
只需要一个分配,并且 ref 计数与对象在同一个高速缓存行上
指针只需要 8 个字节(因为引用计数在对象内)
当需要更多控制时,您可以手动增加或减少参考计数
您可以将原始指针转换回 scoped_refptr ,而不必担心双重释放
- 由于我们控制实现,我们可以实现功能,例如调试构建,捕获每个对象的堆栈跟踪以帮助调试泄漏。
- 引用对象必须从 RefCounted 继承
- 不支持 weak_ptr 的用例
由于 scoped_refptr 通常越来越小,所以尝试在新代码中使用而不是 shared_ptr 。现有代码在许多地方使用 shared_ptr 。当与该代码连接时,可以继续使用 shared_ptr 。
Function Binding and Callbacks ( 函数绑定和回调 )
现有代码使用 boost :: bind 和 boost :: function 来进行函数绑定和回调。 对于新代码,请使用 gutil 中的回调和绑定类。 虽然功能较少(绑定不支持参数占位符,包装函数指针或函数对象),但它们通过参数生命周期管理的方式提供更多选项。 例如,当 Callback 超出范围时,绑定参数的类扩展 RefCounted 将在绑定期间递增,并减少。
有关详细信息,请参阅 gutil/callback.h 中的大文件注释,util/callback_bind-test.cc 作为示例。
CMake Style Guide ( CMake 样式指南 )
CMake 允许以较低,上限或混合大小写的命令。 要保持 CMake 文件一致,请使用以下准则:
小写的 built-in commands
add_subdirectory(some/path)
大写的 built-in arguments
message(STATUS "message goes here")
大写的 custom commands or macros
ADD_KUDU_TEST(some-test)
GFlags
Kudu 使用 gflags 进行命令行和基于文件的配置。使用这些准则添加新的 gflag 。所有新 gflags 必须符合这些准则。现有的不符合要求的产品将及时符合规定。
Name ( 名称 )
gflag 的名字传达了很多信息,所以选择一个好名字。该名称将传播到其他系统,如 配置参考。
- 多字名称的不同部分应以下划线分隔。例如, fs_data_dirs 。
- 该名称应以其影响的上下文为前缀。例如, webserver_num_worker_threads 和 cfile_default_block_size 。上下文可能很难定义,所以请记住,这个前缀将用于将类似的 gflags 组合在一起。如果 gflag 影响整个过程,那么它不应该是前缀。
- 如果 gflag 是一个数量,该名称应该后缀单位。例如, tablet_copy_idle_timeout_ms 。
- 如有可能,请使用短名称。这将为手动输入命令行选项的人节省时间。
- 这个名称是 Kudu 兼容性合同的一部分,不应该没有很好的理由来改变。
Default value ( 默认值 )
选择默认值通常很简单,但像名称一样,它传播到其他系统中。
- 默认值是 Kudu 的 compatibility contract ( 兼容性合同 ) 的一部分,如果没有很好的理由,不应该改变。
Description ( 描述 )
gflag 的描述应该补充名称并提供其他上下文和信息。与名称一样,说明传播到其他系统。
描述可以包括多个句子。每个都应该以一个大写字母开头,以一个句点结尾,并在之前的一个空格开始。
描述不应包含 gflag 的类型或默认值;它们是带外提供的。
- 描述应该在第三人称。不要使用像你这样的话。
- gflag 描述可以自由更改; Kudu 的发行预计不会保持不变。
Tags ( 标志 )
Kudu 的 gflag 标记机制为每个 gflag 添加了机器可读上下文,用于消耗系统,如文档或管理工具。请参阅 flag_tags.h 中的大块注释,以获取准则。
Miscellaneous ( 杂 )
- 避免为同一个逻辑参数创建多个 gflags 。例如,许多 Kudu 二进制文件需要配置一个 WAL 目录。而不是创建 foo_wal_dir 和 bar_wal_dir gflags ,最好使用一个单一的 kudu_wal_dir gflag 来普遍使用。
Testing ( 测试 )
All new code should have tests. ( 所有新的代码都应该有测试。 )
在现有文件中添加新的测试,或根据需要创建新的测试文件。
All bug fixes should have tests. ( 所有错误修复都应该有测试。 )
如果由现有测试用例触发,则可以修复错误而不添加新测试。例如,如果在 20 分钟左右之后运行多线程系统测试时出现了一个 race ,那么值得尝试更有针对性的测试用例来触发该错误。但是如果这很难做,现有的系统测试就够了。
Tests should run quickly (< 1s). ( 测试应该很快运行(<1s)。 )
如果要编写时间密集的测试,请使运行时依赖于通过 KUDU_ALLOW_SLOW_TESTS 环境变量启用的 KuduTest#AllowSlowTests ,并由 Jenkins 测试执行使用。
Tests which run a number of iterations of some task should use a gflags
command-line argument for the number of iterations. ( 运行一些任务的迭代的测试应该使用 gflags 命令行参数来执行迭代次数。 )
这对于编写快速压力测试或性能测试非常方便。
Commits which may affect performance should include before/after perf-stat(1)
output. ( 可能影响性能的提交应包括在 perf-stat(1) 输出 之前/之后。 )
这将显示性能提升或 non-regression ( 不回归 )。Performance-sensitive ( 性能敏感 ) 代码应包括一些可用作目标基准测试用例。