# 機能設計書 22-コード生成（Whole-Stage CodeGen）

## 概要

本ドキュメントは、Apache SparkのWhole-Stage Code Generation（コード生成）機能の設計について記述する。本機能は物理実行計画からJavaバイトコードを動的に生成し、仮想関数呼び出しやメモリアクセスを最適化して実行性能を大幅に向上させる。

### 本機能の処理概要

Whole-Stage CodeGenは、Spark SQLの物理実行計画における複数のオペレータを単一のJavaメソッドに融合（fuse）し、Janino コンパイラを用いてJavaバイトコードを動的に生成する仕組みである。従来のVolcanoモデル（イテレータベースの逐次実行）では、各行ごとに仮想関数呼び出しが発生していたが、コード生成により一連の処理がインライン化され、CPUキャッシュ効率とパイプライン処理効率が劇的に改善される。

**業務上の目的・背景**：分散データ処理において、CPUバウンドなクエリの性能がVolcanoモデルの仮想関数呼び出しオーバーヘッドにより制限されていた。Whole-Stage CodeGenは、この問題を解決するためにProject Tungstenの一部として導入された。現代のCPUアーキテクチャに最適化されたコードを動的に生成することで、手書きのクエリ処理コードに匹敵する性能を自動的に達成する。

**機能の利用シーン**：SQL/DataFrameクエリの実行時に自動的に適用される。特にスキャン、フィルタ、プロジェクション、集約、結合等の操作でコード生成が行われる。spark.sql.codegen.wholeStage設定（デフォルトtrue）で有効/無効を制御可能。

**主要な処理内容**：
1. 物理実行計画のオペレータチェーンの解析とコード生成対象の特定
2. Produce/Consumeパターンによるコードの段階的生成
3. CodegenContextを用いた変数管理と式コード生成
4. Janino コンパイラによるJavaソースコードからバイトコードへのコンパイル
5. 生成コードのメソッド分割（JITコンパイラの最適化制限対応）
6. コード生成失敗時のVolcanoモデルへのフォールバック

**関連システム・外部連携**：Catalystオプティマイザ（物理計画生成）、Janino コンパイラ（バイトコードコンパイル）、JVM JITコンパイラ（実行時最適化）

**権限による制御**：権限による制御はない。全てのクエリに対して透過的に適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | SQL Execution Detail（SQL実行詳細） | 結果表示画面 | WholeStageCodegenの実行ノード情報をDAG内に表示 |

## 機能種別

計算処理 / コード生成 / パフォーマンス最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| spark.sql.codegen.wholeStage | Boolean | No | WholeStageCodeGenの有効/無効（デフォルト: true） | true/false |
| spark.sql.codegen.hugeMethodLimit | Int | No | 生成メソッドのバイトコードサイズ上限（デフォルト: 65535） | 正の整数 |
| spark.sql.codegen.maxFields | Int | No | コード生成が適用されるスキーマの最大フィールド数（デフォルト: 100） | 正の整数 |
| spark.sql.codegen.splitConsumeFuncByOperator | Boolean | No | オペレータ単位でのconsume関数分割（デフォルト: true） | true/false |
| spark.sql.codegen.factoryMode | String | No | コード生成モード（CODEGEN_ONLY/FALLBACK/NO_CODEGEN） | 列挙値 |

### 入力データソース

- 物理実行計画（SparkPlan）のオペレータツリー

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| GeneratedClass | Class | 動的生成されたJavaクラス |
| BufferedRowIterator | Iterator | 生成コードの実行結果イテレータ |

### 出力先

- JVMメモリ上のコンパイル済みバイトコード
- 実行結果はInternalRowのイテレータとして後続処理に渡される

## 処理フロー

### 処理シーケンス

