読者です 読者をやめる 読者になる 読者になる

methaneのブログ

このブログに乗せているサンプルコードはすべてNYSLです。

なぜbzrはhgより遅いのか

(hgの部分をgitに置き換えてもOK)
bzrとhgを比較するベンチマークだと、特にcloneにおいてbzrが遅い。

bzrとhgにおける、リポジトリとブランチの扱いの違いについて

まず、bzrは色々な使い方に対応できるようにしようとしてリポジトリとブランチと作業ツリーを分離して設計している。
bzrの .bzr というディレクトリは、作業ツリー、ブランチ、リポジトリを含む場合もあれば含まない場合もある。

bzr init-repo --no-tree foo       # foo/ はリポジトリ
bzr init foo/bar                  # foo/bar/ はブランチ
bzr co --lightweight foo/bar baz  # baz/ は作業ツリー

さて、bzrのリポジトリ、ブランチ、作業ツリーとは何者か。
リポジトリというのは、リビジョンを格納するものだ。リビジョンとはあるディレクトリツリーの状態に加えて、親リビジョン、コミットログ等の付加情報を加えたものだ。
ブランチとは、リビジョンのグラフ・・・という概念はさておき、ぶっちゃけリポジトリ中の1つのリビジョンを「最新」と記憶するものだ。ブランチに対してコミットすると、「最新」リビジョンを親とする新しいリビジョンを生成し、今度はそのリビジョンが「最新」になる。
最後に作業ツリーとは、あるブランチの最新リビジョンを実際のディレクトリツリーとして展開したものだ。
bzrはこの3つを分離し、しかもそれぞれについてフォーマットを入れ替えられるようにすることで、すばらしい柔軟性を得ている。

それに対してhgはその3つが密結合している。.hgというディレクトリは必ずリポジトリであり、リポジトリの中にはリビジョンとブランチが格納されており、ブランチの一つはactiveになっていて、activeなブランチの作業ツリーが展開される。

なぜcloneが遅いのか

細かい点を言えば、現時点ではbzrのcloneコマンドはbranchコマンドに対するエイリアスになっていて、将来このエイリアスは外される予定なので、hgのcloneとbzrのbranchの比較といった方が適切だ。しかし便宜上ここではcloneで統一する。

hgのcloneはリポジトリのcloneだ。リポジトリ内の全ブランチをcloneする。このとき、動作としてはある時点のリポジトリの中身を丸ごとコピーするだけで済む。
それに対して、bzrのcloneはブランチのcloneだ。このときの動作は、clone元のリポジトリ内のリビジョンのうちそのブランチに必要なものをピックアップして転送し、clone先のリポジトリに格納していく。

大抵の場合、ベンチマークでは一つのブランチのみで構成されるリポジトリを作成し、それをcloneする。
ローカルでのcloneの場合、hgはハードリンクが可能なら大部分をハードリンクするだけで、不可能なら単純なコピーでリポジトリの複製を作成できる。それに対して、bzrではstacked branchかshared repositoryを使わないとリポジトリの再構築が必要になってしまう。大抵のベンチマークでは内部動作ではなく外見上の動作を似せるためにstandalone branchを使っているので遅い。
さらに、リモートでのcloneは問題だ。hgはローカルのハードリンクが使えないときのようにリポジトリ内のデータをそのままコピーするだけだ。bzrはリモートでstacked branchをするとオフライン動作ができなくなるし、shared repositoryはそもそも使えないので、必ずリポジトリの再構築が必要になる。そのほか、リビジョン一つ一つ転送しないといけない。丁寧に設計しないと、まとめて圧縮しているリポジトリ内のデータ構造よりも大量のデータをネットワーク越しに転送することになる。逆に、bzrは関心のあるブランチ以外のデータを転送せずに済むというメリットもあるが、hgはそもそもまったく関連しないブランチを一つのリポジトリに入れることがマレで、たいていの場合ブランチ間で殆どの情報を共有しているので、このメリットはなかなか表に出てこない。

解決する動き

まずリモートからのcloneについて、リビジョンを転送する効率は最近のバージョンでは大分改善された。しかしリポジトリからリビジョンを取り出したり逆にリポジトリにリビジョンを格納して再構築するオーバーヘッドがあるので、リポジトリのうちの一部分だけの転送で済む場合を除いてhgにはまだまだ敵わない。
なのでbzrも、現在branchのエイリアスとなっているcloneを一旦エイリアス解除し、将来的にブランチではなくてリポジトリの複製を作るのにcloneコマンドを割り当てようという動きがある。これでとりあえずリモートからcloneするときのパフォーマンスの問題は解決するだろう。