16.md 15.4 KB
Newer Older
W
mkdocs  
wizardforcel 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
# 贡献于 Kudu

原文链接 : [http://kudu.apache.org/docs/contributing.html](http://kudu.apache.org/docs/contributing.html)

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

贡献者 : [小瑶](/display/~chenyao) [ApacheCN](/display/~apachecn) [Apache中文网](/display/~apachechina)

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

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

有关使用 **Gerrit** 进行代码审查的概述,请参阅 [**Gerrit** 教程](https://www.mediawiki.org/wiki/Gerrit/Tutorial)

### Gerrit 的初始设置

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

    ```
    git clone https://github.com/apache/kudu
    ```

4.  切换到新的 **kudu** 目录。
5.  添加 **gerrit remote** 。在以下命令中,用您的 **Github** 用户名替换 **<username>**

    ```
    git remote add gerrit ssh://<username>@gerrit.cloudera.org:29418/kudu
    ```

6.  运行以下命令来安装 **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/
    ```

7.  默认情况下,您已经设置了 **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** 提交准则和良好做法](https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines)

注意

**--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](https://google.github.io/styleguide/cppguide.html)** ,但有以下例外:

### Notes on C++ 11 ( 关于 C++ 11 的注释 )

**Kudu** 使用 **C ++ 11** 。查看 **C ++ 11** 移动语义和 **rvalue** 引用的方便指南:[https://www.chromium.org/rvalue-references](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** 的名字传达了很多信息,所以选择一个好名字。该名称将传播到其他系统,如 [配置参考](/pages/viewpage.action?pageId=10813644)

*   多字名称的不同部分应以下划线分隔。例如, **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** ( 性能敏感 ) 代码应包括一些可用作目标基准测试用例。