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

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

このコミットは、Go言語の公式ダッシュボードのビルドシステムに、データ競合検出機能(-raceフラグ)をサポートするための変更を導入します。これにより、ビルダが-raceフラグを含むビルドキーを受け取った際に、データ競合検出を有効にしたビルドコマンド(race.batまたはrace.bash)を呼び出すようになります。これは、darwin-amd64linux-amd64windows-amd64といった特定のアーキテクチャのビルダが、データ競合検出あり/なしの両方のビルドを連続して実行できるようにするために重要です。

コミット

commit 26312afd7b7f92201afa5f10e1c54803f27dbcf5
Author: Dave Cheney <dave@cheney.net>
Date:   Tue Apr 9 12:48:04 2013 +1000

    misc/dashboard/builder: add -race builder support
    
    If the build key contains -race, the builder will invoke to the race.{bat,bash} build command. This allows {darwin,linux,windows}-amd64 builders to do race and non race builds in sequence.
    
    R=adg, dvyukov, fullung
    CC=golang-dev
    https://golang.org/cl/8266046

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

https://github.com/golang/go/commit/26312afd7b7f92201afa5f10e1c54803f27dbcf5

元コミット内容

misc/dashboard/builder: add -race builder support

If the build key contains -race, the builder will invoke to the race.{bat,bash} build command. This allows {darwin,linux,windows}-amd64 builders to do race and non race builds in sequence.

R=adg, dvyukov, fullung
CC=golang-dev
https://golang.org/cl/8266046

変更の背景

Go言語は並行処理を強力にサポートしており、ゴルーチンとチャネルを用いた並行プログラミングが容易です。しかし、並行処理はデータ競合(data race)という潜在的なバグを引き起こす可能性があります。データ競合とは、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みである場合に発生する状況です。これは予測不能な動作やクラッシュの原因となり、デバッグが非常に困難です。

Go 1.1から導入されたデータ競合検出器(Race Detector)は、このようなデータ競合をコンパイル時または実行時に検出するための強力なツールです。この検出器は、go build -racego run -racego test -raceなどのコマンドで-raceフラグを付けてビルド・実行することで有効になります。

このコミットの背景には、Go言語の公式ビルドダッシュボード(Go Dashboard)が、Goプロジェクトの継続的インテグレーション(CI)と品質保証において重要な役割を担っていることがあります。ダッシュボードは、様々なプラットフォームや構成でGoのコードベースをビルドし、テストを実行し、その結果を報告します。データ競合は通常のテストでは見過ごされがちであるため、ダッシュボードのビルドプロセスにデータ競合検出を組み込むことは、Go言語自体の安定性と品質を向上させる上で不可欠でした。

この変更により、ダッシュボードは-raceフラグを伴うビルドを自動的に実行できるようになり、Go言語のコア開発チームがデータ競合の発生を早期に発見し、修正することが可能になります。特に、darwin-amd64linux-amd64windows-amd64といった主要な64ビットアーキテクチャでデータ競合検出ビルドをサポートすることは、これらのプラットフォームでのGoの堅牢性を保証するために重要です。

前提知識の解説

Go言語の並行処理とデータ競合

Go言語は、軽量なスレッドである「ゴルーチン(goroutine)」と、ゴルーチン間の安全な通信を可能にする「チャネル(channel)」を言語レベルでサポートしています。これにより、並行処理を比較的容易に記述できます。

しかし、並行処理には「データ競合」という問題がつきものです。データ競合は以下の3つの条件がすべて満たされたときに発生します。

  1. 複数のゴルーチンが同時に同じメモリ位置にアクセスする。
  2. 少なくとも1つのアクセスが書き込み操作である。
  3. それらのアクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。

データ競合が発生すると、プログラムの動作が非決定論的になり、結果が予測できなくなったり、クラッシュしたりする可能性があります。これは非常にデバッグが困難な種類のバグです。

Go Race Detector

