2025 年 3 月 27 日より、AOSP のビルドとコントリビューションには aosp-main
ではなく android-latest-release
を使用することをおすすめします。詳細については、AOSP の変更をご覧ください。
VTS ダッシュボード データベース
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
VTS ダッシュボード バックエンドは、スケーラビリティ、パフォーマンス、柔軟性に優れた継続的インテグレーション ダッシュボードをサポートできるよう、データベースの機能を十分に理解したうえで慎重に設計する必要があります。Google Cloud Datastore は、トランザクション ACID 保証と、エンティティ グループ内での結果整合性、強整合性を提供する NoSQL データベースです。
ただし、SQL データベースとは(そして Cloud Bigtable とさえも)大きく構造が異なります。テーブル、行、セルの代わりに、種類、エンティティ、プロパティを使用します。
以降のセクションでは、VTS ダッシュボード ウェブサービスに有効なバックエンドを作成するためのデータ構造とクエリパターンの概要を説明します。
エンティティ
次のエンティティは、VTS テスト実行からのサマリーとリソースを格納します。
- テスト エンティティ。特定のテストのテスト実行に関するメタデータを格納します。キーはテスト名です。プロパティには、アラートジョブが更新したときからの、不合格の数、合格の数、テストケースの中断のリストが含まれています。
- テスト実行エンティティ。特定のテストの実行に関するメタデータを格納します。テストの開始と終了のタイムスタンプ、テストビルド ID、テストケースの数、実行のタイプ(送信前、送信後、ローカル)、ログリンクのリスト、ホストマシン名、カバレッジ サマリーの数を格納しなければなりません。
- デバイス情報エンティティ。テスト実行中に使用されたデバイスの詳細が含まれます。デバイスビルド ID、製品名、ビルド ターゲット、ブランチ、ABI 情報などです。テスト実行エンティティとは別に格納され、1 対多の形でマルチデバイスのテスト実行をサポートします。
- ポイント実行エンティティのプロファイリング。テスト実行内の特定のプロファイリング ポイントで収集されたデータの集計結果です。プロファイリング データの軸ラベル、プロファイリング ポイント名、値、タイプ、回帰モードが示されます。
- カバレッジ エンティティ。1 つのファイルに対して収集されたカバレッジ データを示します。Git のプロジェクト情報、ファイルパス、ソースファイル内の 1 行ごとのカバレッジ数のリストが含まれています。
- テストケース実行エンティティ。テスト実行における特定のテストケースの結果(テストケース名とその結果など)を示します。
- ユーザーのお気に入りエンティティ。各ユーザー サブスクリプションは、テストへの参照と App Engine ユーザー サービスから生成されたユーザー ID を含むエンティティで表すことができます。これにより、効率的な双方向クエリが可能になります。つまり、テストに登録されたすべてのユーザーに対してと、ユーザーがお気に入りに登録したすべてのテストに対してです。
エンティティのグループ化
各テスト モジュールは、エンティティ グループのルートを表します。テスト実行エンティティは、このグループの子であると同時に、それぞれのテストとテスト実行の祖先に関連するデバイス エンティティ、プロファイリング ポイント エンティティ、カバレッジ エンティティの親でもあります。
図 1. テスト エンティティの系図
重要な点: 系図を設計する際は、効率的で整合性のあるクエリ メカニズムを提供する必要性と、データベースによって適用される制限との間でバランスをとる必要があります。
メリット
整合性の要件により、トランザクションの結果は commit されるまで未来のオペレーションから見えず、過去のトランザクションは現在のオペレーションから見えます。Cloud Datastore では、エンティティのグループ化により、グループ内で読み書きの強整合性アイランドを作成します。この場合は、すべてのテスト実行とテスト モジュールに関するデータです。これには次の利点があります。
- アラートジョブによるテスト モジュールの状態の読み取りと更新は、アトミックなものとして扱うことができます。
- テスト モジュール内のテストケース結果が整合性のある状態で示されることが保証されます。
- 系図の木構造内でのクエリが高速化されます。
制限事項
エンティティ グループへの書き込みを 1 秒あたり 1 エンティティを超える速度で行うと、書き込みが拒否される可能性があるため、推奨されません。アラートジョブとアップロードによる書き込みが 1 秒あたり 1 回を超える速度で行われない限り、構造は破綻せず、強整合性が保証されます。
最終的には、1 テスト モジュール、1 秒あたり 1 回の書き込みという上限は妥当です。通常、テスト実行には VTS フレームワークのオーバーヘッドを含めて 1 分以上かかります。60 台以上のホストで同時にテストを実行しない限り、書き込みのボトルネックは発生しません。各モジュールが 1 時間以上かかるテストプランの一部である場合、このようなことが起こる可能性はさらに低くなります。ホストが同時にテストを実行し、同じホストへのバースト書き込みを引き起こす場合、異常に対処するのは簡単です(例: 書き込みエラーを捉えて再試行するなど)。
スケーリングに関する考慮事項
テスト実行がテストを親として持つ必要は必ずしもありません。たとえば、他のキーを取り、プロパティとしてテスト名やテスト開始時刻を持つこともできます。ただし、強整合性はなくなり、結果整合性に留まることになります。たとえば、アラートジョブから見て、テスト モジュール内にある最新のテスト実行のスナップショットに、テスト実行間での相互の整合性がない可能性があります。これは、グローバルな状態に表れるテスト実行のシーケンスは完全に正確なものではない可能性があるということです。このことは、実行シーケンスの整合性のあるスナップショットでは必ずしもない、単一のテスト モジュール内におけるテスト実行の見え方にも影響します。最終的なスナップショットは整合性のあるものになりますが、最新のデータでは保証されません。
テストケース
もう一つの潜在的なボトルネックは、多数のテストケースがある大規模なテストです。書き込みスループットの最大値を 1 秒あたり 1 エンティティ グループに制限することと、最大トランザクション サイズを 500 エンティティに制限することが効果的です。
一つの方法は、テスト実行を祖先として持つテストケースを指定することです。カバレッジ データ、プロファイリング データ、デバイス情報の保存方法と同様です。
図 2. テストケースをテスト実行の子孫にする(非推奨)
この方法でアトミック性と整合性が得られますが、トランザクションが 500 エンティティに制限されている場合、テストに 498 個を超えるテストケース(カバレッジやプロファイリング データはないものとする)を持たせることができないという強い制限が発生します。
テストがこれを超える場合、1 つのトランザクションでテストケースの結果を一度にすべて書き込むことができず、テストケースを別々のトランザクションに分割すると 1 秒あたり 1 回というエンティティ グループ書き込みの最大スループットを超える可能性があります。この方法は、パフォーマンスを犠牲にすることなくスケールさせることができないため、推奨されません。
ただし、テストケースの結果をテスト実行の子として保存する代わりに、下図のように、テストケースを独立に保存し、そのキーをテスト実行に渡すこともできます(テスト実行にそのテストケース エンティティの ID のリストを持たせます)。
図 3. 独立して保存されたテストケース(推奨)
一見すると、これは強整合性の保証を破るように見えるかもしれません。
しかし、クライアントがテスト実行エンティティとテストケースの ID のリストを持っている場合、クエリを作成する必要はありません。テストケースを ID で直接取得することができ、常に整合性が保証されます。この方法により、エンティティ グループ内で過度の書き込みが発生する恐れなしに強整合性を獲得しながら、テスト実行が持つことのできるテストケースの数の制限を大幅に緩和します。
データアクセス パターン
VTS ダッシュボードでは、次のデータアクセス パターンが使用されます。
- ユーザーのお気に入り。特定の App Engine ユーザー オブジェクトをプロパティとして持つユーザーのお気に入りエンティティに関する等値フィルタを使用して、クエリを実行できます。
- テストリスト。テスト エンティティの単純なクエリ。ホームページのレンダリングに使用される帯域幅を減らすために、合格と不合格の数に予測値を使用して、アラートジョブで使用される不合格になったテストケースの ID とその他のメタデータの長いリストを省略できます。
- テスト実行。テスト実行エンティティにクエリを実行するには、キー(タイムスタンプ)での並べ替えと、ビルド ID、合格回数などのテスト実行プロパティでの適当なフィルタリングが必要です。テスト エンティティ キーを使用して祖先クエリを実行すると、読み取りは強整合となります。この時点で、すべてのテストケースの結果は、テスト実行プロパティに格納されている ID のリストを使用して取得できます。これもデータストアの get オペレーションの性質によって強整合性が保証されます。
- プロファイリングとカバレッジ データ。テストに関連するプロファイリング データやカバレッジ データに対するクエリを、他のテスト実行データ(他のプロファイリング データやカバレッジ データ、テストケース データなど)を取得することなく、実行できます。テストとテスト実行エンティティ キーを使用する祖先クエリでは、テスト実行中に記録されたすべてのプロファイリング ポイントが取得されます。プロファイリング ポイント名またはファイル名でのフィルタリングも行うことで、単一のプロファイリング エンティティまたはカバレッジ エンティティを取得できます。祖先クエリの性質により、このオペレーションには強整合性があります。
これらのデータパターンの実際の UI とスクリーンショットの詳細については、VTS ダッシュボードの UI をご覧ください。
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2025-07-27 UTC。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-07-27 UTC。"],[],[],null,["# VTS Dashboard database\n\nTo support a continuous integration dashboard that is scalable, performant, and\nflexible, the VTS Dashboard backend must be carefully designed with a strong\nunderstanding of database functionality.\n[Google Cloud\nDatastore](https://cloud.google.com/datastore/docs/) is a NoSQL database that offers transactional ACID guarantees and\neventual consistency as well as strong consistency within entity groups.\nHowever, the structure is very different than SQLdatabases (and even Cloud\nBigtable); instead of tables, rows, and cells there are kinds, entities, and\nproperties.\n\n\nThe following sections outline the data structure and querying patterns for\ncreating an effective backend for the VTS Dashboard web service.\n\nEntities\n--------\n\n\nThe following entities store summaries and resources from VTS test runs:\n\n- **Test Entity**. Stores metadata about test runs of a particular test. Its key is the test name and its properties include the failure count, passing count, and list of test case breakages from when the alert jobs update it.\n- **Test Run Entity**. Contains metadata from runs of a particular test. It must store the test start and end timestamps, the test build ID, the number of passing and failing test cases, the type of run (e.g. pre-submit, post-submit, or local), a list of log links, the host machine name, and coverage summary counts.\n- **Device Information Entity**. Contains details about the devices used during the test run. It includes the device build ID, product name, build target, branch, and ABI information. This is stored separately from the test run entity to support multi-device test runs in a one-to-many fashion.\n- **Profiling Point Run Entity**. Summarizes the data gathered for a particular profiling point within a test run. It describes the axis labels, profiling point name, values, type, and regression mode of the profiling data.\n- **Coverage Entity**. Describes the coverage data gathered for one file. It contains the Git project information, file path, and the list of coverage counts per line in the source file.\n- **Test Case Run Entity**. Describes the outcome of a particular test case from a test run, including the test case name and its result.\n- **User Favorites Entity**. Each user subscription can be represented in an entity containing a reference to the test and the user ID generated from the App Engine user service. This allows for efficient bi-directional querying (i.e. for all users subscribed to a test and for all tests favorited by a user).\n\nEntity grouping\n---------------\n\n\nEach test module represents the root of an entity group. Test run entities\nare both children of this group and parents for device entities, profiling point\nentities, and coverage entities relevant to the respective test and test run\nancestor.\n**Figure 1**. Test entity ancestry.\n\n**Key Point:** When designing ancestry\nrelationships, you must balance the need to provide effective and consistent\nquerying mechanisms against the limitations enforced by the database.\n\n### Benefits\n\n\nThe consistency requirement ensures that future operations will not see the\neffects of a transaction until it commits, and that transactions in the past are\nvisible to present operations. In Cloud Datastore, entity grouping creates\nislands of strong read and write consistency within the group, which in this\ncase is all of test runs and data related to a test module. This offers the\nfollowing benefits:\n\n- Reads and updates to test module state by alert jobs can be treated as atomic\n- Guaranteed consistent view of test case results within test modules\n- Faster querying within ancestry trees\n\n### Limitations\n\n\nWriting to an entity group at a rate faster than one entity per second is not\nadvised as some writes may be rejected. As long as the alert jobs and the\nuploading does not happen at a rate faster than one write per second, the\nstructure is solid and guarantees strong consistency.\n\n\nUltimately, the cap of one write per test module per second is reasonable because\ntest runs usually take at least one minute including the overhead of the VTS\nframework; unless a test is consistently being executed simultaneously on more\nthan 60 different hosts, there cannot be a write bottleneck. This becomes even\nmore unlikely given that each module is part of a test plan which often takes\nlonger than one hour. Anomalies can easily be handled if hosts run the tests at\nthe same time, causing short bursts of writes to the same hosts (e.g. by\ncatching write errors and trying again).\n\n### Scaling considerations\n\n\nA test run doesn't necessarily need to have the test as its parent (e.g. it\ncould take some other key and have test name, test start time as properties);\nhowever, this will exchange strong consistency for eventual consistency. For\ninstance, the alert job may not see a mutually consistent snapshot of the most\nrecent test runs within a test module, which means that the global state may not\ndepict a fully accurate representation of sequence of test runs. This may also\nimpact the display of test runs within a single test module, which may not\nnecessarily be a consistent snapshot of the run sequence. Eventually the\nsnapshot will be consistent, but there are no guarantees the freshest data\nwill be.\n\nTest cases\n----------\n\n\nAnother potential bottleneck is large tests with many test cases. The two\noperative constraints are the write throughput maximum within of an entity group\nof one per second, along with a maximum transaction size of 500 entities.\n\n\nOne approach would be to specify a test case that has a test run as an ancestor\n(similar to how coverage data, profiling data, and device information\nare stored):\n**Figure 2**. Test Cases descend from Test Runs (NOT RECOMMENDED).\n\nWhile this approach offers atomicity and consistency, it imposes strong\nlimitations on tests: If a transaction is limited to 500 entities, then a test\ncan have no more than 498 test cases (assuming no coverage or profiling data).\nIf a test were to exceed this, then a single transaction could not write all of\nthe test case results at once, and dividing the test cases into separate\ntransactions could exceed the maximum entity group write throughput of one\niteration per second. As this solution will not scale well without sacrificing\nperformance, it is not recommended.\n\n\nHowever, instead of storing the test case results as children of the test run,\nthe test cases can be stored independently and their keys provided to the test\nrun (a test run contains a list of identifiers to its test cases entities):\n**Figure 3**. Test Cases stored independently (RECOMMENDED).\n\n\nAt first glance, this may appear to break the strong consistency guarantee.\nHowever, if the client has a test run entity and a list of test case\nidentifiers, it doesn't need to construct a query; it can instead directly get\nthe test cases by their identifiers, which is always guaranteed to be\nconsistent. This approach vastly alleviates the constraint on the number of test\ncases a test run may have while gaining strong consistency without threatening\nexcessive writing within an entity group.\n\nData access patterns\n--------------------\n\n\nThe VTS Dashboard uses the following data access patterns:\n\n- **User favorites**. Can be queried for by using an equality filter on user favorites entities having the particular App Engine User object as a property.\n- **Test listing**. Simple query of test entities. To reduce bandwidth to render the home page, a projection can be used on passing and failing counts so as to omit the potentially long listing of failed test case IDs and other metadata used by the alerting jobs.\n- **Test runs**. Querying for test run entities requires a sort on the key (timestamp) and possible filtering on the test run properties such as build ID, passing count, etc. By performing an ancestor query with a test entity key, the read is strongly consistent. At this point, all of the test case results can be retrieved using the list of IDs stored in a test run property; this also is guaranteed to be a strongly consistent outcome by the nature of datastore get operations.\n- **Profiling and coverage data**. Querying for profiling or coverage data associated with a test can be done without also retrieving any other test run data (such as other profiling/coverage data, test case data, etc.). An ancestor query using the test test and test run entity keys will retrieve all profiling points recorded during the test run; by also filtering on the profiling point name or filename, a single profiling or coverage entity can be retrieved. By the nature of ancestor queries, this operation is strongly consistent.\n\n\nFor details on the UI and screenshots of these data patterns in action, see\n[VTS Dashboard UI](/docs/core/tests/vts/ui)."]]