Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 15682] ファイルの概要

このコミットは、Go言語の標準ライブラリである net パッケージ内のUNIXソケットテストに関するものです。具体的には、UNIXドメインソケットを使用するテストが並行して実行される際に発生する可能性のあるファイル名の衝突問題を解決し、並行テストを可能にすることを目的としています。

コミット

commit 2f0a970bde799031fcbe756644fa8c7ed5fb4ef1
Author: Albert Strasheim <fullung@gmail.com>
Date:   Mon Mar 11 13:24:52 2013 -0400

    net: allow concurrent UNIX socket tests if TMPDIR is unique.
    
    Only clever enough to allow concurrent stress testing.
    
    R=mikioh.mikioh, rsc
    CC=golang-dev
    https://golang.org/cl/7703044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/2f0a970bde799031fcbe756644fa8c7ed5fb4ef1

元コミット内容

net: allow concurrent UNIX socket tests if TMPDIR is unique.

Only clever enough to allow concurrent stress testing.

R=mikioh.mikioh, rsc CC=golang-dev https://golang.org/cl/7703044

変更の背景

Go言語のテストフレームワークは、テストを並行して実行する機能(go test -parallel Nなど)を提供しています。しかし、UNIXドメインソケットはファイルシステム上のパスを介して通信を行うため、テスト中に一時的なソケットファイルを作成します。複数のテストが同時に実行され、同じ一時ディレクトリ(TMPDIR環境変数で指定されることが多い)に同じ名前のソケットファイルを作成しようとすると、ファイル名の衝突が発生し、テストが失敗したり、不安定になったりする問題がありました。

このコミットの背景には、特にストレステストのような並行性の高いシナリオにおいて、UNIXソケット関連のテストの信頼性と安定性を向上させる必要があったことが挙げられます。コミットメッセージにある「Only clever enough to allow concurrent stress testing.」という記述は、この変更が特に並行ストレステストの文脈で有効であることを示唆しています。

前提知識の解説

UNIXドメインソケット (UNIX Domain Sockets)

UNIXドメインソケットは、同じホストマシン上で動作するプロセス間通信(IPC: Inter-Process Communication)の一種です。TCP/IPソケットがネットワークを介した通信に使用されるのに対し、UNIXドメインソケットはファイルシステム上の特殊なファイル(ソケットファイル)を介して通信を行います。

特徴:

  • 高速性: ネットワークスタックを介さないため、TCP/IPソケットよりも高速な通信が可能です。
  • セキュリティ: ファイルシステム上のパーミッションによってアクセス制御が行えるため、同じシステム上のプロセス間での安全な通信に適しています。
  • アドレス: ファイルパス(例: /tmp/mysocket)をアドレスとして使用します。このパスはファイルシステム上に存在し、ソケットが閉じられると通常は削除されます。

TMPDIR 環境変数と一時ファイル

TMPDIRは、一時ファイルを作成する際に使用されるディレクトリを指定するための環境変数です。多くのプログラムやライブラリは、一時ファイルを生成する際にこの環境変数の値を利用します。もしTMPDIRが設定されていない場合、システムはデフォルトの一時ディレクトリ(例: Linuxでは/tmp/var/tmp)を使用します。

os.Getpid()

Go言語の os パッケージにある Getpid() 関数は、現在のプロセスのプロセスID(PID)を返します。PIDは、オペレーティングシステムが各実行中のプロセスに割り当てる一意の数値識別子です。

並行テストとファイル名の衝突

Goのテストフレームワークは、デフォルトでテストを並行して実行しようとします。これは、テストスイート全体の実行時間を短縮するのに役立ちます。しかし、複数のテストが同時に実行され、それぞれが同じ名前の一時ファイル(この場合はUNIXソケットファイル)を作成しようとすると、ファイル名の衝突が発生します。これは、一方のテストが作成したファイルが他方のテストによって上書きされたり、アクセス拒否されたりする原因となり、テストの失敗や不安定な動作につながります。

技術的詳細

このコミットの主要な技術的解決策は、UNIXドメインソケットのテストで使用される一時ファイル名に、現在のプロセスのPID(プロセスID)を含めることです。これにより、同じテストスイート内で複数のテストが並行して実行されても、それぞれが異なるPIDを持つため、ソケットファイルのパスが一意になり、ファイル名の衝突を避けることができます。

具体的には、src/pkg/net/server_test.go ファイルに tempfile という新しいヘルパー関数が導入されました。この関数は、与えられたファイル名に現在のプロセスのPIDを付加した文字列を返します。

