# 画面設計書 167-WLM統計一覧

## 概要

本ドキュメントは、OpenSearchのWLM Stats List API（`GET /_list/wlm_stats`）の画面設計書である。ワークロード管理（Workload Management）の統計をページネーション付きで返すREST APIエンドポイントについて、入出力仕様・処理フロー・データベース影響等を定義する。

### 本画面の処理概要

WLM Stats List APIは、クラスタ内の各ノードにおけるワークロードグループの統計情報（完了数、拒否数、キャンセル数、CPU使用率、メモリ使用率）を、ページネーション付きのテーブル形式で返すAPIエンドポイントである。

**業務上の目的・背景**：ワークロード管理（WLM）機能において、各ワークロードグループの実行統計を監視する必要がある。本APIにより、ノードごと・ワークロードグループごとの完了クエリ数、拒否クエリ数、キャンセルクエリ数、CPU/メモリ使用率を確認でき、ワークロードグループの負荷バランスや制限違反の検出を支援する。ページネーションにより大量の統計情報を効率的に取得できる。

**画面へのアクセス方法**：HTTPクライアントから `GET /_list/wlm_stats` にリクエストを送信する。ノードIDやワークロードグループIDによるフィルタリングも可能。

**主要な操作・処理内容**：
1. WlmStatsRequestを構築し、クラスタ全体のWLM統計を取得する
2. WlmPaginationStrategyで統計をワークロードグループ単位に展開・ソートする
3. next_tokenを使用してページネーション位置を特定する
4. pageSizeに基づいてサブセットを返す
5. 次ページがある場合はnext_tokenを生成してレスポンスに含める

**画面遷移**：本APIは`/_list/wlm_stats`パスの場合にテーブル形式で返す。`/_wlm/stats`パスではJSON形式の詳細統計を返す（同一RestWlmStatsActionが処理）。

**権限による表示制御**：セキュリティプラグイン導入時は、WLM関連の権限が必要。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 101 | ワークロードグループ管理 | 主機能 | WLM統計をページネーション付きで返す処理 |
| 102 | ワークロード管理プラグイン | 補助機能 | ワークロード管理プラグインによる統計収集処理 |

## 画面種別

一覧（テーブル形式表示、ページネーション付き）

## URL/ルーティング

| メソッド | パス | 説明 |
|---------|------|------|
| GET | `/_list/wlm_stats` | WLM統計をテーブル形式で返す（ページネーション対応） |
| GET | `/_list/wlm_stats/{nodeId}/stats` | 指定ノードのWLM統計を返す |
| GET | `/_list/wlm_stats/stats/{workloadGroupId}` | 指定ワークロードグループの統計を返す |
| GET | `/_list/wlm_stats/{nodeId}/stats/{workloadGroupId}` | 指定ノード・グループの統計を返す |
| GET | `/_wlm/stats` | WLM統計をJSON形式で返す |
| GET | `/_wlm/{nodeId}/stats` | 指定ノードのWLM統計をJSONで返す |
| GET | `/_wlm/stats/{workloadGroupId}` | 指定グループの統計をJSONで返す |
| GET | `/_wlm/{nodeId}/stats/{workloadGroupId}` | 指定ノード・グループの統計をJSONで返す |

## 入出力項目

### リクエストパラメータ

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
|-------------|------|------|-----------|------|
| nodeId | string | No | - | 対象ノードID（カンマ区切り） |
| workloadGroupId | string | No | _all | 対象ワークロードグループID（カンマ区切り） |
| size | int | No | 10 | 1ページあたりの件数（1-100） |
| next_token | string | No | - | ページネーショントークン |
| sort | string | No | node_id | ソートフィールド（node_id/workload_group） |
| order | string | No | asc | ソート順（asc/desc） |
| v | boolean | No | false | ヘッダを含めるか |
| breach | boolean | No | - | 違反フラグでフィルタ |

## 表示項目

| カラム名 | 説明 |
|---------|------|
| NODE_ID | ノードID |
| WORKLOAD_GROUP_ID | ワークロードグループID |
| TOTAL_COMPLETIONS | 完了クエリ総数 |
| TOTAL_REJECTIONS | 拒否クエリ総数 |
| TOTAL_CANCELLATIONS | キャンセルクエリ総数 |
| CPU_USAGE | CPU使用率 |
| MEMORY_USAGE | メモリ使用率 |

注: カラム間は`|`区切りで表示される。

## イベント仕様

### 1-GETリクエスト受信（テーブル形式）

