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

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

このコミットは、Go言語の標準ライブラリである database/sql パッケージ内の putConnDBLocked メソッドにおける冗長な条件式を削除し、パフォーマンスを改善するものです。具体的には、データベース接続プールのアイドル接続数を管理するロジックにおいて、既に別の条件で暗黙的に満たされているチェックを削除することで、不要なメソッド呼び出しとそれに伴うオーバーヘッドを削減しています。

コミット

commit c8869e9caf17c0b993b515924b163a6c8286be77
Author: Alberto García Hierro <alberto@garciahierro.com>
Date:   Tue Dec 10 16:10:09 2013 +0400

    database/sql: Remove redundant condition in if
    
    The final condition (db.maxIdleConnsLocked() > db.freeConn.Len()) can
    only be true iff db.maxIdleConnsLocked() is greater than 0, so previously
    checking if it's greater than 0 is a waste, specially when that involves
    a method call which (ATM) can't be inlined and includes a switch.
    
    Dissasembly follows (test for err == nil has been omitted for clarity):
    
    Before:
    43c357: cmp    $0x0,%bl
    43c35a: jne    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>
    43c35c: mov    %rax,(%rsp)
    43c360: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>
    43c365: mov    0x8(%rsp),%rbx
    43c36a: cmp    $0x0,%rbx
    43c36e: jle    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>
    43c370: mov    0x30(%rsp),%rbx
    43c375: mov    %rbx,(%rsp)
    43c379: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>
    43c37e: mov    0x30(%rsp),%rdx
    43c383: mov    0x8(%rsp),%rcx
    43c388: mov    0x28(%rdx),%rbp
    43c38c: mov    0x28(%rbp),%rbx
    43c390: cmp    %rcx,%rbx
    43c393: jge    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>
    43c395: mov    0x28(%rdx),%rbp
    43c399: mov    %rbp,(%rsp)
    43c39d: mov    0x38(%rsp),%rcx
    43c3a2: mov    $0x556c60,%eax
    43c3a7: mov    %rax,0x8(%rsp)\n    43c3ac: mov    %rcx,0x10(%rsp)\n    43c3b1: callq  4db5b0 <container/list.(*List).PushFront>\n    \n    After:\n    43c357: cmp    $0x0,%bl\n    43c35a: jne    43c3b5 <database/sql.(*DB).putConnDBLocked+0x1b5>\n    43c35c: mov    %rax,(%rsp)\n    43c360: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>\n    43c365: mov    0x30(%rsp),%rdx\n    43c36a: mov    0x8(%rsp),%rcx\n    43c36f: mov    0x28(%rdx),%rbp\n    43c373: mov    0x28(%rbp),%rbx\n    43c377: cmp    %rcx,%rbx\n    43c37a: jge    43c3b5 <database/sql.(*DB).putConnDBLocked+0x1b5>\n    43c37c: mov    0x28(%rdx),%rbp\n    43c380: mov    %rbp,(%rsp)\n    43c384: mov    0x38(%rsp),%rcx\n    43c389: mov    $0x556c60,%eax\n    43c38e: mov    %rax,0x8(%rsp)\n    43c393: mov    %rcx,0x10(%rsp)\n    43c398: callq  4db590 <container/list.(*List).PushFront>\n    \n    R=golang-dev, bradfitz, iant\n    CC=golang-dev\n    https://golang.org/cl/14656044

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

https://github.com/golang/go/commit/c8869e9caf17c0b993b515924b163a6c8286be77

元コミット内容

このコミットは、Go言語の database/sql パッケージ内の putConnDBLocked 関数における条件式を簡素化するものです。変更前のコードでは、アイドル状態のデータベース接続をプールに戻す際に、以下の条件をチェックしていました。