func tempfile(filename string) string {
	// use /tmp in case it is prohibited to create
	// UNIX sockets in TMPDIR
	return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
}

この関数は、UNIXソケットのテストケースでソケットファイルパスを生成する際に使用されます。例えば、以前は /tmp/gotest1.net のように固定されていたパスが、tempfile("gotest1.net") を通じて /tmp/gotest1.net.<PID> のような形式に動的に生成されるようになります。

また、コメントにある「use /tmp in case it is prohibited to create UNIX sockets in TMPDIR」という記述は、一部のシステム設定やセキュリティポリシーにより、TMPDIRで指定されたディレクトリ(例えば、TMPDIR/var/tmpのような永続的な一時ディレクトリを指している場合)でUNIXソケットの作成が許可されていない可能性があることを考慮し、より一般的な/tmpディレクトリを明示的に使用していることを示しています。これは、テストの移植性と信頼性を高めるための配慮です。

strconv.Itoa(os.Getpid()) は、os.Getpid() が返す整数型のPIDを文字列に変換するために使用されます。

コアとなるコードの変更箇所

変更は src/pkg/net/server_test.go ファイルに集中しています。

  1. strconv パッケージのインポートが追加されました。
  2. tempfile ヘルパー関数が追加されました。
  3. streamConnServerTests, seqpacketConnServerTests, datagramPacketConnServerTests の各テスト構造体定義内で、UNIXドメインソケットのパス指定が tempfile 関数を使用するように変更されました。
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,6 +9,7 @@ import (
 	"io"
 	"os"
 	"runtime"
+	"strconv"
 	"testing"
 	"time"
 )
@@ -41,6 +42,12 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
 	return false
 }
 