```
1. CollapseCodegenStagesルールによるコード生成ステージの特定
   └─ CodegenSupportトレイトを実装するオペレータのチェーンを検出
2. WholeStageCodegenExecノードの挿入
   └─ 連続するCodegenSupport対応オペレータをラップ
3. Produce/Consumeパターンによるコード生成
   └─ 最下層のオペレータからproduce()、最上層に向かってconsume()
4. CodegenContextによる変数・メソッド管理
   └─ 式コード、参照オブジェクト、メソッド分割の管理
5. Janinoによるコンパイル
   └─ 生成されたJavaソースコードをバイトコードにコンパイル
6. 生成クラスのインスタンス化と実行
   └─ BufferedRowIteratorとして実行結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[物理実行計画] --> B[CollapseCodegenStages]
    B --> C[WholeStageCodegenExec挿入]
    C --> D[produce/consume コード生成]
    D --> E[CodegenContext管理]
    E --> F{コード生成成功?}
    F -->|Yes| G[Janinoコンパイル]
    F -->|No| H[Volcanoモデルフォールバック]
    G --> I{コンパイル成功?}
    I -->|Yes| J[生成クラスインスタンス化]
    I -->|No| H
    J --> K[BufferedRowIterator実行]
    H --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-22-01 | CodegenSupport要件 | コード生成対象はCodegenSupportトレイトを実装するオペレータのみ | 全てのオペレータ評価時 |
| BR-22-02 | メソッドサイズ制限 | 生成メソッドのバイトコードサイズがhugeMethodLimitを超える場合は分割 | コード生成時 |
| BR-22-03 | フォールバック | コード生成またはコンパイルに失敗した場合はVolcanoモデルで実行 | コード生成失敗時 |
| BR-22-04 | フィールド数制限 | スキーマのフィールド数がmaxFieldsを超える場合はコード生成を適用しない | スキーマ評価時 |

### 計算ロジック

Produce/Consumeパターン:
- **produce()**: 下流のオペレータがデータを生成するコードを記述。フレームワーク部分（ループ、条件分岐等）を生成し、子オペレータのproduce()を呼び出す。
- **consume()**: 上流のオペレータに対して、処理済みデータを渡すコードを記述。親オペレータのdoConsume()を呼び出す。

## データベース操作仕様

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

本機能は直接的なデータベース操作を行わない。コード生成はインメモリでの処理最適化であり、データソースへのアクセスは生成されたコード内で間接的に行われる。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| CODEGEN_COMPILE_ERROR | コンパイルエラー | 生成コードがJaninoでコンパイル不可 | Volcanoモデルへフォールバック |
| GENERATED_CLASS_TOO_LARGE | サイズ超過 | 生成クラスのサイズがJVMクラスサイズ制限超過 | メソッド分割の調整 |
| N/A | 実行時例外 | 生成コードの実行中にNullPointerException等 | デバッグモードでの生成コード確認 |

### リトライ仕様

コード生成失敗時はVolcanoモデルへの自動フォールバックが行われるため、明示的なリトライは不要。

## トランザクション仕様

本機能はトランザクションに関与しない。

## パフォーマンス要件

- コード生成によりVolcanoモデル比で最大10倍以上の性能向上（TPC-Hベンチマーク実績）
- JITコンパイラの最適化に適した単一メソッドへの融合
- CPUキャッシュヒット率の向上（データのレジスタ保持）
- 仮想関数呼び出しの排除によるCPUパイプライン効率化

## セキュリティ考慮事項

- 動的コード生成はJVMサンドボックス内で実行される
- 生成コードへの外部入力の直接注入は行われない

## 備考

- Spark 2.0でWhole-Stage Code Generationが導入された
- explain("codegen")で生成されたJavaコードを確認可能
- spark.sql.codegen.comments=trueで生成コード内にコメントを挿入可能

---

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

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

### 推奨読解順序

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

コード生成で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CodegenContext.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/CodegenContext.scala` | コード生成コンテキスト、変数管理、メソッド管理 |
| 1-2 | ExprCode | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/javaCode.scala` | 式の生成コード表現（isNull, value, code） |

**読解のコツ**: CodegenContextはコード生成全体で共有されるステートフルなオブジェクト。freshName()による一意変数名生成、addReferenceObj()による外部オブジェクト参照の管理が重要。

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

WholeStageCodegenExecがコード生成の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WholeStageCodegenExec.scala | `sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenExec.scala` | CodegenSupportトレイトとWholeStageCodegenExec本体 |

**主要処理フロー**:
1. **47行目**: CodegenSupportトレイトの定義 - supportCodegen、produce()、consume()
2. **50-63行目**: variablePrefix - 各オペレータの変数名プレフィックス定義
3. **77行目**: supportCodegen - デフォルトtrue
4. **94-100行目**: produce() - コード生成のエントリポイント、doProduce()を呼び出す
5. **153-207行目**: consume() - 親オペレータへの結果受け渡しコード生成

#### Step 3: コード生成パイプラインを理解する

CollapseCodegenStagesルールとコード生成パイプラインを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WholeStageCodegenExec.scala（後半） | `sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenExec.scala` | CollapseCodegenStagesルール、WholeStageCodegenExecクラス |
| 3-2 | WholeStageCodegenEvaluatorFactory.scala | `sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenEvaluatorFactory.scala` | コード評価ファクトリ |

**主要処理フロー**:
- **196-198行目**: constructDoConsumeFunction - consume関数のメソッド分割ロジック
- **279-283行目**: evaluateVariables - 変数評価コードの生成と二重評価防止

#### Step 4: 式コード生成を理解する

各種式（Expression）のコード生成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | CodeGenerator.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/CodeGenerator.scala` | コード生成ユーティリティ、Janinoコンパイル |
| 4-2 | GenerateUnsafeProjection.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/GenerateUnsafeProjection.scala` | UnsafeRow生成コードの生成 |

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

```
CollapseCodegenStages (Rule)
    │
    └─ WholeStageCodegenExec
           │
           ├─ doExecute()
           │      ├─ CodegenContext生成
           │      ├─ child.produce(ctx, this)
           │      │      ├─ doProduce(ctx) - データ生成フレームワーク
           │      │      └─ consume(ctx, outputVars)
           │      │             └─ parent.doConsume(ctx, inputVars, rowVar)
           │      │
           │      ├─ CodeGenerator.compile(code)
           │      │      └─ Janino コンパイラ
           │      │
           │      └─ GeneratedClass.generate(references)
           │             └─ BufferedRowIterator
           │
           └─ InputAdapter (CodegenSupportを実装しないオペレータとの境界)
```

### データフロー図

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

物理実行計画 ─────▶ CollapseCodegenStages ──▶ WholeStageCodegenExec
(SparkPlan)              │                         │
                         ▼                         ▼
                  CodegenSupport            Javaソースコード
                  オペレータ特定                    │
                                                   ▼
                                            Janinoコンパイル
                                                   │
                                                   ▼
                                            バイトコード ──▶ BufferedRowIterator
                                                              (InternalRow列)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WholeStageCodegenExec.scala | `sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenExec.scala` | ソース | CodegenSupportトレイトとWholeStageCodegenExec実装 |
| WholeStageCodegenEvaluatorFactory.scala | `sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenEvaluatorFactory.scala` | ソース | コード生成評価ファクトリ |
| CodegenContext.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/CodegenContext.scala` | ソース | コード生成コンテキスト管理 |
| CodeGenerator.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/CodeGenerator.scala` | ソース | コードコンパイルユーティリティ |
| GenerateUnsafeProjection.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/GenerateUnsafeProjection.scala` | ソース | UnsafeRow生成コード |
| javaCode.scala | `sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/codegen/javaCode.scala` | ソース | ExprCode等のコード表現 |
