[インデックス 13534] ファイルの概要
このコミットは、misc/dashboard/codereview/dashboard/cl.go
ファイルに対して行われた変更を記録しています。このファイルは、Go言語のコードレビューダッシュボードに関連するデータ構造を定義しているものと推測されます。具体的には、CL
(Change List) という構造体の定義が含まれています。
コミット
- コミットハッシュ:
09f1f5d76d648f9dcdc86ff814b7e463ecca93df
- 作者: Russ Cox rsc@golang.org
- コミット日時: 2012年7月30日 月曜日 10:13:54 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/09f1f5d76d648f9dcdc86ff814b7e463ecca93df
元コミット内容
misc/dashboard/codereview: add LastUpdate field to CL
To be filled in by a later CL. I deployed a test version to
App Engine to work on setting the values, so there are
a few records that have this field set already.
That field is breaking the live version, so I have pushed
a new copy with this 1-line change to the live version
I assumed that appengine/datastore was like every other
marshaling and unmarshaling package we have in Go
(for example, encoding/gob, encoding/json, encoding/xml,
and protobuf) and that if it loaded an unknown field it would
just ignore it. Apparently not. Sorry.
R=dsymonds
TBR=dsymonds
CC=golang-dev
https://golang.org/cl/6454064
変更の背景
このコミットの背景には、Go言語のコードレビューダッシュボードシステムにおける、Google App Engine Datastoreの挙動に関する予期せぬ問題がありました。
元々、開発者はCL
構造体にLastUpdate
という新しいフィールドを追加し、その値を設定するためのテストバージョンをApp Engineにデプロイしていました。このテストデプロイメントにより、Datastoreには既にLastUpdate
フィールドが設定されたレコードがいくつか存在していました。
しかし、この新しいフィールドが、本番環境で稼働している既存のアプリケーションを破壊するという問題が発生しました。開発者(Russ Cox氏)は、Go言語の他のマーシャリング/アンマーシャリングパッケージ(encoding/gob
, encoding/json
, encoding/xml
, protobuf
など)と同様に、appengine/datastore
も未知のフィールドを読み込んだ際にそれを無視すると考えていました。しかし、実際にはappengine/datastore
はそのような挙動をせず、未知のフィールドが存在するとエラーを引き起こすことが判明しました。
この問題を解決するため、本番環境のアプリケーションが、テストデプロイメントによってDatastoreに書き込まれたLastUpdate
フィールドを持つレコードを正常に処理できるように、CL
構造体にLastUpdate
フィールドを正式に追加する緊急の1行変更がこのコミットで行われました。これにより、本番環境のアプリケーションがDatastoreからデータを読み込む際に、LastUpdate
フィールドが未知のフィールドとして扱われなくなり、エラーが解消されました。
前提知識の解説
Google App Engine (GAE)
Google App Engineは、Googleが提供するPlatform as a Service (PaaS) です。開発者はインフラストストラクチャの管理を気にすることなく、アプリケーションをデプロイ・実行できます。Go言語はApp Engineでサポートされている言語の一つです。
Google App Engine Datastore
App Engine Datastoreは、Google App Engine上で利用できるNoSQLドキュメントデータベースです。スケーラビリティと可用性に優れており、Webアプリケーションのバックエンドデータストアとしてよく利用されます。Datastoreは、エンティティ(データレコード)とプロパティ(フィールド)の概念を持ち、スキーマレスなデータモデルをサポートしています。
Go言語における構造体とマーシャリング/アンマーシャリング
Go言語では、構造体(struct)は関連するデータをまとめるための型です。構造体のフィールドには、json:"field_name"
やxml:"field_name"
のような「構造体タグ」を付与することができます。これらのタグは、encoding/json
やencoding/xml
といった標準ライブラリのマーシャリング(Goのデータ構造を外部形式に変換)およびアンマーシャリング(外部形式をGoのデータ構造に変換)処理において、フィールド名やその他の挙動を制御するために使用されます。
- マーシャリング (Marshaling): Goのデータ構造(例: 構造体)を、JSON、XML、バイナリなどの外部形式に変換するプロセス。
- アンマーシャリング (Unmarshaling): JSON、XML、バイナリなどの外部形式のデータを、Goのデータ構造に変換するプロセス。
多くのマーシャリング/アンマーシャリングライブラリ(encoding/json
, encoding/gob
, encoding/xml
, protobuf
など)は、デフォルトで、入力データにGoの構造体で定義されていない未知のフィールドが含まれていても、それを無視して処理を続行する挙動をします。これは、前方互換性や後方互換性を保つ上で非常に便利な特性です。例えば、新しいバージョンのAPIが追加フィールドを返すようになっても、古いクライアントは既存のフィールドのみを処理し、未知のフィールドは安全に無視できます。
datastore
構造体タグ
App Engine Datastoreを使用する際、Goの構造体をDatastoreのエンティティにマッピングするために、datastore
タグが使用されます。例えば、datastore:",noindex"
は、そのフィールドがDatastoreでインデックス付けされないことを示します。
技術的詳細
このコミットの核心的な問題は、appengine/datastore
のアンマーシャリング挙動が、Go標準ライブラリや一般的なデータシリアライゼーションライブラリのそれと異なっていた点にあります。
通常、Goのencoding/json
やencoding/xml
などのパッケージは、Goの構造体に対応しないフィールドが入力データに含まれていても、デフォルトでそれらを無視します。これにより、データ形式の進化や異なるバージョンのアプリケーション間での互換性が保たれやすくなります。
しかし、appengine/datastore
は、Goの構造体で定義されていないプロパティ(フィールド)がDatastoreのエンティティに存在する場合、それを未知のフィールドとして扱い、アンマーシャリング時にエラーを発生させました。
今回のケースでは、開発者がテスト目的でCL
構造体にLastUpdate
フィールドを追加し、そのテストバージョンをApp Engineにデプロイした結果、DatastoreにはLastUpdate
プロパティを持つエンティティが作成されました。その後、このテストバージョンとは異なる、LastUpdate
フィールドがまだ追加されていない本番環境のアプリケーションがこれらのエンティティを読み込もうとした際に、appengine/datastore
がLastUpdate
プロパティを未知のフィールドとして認識し、エラーを発生させてしまったのです。
この問題を解決するためには、本番環境のアプリケーションが使用するCL
構造体にもLastUpdate
フィールドを定義し、appengine/datastore
がそれを既知のプロパティとして認識できるようにする必要がありました。たとえそのフィールドがまだアプリケーションロジックで利用されていなくても、構造体に定義されていることで、Datastoreからの読み込みエラーを回避できます。
このコミットは、この緊急の修正として、CL
構造体にLastUpdate string
フィールドを追加することで、本番環境のアプリケーションがDatastoreからデータを正常に読み込めるようにしました。これにより、Datastoreに存在するLastUpdate
プロパティが未知のフィールドとして扱われることがなくなり、アプリケーションのクラッシュが回避されました。
コアとなるコードの変更箇所
変更はmisc/dashboard/codereview/dashboard/cl.go
ファイル内のCL
構造体に対して行われました。
--- a/misc/dashboard/codereview/dashboard/cl.go
+++ b/misc/dashboard/codereview/dashboard/cl.go
@@ -49,6 +49,7 @@ type CL struct {
FirstLine string `datastore:",noindex"`
LGTMs []string
NotLGTMs []string
+ LastUpdate string
// Mail information.
Subject string `datastore:",noindex"`
追加された行は以下の通りです。
LastUpdate string
コアとなるコードの解説
この変更は、CL
構造体にLastUpdate
という名前の新しいフィールドを追加しています。このフィールドの型はstring
です。
type CL struct { ... }
は、Go言語における構造体の定義です。この構造体は、コードレビューシステムにおける「変更リスト」(Change List、略してCL)の情報を表現するためのデータモデルとして機能します。
LastUpdate string
を追加することで、appengine/datastore
がDatastoreからエンティティを読み込む際に、LastUpdate
という名前のプロパティが存在しても、それを未知のフィールドとして扱わなくなります。これにより、Datastoreからのデータ読み込み時に発生していたエラーが解消されます。
この時点では、LastUpdate
フィールドにdatastore
タグは付与されていませんが、Goのappengine/datastore
パッケージは、構造体のフィールド名とDatastoreのプロパティ名をデフォルトでマッピングします。したがって、このシンプルな追加で問題が解決されました。コミットメッセージにあるように、このフィールドへの値の設定は「後のCLで」行われる予定であり、このコミットはあくまで緊急の互換性修正として機能しています。
関連リンク
- Go CL 6454064: https://golang.org/cl/6454064
参考にした情報源リンク
- Go App Engine Datastore documentation (当時の情報に基づく推測): https://cloud.google.com/appengine/docs/standard/go/datastore/reference (現在のドキュメントは変更されている可能性があります)
- Go
encoding/json
package: https://pkg.go.dev/encoding/json - Go
encoding/xml
package: https://pkg.go.dev/encoding/xml - Go
encoding/gob
package: https://pkg.go.dev/encoding/gob - Protocol Buffers (Go): https://developers.google.com/protocol-buffers/docs/reference/go-generated
[インデックス 13534] ファイルの概要
このコミットは、misc/dashboard/codereview/dashboard/cl.go
ファイルに対して行われた変更を記録しています。このファイルは、Go言語のコードレビューダッシュボードに関連するデータ構造を定義しているものと推測されます。具体的には、CL
(Change List) という構造体の定義が含まれています。
コミット
- コミットハッシュ:
09f1f5d76d648f9dcdc86ff814b7e463ecca93df
- 作者: Russ Cox rsc@golang.org
- コミット日時: 2012年7月30日 月曜日 10:13:54 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/09f1f5d76d648f9dcdc86ff814b7e463ecca93df
元コミット内容
misc/dashboard/codereview: add LastUpdate field to CL
To be filled in by a later CL. I deployed a test version to
App Engine to work on setting the values, so there are
a few records that have this field set already.
That field is breaking the live version, so I have pushed
a new copy with this 1-line change to the live version
I assumed that appengine/datastore was like every other
marshaling and unmarshaling package we have in Go
(for example, encoding/gob, encoding/json, encoding/xml,
and protobuf) and that if it loaded an unknown field it would
just ignore it. Apparently not. Sorry.
R=dsymonds
TBR=dsymonds
CC=golang-dev
https://golang.org/cl/6454064
変更の背景
このコミットの背景には、Go言語のコードレビューダッシュボードシステムにおける、Google App Engine Datastoreの挙動に関する予期せぬ問題がありました。
元々、開発者はCL
構造体にLastUpdate
という新しいフィールドを追加し、その値を設定するためのテストバージョンをApp Engineにデプロイしていました。このテストデプロイメントにより、Datastoreには既にLastUpdate
フィールドが設定されたレコードがいくつか存在していました。
しかし、この新しいフィールドが、本番環境で稼働している既存のアプリケーションを破壊するという問題が発生しました。開発者(Russ Cox氏)は、Go言語の他のマーシャリング/アンマーシャリングパッケージ(encoding/gob
, encoding/json
, encoding/xml
, protobuf
など)と同様に、appengine/datastore
も未知のフィールドを読み込んだ際にそれを無視すると考えていました。しかし、実際にはappengine/datastore
はそのような挙動をせず、未知のフィールドが存在するとエラーを引き起こすことが判明しました。
この問題を解決するため、本番環境のアプリケーションが、テストデプロイメントによってDatastoreに書き込まれたLastUpdate
フィールドを持つレコードを正常に処理できるように、CL
構造体にLastUpdate
フィールドを正式に追加する緊急の1行変更がこのコミットで行われました。これにより、本番環境のアプリケーションがDatastoreからデータを読み込む際に、LastUpdate
フィールドが未知のフィールドとして扱われなくなり、エラーが解消されました。
前提知識の解説
Google App Engine (GAE)
Google App Engineは、Googleが提供するPlatform as a Service (PaaS) です。開発者はインフラストラクチャの管理を気にすることなく、アプリケーションをデプロイ・実行できます。Go言語はApp Engineでサポートされている言語の一つです。
Google App Engine Datastore
App Engine Datastoreは、Google App Engine上で利用できるNoSQLドキュメントデータベースです。スケーラビリティと可用性に優れており、Webアプリケーションのバックエンドデータストアとしてよく利用されます。Datastoreは、エンティティ(データレコード)とプロパティ(フィールド)の概念を持ち、スキーマレスなデータモデルをサポートしています。
Go言語における構造体とマーシャリング/アンマーシャリング
Go言語では、構造体(struct)は関連するデータをまとめるための型です。構造体のフィールドには、json:"field_name"
やxml:"field_name"
のような「構造体タグ」を付与することができます。これらのタグは、encoding/json
やencoding/xml
といった標準ライブラリのマーシャリング(Goのデータ構造を外部形式に変換)およびアンマーシャリング(外部形式をGoのデータ構造に変換)処理において、フィールド名やその他の挙動を制御するために使用されます。
- マーシャリング (Marshaling): Goのデータ構造(例: 構造体)を、JSON、XML、バイナリなどの外部形式に変換するプロセス。
- アンマーシャリング (Unmarshaling): JSON、XML、バイナリなどの外部形式のデータを、Goのデータ構造に変換するプロセス。
多くのマーシャリング/アンマーシャリングライブラリ(encoding/json
, encoding/gob
, encoding/xml
, protobuf
など)は、デフォルトで、入力データにGoの構造体で定義されていない未知のフィールドが含まれていても、それを無視して処理を続行する挙動をします。これは、前方互換性や後方互換性を保つ上で非常に便利な特性です。例えば、新しいバージョンのAPIが追加フィールドを返すようになっても、古いクライアントは既存のフィールドのみを処理し、未知のフィールドは安全に無視できます。
datastore
構造体タグ
App Engine Datastoreを使用する際、Goの構造体をDatastoreのエンティティにマッピングするために、datastore
タグが使用されます。例えば、datastore:",noindex"
は、そのフィールドがDatastoreでインデックス付けされないことを示します。
技術的詳細
このコミットの核心的な問題は、appengine/datastore
のアンマーシャリング挙動が、Go標準ライブラリや一般的なデータシリアライゼーションライブラリのそれと異なっていた点にあります。
通常、Goのencoding/json
やencoding/xml
などのパッケージは、Goの構造体に対応しないフィールドが入力データに含まれていても、デフォルトでそれらを無視します。これにより、データ形式の進化や異なるバージョンのアプリケーション間での互換性が保たれやすくなります。
しかし、appengine/datastore
は、Goの構造体で定義されていないプロパティ(フィールド)がDatastoreのエンティティに存在する場合、それを未知のフィールドとして扱い、アンマーシャリング時にErrFieldMismatch
エラーを発生させます。これは、データ読み書き時の意図しないデータ損失を防ぐための設計選択です。
今回のケースでは、開発者がテスト目的でCL
構造体にLastUpdate
フィールドを追加し、そのテストバージョンをApp Engineにデプロイした結果、DatastoreにはLastUpdate
プロパティを持つエンティティが作成されました。その後、このテストバージョンとは異なる、LastUpdate
フィールドがまだ追加されていない本番環境のアプリケーションがこれらのエンティティを読み込もうとした際に、appengine/datastore
がLastUpdate
プロパティを未知のフィールドとして認識し、ErrFieldMismatch
エラーを発生させてしまったのです。
この問題を解決するためには、本番環境のアプリケーションが使用するCL
構造体にもLastUpdate
フィールドを定義し、appengine/datastore
がそれを既知のプロパティとして認識できるようにする必要がありました。たとえそのフィールドがまだアプリケーションロジックで利用されていなくても、構造体に定義されていることで、Datastoreからの読み込みエラーを回避できます。
このコミットは、この緊急の修正として、CL
構造体にLastUpdate string
フィールドを追加することで、本番環境のアプリケーションがDatastoreからデータを正常に読み込めるようにしました。これにより、Datastoreに存在するLastUpdate
プロパティが未知のフィールドとして扱われることがなくなり、アプリケーションのクラッシュが回避されました。
コアとなるコードの変更箇所
変更はmisc/dashboard/codereview/dashboard/cl.go
ファイル内のCL
構造体に対して行われました。
--- a/misc/dashboard/codereview/dashboard/cl.go
+++ b/misc/dashboard/codereview/dashboard/cl.go
@@ -49,6 +49,7 @@ type CL struct {
FirstLine string `datastore:",noindex"`
LGTMs []string
NotLGTMs []string
+ LastUpdate string
// Mail information.
Subject string `datastore:",noindex"`
追加された行は以下の通りです。
LastUpdate string
コアとなるコードの解説
この変更は、CL
構造体にLastUpdate
という名前の新しいフィールドを追加しています。このフィールドの型はstring
です。
type CL struct { ... }
は、Go言語における構造体の定義です。この構造体は、コードレビューシステムにおける「変更リスト」(Change List、略してCL)の情報を表現するためのデータモデルとして機能します。
LastUpdate string
を追加することで、appengine/datastore
がDatastoreからエンティティを読み込む際に、LastUpdate
という名前のプロパティが存在しても、それを未知のフィールドとして扱わなくなります。これにより、Datastoreからのデータ読み込み時に発生していたエラーが解消されます。
この時点では、LastUpdate
フィールドにdatastore
タグは付与されていませんが、Goのappengine/datastore
パッケージは、構造体のフィールド名とDatastoreのプロパティ名をデフォルトでマッピングします。したがって、このシンプルな追加で問題が解決されました。コミットメッセージにあるように、このフィールドへの値の設定は「後のCLで」行われる予定であり、このコミットはあくまで緊急の互換性修正として機能しています。
関連リンク
- Go CL 6454064: https://golang.org/cl/6454064
参考にした情報源リンク
- Go App Engine Datastore documentation (当時の情報に基づく推測): https://cloud.google.com/appengine/docs/standard/go/datastore/reference (現在のドキュメントは変更されている可能性があります)
- Go
encoding/json
package: https://pkg.go.dev/encoding/json - Go
encoding/xml
package: https://pkg.go.dev/encoding/xml - Go
encoding/gob
package: https://pkg.go.dev/encoding/gob - Protocol Buffers (Go): https://developers.google.com/protocol-buffers/docs/reference/go-generated
- Go App Engine Datastore
ErrFieldMismatch
behavior: https://cloud.google.com/appengine/docs/standard/go/datastore/reference#PropertyLoadSaver (現在のドキュメントにおける関連情報)