# 機能設計書 43-ファイルキャッシュ

## 概要

本ドキュメントは、webpackのファイルキャッシュ機能について、IdleFileCachePluginおよびPackFileCacheStrategyを中心に設計内容を記述する。

### 本機能の処理概要

本機能は、コンパイル結果をファイルシステムに永続化し、webpackプロセスの再起動後もキャッシュを再利用可能にする。アイドル時間を利用してバックグラウンドでキャッシュをディスクに書き出す。

**業務上の目的・背景**：メモリキャッシュはプロセス終了とともに消失するため、webpackの再起動(特にCI/CD環境やコールドスタート)時にすべてのモジュールを再処理する必要がある。ファイルキャッシュにより、プロセス間でコンパイル結果を共有し、初回リビルド時間を大幅に短縮する。

**機能の利用シーン**：webpack設定の`cache.type`が`filesystem`の場合に有効化される。CI/CDパイプラインでのビルド高速化、開発サーバー再起動時のウォームアップ短縮に利用される。

**主要な処理内容**：
1. IdleFileCachePlugin: コンパイラのアイドル状態を検知し、バックグラウンドでキャッシュをディスクに書き出す
2. PackFileCacheStrategy: Pack形式でキャッシュデータをシリアライズ・デシリアライズする
3. ビルド依存関係(build dependencies)のスナップショット管理でキャッシュ無効化を制御
4. STAGE_DISKでstore/getフックに登録し、メモリキャッシュの後段として動作

**関連システム・外部連携**：メモリキャッシュ(No.42)の後段キャッシュとして多段構成。FileSystemInfoによるスナップショット管理。シリアライゼーション機能(No.77)によるデータ永続化。

**権限による制御**：ファイルシステムの読み書き権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面との直接的な関連なし（内部キャッシュ機構） |

## 機能種別

キャッシュ管理 / ファイルI/O

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| strategy | PackFileCacheStrategy | Yes | キャッシュストレージ戦略 | - |
| idleTimeout | number | Yes | アイドル状態後のキャッシュ書き出し待機時間(ms) | 正の整数 |
| idleTimeoutForInitialStore | number | Yes | 初回キャッシュ書き出しの待機時間(ms) | 正の整数 |
| idleTimeoutAfterLargeChanges | number | Yes | 大量変更後の短縮待機時間(ms) | 正の整数 |

### 入力データソース

- Compiler.cacheインスタンスのstore/getフック経由
- ファイルシステム上のキャッシュファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | Data | キャッシュされたデータ(restore時) |
| キャッシュファイル | バイナリ | Pack形式でシリアライズされたキャッシュデータ |

### 出力先

- ファイルシステム（デフォルト: `node_modules/.cache/webpack/`）

## 処理フロー

### 処理シーケンス

```
1. storeフック(STAGE_DISK): pendingIdleTasksに保存処理を登録
   └─ 即時書き出しは行わず遅延実行

2. getフック(STAGE_DISK): strategy.restore()でファイルから復元
   └─ キャッシュヒット: データ返却
   └─ キャッシュミス: gotHandlersにstore処理を登録

3. beginIdleフック: idleTimerを設定
   └─ 初回/大量変更/通常の3段階のタイムアウト判定

4. アイドル状態検知後: processIdleTasks()実行
   └─ pendingIdleTasksから最大100件ずつバッチ処理
   └─ strategy.store()でディスクに書き出し
   └─ 全タスク完了後strategy.afterAllStored()

5. shutdownフック: 全pendingIdleTasksを即座に実行
   └─ strategy.afterAllStored()
   └─ strategy.clear()でリセット
```

### フローチャート