else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {

この条件式には db.maxIdleConnsLocked() > 0 という部分が含まれており、これは db.maxIdleConnsLocked() > db.freeConn.Len() という後続の条件が真であるためには、db.maxIdleConnsLocked() が必然的に0より大きい値でなければならないため、冗長でした。

変更の背景

この変更の背景には、Go言語のランタイムとコンパイラの最適化に関する考慮があります。コミットメッセージに明記されているように、db.maxIdleConnsLocked() メソッドの呼び出しは、当時(2013年)のGoコンパイラではインライン化されず、さらに内部で switch ステートメントを含んでいたため、比較的高価な操作でした。

冗長な条件 db.maxIdleConnsLocked() > 0 を削除することで、この高価なメソッド呼び出しを1回減らすことができます。これにより、putConnDBLocked 関数が実行される際のCPUサイクルを節約し、データベース接続の解放およびプールへの返却処理の効率を向上させることが目的です。特に、高負荷なシステムで頻繁にデータベース接続が取得・解放される場合、このような小さな最適化が全体のスループットに寄与する可能性があります。

コミットメッセージに示されているアセンブリコードの比較は、この最適化が実際に生成される機械語レベルで命令数を削減していることを明確に示しています。

前提知識の解説

Go言語の database/sql パッケージ

database/sql パッケージは、Go言語でSQLデータベースを操作するための汎用的なインターフェースを提供します。このパッケージ自体は特定のデータベースドライバーを含まず、データベース固有の機能は外部のドライバーパッケージによって提供されます。主な機能は以下の通りです。

  • sql.DB: データベースへの接続プールを管理する構造体です。複数のゴルーチンから安全に利用できるように設計されており、接続のオープン、クローズ、アイドル接続の管理などを自動的に行います。
  • 接続プール: データベースへの接続はコストの高い操作であるため、database/sql は接続プールを内部に持ち、一度確立した接続を再利用します。これにより、接続の確立・切断のオーバーヘッドを削減し、アプリケーションのパフォーマンスを向上させます。
  • maxIdleConns: アイドル状態(使用されていない)でプールに保持される接続の最大数を設定します。この設定は、接続の再利用効率に直接影響します。
  • freeConn: sql.DB 構造体内部で、現在アイドル状態にある接続を保持するためのリスト(または同様のデータ構造)です。

Goコンパイラの最適化とインライン化

Goコンパイラは、生成されるバイナリのパフォーマンスを向上させるために様々な最適化を行います。その一つが「インライン化(inlining)」です。

  • インライン化: 関数呼び出しのオーバーヘッド(スタックフレームの作成、引数の渡し、戻り値の処理など)を避けるために、呼び出し元のコードに関数本体のコードを直接埋め込む最適化手法です。これにより、実行時のパフォーマンスが向上しますが、バイナリサイズが増加する可能性があります。
  • インライン化の制約: Goコンパイラは、関数のサイズ、複雑さ、再帰の有無など、様々な要因に基づいてインライン化を行うかどうかを決定します。特に、switch ステートメントのような制御フローが複雑な関数は、インライン化されにくい傾向があります。

アセンブリコードの分析

アセンブリコードは、CPUが直接実行する機械語命令を人間が読める形式で表現したものです。このコミットメッセージに含まれるアセンブリコードは、Goプログラムがコンパイルされた後の低レベルな動作を示しています。

  • cmp: 比較命令。2つのオペランドを比較し、フラグレジスタを設定します。
  • jne / jle / jge: 条件分岐命令。フラグレジスタの状態に基づいて、指定されたアドレスにジャンプします。
  • mov: データ転送命令。レジスタやメモリ間でデータを移動します。
  • callq: 関数呼び出し命令。指定されたアドレスの関数を実行し、戻りアドレスをスタックにプッシュします。

アセンブリコードを比較することで、Goのソースコードの変更が、最終的な実行ファイルにどのような影響を与え、命令数がどのように変化したかを正確に把握することができます。

技術的詳細

このコミットの技術的詳細なポイントは、論理的な冗長性の排除と、それがもたらすパフォーマンス上のメリットにあります。

変更前の条件式は以下の通りでした。 err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len()

ここで注目すべきは、db.maxIdleConnsLocked() > 0db.maxIdleConnsLocked() > db.freeConn.Len() の2つの条件です。 もし db.maxIdleConnsLocked() > db.freeConn.Len() が真であるならば、db.maxIdleConnsLocked()db.freeConn.Len() よりも大きい値である必要があります。db.freeConn.Len() は接続プールの現在のアイドル接続数であり、これは非負の値(0以上)です。したがって、db.maxIdleConnsLocked()db.freeConn.Len() よりも大きいということは、db.maxIdleConnsLocked() が必然的に0よりも大きいことを意味します。

つまり、db.maxIdleConnsLocked() > db.freeConn.Len() が真である限り、db.maxIdleConnsLocked() > 0 も常に真となります。このため、db.maxIdleConnsLocked() > 0 の条件は冗長であり、評価する必要がありません。

この冗長な条件を削除することで、db.maxIdleConnsLocked() メソッドの呼び出しが1回削減されます。コミットメッセージによると、このメソッドは当時インライン化されず、内部に switch ステートメントを含んでいたため、呼び出しコストが無視できないものでした。インライン化されない関数呼び出しは、スタックフレームのセットアップ、引数のプッシュ、レジスタの保存・復元など、一定のオーバーヘッドを伴います。

コミットメッセージに示されたアセンブリコードの比較は、この最適化の効果を具体的に示しています。

Before: 43c360: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 43c379: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 変更前は maxIdleConnsLocked が2回呼び出されています。

After: 43c360: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 変更後は maxIdleConnsLocked が1回しか呼び出されていません。

このアセンブリコードの比較から、冗長な条件の削除によって、実際に maxIdleConnsLocked メソッドの呼び出しが1回減少し、それに伴う命令数も削減されていることが確認できます。これにより、putConnDBLocked 関数が実行される際のCPUサイクルが節約され、全体的なパフォーマンスが向上します。これは、特にデータベース接続のライフサイクルが頻繁に発生するような高負荷なアプリケーションにおいて、顕著な効果をもたらす可能性があります。

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

変更は src/pkg/database/sql/sql.go ファイルの1箇所のみです。

--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -791,7 +791,7 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 		req <- dc
 		return true
-	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
+	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > db.freeConn.Len() {
 		dc.listElem = db.freeConn.PushFront(dc)
 		return true
 	}

具体的には、putConnDBLocked 関数の else if 条件式から db.maxIdleConnsLocked() > 0 という部分が削除されました。

コアとなるコードの解説

putConnDBLocked 関数は、データベース接続(dc *driverConn)をプールに戻す際に呼び出される内部関数です。この関数は、接続が再利用可能かどうか、またアイドル接続の最大数を超えていないかなどを判断します。

変更前のコードでは、接続をアイドルプールに戻す条件として、以下の4つを論理積(AND)で結合していました。

  1. err == nil: 接続がエラーなく正常にクローズされたか、または使用後にエラーが発生しなかったか。
  2. !db.closed: データベース接続プール自体が閉じられていないか。
  3. db.maxIdleConnsLocked() > 0: アイドル接続の最大数が0より大きいか(つまり、アイドル接続を許可しているか)。
  4. db.maxIdleConnsLocked() > db.freeConn.Len(): 現在のアイドル接続数が、設定された最大アイドル接続数よりも少ないか。

このコミットでは、3番目の条件 db.maxIdleConnsLocked() > 0 が削除されました。 その理由は、4番目の条件 db.maxIdleConnsLocked() > db.freeConn.Len() が真である場合、db.maxIdleConnsLocked() は必ず db.freeConn.Len() よりも大きい値であるため、自動的に db.maxIdleConnsLocked() が0より大きいことが保証されるからです。db.freeConn.Len() はアイドル接続の数を表し、常に0以上の値を取ります。したがって、db.maxIdleConnsLocked()db.freeConn.Len() より大きいということは、db.maxIdleConnsLocked() が負の値であることはありえず、必然的に正の値であると判断できます。

この変更により、db.maxIdleConnsLocked() メソッドの呼び出しが1回削減され、特にこのメソッドがインライン化されず、内部に switch ステートメントを持つためにコストが高いという当時の状況において、パフォーマンスの向上が期待されました。コードの論理的な簡潔さも向上しています。

関連リンク

参考にした情報源リンク

  • Go CL 14656044: https://golang.org/cl/14656044
  • Go言語のインライン化に関する一般的な情報(Goのバージョンによって挙動は異なる可能性があります): https://go.dev/blog/go1.10 (Go 1.10のブログ記事ですが、インライン化の概念について触れられています)
  • アセンブリ言語の基礎知識(一般的な情報源)
  • Go言語の database/sql パッケージのソースコード (コミット当時のバージョン)
  • Go言語のコンパイラ最適化に関する一般的な情報# [インデックス 17948] ファイルの概要

このコミットは、Go言語の標準ライブラリである database/sql パッケージ内の putConnDBLocked メソッドにおける冗長な条件式を削除し、パフォーマンスを改善するものです。具体的には、データベース接続プールのアイドル接続数を管理するロジックにおいて、既に別の条件で暗黙的に満たされているチェックを削除することで、不要なメソッド呼び出しとそれに伴うオーバーヘッドを削減しています。

コミット

commit c8869e9caf17c0b993b515924b163a6c8286be77
Author: Alberto García Hierro <alberto@garciahierro.com>
Date:   Tue Dec 10 16:10:09 2013 +0400

    database/sql: Remove redundant condition in if
    
    The final condition (db.maxIdleConnsLocked() > db.freeConn.Len()) can
    only be true iff db.maxIdleConnsLocked() is greater than 0, so previously
    checking if it's greater than 0 is a waste, specially when that involves
    a method call which (ATM) can't be inlined and includes a switch.
    
    Dissasembly follows (test for err == nil has been omitted for clarity):
    
    Before:
    43c357: cmp    $0x0,%bl
    43c35a: jne    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>
    43c35c: mov    %rax,(%rsp)\n    43c360: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>\n    43c365: mov    0x8(%rsp),%rbx\n    43c36a: cmp    $0x0,%rbx\n    43c36e: jle    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>\n    43c370: mov    0x30(%rsp),%rbx\n    43c375: mov    %rbx,(%rsp)\n    43c379: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>\n    43c37e: mov    0x30(%rsp),%rdx\n    43c383: mov    0x8(%rsp),%rcx\n    43c388: mov    0x28(%rdx),%rbp\n    43c38c: mov    0x28(%rbp),%rbx\n    43c390: cmp    %rcx,%rbx\n    43c393: jge    43c3ce <database/sql.(*DB).putConnDBLocked+0x1ce>\n    43c395: mov    0x28(%rdx),%rbp\n    43c399: mov    %rbp,(%rsp)\n    43c39d: mov    0x38(%rsp),%rcx\n    43c3a2: mov    $0x556c60,%eax\n    43c3a7: mov    %rax,0x8(%rsp)\n    43c3ac: mov    %rcx,0x10(%rsp)\n    43c3b1: callq  4db5b0 <container/list.(*List).PushFront>\n    \n    After:\n    43c357: cmp    $0x0,%bl\n    43c35a: jne    43c3b5 <database/sql.(*DB).putConnDBLocked+0x1b5>\n    43c35c: mov    %rax,(%rsp)\n    43c360: callq  43aec0 <database/sql.(*DB).maxIdleConnsLocked>\n    43c365: mov    0x30(%rsp),%rdx\n    43c36a: mov    0x8(%rsp),%rcx\n    43c36f: mov    0x28(%rdx),%rbp\n    43c373: mov    0x28(%rbp),%rbx\n    43c377: cmp    %rcx,%rbx\n    43c37a: jge    43c3b5 <database/sql.(*DB).putConnDBLocked+0x1b5>\n    43c37c: mov    0x28(%rdx),%rbp\n    43c380: mov    %rbp,(%rsp)\n    43c384: mov    0x38(%rsp),%rcx\n    43c389: mov    $0x556c60,%eax\n    43c38e: mov    %rax,0x8(%rsp)\n    43c393: mov    %rcx,0x10(%rsp)\n    43c398: callq  4db590 <container/list.(*List).PushFront>\n    \n    R=golang-dev, bradfitz, iant\n    CC=golang-dev\n    https://golang.org/cl/14656044

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

https://github.com/golang/go/commit/c8869e9caf17c0b993b515924b163a6c8286be77

元コミット内容

このコミットは、Go言語の database/sql パッケージ内の putConnDBLocked 関数における条件式を簡素化するものです。変更前のコードでは、アイドル状態のデータベース接続をプールに戻す際に、以下の条件をチェックしていました。

else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {

この条件式には db.maxIdleConnsLocked() > 0 という部分が含まれており、これは db.maxIdleConnsLocked() > db.freeConn.Len() という後続の条件が真であるためには、db.maxIdleConnsLocked() が必然的に0より大きい値でなければならないため、冗長でした。

変更の背景

この変更の背景には、Go言語のランタイムとコンパイラの最適化に関する考慮があります。コミットメッセージに明記されているように、db.maxIdleConnsLocked() メソッドの呼び出しは、当時(2013年)のGoコンパイラではインライン化されず、さらに内部で switch ステートメントを含んでいたため、比較的高価な操作でした。

冗長な条件 db.maxIdleConnsLocked() > 0 を削除することで、この高価なメソッド呼び出しを1回減らすことができます。これにより、putConnDBLocked 関数が実行される際のCPUサイクルを節約し、データベース接続の解放およびプールへの返却処理の効率を向上させることが目的です。特に、高負荷なシステムで頻繁にデータベース接続が取得・解放される場合、このような小さな最適化が全体のスループットに寄与する可能性があります。

コミットメッセージに示されているアセンブリコードの比較は、この最適化が実際に生成される機械語レベルで命令数を削減していることを明確に示しています。

前提知識の解説

Go言語の database/sql パッケージ

database/sql パッケージは、Go言語でSQLデータベースを操作するための汎用的なインターフェースを提供します。このパッケージ自体は特定のデータベースドライバーを含まず、データベース固有の機能は外部のドライバーパッケージによって提供されます。主な機能は以下の通りです。

  • sql.DB: データベースへの接続プールを管理する構造体です。複数のゴルーチンから安全に利用できるように設計されており、接続のオープン、クローズ、アイドル接続の管理などを自動的に行います。
  • 接続プール: データベースへの接続はコストの高い操作であるため、database/sql は接続プールを内部に持ち、一度確立した接続を再利用します。これにより、接続の確立・切断のオーバーヘッドを削減し、接続の確立・切断のオーバーヘッドを削減し、アプリケーションのパフォーマンスを向上させます。
  • maxIdleConns: アイドル状態(使用されていない)でプールに保持される接続の最大数を設定します。この設定は、接続の再利用効率に直接影響します。
  • freeConn: sql.DB 構造体内部で、現在アイドル状態にある接続を保持するためのリスト(または同様のデータ構造)です。

Goコンパイラの最適化とインライン化

Goコンパイラは、生成されるバイナリのパフォーマンスを向上させるために様々な最適化を行います。その一つが「インライン化(inlining)」です。

  • インライン化: 関数呼び出しのオーバーヘッド(スタックフレームの作成、引数の渡し、戻り値の処理など)を避けるために、呼び出し元のコードに関数本体のコードを直接埋め込む最適化手法です。これにより、実行時のパフォーマンスが向上しますが、バイナリサイズが増加する可能性があります。
  • インライン化の制約: Goコンパイラは、関数のサイズ、複雑さ、再帰の有無など、様々な要因に基づいてインライン化を行うかどうかを決定します。特に、switch ステートメントのような制御フローが複雑な関数は、インライン化されにくい傾向があります。

アセンブリコードの分析

アセンブリコードは、CPUが直接実行する機械語命令を人間が読める形式で表現したものです。このコミットメッセージに含まれるアセンブリコードは、Goプログラムがコンパイルされた後の低レベルな動作を示しています。

  • cmp: 比較命令。2つのオペランドを比較し、フラグレジスタを設定します。
  • jne / jle / jge: 条件分岐命令。フラグレジスタの状態に基づいて、指定されたアドレスにジャンプします。
  • mov: データ転送命令。レジスタやメモリ間でデータを移動します。
  • callq: 関数呼び出し命令。指定されたアドレスの関数を実行し、戻りアドレスをスタックにプッシュします。

アセンブリコードを比較することで、Goのソースコードの変更が、最終的な実行ファイルにどのような影響を与え、命令数がどのように変化したかを正確に把握することができます。

技術的詳細

このコミットの技術的詳細なポイントは、論理的な冗長性の排除と、それがもたらすパフォーマンス上のメリットにあります。

変更前の条件式は以下の通りでした。 err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len()

ここで注目すべきは、db.maxIdleConnsLocked() > 0db.maxIdleConnsLocked() > db.freeConn.Len() の2つの条件です。 もし db.maxIdleConnsLocked() > db.freeConn.Len() が真であるならば、db.maxIdleConnsLocked()db.freeConn.Len() よりも大きい値である必要があります。db.freeConn.Len() は接続プールの現在のアイドル接続数であり、これは非負の値(0以上)です。したがって、db.maxIdleConnsLocked()db.freeConn.Len() よりも大きいということは、db.maxIdleConnsLocked() が必然的に0よりも大きいことを意味します。

つまり、db.maxIdleConnsLocked() > db.freeConn.Len() が真である限り、db.maxIdleConnsLocked() > 0 も常に真となります。このため、db.maxIdleConnsLocked() > 0 の条件は冗長であり、評価する必要がありません。

この冗長な条件を削除することで、db.maxIdleConnsLocked() メソッドの呼び出しが1回削減されます。コミットメッセージによると、このメソッドは当時インライン化されず、内部に switch ステートメントを含んでいたため、呼び出しコストが無視できないものでした。インライン化されない関数呼び出しは、スタックフレームのセットアップ、引数のプッシュ、レジスタの保存・復元など、一定のオーバーヘッドを伴います。

コミットメッセージに示されたアセンブリコードの比較は、この最適化の効果を具体的に示しています。

Before: 43c360: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 43c379: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 変更前は maxIdleConnsLocked が2回呼び出されています。

After: 43c360: callq 43aec0 <database/sql.(*DB).maxIdleConnsLocked> 変更後は maxIdleConnsLocked が1回しか呼び出されていません。

このアセンブリコードの比較から、冗長な条件の削除によって、実際に maxIdleConnsLocked メソッドの呼び出しが1回減少し、それに伴う命令数も削減されていることが確認できます。これにより、putConnDBLocked 関数が実行される際のCPUサイクルが節約され、全体的なパフォーマンスが向上します。これは、特にデータベース接続のライフサイクルが頻繁に発生するような高負荷なアプリケーションにおいて、顕著な効果をもたらす可能性があります。

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

変更は src/pkg/database/sql/sql.go ファイルの1箇所のみです。

--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -791,791,7 +791,7 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 		req <- dc
 		return true
-	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
+	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > db.freeConn.Len() {
 		dc.listElem = db.freeConn.PushFront(dc)
 		return true
 	}

具体的には、putConnDBLocked 関数の else if 条件式から db.maxIdleConnsLocked() > 0 という部分が削除されました。

コアとなるコードの解説

putConnDBLocked 関数は、データベース接続(dc *driverConn)をプールに戻す際に呼び出される内部関数です。この関数は、接続が再利用可能かどうか、またアイドル接続の最大数を超えていないかなどを判断します。

変更前のコードでは、接続をアイドルプールに戻す条件として、以下の4つを論理積(AND)で結合していました。

  1. err == nil: 接続がエラーなく正常にクローズされたか、または使用後にエラーが発生しなかったか。
  2. !db.closed: データベース接続プール自体が閉じられていないか。
  3. db.maxIdleConnsLocked() > 0: アイドル接続の最大数が0より大きいか(つまり、アイドル接続を許可しているか)。
  4. db.maxIdleConnsLocked() > db.freeConn.Len(): 現在のアイドル接続数が、設定された最大アイドル接続数よりも少ないか。

このコミットでは、3番目の条件 db.maxIdleConnsLocked() > 0 が削除されました。 その理由は、4番目の条件 db.maxIdleConnsLocked() > db.freeConn.Len() が真である場合、db.maxIdleConnsLocked() は必ず db.freeConn.Len() よりも大きい値であるため、自動的に db.maxIdleConnsLocked() が0より大きいことが保証されるからです。db.freeConn.Len() はアイドル接続の数を表し、常に0以上の値を取ります。したがって、db.maxIdleConnsLocked()db.freeConn.Len() より大きいということは、db.maxIdleConnsLocked() が負の値であることはありえず、必然的に正の値であると判断できます。

この変更により、db.maxIdleConnsLocked() メソッドの呼び出しが1回削減され、特にこのメソッドがインライン化されず、内部に switch ステートメントを持つためにコストが高いという当時の状況において、パフォーマンスの向上が期待されました。コードの論理的な簡潔さも向上しています。

関連リンク

参考にした情報源リンク

  • Go CL 14656044: https://golang.org/cl/14656044
  • Go言語のインライン化に関する一般的な情報(Goのバージョンによって挙動は異なる可能性があります): https://go.dev/blog/go1.10 (Go 1.10のブログ記事ですが、インライン化の概念について触れられています)
  • アセンブリ言語の基礎知識(一般的な情報源)
  • Go言語の database/sql パッケージのソースコード (コミット当時のバージョン)
  • Go言語のコンパイラ最適化に関する一般的な情報