贡献于 Kudu

原文链接 : http://kudu.apache.org/docs/contributing.html

译文链接 : http://cwiki.apachecn.org/pages/viewpage.action?pageId=10813653

贡献者 : 小瑶 ApacheCN Apache中文网

Contributing Patches Using Gerrit ( 使用 Gerrit 贡献补丁 )

Kudu 团队使用 Gerrit 进行代码审查,而不是 Github pull requests。通常,您从 Github pull ,但是 pushGerritGerrit 用于查看代码并将其合并到 Github 中。

有关使用 Gerrit 进行代码审查的概述,请参阅 Gerrit 教程

Gerrit 的初始设置

  1. 使用您的 Github 用户名登录 Gerrit
  2. 前往 Setting 。在 Contact Information 页面上更新您的姓名和电子邮件地址,并上传 SSH 公钥。如果您不更新您的姓名,它将在 Gerrit 评论中显示为 “Anonymous Coward”
  3. 如果还没有这样做,请 clone the main Kudu repository 。默认情况下,main remote 称为 origin 。当你 fetch pull ,你会从 origin 这样做。

    1. git clone https://github.com/apache/kudu
  4. 切换到新的 kudu 目录。

  5. 添加 gerrit remote 。在以下命令中,用您的 Github 用户名替换 <username>

    1. git remote add gerrit ssh://&lt;username&gt;@gerrit.cloudera.org:29418/kudu
  6. 运行以下命令来安装 Gerrit commit-msg hook 。使用以下命令,用您的 Github 用户名替换 <username>

    1. gitdir=$(git rev-parse --git-dir); scp -p -P 29418 &lt;username&gt;@gerrit.cloudera.org:hooks/commit-msg ${gitdir}/hooks/
  7. 默认情况下,您已经设置了 Kudu 存储库使用 pull -rebase 。您可以使用以下两个命令,假设您至今已经检查过主机:

    1. git config branch.autosetuprebase always
    2. git config branch.master.rebase true

如果由于某种原因,您已经 checked out branches 而不是 master ,请在上面的第二个命令中替换 master 以获取 other branch names

Submitting Patches ( 提交补丁 )

要提交修补程序,首先提交您的更改(如果可能,使用描述性多行提交消息),然后将请求 pushgerrit remote。例如,要将更改推送到 master 分支:

  1. git push gerrit HEAD:refs/for/master --no-thin

或者将更改 pushgh-pages 分支 ( 更新网页 ):

  1. 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 。将您的更改再次 pushGerrit ,这将在 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 类引入依赖关系。例如,喜欢来自 gutilstrings :: Split() ,而不是 boost :: split
  • 喜欢使用 boost 的功能而不是重新实现相同的功能,除非使用 boost 功能需要过度使用我们的风格指南不允许的 C ++ 功能。例如,boost :: spirit 非常基于模板元编程,不应该使用。
  • 不要在 Kudu C ++ 客户端的任何公用头文件中使用 boost ,因为 boost 通常会破坏向后兼容性,并且在两个升级版本之间传递数据(一个由用户由 Kudu 导出)会导致严重的问题。

如果有任何提升功能引入新的依赖关系,最好发送电子邮件至 dev@kudu.apache.org 开始讨论。

Line length ( 线长 )

Kudu 团队允许每行 100 个字符的行长度,而不是 Google80 标准。尽可能保持在 80 以下,但如果需要,您可以溢出到 100 个左右。

Pointers ( 指针 )

Smart Pointers and Singly-Owned Pointers ( 智能指针和单独指针 )

通常,大多数对象应该有明确的 “single-owner” 语义。大多数时候, singly-owned 的对象可以包装在 unique_ptr <> 中,确保在范围退出时删除,并防止意外复制。

如果对象是 singly owned 的,但是从多个位置引用,例如当已知指向对象至少与指针本身一样长时,将注释与将原始指针存储并存储的构造函数相关联,如在下面的例子中。

  1. // 'blah' must remain valid for the lifetime of this class
  2. MyClass(const Blah* blah) :
  3. blah_(blah) {
  4. }