Go Race Detectorは、Go 1.1で導入されたデータ競合検出ツールです。これは実行時インストルメンテーション(runtime instrumentation)に基づいており、プログラムの実行中にメモリアクセスを監視し、データ競合のパターンを検出します。

Race Detectorを有効にするには、go buildgo rungo testなどのコマンドに-raceフラグを追加します。 例: go build -race myprogram.go

-raceフラグを付けてビルドされたプログラムは、通常のプログラムよりも実行速度が遅くなり、メモリ使用量も増えますが、データ競合が発生した場合には詳細なレポートを出力してくれます。このレポートには、競合が発生したメモリ位置、関連するゴルーチンのスタックトレースなどが含まれ、デバッグに役立ちます。

Go Dashboard (Go Build Dashboard)

Go Dashboardは、Go言語プロジェクトの公式な継続的インテグレーション(CI)システムです。世界中の様々なハードウェア、オペレーティングシステム、Goのバージョン(開発版、安定版など)の組み合わせでGoのコードベースをビルドし、テストを実行します。その結果はウェブインターフェースで公開され、Goのコードベースが様々な環境で正しく動作するかどうかを常に監視しています。

ダッシュボードは、Goの変更がコミットされるたびに自動的にビルドとテストを実行し、問題があれば開発者にフィードバックします。これにより、Go言語の品質と互換性が維持されています。

ビルドキーとビルドコマンド

Go Dashboardの文脈では、「ビルドキー」は特定のビルド構成(例: linux-amd64-racewindows-amd64)を識別する文字列を指します。このビルドキーに基づいて、ビルダは適切なビルドコマンド(例: all.bashrace.bashall.batrace.bat)を呼び出します。

  • all.bash / all.bat: 通常のビルドとテストを実行するためのスクリプト。
  • race.bash / race.bat: データ競合検出を有効にしたビルドとテストを実行するためのスクリプト。

これらのスクリプトは、Goのソースツリー内のsrc/all.bashsrc/race.bashなどに存在し、Goのビルドシステムを駆動します。

技術的詳細

このコミットは、Go Dashboardのビルダが、ビルドキーに-raceが含まれている場合に、通常のビルドコマンド(all.bat/all.bash)ではなく、データ競合検出用のビルドコマンド(race.bat/race.bash)を動的に選択して実行するように変更します。

変更の対象はmisc/dashboard/builder/main.goファイルです。このファイルは、Go Dashboardのビルダのロジックを実装しています。

具体的な変更点は以下の通りです。

  1. raceCmd変数の追加: raceCmdという新しいグローバル変数が定義され、その値は"race" + suffixとなります。ここでsuffixはオペレーティングシステムに応じて.bat(Windows)または.bash(Unix系)になります。これにより、race.batまたはrace.bashというコマンド名が動的に生成されます。

  2. Builder構造体へのbuildCmd()メソッドの追加: Builder構造体にbuildCmd()という新しいメソッドが追加されました。このメソッドの役割は、現在のビルダのname(ビルドキー)をチェックし、-raceという文字列が含まれているかどうかを判断することです。

    • もしb.name-raceが含まれていれば、raceCmd(つまりrace.batまたはrace.bash)を返します。
    • 含まれていなければ、既存のデフォルトのビルドコマンド(*buildCmd)を返します。
  3. buildHash()関数でのbuildCmd()メソッドの利用: buildHash()関数は、特定のコミットハッシュに対してビルドを実行する主要なロジックを含んでいます。この関数内で、以前は直接*buildCmdというグローバル変数を使用してビルドコマンドを決定していましたが、この変更によりb.buildCmd()メソッドを呼び出すように修正されました。

    変更前: cmd := *buildCmd 変更後: cmd := b.buildCmd()

この修正により、ビルダは自身の名前(ビルドキー)に基づいて、データ競合検出を有効にするかどうかを自動的に判断し、適切なビルドスクリプトを実行できるようになります。これにより、Go Dashboardは、通常のビルドとデータ競合検出ビルドの両方を、同じビルダインスタンスで、または異なるビルダインスタンスで、柔軟に実行できるようになります。

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

