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

[インデックス 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/jsonencoding/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/jsonencoding/xmlなどのパッケージは、Goの構造体に対応しないフィールドが入力データに含まれていても、デフォルトでそれらを無視します。これにより、データ形式の進化や異なるバージョンのアプリケーション間での互換性が保たれやすくなります。

しかし、appengine/datastoreは、Goの構造体で定義されていないプロパティ(フィールド)がDatastoreのエンティティに存在する場合、それを未知のフィールドとして扱い、アンマーシャリング時にエラーを発生させました。

今回のケースでは、開発者がテスト目的でCL構造体にLastUpdateフィールドを追加し、そのテストバージョンをApp Engineにデプロイした結果、DatastoreにはLastUpdateプロパティを持つエンティティが作成されました。その後、このテストバージョンとは異なる、LastUpdateフィールドがまだ追加されていない本番環境のアプリケーションがこれらのエンティティを読み込もうとした際に、appengine/datastoreLastUpdateプロパティを未知のフィールドとして認識し、エラーを発生させてしまったのです。

この問題を解決するためには、本番環境のアプリケーションが使用する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で」行われる予定であり、このコミットはあくまで緊急の互換性修正として機能しています。

関連リンク

参考にした情報源リンク

[インデックス 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/jsonencoding/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/jsonencoding/xmlなどのパッケージは、Goの構造体に対応しないフィールドが入力データに含まれていても、デフォルトでそれらを無視します。これにより、データ形式の進化や異なるバージョンのアプリケーション間での互換性が保たれやすくなります。

しかし、appengine/datastoreは、Goの構造体で定義されていないプロパティ(フィールド)がDatastoreのエンティティに存在する場合、それを未知のフィールドとして扱い、アンマーシャリング時にErrFieldMismatchエラーを発生させます。これは、データ読み書き時の意図しないデータ損失を防ぐための設計選択です。

今回のケースでは、開発者がテスト目的でCL構造体にLastUpdateフィールドを追加し、そのテストバージョンをApp Engineにデプロイした結果、DatastoreにはLastUpdateプロパティを持つエンティティが作成されました。その後、このテストバージョンとは異なる、LastUpdateフィールドがまだ追加されていない本番環境のアプリケーションがこれらのエンティティを読み込もうとした際に、appengine/datastoreLastUpdateプロパティを未知のフィールドとして認識し、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で」行われる予定であり、このコミットはあくまで緊急の互換性修正として機能しています。

関連リンク

参考にした情報源リンク