注意

Kudu 代码库的较旧部分使用 gscoped_ptr 而不是 unique_ptr 。这些都是在 Kudu 采用 C ++ 11 之前进行的。新代码不应该使用 gscoped_ptr ,除非需要与现有代码进行接口。或者,考虑在您遇到这些问题时更新用法。

注意

严格禁止使用 std :: auto_ptr ,因为它的难度大且易出错的语义。此外, std :: auto_ptrC ++ 11 被声明为不推荐使用。

Smart Pointers for Multiply-Owned Pointers ( 多指针指针的智能指针 ):

虽然 single ownership 是理想的,但有时候是不可能的,特别是当多个线程正在运行时,指针的生命周期没有明确定义。在这些情况下,您可以使用 std :: shared_ptrKudu 自己的 scoped_refptrgutil/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 :: bindboost :: function 来进行函数绑定和回调。 对于新代码,请使用 gutil 中的回调和绑定类。 虽然功能较少(绑定不支持参数占位符,包装函数指针或函数对象),但它们通过参数生命周期管理的方式提供更多选项。 例如,当 Callback 超出范围时,绑定参数的类扩展 RefCounted 将在绑定期间递增,并减少。

有关详细信息,请参阅 gutil/callback.h 中的大文件注释,util/callback_bind-test.cc 作为示例。

CMake Style Guide ( CMake 样式指南 )

CMake 允许以较低,上限或混合大小写的命令。 要保持 CMake 文件一致,请使用以下准则:

  • 小写的 built-in commands

    1. add_subdirectory(some/path)
  • 大写的 built-in arguments

    1. message(STATUS "message goes here")
  • 大写的 custom commands or macros

    1. ADD_KUDU_TEST(some-test)

GFlags

Kudu 使用 gflags 进行命令行和基于文件的配置。使用这些准则添加新的 gflag 。所有新 gflags 必须符合这些准则。现有的不符合要求的产品将及时符合规定。

Name ( 名称 )

gflag 的名字传达了很多信息,所以选择一个好名字。该名称将传播到其他系统,如 配置参考

  • 多字名称的不同部分应以下划线分隔。例如, fs_data_dirs
  • 该名称应以其影响的上下文为前缀。例如, webserver_num_worker_threadscfile_default_block_size 。上下文可能很难定义,所以请记住,这个前缀将用于将类似的 gflags 组合在一起。如果 gflag 影响整个过程,那么它不应该是前缀。
  • 如果 gflag 是一个数量,该名称应该后缀单位。例如, tablet_copy_idle_timeout_ms
  • 如有可能,请使用短名称。这将为手动输入命令行选项的人节省时间。
  • 这个名称是 Kudu 兼容性合同的一部分,不应该没有很好的理由来改变。

Default value ( 默认值 )

选择默认值通常很简单,但像名称一样,它传播到其他系统中。

  • 默认值是 Kuducompatibility contract ( 兼容性合同 ) 的一部分,如果没有很好的理由,不应该改变。

Description ( 描述 )

gflag 的描述应该补充名称并提供其他上下文和信息。与名称一样,说明传播到其他系统。

  • 描述可以包括多个句子。每个都应该以一个大写字母开头,以一个句点结尾,并在之前的一个空格开始。

  • 描述不应包含 gflag 的类型或默认值;它们是带外提供的。

  • 描述应该在第三人称。不要使用像你这样的话。
  • gflag 描述可以自由更改; Kudu 的发行预计不会保持不变。

Tags ( 标志 )

Kudugflag 标记机制为每个 gflag 添加了机器可读上下文,用于消耗系统,如文档或管理工具。请参阅 flag_tags.h 中的大块注释,以获取准则。

Miscellaneous ( 杂 )

  • 避免为同一个逻辑参数创建多个 gflags 。例如,许多 Kudu 二进制文件需要配置一个 WAL 目录。而不是创建 foo_wal_dirbar_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 ( 性能敏感 ) 代码应包括一些可用作目标基准测试用例。