(利用状況次第では) Mercurial 2.3 版利用の回避を推奨
簡単にまとめると:
リビジョン指定に revsets 表記を多様する人は、想定外の挙動が発生する可能性があるので、Mercurial 2.3 版の利用は回避することを推奨
最新の情報に関しては、こちらのエントリを参照のこと。
以下、詳細というか、障害要因調査の顛末。
事の発端は、"hg convert
" と filemap 指定の併用により、追加したファイルを履歴を遡って改名する実験をしていた際の、以下のような挙動の発見。
$ ADDEDREV=`hg -R src log -r "min(filelog('re:b'))" --template '{node}'` $ echo ${ADDEDREV} 9c7bcdc44ce39d06d3fb9e4e0ee6a53c72122673 $ PARENTREV=`hg -R src log -r "${ADDEDREV}^1" --template '{node}'` $ echo ${PARENTREV} 9c7bcdc44ce39d06d3fb9e4e0ee6a53c72122673 $
は????? "^1
" (第1親リビジョン)指定を付けているのに、なんで ADDEDREV
と PARENTREV
が同じなの?
あれこれ試行錯誤してみたけれど、さっぱり埒があかない。
そう言えば、revsets 指定の解釈だけを行うデバッグ用コマンドってなかったっけ?と "hg debugrevspec
" の存在を思い出して、こちらでも試してみることに。
$ hg -R src debugrevspec "${ADDEDREV}" 3 $ hg -R src debugrevspec "${ADDEDREV}^1" 2 $
こっちは想定通りに解釈されてる (親のリビジョン番号 = 自身のリビジョン番号 - 1)。
"hg log
" の "-r
" 指定と "hg debugrevspec
" の引数指定では、解釈処理のルートが違うとか?
色々原因箇所の絞り込みを試みたのだけれど、結構根が深そうなので、とりあえずどのあたりの版がヤバイのかをざっと確認したら、まずは障害報告だけ先に済ませてしまおう&できれば他の人に直してもらおう(笑)、という結論に。
版違いで挙動を確認してみると……あれ?ピンポイントに 2.3 版でだけ現象が再現する。
デスクトップ PC 上で使っていた版が、更新をサボっていたために、たまたま障害を踏む 2.3 版だっただけで、最新版にしておけば大丈夫だったんだ……orz
まぁ、慌てて『バグだ!バグだ!』と騒がなくて済んだのだから、良しとしよう。いや、バグではあるんだけど、既に修正済みだからね。
『revset』をキーワードに履歴を検索してみたけど:
$ hg log -r '2.3::2.3.1 and keyword(revset)' チェンジセット: 17410:7c865f30e2b8 ブランチ: stable ユーザ: Pierre-Yves David日付: Fri Aug 31 23:27:26 2012 +0200 ファイル: mercurial/repair.py 説明: strip: fix revset usage (issue3604) The `repair` code builds a giant revset query instead of using the "%lr" idiom. It is inefficient and crash when the number of stripped changeset is too big. This changeset replaces the bad code by a better revset usage.
これしか抽出されないし、issue3604 は何か違う感じ。
何の気なしに試してみたところ:
- 40 桁のハッシュ値を使った "
${ADDEDREV}^1
" 記述は正しく機能しない - 12 桁のハッシュ値を使った "
${ADDEDREV}^1
" 記述は正しく機能する - リビジョン番号を使った "
${ADDEDREV}^1
" 記述は正しく機能する
ということが判明。更には 39 桁のハッシュ値でも但しく機能したので、どうやら『40 桁』が現象発生の閾値っぽい。
駄目元で『40』をキーワードに検索してみると:
$ hg log -r '2.3::2.3.1 and keyword(40)' -v チェンジセット: 17353:bde1185f406c ブランチ: stable 親: 17351:9d9d15928521 ユーザ: sorcerer 日付: Thu Aug 02 19:10:45 2012 +0400 ファイル: mercurial/parsers.c 説明: revlog: don't try to partialmatch strings those length > 40 _partialmatch() does prefix matching against nodes. String passed to _partialmetch() actualy may be any string, not prefix only. For example, "e410be8603932e46a51298748a4b874739037fad or 300" is a good argument for _partialmatch(). When _partialmatch() searches using radix tree, index_partialmatch() C function shouldn't try to match too long strings.
あったよ、おい!
簡易テストで試してみても、このリビジョンを契機に、動作が修正されているのが確認出来たので、間違いなさそう。
ただし、この修正、どうやらテスト追加とか全然やってなさそう (前後のリビジョンでも実施してない) なので、デグレード防止のテストを追加した方が良さそうな感じ。
なお、"[http://mercurial-users.jp/manual/hg.1.html#bisect:title=hg bisect]
" を使って、障害要因リビジョンの絞込みをしてみると……
チェンジセット: 16665:e410be860393 ユーザ: Bryan O'Sullivan日付: Sat May 12 10:55:08 2012 +0200 ファイル: mercurial/parsers.c mercurial/revlog.py 説明: revlog: speed up prefix matching against nodes The radix tree already contains all the information we need to determine whether a short string is an unambiguous node identifier. We now make use of this information. In a kernel tree, this improves the performance of "hg log -q -r24bf01de75" from 0.27 seconds to 0.06.
この修正が原因だった模様。