# 画面設計書 21-Spark Connect Server Session Detail（Connectセッション詳細）

## 概要

本ドキュメントは、Spark Connect Serverの特定セッションの詳細情報とSQL実行履歴を表示する画面「Spark Connect Server Session Detail（Connectセッション詳細）」の設計書である。

### 本画面の処理概要

本画面は、Spark Connect Serverに接続された個別セッションの詳細情報と、そのセッションで実行されたSQL/リクエストの一覧を表示する画面である。

**業務上の目的・背景**：Spark Connect Serverでは複数のクライアントセッションが同時に接続し、それぞれ独立してSQLリクエストを発行する。運用管理者が特定セッションの利用状況を把握するため、セッション単位でのリクエスト実行履歴・実行時間・ステータスの確認が必要となる。本画面は、特定セッションに紐づく全リクエストの詳細を一覧表示することで、セッション単位のトラブルシュートや性能分析を可能にする。

**画面へのアクセス方法**：Spark Application UIのConnectタブ（/connect/）にあるSpark Connect Server Overview画面のSession Statisticsテーブルにおいて、セッションIDのリンクをクリックすることで本画面に遷移する。URLパラメータとしてセッションID（id）が必要である。

**主要な操作・処理内容**：
1. セッション基本情報の表示（Session ID、サーバー起動時刻、起動からの経過時間）
2. セッションユーザー情報の表示（ユーザー名、セッション作成日時、総リクエスト実行数）
3. Request Statisticsテーブルの表示（セッションに紐づくSQL実行履歴のページネーション付き一覧）
4. リクエスト統計テーブルのソート（カラムヘッダクリックによる昇順/降順切り替え）
5. 関連ジョブ・SQL実行詳細画面へのリンク遷移

**画面遷移**：
- 遷移元：Spark Connect Server Overview画面（No.20）のSession StatisticsテーブルからセッションID選択
- 遷移先：Jobs画面（Job Detail）へジョブIDリンクから遷移、SQL Execution Detail画面へSQL Query IDリンクから遷移

**権限による表示制御**：特になし。Spark UIのアクセス制御（spark.ui.filters等）に依存する。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | Spark Web UI | 主機能 | 特定Spark Connectセッションの詳細情報とSQL実行履歴をテーブル表示する主処理 |
| 80 | Spark Connectサーバー | 主機能 | セッションの開始時間・実行SQL一覧・ステータスを取得して表示 |

## 画面種別

詳細

## URL/ルーティング

- **URL**: `/connect/session/?id={sessionId}`
- **HTTPメソッド**: GET
- **パラメータ**: `id` - セッションID（必須）
- **ページ名（WebUIPage）**: `session`
- **親タブ**: SparkConnectServerTab（`/connect/`）

## 入出力項目

| 項目名 | 入出力 | 型 | 必須 | 説明 |
|--------|--------|------|------|------|
| id | 入力（URLパラメータ） | String | 必須 | 対象セッションID |
| sqlsessionstat.page | 入力（URLパラメータ） | Int | 任意 | SQLテーブルのページ番号（デフォルト: 1） |
| sqlsessionstat.sort | 入力（URLパラメータ） | String | 任意 | ソート対象カラム（デフォルト: "Start Time"） |
| sqlsessionstat.desc | 入力（URLパラメータ） | Boolean | 任意 | 降順ソートフラグ |
| sqlsessionstat.pageSize | 入力（URLパラメータ） | Int | 任意 | 1ページあたりの表示件数 |

## 表示項目

### 基本情報セクション

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| Session ID | URLパラメータ `id` | セッション識別子 |
| Started at | parent.startTime | サーバー起動日時 |
| Time since start | 現在時刻 - startTime | サーバー起動からの経過時間 |

### セッション概要セクション

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| User | sessionStat.userId | セッションのユーザーID |
| Session created at | sessionStat.startTimestamp | セッション作成日時 |
| Total run | sessionStat.totalExecution | 総リクエスト実行数 |

### Request Statisticsテーブル

| カラム名 | ソート可能 | 説明 |
|----------|-----------|------|
| User | はい | リクエスト実行ユーザー |
| Job ID | はい | 関連するSparkジョブID（リンク付き） |
| SQL Query ID | はい | 関連するSQL実行ID（リンク付き） |
| Start Time | はい | リクエスト開始日時 |
| Finish Time | はい | リクエスト終了日時 |
| Close Time | はい | リクエストクローズ日時 |
| Execution Time | はい | 実行時間（開始〜終了） |
| Duration | はい | 全体所要時間（開始〜クローズ） |
| Statement | はい | 実行SQL文 |
| State | はい | 実行状態（RUNNING/STARTED/COMPILED/READY/CANCELED/FAILED/FINISHED/CLOSED） |
| Operation ID | はい | オペレーション識別子 |
| Job Tag | はい | ジョブタグ |
| Spark Session Tags | はい | Sparkセッションタグ（カンマ区切り） |
| Detail | はい | 詳細情報（エラーメッセージ等） |

## イベント仕様

### 1-ページ読み込み

