Open3
reposoup: `git commit` の代わりにtreeを直接コミットする
gitリポジトリをデータベース代わりに使うと、割と10〜100万件くらいからスケーラビリティ的な限界が出てくる。特にWindowsはファイルシステムが超クッソ激烈に遅いためgitを普通に使うんではパフォーマンス的に厳しいものがある。
git commit
の代替
データベースをGitリポジトリに格納する...というと、
- ファイルシステム上にデータファイルをばらまく
git add .
-
git commit -m "Update"
← これが超時間掛かる git push
のような流れでデータの追加を行いたくなる。
しかし、Windows上では、100〜1000万ファイルあるリポジトリ上でGit commitを呼ぶだけで数時間掛かってしまう。というわけでデータベースにレコードを追加する場合は:
- 追加されるディレクトリを覚えておく(データベースを設計する上で少くとも意味のあるディレクトリ単位でデータを追加するように配慮する)
-
git add <path> ...
のようにしてpathを直接指定してGitが無駄なディレクトリを見なくても良い様にする -
git write-tree
でadd
したデータをtreeに変換する -
git commit-tree
で tree を参照するコミットオブジェクトを作成する -
git update-ref
で、master
ブランチを更新する
のような流れにすると、ほぼ git add
に掛かるコストだけでコミットを作成できる。
...というか何で git commit
はあんなに遅いんだろう。。
標準ではコミットメッセージのデフォルトに変更されたファイルや add
していないファイルの一覧が出るので、それらを出すためにリポジトリのあるディレクトリをスキャンしているのではないかと思ったけど、 git commit -m "Update"
のようにコミットログメッセージをコマンドラインから与えても全く改善しない。
CMakeスクリプトでのやり方
message(STATUS "Git Add ...")
execute_process(
COMMAND git add
${targetdirs} # ★ 変数にあらかじめgit addが必要なパスを入れておき、add . での手抜きは避ける
WORKING_DIRECTORY ${ROOT})
message(STATUS "Git write-tree...")
execute_process(
COMMAND git write-tree # ★ write-treeには特に引数は不要。indexがtreeに変換される
WORKING_DIRECTORY ${ROOT}
OUTPUT_VARIABLE out # ★ treeオブジェクトのハッシュ(と改行)を受けとる
RESULT_VARIABLE rr)
if(rr)
message(FATAL_ERROR "Write-tree error: ${rr}")
endif()
string(STRIP "${out}" tree) # ★ 余計なスペースを消す
message(STATUS "Git create commit(${tree})...")
execute_process(
COMMAND git commit-tree -p HEAD -m "Update"
${tree} # ★ commit-tree コマンドでコミットを作成
WORKING_DIRECTORY ${ROOT}
OUTPUT_VARIABLE out # ★ sha1を受けとる
RESULT_VARIABLE rr)
if(rr)
message(FATAL_ERROR "Commit-tree error: ${rr}")
endif()
string(STRIP "${out}" commit)
message(STATUS "Git update ref(${commit})...")
execute_process( # ★ update-ref でmasterを更新
COMMAND git update-ref refs/heads/master ${commit}
WORKING_DIRECTORY ${ROOT}
OUTPUT_VARIABLE out
RESULT_VARIABLE rr)
if(rr)
message(FATAL_ERROR "Update-ref error: ${rr}")
endif()
↑ この方法だとgcがトリガされない。。?
数百回コミットして300万ファイルくらいにしてみたけど一度もgcした様子が無い。。
まぁ別に手動gcを発動するようにスクリプトを組めば良い話ではあるけど。。