generaldeltaを有効にしてmercurialのリポジトリサイズを減らす

Mercurialリポジトリの履歴のフォーマットは通常のフォーマット以外にgeneraldeltaというものが有ります。

と偉そうに言ってみましたが、NetBSDリポジトリに関するMLのツイートをtwitterで見て初めて知りました。

通常のフォーマットと比べるとリポジトリサイズが小さくなるらしい*1ので、pypyのリポジトリで試してみました。

有効にする

.hgrcに次の設定をしてください。

[format]
generaldelta = true

クローンしてみる

  • generaldeltaを無効にした場合(通常)
% time (hg clone -U --config format.generaldelta=0 --pull pypy pypy-non-generaldelta)
requesting all changes
adding changesets
adding manifests
adding file changes
added 70529 changesets with 223487 changes to 44701 files (+124 heads)
( hg clone -U --config format.generaldelta=0 --pull pypy pypy-non-generaldelt)  152.55s user 19.13s system 61% cpu 4:38.12 total
% du -sh pypy-non-generaldelta
617M    pypy-non-generaldelta
% hg debugrevlog -m -R pypy-non-generaldelta
format : 1
flags  : (none)

revisions     :     70061
    merges    :      4767 ( 6.80%)
    normal    :     65294 (93.20%)
revisions     :     70061
    full      :       394 ( 0.56%)
    deltas    :     69667 (99.44%)
revision size : 288714045
    full      :  55492796 (19.22%)
    deltas    : 233221249 (80.78%)

avg chain length  : 505
compression ratio :  88

uncompressed data size (min/max/avg) : 0 / 916642 / 364444
full revision size (min/max/avg)     : 0 / 222686 / 140844
delta size (min/max/avg)             : 0 / 217544 / 3347

deltas against prev  : 69667 (100.00%)
    where prev = p1  : 58075     (83.36%)
    where prev = p2  :  1057     ( 1.52%)
    other            : 10535     (15.12%)
  • generaldeltaを有効にした場合
% time (hg clone -U --config format.generaldelta=1 --pull pypy pypy-generaldelta)
requesting all changes
adding changesets
adding manifests
adding file changes
added 70529 changesets with 223487 changes to 44701 files (+124 heads)
( hg clone -U --config format.generaldelta=1 --pull pypy pypy-generaldelta; )  297.99s user 30.27s system 69% cpu 7:53.03 total
% du -sh pypy-generaldelta
398M    pypy-generaldelta
% hg debugrevlog -m -R pypy-generaldelta
format : 1
flags  : generaldelta

revisions     :    70061
    merges    :     4767 ( 6.80%)
    normal    :    65294 (93.20%)
revisions     :    70061
    full      :      124 ( 0.18%)
    deltas    :    69937 (99.82%)
revision size : 65592031
    full      : 10731965 (16.36%)
    deltas    : 54860066 (83.64%)

avg chain length  : 491
compression ratio : 389

uncompressed data size (min/max/avg) : 0 / 916642 / 364444
full revision size (min/max/avg)     : 0 / 214457 / 86548
delta size (min/max/avg)             : 0 / 217544 / 784

deltas against prev  : 58927 (84.26%)
    where prev = p1  : 58076     (98.56%)
    where prev = p2  :    90     ( 0.15%)
    other            :   761     ( 1.29%)
deltas against p1    : 10881 (15.56%)
deltas against p2    :   129 ( 0.18%)
deltas against other :     0 ( 0.00%)

ちなみに、リポジトリがgeneraldeltaで保存されているかどうかは.hg/requiresでわかります。

% diff -u pypy-non-generaldelta/.hg/requires pypy-generaldelta/.hg/requires
--- pypy-non-generaldelta/.hg/requires  2014-04-10 11:06:25.000000000 +0900
+++ pypy-generaldelta/.hg/requires      2014-04-10 10:56:47.000000000 +0900
@@ -1,4 +1,5 @@
 dotencode
 fncache
+generaldelta
 revlogv1
 store

結果

generaldelta enable disable
リポジトリサイズ 398M 617M
通常リポジトリからのcloneにかかる時間 7:53.03 4:38.12

今回の例ではリポジトリサイズは40%削減、通常リポジトリからのcloneにかかる時間は70%増加しました。

これくらいなら、サイズが大きくて困っている場合に奥の手として利用できそうです。

*1:NetBSDの場合は15GBから2.1GBに削減されたらしい