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

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

このコミットは、Go言語の標準ライブラリ encoding/json パッケージにおける json.Decoder のバッファリング動作に関するドキュメントを追加するものです。具体的には、NewDecoder 関数が io.Reader からJSON値を読み取る際に、要求されたJSON値を超えてデータを読み込む可能性があることを明記し、開発者がこの挙動を理解し、適切に処理できるようにすることを目的としています。これは、Go issue #1955 の修正の一環として行われました。

コミット

  • コミットハッシュ: 49110eaa2203bc59c754bc2534ba11f969e448f6
  • Author: Russ Cox rsc@golang.org
  • Date: Wed Feb 8 13:48:03 2012 -0500
  • コミットメッセージ:
    encoding/json: document buffering
    
    Fixes #1955.
    
    R=golang-dev, gri
    CC=golang-dev
    https://golang.org/cl/5643058
    

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

https://github.com/golang/go/commit/49110eaa2203bc59c754bc2534ba11f969e448f6

元コミット内容

encoding/json: document buffering

Fixes #1955.

R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5643058

変更の背景

encoding/json パッケージの json.Decoder は、io.Reader からJSONデータを効率的にデコードするように設計されています。このデコード処理中に、デコーダは単一のJSON値をデコードするために厳密に必要なバイト数よりも多くのバイトを基になるリーダーから読み取ることがあります。この「読み過ぎた(overread)」データは、デコーダの内部でバッファリングされます。

Go issue #1955 は、この読み過ぎたデータにアクセスすることが困難であるという問題点を指摘していました。これにより、複数のJSON値を含むストリームや、混合されたデータ形式のストリームを処理することが困難になっていました。例えば、json.Decoder でJSONオブジェクトを読み取った後、その直後に続く非JSONデータを同じ io.Reader から読み取ろうとすると、json.Decoder が既にその非JSONデータの一部を読み込んでしまっているため、期待通りに動作しないという問題が発生していました。

このコミットは、この問題に対する直接的なコード変更ではなく、json.DecoderNewDecoder 関数に、このバッファリング動作に関する重要なドキュメントを追加することで、開発者がこの挙動を認識し、適切に対応できるようにすることを目的としています。これにより、将来的に Decoder.Buffered() メソッド(Go 1.1で導入)のような機能が追加された際に、その必要性や利用方法がより明確になります。

前提知識の解説

io.Reader インターフェース

Go言語における io.Reader は、データを読み取るための基本的なインターフェースです。これは、Read(p []byte) (n int, err error) メソッドを定義しており、このメソッドはバイトスライス p にデータを読み込み、読み込んだバイト数 n とエラー err を返します。ファイル、ネットワーク接続、メモリ上のバイトスライスなど、様々なデータソースが io.Reader インターフェースを実装しています。

encoding/json パッケージ

encoding/json パッケージは、Goのデータ構造とJSONデータの間でエンコード(GoからJSONへ)およびデコード(JSONからGoへ)を行うための機能を提供します。

  • json.Encoder: Goの値をJSON形式にエンコードし、io.Writer に書き込みます。
  • json.Decoder: io.Reader からJSONデータを読み取り、Goの値にデコードします。

バッファリング

バッファリングとは、データ処理の効率を向上させるために、データを一時的にメモリに蓄える技術です。json.Decoder の文脈では、デコーダが io.Reader からデータを読み取る際に、一度に多くのデータを読み込み、それを内部バッファに保持することを指します。これにより、JSONの解析に必要なデータを細かく何度も読み取るのではなく、まとめて読み取ることができ、I/O操作の回数を減らしてパフォーマンスを向上させることができます。

しかし、このバッファリングは、デコーダが要求されたJSON値の終端を超えてデータを読み込んでしまう「読み過ぎ(overread)」を引き起こす可能性があります。この読み過ぎたデータは内部バッファに保持され、基になる io.Reader からは既に消費された状態になります。

技術的詳細

このコミットは、src/pkg/encoding/json/stream.go ファイル内の NewDecoder 関数のドキュメントに、以下の2行を追加しています。

// The decoder introduces its own buffering and may
// read data from r beyond the JSON values requested.

このドキュメントは、json.Decoderio.Reader からデータを読み取る際の重要な挙動を明確にしています。

  1. The decoder introduces its own buffering: json.Decoder は、独自のバッファリングメカニズムを持っていることを示しています。これは、デコーダが効率的な読み取りのために、内部的にデータをキャッシュしていることを意味します。
  2. and may read data from r beyond the JSON values requested: 最も重要な点として、デコーダが要求されたJSON値(例えば、単一のJSONオブジェクトや配列)の範囲を超えて、基になる io.Reader からデータを読み込む可能性があることを明記しています。

この「読み過ぎ」の挙動は、特に以下のようなシナリオで重要になります。

  • 複数のJSON値が連続するストリーム: io.Reader{"key": "value"}{"another": "object"} のように複数のJSONオブジェクトを連続して含んでいる場合、最初の Decode() 呼び出しで最初のオブジェクトを読み取った後、デコーダは既に2番目のオブジェクトの一部または全体を読み込んでしまっている可能性があります。
  • JSONデータの後に非JSONデータが続くストリーム: {"data": 123}END_OF_STREAM のように、JSONデータの直後に別の形式のデータが続く場合、json.Decoder がJSON部分を読み取った後、END_OF_STREAM の一部を読み込んでしまう可能性があります。この場合、後続の処理で io.Reader から END_OF_STREAM を読み取ろうとしても、既にデコーダによって消費されているため、期待通りの動作にならないことがあります。

このドキュメントの追加は、Go issue #1955 で提起された問題への対応の一環です。この問題は、json.Decoder が読み過ぎたデータをどのように扱うか、そしてそのデータにアクセスする方法がないことに関するものでした。このコミット自体はコードの動作を変更するものではありませんが、この挙動を明示することで、開発者がこの潜在的な問題を認識し、必要に応じて Decoder.Buffered() のような後続の機能(Go 1.1で導入)を利用して、読み過ぎたデータにアクセスしたり、ストリームを適切に処理したりするための基盤を提供します。

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

変更は src/pkg/encoding/json/stream.go ファイルの Decoder 構造体と NewDecoder 関数の定義部分にあります。

--- a/src/pkg/encoding/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -19,6 +19,9 @@ type Decoder struct {
 }
 
 // NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may
+// read data from r beyond the JSON values requested.
 func NewDecoder(r io.Reader) *Decoder {
 	return &Decoder{r: r}
 }

コアとなるコードの解説

追加されたコードは、NewDecoder 関数のGoDocコメントです。

// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may
// read data from r beyond the JSON values requested.
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r: r}
}

このコメントは、NewDecoderio.Reader から新しい Decoder を作成することを説明しています。そして、追加された2行が、json.Decoder の内部的なバッファリング動作と、それが io.Reader からの読み取りにどのように影響するかを明確に記述しています。

  • The decoder introduces its own buffering: デコーダが内部的にデータをバッファリングすることを示唆しています。
  • and may read data from r beyond the JSON values requested.: このバッファリングの結果として、デコーダが要求されたJSON値の範囲を超えて、基になる io.Reader からデータを読み込んでしまう可能性があることを警告しています。

このドキュメントの追加により、json.Decoder を使用する開発者は、デコーダが io.Reader から読み取るデータの量とタイミングについて、より正確な理解を持つことができます。これにより、特に複数のJSON値が連続するストリームや、JSONデータの後に他のデータが続くストリームを扱う際に、予期せぬ挙動を避けるための適切な設計や対処が可能になります。

関連リンク

参考にした情報源リンク