```mermaid
flowchart TD
    A[コンパイル完了] --> B[beginIdleフック]
    B --> C{タイムアウト判定}
    C -->|初回| D[idleTimeoutForInitialStore]
    C -->|大量変更| E[idleTimeoutAfterLargeChanges]
    C -->|通常| F[idleTimeout]
    D --> G[processIdleTasks]
    E --> G
    F --> G
    G --> H{タスクあり?}
    H -->|Yes| I[最大100件バッチ処理]
    I --> J[strategy.store]
    J --> G
    H -->|No| K[strategy.afterAllStored]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | 遅延書き出し | storeは即座にディスクに書かず、アイドル時にバッチ処理 | 常時 |
| BR-43-02 | バッチ制限 | 一度に最大100件、100msまでのタスクを処理 | processIdleTasks実行時 |
| BR-43-03 | 大量変更検出 | ビルド時間がキャッシュ書き出し平均時間の2倍を超える場合 | idleTimeoutAfterLargeChanges適用 |
| BR-43-04 | ビルド依存関係検証 | キャッシュ読み込み時にビルド依存関係のスナップショットを検証 | キャッシュリストア時 |

### 計算ロジック

- 大量変更判定: `timeSpendInBuild > avgTimeSpendInStore * 2`
- 平均書き出し時間: `avgTimeSpendInStore = max(avgTimeSpendInStore, timeSpendInStore) * 0.9 + timeSpendInStore * 0.1`

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

該当なし（ファイルシステムへの読み書き）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Warning | バックグラウンドタスクの失敗 | ログ出力後継続 |
| - | Error | キャッシュファイルの読み取り失敗 | キャッシュ無効化して再ビルド |

### リトライ仕様

リトライは行わない。エラー時はキャッシュミスとして扱い通常処理を継続。

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

- キャッシュの書き出しは非トランザクション。部分的な書き出し失敗は次回起動時にキャッシュ無効化で対処。

## パフォーマンス要件

- アイドル時間を利用してバックグラウンドで書き出すため、ビルドパフォーマンスへの影響を最小化
- timer.unref()によりNode.jsプロセスの終了を阻害しない

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

- キャッシュファイルはソースコードの処理結果を含むため、適切なファイルパーミッション管理が必要

## 備考

- PackFileCacheStrategyは内部的にPackContainer/Pack/PackContentの3階層構造でデータを管理
- MIN_CONTENT_SIZE(1MB)、MAX_ITEMS_IN_FRESH_PACK(50000)等の定数で最適化を制御

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | **38-99行目**: PackContainer - バージョン・スナップショット・ビルド依存関係を含むコンテナ |
| 1-2 | PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | **107-125行目**: PackItemInfo - 個別キャッシュアイテムの情報(identifier, etag, location, lastAccess) |
| 1-3 | PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | **127-149行目**: Pack - キャッシュデータの主要コンテナ |

**読解のコツ**: locationが-1の場合は「freshValue」（まだPackContentに格納されていないデータ）を意味する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | IdleFileCachePlugin.js | `lib/cache/IdleFileCachePlugin.js` | **17-34行目**: コンストラクタ(strategy, idleTimeout, idleTimeoutForInitialStore, idleTimeoutAfterLargeChanges) |
| 2-2 | IdleFileCachePlugin.js | `lib/cache/IdleFileCachePlugin.js` | **41-238行目**: apply()メソッド全体 |

**主要処理フロー**:
1. **58-65行目**: storeフック - pendingIdleTasksにタスクを登録
2. **67-92行目**: getフック - strategy.restore()で復元、ミス時にstoreを登録
3. **94-103行目**: storeBuildDependenciesフック
4. **137-178行目**: processIdleTasks - バッチ処理ロジック
5. **181-231行目**: beginIdle/endIdleフック - タイマー管理

#### Step 3: Pack形式のストレージを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | **101-106行目**: 定数定義(MIN_CONTENT_SIZE, CONTENT_COUNT_TO_MERGE等) |
| 3-2 | PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | **176-193行目**: Pack.get() - キャッシュ取得ロジック |

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

```
IdleFileCachePlugin.apply(compiler)
    |
    +-- compiler.cache.hooks.store.tap (STAGE_DISK)
    |       +-- pendingIdleTasks.set(identifier, () => strategy.store())
    |
    +-- compiler.cache.hooks.get.tapPromise (STAGE_DISK)
    |       +-- strategy.restore(identifier, etag)
    |
    +-- compiler.cache.hooks.beginIdle.tap
    |       +-- setTimeout(processIdleTasks, timeout)
    |
    +-- processIdleTasks()
    |       +-- pendingIdleTasks.forEach(factory => factory())
    |       +-- strategy.store(identifier, etag, data)
    |       +-- strategy.afterAllStored()
    |
    +-- compiler.cache.hooks.shutdown.tapPromise
            +-- 全pendingIdleTasksを即座実行
            +-- strategy.afterAllStored()
            +-- strategy.clear()
```

### データフロー図

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

identifier/etag/data ──▶ IdleFileCachePlugin           ──▶ ファイルシステム
                         ├─ store: pendingIdleTasksに登録     (.cache/webpack/)
                         ├─ get: strategy.restore()
                         └─ idle: processIdleTasks()
                              |
                              v
                         PackFileCacheStrategy
                         ├─ Pack (メモリ上のキャッシュ構造)
                         ├─ PackContent (シリアライズ単位)
                         └─ FileSerializer (ファイルI/O)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| IdleFileCachePlugin.js | `lib/cache/IdleFileCachePlugin.js` | ソース | アイドル時ファイルキャッシュ制御 |
| PackFileCacheStrategy.js | `lib/cache/PackFileCacheStrategy.js` | ソース | Pack形式キャッシュストレージ戦略 |
| AddBuildDependenciesPlugin.js | `lib/cache/AddBuildDependenciesPlugin.js` | ソース | ビルド依存関係の追加 |
| AddManagedPathsPlugin.js | `lib/cache/AddManagedPathsPlugin.js` | ソース | 管理パスの追加 |
| getLazyHashedEtag.js | `lib/cache/getLazyHashedEtag.js` | ソース | 遅延ハッシュEtag生成 |
| mergeEtags.js | `lib/cache/mergeEtags.js` | ソース | Etagマージ |