+func tempfile(filename string) string {
+	// use /tmp in case it is prohibited to create
+	// UNIX sockets in TMPDIR
+	return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
+}
+
 var streamConnServerTests = []struct {
 	snet    string // server side
 	saddr   string
@@ -86,7 +93,7 @@ var streamConnServerTests = []struct {
 
 	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+	{snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
 	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
 }
 
@@ -135,7 +142,7 @@ var seqpacketConnServerTests = []struct {
 	caddr string // client address
 	empty bool   // test with empty data
 }{
-	{net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+	{net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
 	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
 }
 
@@ -294,10 +301,10 @@ var datagramPacketConnServerTests = []struct {
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
 
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true},
 
 	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
 }

コアとなるコードの解説

このコミットの核心は、tempfile 関数と、それがUNIXソケットテストのファイルパス生成にどのように統合されたかです。

tempfile 関数は、UNIXソケットがファイルシステム上に作成される際に、そのファイル名が一意になるようにするためのシンプルなメカニズムを提供します。os.Getpid() を利用することで、各テストプロセスが異なるソケットファイル名を使用するようになり、並行実行時のファイル名衝突が解消されます。

例えば、streamConnServerTests の最初のUNIXソケットテストケースでは、サーバー側のアドレス (saddr) とクライアント側のアドレス (caddr) が以下のように変更されました。

変更前: {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"}

変更後: {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")}

これにより、もしPIDが 12345 のプロセスがこのテストを実行した場合、ソケットファイルは /tmp/gotest1.net.12345/tmp/gotest1.net.local.12345 のようなパスで作成されます。別のPIDを持つプロセスが同時に同じテストを実行しても、そのプロセスは自身のPID(例: 67890)を使用して /tmp/gotest1.net.67890 のような異なるパスでソケットファイルを作成するため、衝突は発生しません。

この変更は、GoのテストスイートがUNIXドメインソケットを使用するテストをより堅牢かつ効率的に実行できるようにするための重要な改善です。特に、CI/CD環境や開発者のローカルマシンで並行テストが頻繁に実行される場合に、テストの信頼性を大幅に向上させます。

関連リンク

参考にした情報源リンク

  • UNIXドメインソケットに関する一般的な情報 (例: Wikipedia, 各種OSのドキュメント)
  • Go言語のテストに関するドキュメント (例: go test コマンドのヘルプ、Goブログのテストに関する記事)
  • Go言語のソースコード(特に src/pkg/net ディレクトリ内のテストファイル)
  • TMPDIR 環境変数に関する一般的な情報 (例: Linux manページ)
  • os.Getpid() の使用例に関する情報# [インデックス 15682] ファイルの概要

このコミットは、Go言語の標準ライブラリである net パッケージ内のUNIXソケットテストに関するものです。具体的には、UNIXドメインソケットを使用するテストが並行して実行される際に発生する可能性のあるファイル名の衝突問題を解決し、並行テストを可能にすることを目的としています。

コミット

commit 2f0a970bde799031fcbe756644fa8c7ed5fb4ef1
Author: Albert Strasheim <fullung@gmail.com>
Date:   Mon Mar 11 13:24:52 2013 -0400

    net: allow concurrent UNIX socket tests if TMPDIR is unique.
    
    Only clever enough to allow concurrent stress testing.
    
    R=mikioh.mikioh, rsc
    CC=golang-dev
    https://golang.org/cl/7703044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/2f0a970bde799031fcbe756644fa8c7ed5fb4ef1

元コミット内容

net: allow concurrent UNIX socket tests if TMPDIR is unique.

Only clever enough to allow concurrent stress testing.

R=mikioh.mikioh, rsc CC=golang-dev https://golang.org/cl/7703044

変更の背景

Go言語のテストフレームワークは、テストを並行して実行する機能(go test -parallel Nなど)を提供しています。しかし、UNIXドメインソケットはファイルシステム上のパスを介して通信を行うため、テスト中に一時的なソケットファイルを作成します。複数のテストが同時に実行され、同じ一時ディレクトリ(TMPDIR環境変数で指定されることが多い)に同じ名前のソケットファイルを作成しようとすると、ファイル名の衝突が発生し、テストが失敗したり、不安定になったりする問題がありました。

このコミットの背景には、特にストレステストのような並行性の高いシナリオにおいて、UNIXソケット関連のテストの信頼性と安定性を向上させる必要があったことが挙げられます。コミットメッセージにある「Only clever enough to allow concurrent stress testing.」という記述は、この変更が特に並行ストレステストの文脈で有効であることを示唆しています。

前提知識の解説

UNIXドメインソケット (UNIX Domain Sockets)

UNIXドメインソケットは、同じホストマシン上で動作するプロセス間通信(IPC: Inter-Process Communication)の一種です。TCP/IPソケットがネットワークを介した通信に使用されるのに対し、UNIXドメインソケットはファイルシステム上の特殊なファイル(ソケットファイル)を介して通信を行います。

特徴:

  • 高速性: ネットワークスタックを介さないため、TCP/IPソケットよりも高速な通信が可能です。
  • セキュリティ: ファイルシステム上のパーミッションによってアクセス制御が行えるため、同じシステム上のプロセス間での安全な通信に適しています。
  • アドレス: ファイルパス(例: /tmp/mysocket)をアドレスとして使用します。このパスはファイルシステム上に存在し、ソケットが閉じられると通常は削除されます。

TMPDIR 環境変数と一時ファイル

TMPDIRは、一時ファイルを作成する際に使用されるディレクトリを指定するための環境変数です。多くのプログラムやライブラリは、一時ファイルを生成する際にこの環境変数の値を利用します。もしTMPDIRが設定されていない場合、システムはデフォルトの一時ディレクトリ(例: Linuxでは/tmp/var/tmp)を使用します。

os.Getpid()

Go言語の os パッケージにある Getpid() 関数は、現在のプロセスのプロセスID(PID)を返します。PIDは、オペレーティングシステムが各実行中のプロセスに割り当てる一意の数値識別子です。

並行テストとファイル名の衝突

Goのテストフレームワークは、デフォルトでテストを並行して実行しようとします。これは、テストスイート全体の実行時間を短縮するのに役立ちます。しかし、複数のテストが同時に実行され、それぞれが同じ名前の一時ファイル(この場合はUNIXソケットファイル)を作成しようとすると、ファイル名の衝突が発生します。これは、一方のテストが作成したファイルが他方のテストによって上書きされたり、アクセス拒否されたりする原因となり、テストの失敗や不安定な動作につながります。

技術的詳細

このコミットの主要な技術的解決策は、UNIXドメインソケットのテストで使用される一時ファイル名に、現在のプロセスのPID(プロセスID)を含めることです。これにより、同じテストスイート内で複数のテストが並行して実行されても、それぞれが異なるPIDを持つため、ソケットファイルのパスが一意になり、ファイル名の衝突を避けることができます。

具体的には、src/pkg/net/server_test.go ファイルに tempfile という新しいヘルパー関数が導入されました。この関数は、与えられたファイル名に現在のプロセスのPIDを付加した文字列を返します。

func tempfile(filename string) string {
	// use /tmp in case it is prohibited to create
	// UNIX sockets in TMPDIR
	return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
}

この関数は、UNIXソケットのテストケースでソケットファイルパスを生成する際に使用されます。例えば、以前は /tmp/gotest1.net のように固定されていたパスが、tempfile("gotest1.net") を通じて /tmp/gotest1.net.<PID> のような形式に動的に生成されるようになります。

また、コメントにある「use /tmp in case it is prohibited to create UNIX sockets in TMPDIR」という記述は、一部のシステム設定やセキュリティポリシーにより、TMPDIRで指定されたディレクトリ(例えば、TMPDIR/var/tmpのような永続的な一時ディレクトリを指している場合)でUNIXソケットの作成が許可されていない可能性があることを考慮し、より一般的な/tmpディレクトリを明示的に使用していることを示しています。これは、テストの移植性と信頼性を高めるための配慮です。

strconv.Itoa(os.Getpid()) は、os.Getpid() が返す整数型のPIDを文字列に変換するために使用されます。

コアとなるコードの変更箇所

変更は src/pkg/net/server_test.go ファイルに集中しています。

  1. strconv パッケージのインポートが追加されました。
  2. tempfile ヘルパー関数が追加されました。
  3. streamConnServerTests, seqpacketConnServerTests, datagramPacketConnServerTests の各テスト構造体定義内で、UNIXドメインソケットのパス指定が tempfile 関数を使用するように変更されました。
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,6 +9,7 @@ import (
 	"io"
 	"os"
 	"runtime"
+	"strconv"
 	"testing"
 	"time"
 )
@@ -41,6 +42,12 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
 	return false
 }
 
+func tempfile(filename string) string {
+	// use /tmp in case it is prohibited to create
+	// UNIX sockets in TMPDIR
+	return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
+}
+
 var streamConnServerTests = []struct {
 	snet    string // server side
 	saddr   string
@@ -86,7 +93,7 @@ var streamConnServerTests = []struct {
 
 	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+	{snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
 	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
 }
 
@@ -135,7 +142,7 @@ var seqpacketConnServerTests = []struct {
 	caddr string // client address
 	empty bool   // test with empty data
 }{
-	{net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+	{net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
 	{net: "unixpacket", saddr: "@gotest4/net", cnet: "unix", caddr: "@gotest4/net.local"},
 }
 
@@ -294,10 +301,10 @@ var datagramPacketConnServerTests = []struct {
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
 
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
-	{snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
+	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true},
 
 	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
 }

コアとなるコードの解説

このコミットの核心は、tempfile 関数と、それがUNIXソケットテストのファイルパス生成にどのように統合されたかです。

tempfile 関数は、UNIXソケットがファイルシステム上に作成される際に、そのファイル名が一意になるようにするためのシンプルなメカニズムを提供します。os.Getpid() を利用することで、各テストプロセスが異なるソケットファイル名を使用するようになり、並行実行時のファイル名衝突が解消されます。

例えば、streamConnServerTests の最初のUNIXソケットテストケースでは、サーバー側のアドレス (saddr) とクライアント側のアドレス (caddr) が以下のように変更されました。

変更前: {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"}

変更後: {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")}

これにより、もしPIDが 12345 のプロセスがこのテストを実行した場合、ソケットファイルは /tmp/gotest1.net.12345/tmp/gotest1.net.local.12345 のようなパスで作成されます。別のPIDを持つプロセスが同時に同じテストを実行しても、そのプロセスは自身のPID(例: 67890)を使用して /tmp/gotest1.net.67890 のような異なるパスでソケットファイルを作成するため、衝突は発生しません。

この変更は、GoのテストスイートがUNIXドメインソケットを使用するテストをより堅牢かつ効率的に実行できるようにするための重要な改善です。特に、CI/CD環境や開発者のローカルマシンで並行テストが頻繁に実行される場合に、テストの信頼性を大幅に向上させます。

関連リンク

参考にした情報源リンク

  • UNIXドメインソケットに関する一般的な情報 (例: Wikipedia, 各種OSのドキュメント)
  • Go言語のテストに関するドキュメント (例: go test コマンドのヘルプ、Goブログのテストに関する記事)
  • Go言語のソースコード(特に src/pkg/net ディレクトリ内のテストファイル)
  • TMPDIR 環境変数に関する一般的な情報 (例: Linux manページ)
  • os.Getpid() の使用例に関する情報