1. URLパラメータ `id` からセッションIDを取得する
2. `store.getSession(sessionId)` でセッション情報を取得する
3. セッションが存在しない場合、「No information to display for session {sessionId}」と表示する
4. セッションが存在する場合、基本情報と概要を生成する
5. `store.getExecutionList` から全実行情報を取得し、`sessionId` でフィルタリングする
6. フィルタリングされたリクエスト一覧を `SqlStatsPagedTable` でページネーション付きテーブルとして表示する

### 2-テーブルソート

カラムヘッダをクリックすると、該当カラムで昇順/降順ソートされたページに遷移する。ソート状態はURLパラメータ `sqlsessionstat.sort` および `sqlsessionstat.desc` で管理される。

### 3-ページネーション

テーブル下部のページ番号リンクをクリックすると、該当ページに遷移する。ページ番号はURLパラメータ `sqlsessionstat.page` で管理される。

### 4-ジョブIDリンク押下

Job IDカラムのリンクをクリックすると、`{basePath}/jobs/job/?id={jobId}` に遷移し、ジョブ詳細画面が表示される。

### 5-SQL Query IDリンク押下

SQL Query IDカラムのリンクをクリックすると、`{basePath}/SQL/execution/?id={sqlExecId}` に遷移し、SQL実行詳細画面が表示される。

### 6-Request Statisticsセクション折りたたみ

Request Statisticsのヘッダをクリックすると、`collapseTable` JavaScript関数が呼び出され、テーブルの表示/非表示が切り替わる。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ読み込み | SessionInfo（KVStore） | SELECT | セッション情報の取得 |
| ページ読み込み | ExecutionInfo（KVStore） | SELECT | リクエスト実行情報一覧の取得 |

### テーブル別更新項目詳細

#### SessionInfo（KVStore）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | sessionId | URLパラメータ `id` と一致 | KVStoreからの読み取り |
| SELECT | userId | - | セッションユーザー名 |
| SELECT | startTimestamp | - | セッション開始タイムスタンプ |
| SELECT | totalExecution | - | 総実行回数 |

#### ExecutionInfo（KVStore）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | sessionId | 対象セッションIDと一致するもの | フィルタリング条件 |
| SELECT | statement, userId, operationId, startTimestamp, finishTimestamp, closeTimestamp, state, jobId, sqlExecId, sparkSessionTags, detail, jobTag | - | テーブル表示用 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 発生条件 |
|-------------|------|--------------|----------|
| MSG-01 | 情報 | "No information to display for session {sessionId}" | セッションIDに対応するセッションが見つからない場合 |
| MSG-02 | 情報 | "No statistics have been generated yet." | セッションに紐づくリクエストが0件の場合 |
| MSG-03 | エラー | "Error while rendering job table: {exception}" | テーブルレンダリング中にIllegalArgumentExceptionまたはIndexOutOfBoundsExceptionが発生した場合 |

## 例外処理

| 例外 | 発生条件 | 処理 |
|------|----------|------|
| IllegalArgumentException | `id` パラメータが null または空文字の場合 | `require` によりエラーページ表示（"Missing id parameter"） |
| IllegalArgumentException | テーブルレンダリング時に無効なソートカラムが指定された場合 | エラーメッセージをアラートdivで表示 |
| IndexOutOfBoundsException | テーブルレンダリング時にページ番号が範囲外の場合 | エラーメッセージをアラートdivで表示 |

## 備考

- store.synchronized ブロック内で全データ取得が行われるため、ページ表示中のデータ一貫性が保証される
- Request Statisticsテーブルは `showSessionLink = false` で生成されるため、Session IDカラムは表示されない（既にセッション詳細画面にいるため）
- 本画面はSpark Connect Server使用時にのみConnectタブとして表示される
- ExecutionInfoのstate値はExecutionState列挙型（STARTED, COMPILED, READY, CANCELED, FAILED, FINISHED, CLOSED）に基づく
- isExecutionActiveがtrueの場合、State列には"RUNNING"と表示される（実際のstate値に関わらず）

---

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

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

### 推奨読解順序

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

まず、セッション情報とリクエスト実行情報のデータモデルを把握することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SparkConnectServerAppStatusStore.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerAppStatusStore.scala` | SessionInfo（76-91行目）: sessionId, startTimestamp, userId, finishTimestamp, totalExecution フィールドを確認。ExecutionInfo（93-126行目）: jobTag, statement, sessionId, startTimestamp, userId, operationId, sparkSessionTags, finishTimestamp, closeTimestamp, detail, state, jobId, sqlExecId フィールドを確認。ExecutionState列挙型（128-131行目）: STARTED, COMPILED, READY, CANCELED, FAILED, FINISHED, CLOSED を確認 |

**読解のコツ**: SessionInfo と ExecutionInfo は KVStore に永続化されるエンティティクラスであり、`@KVIndexParam` アノテーションがプライマリキー、`@KVIndex` アノテーションがセカンダリインデックスを示す。

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

処理の起点となるページクラスの `render` メソッドを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SparkConnectServerSessionPage.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerSessionPage.scala` | renderメソッド（38-64行目）: リクエストからセッションIDを取得し、store.getSession でセッション情報を取得。存在すれば基本統計とSQLテーブルを生成する流れを確認 |