1. `RestWlmStatsAction.prepareRequest()`がリクエストを受信する
2. パスが`/_list/wlm_stats`で始まる場合、`handleTabularRequest()`に処理を委譲する
3. `WlmStatsRequest`を構築し、`client.admin().cluster().wlmStats()`を実行する
4. `WlmPaginationStrategy`を生成し、ページネーション処理を行う
5. `createTableWithHeaders()`でページトークン付きテーブルヘッダを構築する
6. `buildTable()`でワークロードグループごとにテーブル行を構築する
7. 最終ページの場合は"No more pages available"のフッター行を追加する

### 2-ページネーションエラー

1. next_tokenが無効または期限切れの場合、`OpenSearchParseException`が発生する
2. `handlePaginationError()`でユーザー向けエラーメッセージとともに400エラーを返す

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| GETリクエスト | - | SELECT | WLM統計情報を参照のみ。データ更新なし |

## メッセージ仕様

| 種別 | 条件 | メッセージ/レスポンス |
|------|------|---------------------|
| 成功 | 正常取得時 | テーブル形式のWLM統計（HTTPステータス200） |
| 成功 | 最終ページ | テーブル + "No more pages available"フッター行 |
| 成功 | 統計なし | 空テーブル（HTTPステータス200） |
| エラー | 無効なnext_token | "Pagination state has changed..."（HTTPステータス400） |
| エラー | 無効なsizeパラメータ | "Invalid value for 'size'. Allowed range: 1 to 100" |
| エラー | 無効なsortパラメータ | "Invalid value for 'sort'. Allowed: 'node_id', 'workload_group'" |
| エラー | 無効なorderパラメータ | "Invalid value for 'order'. Allowed: 'asc', 'desc'" |

## 例外処理

- `size`パラメータが0以下または100超の場合、`OpenSearchParseException`をスローする（行148-149）
- `sort`パラメータが無効な値の場合、`OpenSearchParseException`をスローする（行134）
- `order`パラメータが無効な値の場合、`OpenSearchParseException`をスローする（行142）
- `next_token`が無効または期限切れの場合、ユーザー向けメッセージとともに400エラーを返す（行154-180）
- ページネーション中にワークロードグループが追加/削除された場合、ハッシュ不一致によりトークンが無効化される
- CPU/メモリ統計が利用不可の場合は"NA"を表示する（行220-221）

## 備考

- 本APIは**experimental**（実験的）ステータスである
- `/_list/wlm_stats`パスではテーブル形式、`/_wlm/stats`パスではJSON形式を返す
- ページネーショントークンはSHA-256ハッシュで整合性を検証する
- デフォルトページサイズは10、最大は100
- ソートフィールドはnode_idとworkload_groupの2種類
- ワークロードグループの追加/削除によりページネーション状態が変化した場合、トークンは無効化される
- フッター行"No more pages available"は最終ページのみに追加される
- ResourceTypeとしてCPUとMEMORYが定義されている

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wlm_stats_list.json | `rest-api-spec/src/main/resources/rest-api-spec/api/wlm_stats_list.json` | APIパス・パラメータ定義 |
| 1-2 | WlmStats.java | `server/src/main/java/org/opensearch/wlm/stats/WlmStats.java` | WLM統計データ構造（node, workloadGroupStats） |
| 1-3 | WorkloadGroupStats.java | `server/src/main/java/org/opensearch/wlm/stats/WorkloadGroupStats.java` | ワークロードグループ統計（completions, rejections, cancellations, resourceStats） |
| 1-4 | SortBy.java | `server/src/main/java/org/opensearch/wlm/stats/SortBy.java` | ソートフィールド列挙（NODE_ID, WORKLOAD_GROUP） |
| 1-5 | SortOrder.java | `server/src/main/java/org/opensearch/wlm/stats/SortOrder.java` | ソート順列挙（ASC, DESC） |

**読解のコツ**: WlmStatsがノード単位、WorkloadGroupStats.WorkloadGroupStatsHolderがワークロードグループ単位の統計であることを理解する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestWlmStatsAction.java | `server/src/main/java/org/opensearch/rest/action/admin/cluster/RestWlmStatsAction.java` | BaseRestHandlerを継承したRESTハンドラ |

**主要処理フロー**:
1. **行59-72**: ルート定義（8パス）。`/_list/wlm_stats`系と`/_wlm/stats`系の両方を処理
2. **行80-97**: `prepareRequest()`でパスに基づきテーブル形式/JSON形式を判定
3. **行99-128**: `handleTabularRequest()`でページネーション付きテーブルレスポンスを構築
4. **行182-199**: `createTableWithHeaders()`で7カラム+区切り文字カラムを定義
5. **行202-224**: `addRow()`でワークロードグループごとの行を構築
6. **行238-255**: `buildTable()`でWlmStatsからテーブルを構築

