[インデックス 17587] ファイルの概要
このコミットは、Go言語の標準ライブラリ encoding/xml
パッケージに Encoder.Flush
メソッドを追加するものです。これにより、XMLエンコーダのバッファリングされたデータを強制的に基になるライターに書き出す機能が提供され、特に EncodeToken
を直接使用する場合のデータの一貫性と即時性が向上します。
コミット
commit 3c11dd8ebc46a306c7fb196da63328426160cd6a
Author: Russ Cox <rsc@golang.org>
Date: Thu Sep 12 16:54:01 2013 -0400
encoding/xml: add Encoder.Flush
Fixes #6365.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/13627046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3c11dd8ebc46a306c7fb196da63328426160cd6a
元コミット内容
encoding/xml
パッケージの Encoder
に Flush
メソッドを追加し、関連するドキュメントを更新しました。また、Flush
メソッドの動作を検証するためのテストケースも追加されています。
変更の背景
この変更は、Go issue #6365 を解決するために行われました。このイシューは、encoding/xml
パッケージの Encoder
が内部的に bufio.Writer
を使用しているにもかかわらず、バッファリングされたデータを強制的に書き出す Flush
メソッドが提供されていないことに関するものでした。
Encoder
の Encode
や EncodeElement
メソッドは内部で Flush
を呼び出すため、通常の使用では問題になりません。しかし、EncodeToken
メソッドを直接使用してXMLトークンを書き込む場合、EncodeToken
自体は Flush
を呼び出しません。このため、ユーザーが EncodeToken
を繰り返し呼び出してXMLを構築する際に、データが内部バッファに留まり、基になる io.Writer
に書き込まれないという問題が発生していました。特に、ネットワークストリームなど、データが即座に送信されることが期待されるシナリオでは、このバッファリングが問題となる可能性がありました。
Flush
メソッドの追加により、開発者は必要に応じて明示的にバッファをフラッシュし、XMLデータが確実に基になるライターに書き込まれるようにすることができるようになりました。
前提知識の解説
encoding/xml
パッケージ: Go言語の標準ライブラリの一部で、Goの構造体とXMLの間でデータをエンコード(マーシャリング)およびデコード(アンマーシャリング)するための機能を提供します。Encoder
:encoding/xml
パッケージの中心的な型の一つで、Goの値をXML形式でio.Writer
に書き込むための機能を提供します。内部でバッファリングを行うことで、I/O操作の効率を高めています。Token
: XMLドキュメントの構成要素(例: 開始タグ、終了タグ、文字データ、コメントなど)を表すインターフェースです。Encoder.EncodeToken
メソッドは、これらのトークンを一つずつ書き込むために使用されます。bufio.Writer
:bufio
パッケージで提供されるバッファリングされたライターです。I/O操作の回数を減らすことで、パフォーマンスを向上させます。データはまず内部バッファに書き込まれ、バッファが満杯になるか、明示的にフラッシュされるか、またはライターがクローズされるまで、基になるio.Writer
には書き込まれません。- フラッシュ (Flush): バッファリングされたI/Oにおいて、内部バッファに蓄積されたデータを強制的に基になるI/Oデバイス(この場合は
io.Writer
)に書き出す操作を指します。これにより、データが確実に永続化されるか、または次の処理段階に渡されることが保証されます。
技術的詳細
encoding/xml
パッケージの Encoder
は、効率的なXML生成のために内部的にバッファリングメカニズムを使用しています。これは通常、bufio.Writer
を介して実現されます。Encode
や EncodeElement
のような高レベルのメソッドは、XMLのエンコードが完了した後に自動的に内部バッファをフラッシュするように設計されています。これにより、これらのメソッドを使用する開発者は、データの書き込みについて意識する必要がありませんでした。
しかし、EncodeToken
メソッドは、より低レベルなXMLトークンのストリーム処理を目的としており、単一のトークンを書き込むたびにフラッシュを行うとパフォーマンスが低下する可能性があるため、自動的なフラッシュは行われませんでした。これは、カスタムの Marshaler
実装や、XMLをトークン単位で細かく制御して生成するような高度なシナリオで EncodeToken
が使用されることを想定しているためです。
この設計上の選択は、EncodeToken
を直接使用する際に、データがバッファに留まり、期待通りに基になるライターに書き込まれないという問題を引き起こしました。特に、XMLデータをリアルタイムで処理する必要がある場合や、部分的なXMLドキュメントをストリームとして送信する場合に、この遅延が問題となります。
Encoder.Flush()
メソッドの追加は、この問題を解決するための直接的なアプローチです。このメソッドは、Encoder
の内部 printer
型が持つ Flush
メソッドを呼び出すことで、bufio.Writer
のバッファを強制的にフラッシュします。これにより、EncodeToken
を使用してXMLを構築する開発者は、必要に応じて明示的に Flush()
を呼び出すことで、バッファリングされたXMLデータが即座に基になる io.Writer
に書き込まれることを保証できるようになりました。
この変更は、encoding/xml
パッケージの柔軟性を高め、より多様なXML生成シナリオに対応できるようにするものです。
コアとなるコードの変更箇所
このコミットでは、主に以下の2つのファイルが変更されています。
src/pkg/encoding/xml/marshal.go
:Encoder.Flush
メソッドの追加と、既存メソッドのドキュメント更新。src/pkg/encoding/xml/marshal_test.go
:Encoder.Flush
メソッドの動作を検証するテストケースの追加。
src/pkg/encoding/xml/marshal.go
の変更点
-
Encoder.Flush()
メソッドの追加:// Flush flushes any buffered XML to the underlying writer. // See the EncodeToken documentation for details about when it is necessary. func (enc *Encoder) Flush() error { return enc.p.Flush() }
この新しいメソッドは、
Encoder
の内部printer
型のFlush
メソッドを呼び出すことで、バッファリングされたXMLデータを基になるライターに書き出します。 -
Encoder.Encode()
メソッドのドキュメント更新:Encode calls Flush before returning.
という記述が追加され、Encode
メソッドが戻る前にFlush
を呼び出すことが明記されました。 -
Encoder.EncodeElement()
メソッドのドキュメント更新:EncodeElement calls Flush before returning.
という記述が追加され、EncodeElement
メソッドが戻る前にFlush
を呼び出すことが明記されました。 -
Encoder.EncodeToken()
メソッドのドキュメント更新:EncodeToken does not call Flush, because usually it is part of a larger operation such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked during those), and those will call Flush when finished.
およびCallers that create an Encoder and then invoke EncodeToken directly, without using Encode or EncodeElement, need to call Flush when finished to ensure that the XML is written to the underlying writer.
という記述が追加されました。これは、EncodeToken
がFlush
を呼び出さない理由と、EncodeToken
を直接使用する場合にFlush
を呼び出す必要があることを明確にしています。
src/pkg/encoding/xml/marshal_test.go
の変更点
TestMarshalFlush()
テスト関数の追加:
このテストは、func TestMarshalFlush(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.EncodeToken(CharData("hello world")); err != nil { t.Fatalf("enc.EncodeToken: %v", err) } if buf.Len() > 0 { t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes()) } if err := enc.Flush(); err != nil { t.Fatalf("enc.Flush: %v", err) } if buf.String() != "hello world" { t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world") } }
EncodeToken
でデータを書き込んだ後、Flush
を呼び出すまでbytes.Buffer
にデータが書き込まれないことを確認し、Flush
呼び出し後にデータが正しく書き込まれることを検証しています。
コアとなるコードの解説
このコミットの核心は、encoding/xml.Encoder
型に Flush()
メソッドを追加したことです。
// Flush flushes any buffered XML to the underlying writer.
// See the EncodeToken documentation for details about when it is necessary.
func (enc *Encoder) Flush() error {
return enc.p.Flush()
}
このメソッドは、Encoder
の内部フィールドである p
(型は printer
) の Flush()
メソッドを呼び出しています。printer
型は、XMLデータを実際にバッファリングし、基になる io.Writer
に書き込む役割を担っています。通常、printer
は bufio.Writer
をラップしているため、この Flush()
呼び出しは bufio.Writer
の Flush()
メソッドに相当し、内部バッファの内容を強制的に書き出します。
この変更に伴い、既存の Encode
、EncodeElement
、EncodeToken
メソッドのドキュメントが更新されました。
-
Encode
とEncodeElement
のドキュメントには、「Encode calls Flush before returning.
」および「EncodeElement calls Flush before returning.
」という記述が追加されました。これは、これらの高レベルなエンコードメソッドが、処理の完了時に自動的にバッファをフラッシュすることを明確にしています。これにより、これらのメソッドを使用する開発者は、通常、明示的にFlush()
を呼び出す必要がないことが示唆されます。 -
EncodeToken
のドキュメントは、より詳細な説明が追加されました。- 「
EncodeToken does not call Flush, because usually it is part of a larger operation such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked during those), and those will call Flush when finished.
」 これは、EncodeToken
が単独でFlush
を呼び出さない理由を説明しています。通常、EncodeToken
はEncode
やEncodeElement
のようなより大きな操作の一部として、またはカスタムのMarshaler
の中で使用されるため、それらの上位の操作が最終的にFlush
を担当するという設計思想が示されています。 - 「
Callers that create an Encoder and then invoke EncodeToken directly, without using Encode or EncodeElement, need to call Flush when finished to ensure that the XML is written to the underlying writer.
」 この文は、EncodeToken
を直接、かつEncode
やEncodeElement
を介さずに使用する開発者に対する重要な指示です。このようなシナリオでは、XMLデータが実際に基になるライターに書き込まれることを保証するために、明示的にEncoder.Flush()
を呼び出す必要があることを強調しています。
- 「
これらのドキュメントの更新は、Flush
メソッドの導入と合わせて、encoding/xml
パッケージのバッファリング動作と、開発者がいつ Flush
を呼び出すべきかについての明確なガイドラインを提供します。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/3c11dd8ebc46a306c7fb196da63328426160cd6a
- Go CL (Change List): https://golang.org/cl/13627046
参考にした情報源リンク
- Go issue #6365 (検索結果から直接的なリンクは見つかりませんでしたが、コミットメッセージに記載されているため、このコミットの背景にある問題として参照しています。)
- Go言語
encoding/xml
パッケージ公式ドキュメント:Encoder.Flush
の説明 (検索結果から得られた情報に基づいています)