[インデックス 14618] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるTestDialTimeoutFDLeak
テストの信頼性に関する問題を修正するものです。具体的には、ファイルディスクリプタのリークを検出するためのテストが、特定の条件下で不安定になる事象(Issue 4384)に対応しています。テスト内のmaxGoodConnect
という変数の値を調整することで、テストの安定性を向上させています。
コミット
- コミットハッシュ:
4766a35e7c4c00dd060313080f6d85e32c9aa970
- Author: Dave Cheney dave@cheney.net
- Date: Wed Dec 12 07:25:07 2012 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4766a35e7c4c00dd060313080f6d85e32c9aa970
元コミット内容
net: TestDialTimeoutFDLeak failure
Fixes #4384.
Implments the suggestion by rsc in comment 15, http://code.google.com/p/go/issues/detail?id=4384#c15
An alternate suggestion would be to temporarily set GOMAXPROCS to 1 during this test.
R=fullung, rsc
CC=golang-dev
https://golang.org/cl/6923046
変更の背景
このコミットは、Go言語のnet
パッケージに含まれるTestDialTimeoutFDLeak
というテストが、特定の環境や実行条件下で失敗する問題(Issue 4384)を解決するために行われました。TestDialTimeoutFDLeak
は、ネットワーク接続のタイムアウト処理中にファイルディスクリプタ(FD)が適切に閉じられず、リークが発生しないことを検証するための重要なテストです。
しかし、このテストはlistenerBacklog + 5
という動的な値に依存するmaxGoodConnect
という変数の設定が原因で、不安定な挙動を示していました。listenerBacklog
はシステムや環境によって異なる可能性があり、その結果、テストが期待通りの数の接続を確立できず、誤ってFDリークを報告したり、単にテストが失敗したりすることがありました。
この不安定性は、Goの標準ライブラリの品質保証において問題となるため、テストの信頼性を向上させる必要がありました。コミットメッセージには、rsc
(Russ Cox)によるコメント15の提案が実装されたと明記されており、これはテストのロバスト性を高めるための具体的な解決策を示唆しています。
前提知識の解説
ファイルディスクリプタ (File Descriptor, FD)
ファイルディスクリプタは、Unix系オペレーティングシステムにおいて、プロセスが開いているファイルやソケットなどのI/Oリソースを識別するために使用される抽象的なハンドルです。プログラムがファイルを開いたり、ネットワーク接続を確立したりするたびに、カーネルは対応するファイルディスクリプタをプロセスに割り当てます。
ファイルディスクリプタリーク (File Descriptor Leak)
ファイルディスクリプタリークとは、プログラムがファイルディスクリプタを使い終わった後に適切に閉じないために、そのFDがシステムに解放されずに残り続ける状態を指します。FDは有限のリソースであり、リークが続くと、最終的にはプロセスが利用可能なFDの最大数(ulimit -n
などで設定される)に達し、「Too many open files (EMFILE)」エラーが発生します。これは、新しいファイルを開いたり、ネットワーク接続を確立したりできなくなることを意味し、アプリケーションのクラッシュやサービス停止につながる可能性があります。
特にネットワークプログラミングでは、多数の接続を扱うため、FDリークは深刻な問題となります。接続が確立されるたびにソケットがFDを消費し、閉じられないソケットが蓄積されると、システムリソースを枯渇させます。
net.Dial
とタイムアウト
Go言語のnet
パッケージは、ネットワークI/Oの基本的な機能を提供します。net.Dial
関数は、指定されたネットワークアドレスへの接続を確立するために使用されます。ネットワーク接続は、様々な理由(例: サーバーが応答しない、ネットワークが混雑している)で時間がかかる場合があるため、タイムアウトを設定することが重要です。タイムアウトは、接続確立に許容される最大時間を指定し、その時間を超えた場合は接続試行を中止します。
TestDialTimeoutFDLeak
テスト
TestDialTimeoutFDLeak
は、net
パッケージの内部テストであり、net.Dial
関数がタイムアウトした場合にファイルディスクリプタがリークしないことを検証します。このテストは、多数の同時接続試行を行い、そのうちの一部がタイムアウトするように設計されています。テストの目的は、タイムアウトによって接続が中断された場合でも、関連するFDが適切に閉じられ、システムリソースが解放されることを確認することです。
技術的詳細
TestDialTimeoutFDLeak
テストは、listenerBacklog
という値を利用して、同時に確立される「良い」接続の数を制御していました。listenerBacklog
は、TCPリスナーがキューに入れることができる保留中の接続の最大数を指します。元のコードでは、maxGoodConnect
という変数がlistenerBacklog + 5
と設定されていました。これは、リスナーのバックログサイズに少し余裕を持たせた数の接続が成功することを期待していました。
しかし、このアプローチには問題がありました。listenerBacklog
の値はオペレーティングシステムやその設定によって異なり、必ずしも予測可能ではありません。例えば、Linuxではnet.core.somaxconn
カーネルパラメータによって制御され、デフォルト値は128や4096など様々です。この変動性のため、listenerBacklog + 5
という計算されたmaxGoodConnect
の値が、テストが実際に成功させられる接続数と一致しないことがありました。
具体的には、テストがmaxGoodConnect
で指定された数よりも少ない「良い」接続しか確立できなかった場合、テストはFDリークが発生したと誤って判断し、失敗していました。これは実際のFDリークではなく、テストのロジックが環境に依存しすぎていたために発生する不安定な失敗でした。
コミットメッセージにある「rsc in comment 15」の提案は、このmaxGoodConnect
の値を固定値にすることで、テストの信頼性を高めるというものでした。これにより、テストは特定の環境設定に左右されず、常に同じ数の成功接続を期待するようになります。
コアとなるコードの変更箇所
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -240,7 +240,8 @@ func TestDialTimeoutFDLeak(t *testing.T) {
err error
}
dials := listenerBacklog + 100
- maxGoodConnect := listenerBacklog + 5 // empirically 131 good ones (of 128). who knows?
+ // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
+ maxGoodConnect := 150
resc := make(chan connErr)
for i := 0; i < dials; i++ {
go func() {
コアとなるコードの解説
変更はsrc/pkg/net/dial_test.go
ファイル内のTestDialTimeoutFDLeak
関数にあります。
元のコードでは、maxGoodConnect
変数が以下のように定義されていました。
maxGoodConnect := listenerBacklog + 5 // empirically 131 good ones (of 128). who knows?
この行は、listenerBacklog
という動的な値に依存してmaxGoodConnect
を計算していました。コメントには「経験的に131の良い接続(128のうち)。誰にもわからない?」とあり、この値が経験的なものであり、その信頼性に疑問があることが示唆されています。
このコミットでは、この行が以下のように変更されました。
// used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
maxGoodConnect := 150
変更のポイントは以下の通りです。
- コメントの追加:
listenerBacklog + 5
が以前使用されていたが、Issue 4384で信頼性がないことが判明した、という説明が追加されました。これは、この変更の背景と理由を明確にしています。 - 固定値への変更:
maxGoodConnect
の値がlistenerBacklog + 5
から150
という固定値に変更されました。これにより、テストはオペレーティングシステムのlistenerBacklog
設定に依存しなくなり、より予測可能で安定した挙動を示すようになります。150
という値は、テストが意図するシナリオ(一部の接続が成功し、一部がタイムアウトする)を確実に再現できる十分な数として選ばれたと考えられます。
この変更により、TestDialTimeoutFDLeak
テストは、環境による変動に左右されずに、ファイルディスクリプタリークの検出という本来の目的をより信頼性高く果たすことができるようになりました。
関連リンク
- Go Issue 4384: https://code.google.com/p/go/issues/detail?id=4384 (元のコミットメッセージに記載されているリンク)
- Go CL 6923046: https://golang.org/cl/6923046 (元のコミットメッセージに記載されているGoの変更リストへのリンク)
参考にした情報源リンク
- j4mcs.dev: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGVn-K89Ymk6ZkI7ebUodmKHQWozM8PRShJX00eN8ZYdHWT1Mh2LWCFyDMYf1FCOseFJH13IjKI5DufJHJDF2U7y9HTUTKTKRjxqJYJbg4gDM_k2Xps5P6YeWWlgr00dZcKotv-1Gu36L-PHsQ=
- google.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG_-fzy7UPj6vodKF5OpXKWd6n7Gp85KsQxzhMiAkUKz3Nw-4Lw0SWrX4rnWAS8pYMgVXtCm3jxGBFecwTfjRLd18KiNKdbQhaDOmyqPt4FJq4bhOnnR2DA8HREa_aUrpwRZ6GibKX9zhk0nwypbyMN
- huizhou92.com: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEuhCglyWRptxN25st7OHxRaWOBBMTYlduCIfV8Rr3zovj3tZCij_kAei3MpaTqd1RP3xc7ObGnNjdh26XaWTp23EOzpMd55hYPBfzGuLLlA1qcCLWt9dzV8lGhce7b5KV38mmskXKEO8M8bQ-UjtuY62R9lKADHPSjZzo1MBED3RBSceMIUEbBfg==