**主要処理フロー**:
1. **39行目**: `request.getParameter("id")` でセッションIDを取得
2. **40行目**: `require` でセッションIDの存在チェック
3. **42行目**: `store.synchronized` ブロック開始（データ一貫性保証）
4. **44行目**: `store.getSession(sessionId)` でセッション情報取得
5. **46行目**: `generateBasicStats` でサーバー基本情報を生成
6. **59行目**: `generateSQLStatsTable` でリクエスト統計テーブルを生成
7. **63行目**: `UIUtils.headerSparkPage` でSparkページヘッダ付きHTMLとして出力

#### Step 3: 基本統計情報の生成処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SparkConnectServerSessionPage.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerSessionPage.scala` | generateBasicStatsメソッド（67-80行目）: Session ID、起動時刻、経過時間のHTML生成。generateSQLStatsTableメソッド（83-130行目）: ExecutionListのフィルタリングとページネーションテーブル生成 |

**主要処理フロー**:
- **84行目**: `store.getExecutionList` で全実行情報を取得
- **85行目**: `.filter(_.sessionId == sessionID)` で対象セッションの実行情報のみ抽出
- **96-103行目**: `SqlStatsPagedTable` を生成（`showSessionLink = false`）

#### Step 4: ページネーションテーブルの理解

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SparkConnectServerPage.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerPage.scala` | SqlStatsPagedTable（170-341行目）: ヘッダ定義・行レンダリング・ソート・ページリンク生成。SqlStatsTableDataSource（431-491行目）: データのソート処理。SessionStatsTableDataSource（493-526行目）: セッション統計テーブルのデータソース |

#### Step 5: データストアの理解

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | SparkConnectServerAppStatusStore.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerAppStatusStore.scala` | getSession（42-48行目）: KVStoreからSessionInfoを読み取る。getExecutionList（34-36行目）: KVStoreから全ExecutionInfoを取得。getTotalRunning（63-65行目）: アクティブ実行数のカウント |

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

```
SparkConnectServerSessionPage.render(request)
    |
    +-- request.getParameter("id")
    |
    +-- store.synchronized {
    |       |
    |       +-- store.getSession(sessionId)
    |       |       +-- KVStore.read(SessionInfo, sessionId)
    |       |
    |       +-- generateBasicStats(sessionId)
    |       |       +-- formatDate(startTime)
    |       |       +-- formatDurationVerbose(timeSinceStart)
    |       |
    |       +-- generateSQLStatsTable(request, sessionId)
    |               |
    |               +-- store.getExecutionList
    |               |       +-- KVStore.view(ExecutionInfo)
    |               |
    |               +-- .filter(_.sessionId == sessionID)
    |               |
    |               +-- SqlStatsPagedTable(showSessionLink=false)
    |                       |
    |                       +-- SqlStatsTableDataSource
    |                       |       +-- sqlStatsTableRow() [変換]
    |                       |       +-- ordering() [ソート]
    |                       |
    |                       +-- table(sqlTablePage)
    |                               +-- headers [ヘッダ生成]
    |                               +-- row() [各行生成]
    |                                       +-- jobURL() [ジョブリンク]
    |                                       +-- sqlURL() [SQLリンク]
    |   }
    |
    +-- UIUtils.headerSparkPage(request, "Spark Connect Session", content, parent)
```

### データフロー図

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

URLパラメータ "id"   ───> SparkConnectServerSessionPage   ───> HTML Page
                              |                                  |
KVStore                       |                                  +-- 基本統計情報
  +-- SessionInfo    ───> store.getSession()               ───> セッション概要
  +-- ExecutionInfo  ───> store.getExecutionList()         ───> Request Statistics
                              |                                テーブル
                         .filter(sessionId)                     |
                              |                                  +-- ページネーション
                         SqlStatsPagedTable                     +-- ソート
                              |                                  +-- Job/SQLリンク
                         SqlStatsTableDataSource
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SparkConnectServerSessionPage.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerSessionPage.scala` | ソース | セッション詳細画面のメインページクラス |
| SparkConnectServerPage.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerPage.scala` | ソース | SqlStatsPagedTable、SessionStatsPagedTable等のテーブルコンポーネント定義 |
| SparkConnectServerAppStatusStore.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerAppStatusStore.scala` | ソース | KVStoreラッパー、SessionInfo/ExecutionInfoデータモデル定義 |
| SparkConnectServerTab.scala | `sql/connect/server/src/main/scala/org/apache/spark/sql/connect/ui/SparkConnectServerTab.scala` | ソース | Connectタブの定義、ページ登録 |
| UIUtils.scala | `core/src/main/scala/org/apache/spark/ui/UIUtils.scala` | ソース | HTML生成ユーティリティ（headerSparkPage, formatDate, formatDurationVerbose等） |
| PagedTable.scala | `core/src/main/scala/org/apache/spark/ui/PagedTable.scala` | ソース | ページネーション付きテーブルの基底クラス |
