# 画面設計書 7-Storage（ストレージ一覧）

## 概要

本ドキュメントは、Apache Spark Web UIの「Storage（ストレージ一覧）」画面の設計書である。クラスタ内の全RDDのストレージ状況とStreamingレシーバブロック情報を表示する。

### 本画面の処理概要

**業務上の目的・背景**：Sparkアプリケーションのメモリ使用状況を把握するための画面である。persist/cacheされたRDDの一覧とそのストレージレベル、キャッシュされたパーティション数、メモリ・ディスク使用量を確認できる。Sparkストリーミング使用時にはレシーバブロックの情報も表示され、データ受信状況の監視にも使用される。メモリ不足やキャッシュ戦略の見直し時に参照する。

**画面へのアクセス方法**：SparkアプリケーションWeb UIのナビゲーションバーから「Storage」タブを選択してアクセスする。

**主要な操作・処理内容**：
1. 永続化RDDの一覧テーブル表示（ID、RDD名、Storage Level、Cached Partitions、Fraction Cached、Size in Memory、Size on Disk）
2. Streamingレシーバブロック情報の表示（Executor別集約テーブル、ブロック詳細テーブル）
3. RDD名リンクからRDD Detail画面への遷移

**画面遷移**：
- この画面からの遷移先：RDD Detail（RDD詳細）画面（RDD名リンク選択時）
- この画面への遷移元：全画面からのナビゲーションバー経由

**権限による表示制御**：特になし。全ユーザーが同一の表示を閲覧できる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | Spark Web UI | 主機能 | クラスタ内の全永続化RDD一覧とストリーミングレシーバブロック情報をテーブル表示する主処理 |
| 7 | ブロックストレージ管理 | 主機能 | RDDのストレージレベル・キャッシュパーティション数・メモリ/ディスク使用量を取得して表示 |
| 95 | KVStore | API連携 | AppStatusStore.rddList()経由でRDDストレージ情報を非同期取得 |

## 画面種別

一覧

## URL/ルーティング

- パス: `/storage/`
- クラス: `StoragePage` (WebUIPage(""))
- タブ: `StorageTab` (SparkUITab(parent, "storage"))

## 入出力項目

本画面はURLパラメータを受け取らない。

## 表示項目

### RDD一覧テーブル

| カラム名 | データソース | ツールチップ | 説明 |
|----------|-------------|-------------|------|
| ID | rdd.id | なし | RDDのID |
| RDD Name | rdd.name | RDD_NAME | RDDの名前（RDD Detail画面へのリンク付き） |
| Storage Level | rdd.storageLevel | STORAGE_LEVEL | ストレージレベル（MEMORY_ONLY, DISK_ONLY等） |
| Cached Partitions | rdd.numCachedPartitions | CACHED_PARTITIONS | キャッシュされたパーティション数 |
| Fraction Cached | numCachedPartitions / numPartitions | FRACTION_CACHED | キャッシュ率（パーセント表示） |
| Size in Memory | rdd.memoryUsed | SIZE_IN_MEMORY | メモリ上のサイズ（bytesToString形式） |
| Size on Disk | rdd.diskUsed | SIZE_ON_DISK | ディスク上のサイズ（bytesToString形式） |

RDDが永続化されていない場合、テーブルは表示されない。

### Receiver Blocks セクション（Streaming使用時のみ）

ストリーミングレシーバブロックが存在する場合のみ表示される。

#### Aggregated Block Metrics by Executor テーブル

| カラム名 | データソース | 説明 |
|----------|-------------|------|
| Executor ID | blocks.head.executorId | エグゼキュータID |
| Address | blocks.head.hostPort | ホスト:ポート |
| Total Size in Memory | blocks.map(_.memSize).sum | メモリ上の合計サイズ |
| Total Size on Disk | blocks.map(_.diskSize).sum | ディスク上の合計サイズ |
| Stream Blocks | blocks.size | ストリームブロック数 |

#### Blocks テーブル

| カラム名 | データソース | 説明 |
|----------|-------------|------|
| Block ID | block.name | ブロックID |
| Replication Level | replications.size | レプリケーション数 |
| Location | block.hostPort | ホスト:ポート |
| Storage Level | streamBlockStorageLevelDescriptionAndSize | ストレージレベル（Disk/Memory/Memory Serialized） |
| Size | streamBlockStorageLevelDescriptionAndSize | サイズ |

## イベント仕様

### 1-RDD名リンク選択

RDD一覧テーブルのRDD名リンクをクリックすると、RDD Detail画面に遷移する。遷移先URL: `{basePath}/storage/rdd/?id={rddId}`

### 2-RDD一覧テーブルの折りたたみ

「RDDs ({count})」ヘッダーをクリックすると、RDDテーブルの表示/非表示が切り替わる。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ表示 | KVStore (AppStatusStore) | SELECT | RDDストレージ情報一覧・ストリームブロック一覧の読み取り |

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

本画面はデータの読み取り専用である。

## メッセージ仕様

特記すべきメッセージはない。RDDが永続化されていない場合やストリームブロックが存在しない場合は、該当セクションが非表示となる。

## 例外処理

