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

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

コミット

このコミットは、Windows環境におけるGoのsyscallパッケージのErrno型に対してnet.Errorインターフェイスを実装するための修正です。具体的には、Temporary()メソッドとTimeout()メソッドを追加することで、ネットワークエラーハンドリングの一貫性を確保し、ビルドエラーを修正しています。

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

https://github.com/golang/go/commit/6677d2954eaa4d2ff89a5c962168440825b38611

元コミット内容

commit 6677d2954eaa4d2ff89a5c962168440825b38611
Author: Russ Cox <rsc@golang.org>
Date:   Mon Nov 14 01:21:38 2011 -0500

    syscall: make windows Errno implement net.Error (fix build)
    
    TBR=brainman
    CC=golang-dev
    https://golang.org/cl/5371086

変更されたファイル:

  • src/pkg/syscall/dll_windows.go: 8行の追加

追加されたメソッド:

func (e Errno) Temporary() bool {
	return e == EINTR || e == EMFILE || e.Timeout()
}

func (e Errno) Timeout() bool {
	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}

変更の背景

2011年当時のGo言語では、ネットワークプログラミングにおけるエラーハンドリングの統一性が重要な課題でした。特に、異なるオペレーティングシステム間でのエラー処理の一貫性を保つことが求められていました。

このコミットの背景には以下のような状況がありました:

  1. クロスプラットフォーム対応の必要性: Go言語はクロスプラットフォーム対応を重視しており、UnixライクシステムとWindows間でのAPI互換性が重要でした。

  2. ビルドエラーの発生: net.Errorインターフェイスを期待するコードがWindows環境で正しく動作しない状況が発生していました。

  3. ネットワークエラーハンドリングの標準化: 一時的なエラー(リトライ可能)とタイムアウトエラーを区別することで、より堅牢なネットワークアプリケーションの開発が可能になります。

前提知識の解説

net.Errorインターフェイス

net.Errorは、Goの標準ライブラリにおけるネットワークエラーハンドリングの基盤となるインターフェイスです:

type Error interface {
    error
    Timeout() bool   // エラーがタイムアウトによるものか?
    Temporary() bool // エラーが一時的なものか?
}

このインターフェイスにより、クライアントコードは以下のような処理が可能になります:

if netErr, ok := err.(net.Error); ok {
    if netErr.Temporary() {
        // 一時的なエラー - リトライ可能
        continue
    }
    if netErr.Timeout() {
        // タイムアウトエラー - 適切な処理
        return
    }
}

syscallパッケージのErrno型

syscallパッケージのErrno型は、オペレーティングシステムのシステムコールから返されるエラーコードを表現します。Unix系システムでは標準的なerrno値を、WindowsではWindows APIのエラーコードをGo風にラップしています。

Windows特有のエラーコード

実装されたメソッドで使用されているエラーコードの意味:

  • EINTR (Interrupted system call): システムコールが割り込みによって中断された
  • EMFILE (Too many open files): プロセスが開けるファイル数の上限に達した
  • EAGAIN (Resource temporarily unavailable): リソースが一時的に利用できない
  • EWOULDBLOCK (Operation would block): ノンブロッキング操作がブロックする状況
  • ETIMEDOUT (Connection timed out): 接続がタイムアウトした

技術的詳細

Temporary()メソッドの実装

func (e Errno) Temporary() bool {
	return e == EINTR || e == EMFILE || e.Timeout()
}

このメソッドは以下の条件でtrueを返します:

  1. EINTR: システムコールが割り込まれた場合。これは通常リトライ可能な状況です。
  2. EMFILE: ファイルディスクリプタの上限に達した場合。アプリケーションが適切にリソース管理を行えばリトライ可能です。
  3. Timeout()がtrue: タイムアウトエラーも一般的に一時的なものとして扱われます。

Timeout()メソッドの実装

func (e Errno) Timeout() bool {
	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}

このメソッドは以下のエラーコードでtrueを返します:

  1. EAGAIN: リソースが一時的に利用できない状態
  2. EWOULDBLOCK: ノンブロッキング操作がブロックする状況
  3. ETIMEDOUT: 明示的なタイムアウト

設計上の考慮点

  1. 相互依存関係: Temporary()Timeout()を呼び出す設計により、タイムアウトエラーは常に一時的なエラーとしても扱われます。

  2. Windows固有の対応: Windows環境でのエラーコードをUnix風のerrno値にマッピングし、クロスプラットフォーム互換性を実現しています。

  3. 最小限の実装: 必要最小限のエラーコードのみを対象とし、シンプルな実装を保っています。

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

変更はsrc/pkg/syscall/dll_windows.goファイルの1箇所のみです:

@@ -15,6 +15,14 @@ func (e Errno) Error() string {
 	return errstr(e)
 }
 
+func (e Errno) Temporary() bool {
+	return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
 // DLLError describes reasons for DLL load failures.
 type DLLError struct {
 	Err     error

コアとなるコードの解説

メソッドの配置

新しいメソッドは既存のError()メソッドの直後、DLLError構造体の定義の前に配置されています。これにより、Errno型に関連するすべてのメソッドが論理的にグループ化されています。

エラー分類の論理

実装されたロジックは以下の階層構造を持ちます:

Temporary() = EINTR || EMFILE || Timeout()
Timeout()   = EAGAIN || EWOULDBLOCK || ETIMEDOUT

この設計により:

  • すべてのタイムアウトエラーは一時的エラーとしても扱われる
  • システム割り込み(EINTR)とリソース不足(EMFILE)も一時的エラーとして扱われる
  • 明確な分類により、適切なエラーハンドリング戦略を選択可能

Windows環境での意義

Windows環境において、これらのPOSIX風エラーコードを使用することで:

  1. プラットフォーム抽象化: Unix系とWindows系で統一されたエラーハンドリング
  2. 既存コードとの互換性: net.Errorインターフェイスを期待するコードとの互換性
  3. 開発者体験の向上: プラットフォーム固有のエラーハンドリングコードの削減

関連リンク

参考にした情報源リンク