# 貢獻于 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** ( 性能敏感?) 代碼應包括一些可用作目標基準測試用例。