#### Step 3: ページネーションロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WlmPaginationStrategy.java | `server/src/main/java/org/opensearch/action/pagination/WlmPaginationStrategy.java` | ページネーション戦略の実装 |

**主要処理フロー**:
- **行44-60**: コンストラクタでページネーション処理を実行（ハッシュ計算、トークン検証、ページ取得）
- **行93-109**: `applyPagination()`でワークロードグループ単位に展開、ソート、サブセット取得
- **行112-123**: `extractWorkloadGroupStats()`でノード単位をワークロードグループ単位に展開
- **行125-137**: `getStartIndex()`でトークンから開始位置を特定
- **行144-164**: `setResponseToken()`で次ページトークンを生成（SHA-256暗号化）
- **行190-272**: `WlmStrategyToken`内部クラスでトークンの生成・解析・検証

### プログラム呼び出し階層図

```
RestWlmStatsAction.prepareRequest() [行80]
    |
    +-- パス判定 [行91-96]
    |       +-- /_list/wlm_stats -> handleTabularRequest()
    |       +-- /_wlm/stats -> JSON形式レスポンス
    |
    +-- handleTabularRequest() [行99]
    |       |
    |       +-- WlmStatsRequest 構築 [行84]
    |       +-- client.admin().cluster().wlmStats() [行109]
    |       |       |
    |       |       +-- WlmStatsAction
    |       |               +-- 各ノードからWLM統計収集
    |       |
    |       +-- WlmPaginationStrategy 生成 [行113]
    |       |       +-- extractWorkloadGroupStats()
    |       |       +-- ソート(sortBy, sortOrder)
    |       |       +-- getStartIndex(token)
    |       |       +-- getPage(pageSize)
    |       |       +-- setResponseToken()
    |       |
    |       +-- createTableWithHeaders() [行118]
    |       +-- buildTable() [行119]
    |       |       +-- addRow() ループ
    |       |       +-- addFooterRow() (最終ページ時)
    |       |
    |       +-- RestTable.buildResponse() [行121]
```

### データフロー図

```
[入力]                        [処理]                          [出力]

GET /_list/wlm_stats    ---> RestWlmStatsAction            テーブル形式
  ?size=10                    |                              レスポンス
  &next_token=xxx             +-> WlmStatsAction             + next_token
  &sort=node_id               |     +-> 各ノードWLM統計
  &order=asc                  +-> WlmPaginationStrategy
                              |     +-> 展開・ソート
                              |     +-> ページ切り出し
                              |     +-> トークン生成
                              +-> buildTable()
                              +-> RestTable.buildResponse()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RestWlmStatsAction.java | `server/src/main/java/org/opensearch/rest/action/admin/cluster/RestWlmStatsAction.java` | ソース | RESTエンドポイントハンドラ |
| WlmPaginationStrategy.java | `server/src/main/java/org/opensearch/action/pagination/WlmPaginationStrategy.java` | ソース | ページネーション戦略 |
| WlmStatsRequest.java | `server/src/main/java/org/opensearch/action/admin/cluster/wlm/WlmStatsRequest.java` | ソース | リクエストオブジェクト |
| WlmStatsResponse.java | `server/src/main/java/org/opensearch/action/admin/cluster/wlm/WlmStatsResponse.java` | ソース | レスポンスオブジェクト |
| WlmStats.java | `server/src/main/java/org/opensearch/wlm/stats/WlmStats.java` | ソース | WLM統計データ構造 |
| WorkloadGroupStats.java | `server/src/main/java/org/opensearch/wlm/stats/WorkloadGroupStats.java` | ソース | ワークロードグループ統計 |
| SortBy.java | `server/src/main/java/org/opensearch/wlm/stats/SortBy.java` | ソース | ソートフィールド定義 |
| SortOrder.java | `server/src/main/java/org/opensearch/wlm/stats/SortOrder.java` | ソース | ソート順定義 |
| ResourceType.java | `server/src/main/java/org/opensearch/wlm/ResourceType.java` | ソース | リソースタイプ（CPU/MEMORY） |
| wlm_stats_list.json | `rest-api-spec/src/main/resources/rest-api-spec/api/wlm_stats_list.json` | 設定 | REST APIスペック定義 |
| RestWlmStatsActionTests.java | `server/src/test/java/org/opensearch/rest/action/admin/cluster/RestWlmStatsActionTests.java` | テスト | ユニットテスト |