| 例外 | 発生条件 | 処理 |
|------|----------|------|
| IllegalStateException | 不正なStorage Level（Disk/Memory/Memory Serialized以外） | streamBlockStorageLevelDescriptionAndSizeで例外スロー |

## 備考

- RDD一覧テーブルにはtooltipヘッダーが設定されており、各カラムにToolTipsオブジェクトから説明が表示される
- Fraction Cachedは"%.2f%%"フォーマットで表示される
- Size in Memory / Size on Diskカラムにはsorttable_customkey属性が設定され、バイト数でのソートが可能
- Receiver Blocksのストレージレベル判定は、useDisk -> useMemory && deserialized -> useMemory && !deserialized の優先順
- ストリームブロックはgroupByでブロック名ごとにグループ化され、レプリケーション数が表示される
- Blocksテーブルはソート不可（sortable = false）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api.scala | `core/src/main/scala/org/apache/spark/status/api/v1/api.scala` | RDDStorageInfoクラス（id, name, numPartitions, numCachedPartitions, storageLevel, memoryUsed, diskUsed） |
| 1-2 | storeTypes.scala | `core/src/main/scala/org/apache/spark/status/storeTypes.scala` | StreamBlockDataクラス（name, executorId, hostPort, storageLevel, useMemory, useDisk, deserialized, memSize, diskSize） |

**読解のコツ**: RDDStorageInfoはREST API用のデータクラス。StreamBlockDataはKVStore保存用の内部データクラス。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StoragePage.scala | `core/src/main/scala/org/apache/spark/ui/storage/StoragePage.scala` | renderメソッド（34行目）が主処理 |

**主要処理フロー**:
1. **35行目**: `store.rddList()` でRDD一覧を取得し `rddTable()` でテーブルHTML生成
2. **36行目**: `store.streamBlocksList()` でストリームブロック一覧を取得し `receiverBlockTables()` でテーブルHTML生成
3. **37行目**: UIUtils.headerSparkPageでページをラップ

#### Step 3: RDDテーブル生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StoragePage.scala | `core/src/main/scala/org/apache/spark/ui/storage/StoragePage.scala` | rddTable（40行目）、rddHeader（68行目）、rddRow（88行目）を理解する |

**主要処理フロー**:
- **40-65行目**: rddTableがRDD一覧をHTMLテーブルに変換。RDDが空なら表示しない
- **68-75行目**: rddHeaderで7カラムを定義
- **88-106行目**: rddRowで各RDDの行をレンダリング。Fraction Cachedは計算値

#### Step 4: Receiver Blocksテーブル生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | StoragePage.scala | `core/src/main/scala/org/apache/spark/ui/storage/StoragePage.scala` | receiverBlockTables（108行目）がExecutor別集約とブロック詳細の2テーブルを生成 |

**主要処理フロー**:
- **108-121行目**: receiverBlockTablesがブロック存在時のみ2つのテーブルを生成
- **123-134行目**: executorMetricsTableがExecutor別集約テーブルを生成（ExecutorStreamSummaryクラス）
- **163-177行目**: streamBlockTableがブロック名でグループ化したテーブルを生成
- **222-233行目**: streamBlockStorageLevelDescriptionAndSizeがストレージレベルの判定ロジック

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

```
StoragePage.render(request)
    |
    +-- store.rddList()                    ... RDD一覧取得
    |     +-- rddTable()                   ... RDDテーブルHTML生成
    |           +-- rddRow()               ... 各RDD行のレンダリング
    |
    +-- store.streamBlocksList()           ... ストリームブロック一覧取得
    |     +-- receiverBlockTables()        ... ブロックテーブル群HTML生成
    |           +-- executorMetricsTable()  ... Executor別集約テーブル
    |           |     +-- ExecutorStreamSummary
    |           +-- streamBlockTable()     ... ブロック詳細テーブル
    |                 +-- streamBlockTableRow()
    |                       +-- streamBlockStorageLevelDescriptionAndSize()
    |
    +-- UIUtils.headerSparkPage()          ... ページラップ
```

### データフロー図

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

HttpServletRequest ---> StoragePage.render()
                            |
KVStore              --> rddList()              --> RDDテーブル
                     --> streamBlocksList()      --> Receiver Blocksテーブル
                            |
                            v
                        HTML(Seq[Node])          --> ブラウザ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StoragePage.scala | `core/src/main/scala/org/apache/spark/ui/storage/StoragePage.scala` | ソース | 画面のメインページクラスとExecutorStreamSummary |
| StorageTab.scala | `core/src/main/scala/org/apache/spark/ui/storage/StorageTab.scala` | ソース | Storageタブ定義 |
| ToolTips.scala | `core/src/main/scala/org/apache/spark/ui/storage/ToolTips.scala` | ソース | テーブルヘッダーのツールチップ定義 |
| AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | ソース | データアクセス層 |
| api.scala | `core/src/main/scala/org/apache/spark/status/api/v1/api.scala` | ソース | RDDStorageInfoデータモデル |
| storeTypes.scala | `core/src/main/scala/org/apache/spark/status/storeTypes.scala` | ソース | StreamBlockDataデータモデル |