misc/dashboard/builder/main.go

--- a/misc/dashboard/builder/main.go
+++ b/misc/dashboard/builder/main.go
@@ -64,6 +64,7 @@ var (
  	binaryTagRe = regexp.MustCompile(`^(release\\.r|weekly\\.)[0-9\\-.]+`)\n \treleaseRe   = regexp.MustCompile(`^release\\.r[0-9\\-.]+`)\n \tallCmd      = "all" + suffix\n+\traceCmd     = "race" + suffix\n \tcleanCmd    = "clean" + suffix\n \tsuffix      = defaultSuffix()\n )\n@@ -211,6 +212,16 @@ func NewBuilder(goroot *Repo, name string) (*Builder, error) {\n  	return b, nil\n  }\n  \n+// buildCmd returns the build command to invoke.\n+// Builders which contain the string \'-race\' in their\n+// name will override *buildCmd and return raceCmd.\n+func (b *Builder) buildCmd() string {\n+\tif strings.Contains(b.name, "-race") {\n+\t\treturn raceCmd\n+\t}\n+\treturn *buildCmd\n+}\n+\n  // build checks for a new commit for this builder\n  // and builds it if one is found.\n  // It returns true if a build was attempted.\n@@ -262,7 +273,7 @@ func (b *Builder) buildHash(hash string) error {\n  	defer f.Close()\n  	w := io.MultiWriter(f, &buildlog)\n  \n-\tcmd := *buildCmd\n+\tcmd := b.buildCmd()\n  \tif !filepath.IsAbs(cmd) {\n  \t\tcmd = filepath.Join(srcDir, cmd)\n  \t}\

コアとなるコードの解説

  1. raceCmdの追加:

    +	raceCmd     = "race" + suffix
    

    この行は、データ競合検出ビルド用のコマンド名(例: race.bashまたはrace.bat)を定義する新しいグローバル変数raceCmdを導入しています。suffixは、実行環境(Windowsかそれ以外か)に応じて.batまたは.bashに解決されます。

  2. Builder.buildCmd()メソッドの追加:

    +// buildCmd returns the build command to invoke.
    +// Builders which contain the string '-race' in their
    +// name will override *buildCmd and return raceCmd.
    +func (b *Builder) buildCmd() string {
    +	if strings.Contains(b.name, "-race") {
    +		return raceCmd
    +	}
    +	return *buildCmd
    +}
    

    これはBuilder構造体に追加された新しいメソッドです。

    • b.nameは、このBuilderインスタンスが担当するビルド構成の名前(例: linux-amd64-racewindows-amd64など)です。
    • strings.Contains(b.name, "-race")は、ビルダの名前に文字列-raceが含まれているかどうかをチェックします。
    • もし含まれていれば、このビルダはデータ競合検出ビルドを行うべきであると判断し、raceCmdrace.bashまたはrace.bat)を返します。
    • 含まれていなければ、通常のビルドコマンドである*buildCmdall.bashまたはall.bat)を返します。 このメソッドにより、ビルドコマンドの選択ロジックがカプセル化され、ビルダの名前から動的に適切なコマンドが決定されるようになります。
  3. buildHash()関数でのbuildCmd()の呼び出し:

    -	cmd := *buildCmd
    +	cmd := b.buildCmd()
    

    buildHash関数は、特定のコミットハッシュに対してビルドを実行する際に、実際に呼び出すコマンドを決定します。この変更により、以前は直接グローバル変数*buildCmdを参照していた箇所が、b.buildCmd()メソッドの呼び出しに置き換えられました。 これにより、buildHash関数は、ビルダの構成(名前)に基づいて、データ競合検出ビルドを行うかどうかの判断をbuildCmd()メソッドに委ねる形になります。この修正が、-raceビルドサポートの核心部分です。

これらの変更により、Go Dashboardのビルダは、ビルドキーに-raceが含まれる場合に自動的にデータ競合検出ビルドを実行できるようになり、Go言語の品質保証プロセスが強化されました。

関連リンク

参考にした情報源リンク