# バッチ設計書 11-CacheCleaner (FieldDataCache)

## 概要

本ドキュメントは、OpenSearchのフィールドデータキャッシュを定期的にクリーンアップするバッチ処理「CacheCleaner (FieldDataCache)」の設計仕様を記載する。

### 本バッチの処理概要

CacheCleanerは、IndicesServiceで管理されるフィールドデータキャッシュ（IndicesFieldDataCache）に対して、無効化済みのエントリを定期的にクリーンアップするバッチ処理である。

**業務上の目的・背景**：フィールドデータキャッシュはGuavaベースのキャッシュ実装を使用しており、エントリが無効化されても、その後の読み取りまたは書き込み操作が行われない限り、実際にクリーンアップされない特性がある。このバッチは、そのようなエントリを定期的にクリーンアップし、メモリリソースの適切な管理を行うために必要である。フィールドデータはソートや集約処理で使用されるため、不要なキャッシュエントリの蓄積はヒープメモリの圧迫につながる。

**バッチの実行タイミング**：`indices.cache.cleanup_interval`設定に基づく定期実行（デフォルト1分間隔）。ノード起動時にスケジューリングされ、以降は自身を再スケジュールすることで繰り返し実行される。

**主要な処理内容**：
1. IndicesFieldDataCacheのclear()メソッドを呼び出し、無効化済みキャッシュエントリを解放する
2. 処理時間をトレースログに記録する
3. ノードがシャットダウン中でなければ、次回実行を再スケジュールする

**前後の処理との関連**：本バッチは独立して動作する。IndicesServiceのライフサイクルに紐づき、IndicesServiceの停止時にCacheCleanerもclose()される。フィールドデータキャッシュの無効化はインデックスのクローズ、削除、シャード移動時などに発生するが、本バッチはそれらのイベントとは非同期に動作する。

**影響範囲**：各ノードのフィールドデータキャッシュ（ヒープメモリ）に影響する。キャッシュクリアにより一時的にフィールドデータの再ロードが発生する可能性があるが、無効化済みエントリのみを対象とするため正常な動作に影響はない。

## バッチ種別

キャッシュ管理 / メモリクリーンアップ

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 定期実行（デフォルト1分間隔） |
| 実行時刻 | ノード起動後、設定間隔ごとに繰り返し実行 |
| 実行曜日 | 該当なし（常時） |
| 実行日 | 該当なし（常時） |
| トリガー | ThreadPoolによるスケジューリング（scheduleUnlessShuttingDown） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| ノードが起動中であること | ノードシャットダウン時はスケジュールされない |
| IndicesServiceが初期化済みであること | IndicesFieldDataCacheが利用可能であること |

### 実行可否判定

CacheCleanerインスタンスのclosedフラグがfalseの場合に実行される。close()が呼ばれるとclosedフラグがtrueとなり、次回以降のスケジューリングが停止する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| indices.cache.cleanup_interval | TimeValue | No | 1m | キャッシュクリーンアップの実行間隔 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| IndicesFieldDataCache | インメモリキャッシュ | クリーンアップ対象のフィールドデータキャッシュ |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ヒープメモリ | メモリ解放 | 無効化済みキャッシュエントリの解放 |

### 出力ファイル仕様

ファイル出力はなし。

## 処理フロー

### 処理シーケンス

```
1. run()メソッド実行
   └─ 開始時刻を記録（System.nanoTime）
2. IndicesFieldDataCache.clear()を呼び出し
   └─ 無効化済みキャッシュエントリを解放
3. トレースログ出力
   └─ 処理時間をミリ秒で記録
4. 再スケジュール判定
   └─ closedフラグがfalseの場合、threadPool.scheduleUnlessShuttingDown()で次回実行をスケジュール
```

### フローチャート

```mermaid
flowchart TD
    A[CacheCleaner.run 開始] --> B[開始時刻記録]
    B --> C[IndicesFieldDataCache.clear 実行]
    C --> D{例外発生?}
    D -->|なし| E[トレースログ出力: 処理時間]
    D -->|あり| F[警告ログ出力: 例外内容]
    E --> G{closed == false?}
    F --> G
    G -->|Yes| H[次回実行をスケジュール]
    G -->|No| I[終了: 再スケジュールなし]
    H --> J[CacheCleaner.run 終了]
    I --> J
```

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

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

本バッチはデータベース操作を行わない。インメモリキャッシュの操作のみを行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | Exception | cache.clear()実行中の例外 | 警告ログを出力し、処理を継続。次回実行は正常にスケジュールされる |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 明示的なリトライなし（定期実行により自動的に再試行される） |
| リトライ間隔 | 次回定期実行間隔（デフォルト1分） |
| リトライ対象エラー | すべてのException |

### 障害時対応

バッチ失敗時はログに警告メッセージが出力される。例外が発生しても再スケジュールは行われるため、次回実行で自動的に再試行される。メモリが異常に増加する場合は、設定`indices.cache.cleanup_interval`を短くすることを検討する。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（インメモリ操作のみ） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | キャッシュ内の無効化済みエントリ数に依存 |
| 目標処理時間 | ミリ秒単位（トレースログで監視可能） |
| メモリ使用量上限 | 該当なし（メモリ解放処理） |

## 排他制御

CacheCleanerのrun()メソッドは同一スレッド（ThreadPool.Names.SAME）上で実行され、前回の実行が完了してから次回がスケジュールされるため、同時実行は発生しない。closedフラグにはAtomicBooleanが使用され、スレッドセーフにクローズ判定が行われる。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| トレースログ | キャッシュクリーンアップ開始時 | "running periodic field data cache cleanup" |
| トレースログ | キャッシュクリーンアップ完了時 | "periodic field data cache cleanup finished in {X} milliseconds" |
| 警告ログ | 例外発生時 | "Exception during periodic field data cache cleanup:" + 例外詳細 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| フィールドデータキャッシュサイズ | indices.fielddata.cache.sizeで設定 | OpenSearchログ |
| クリーンアップ処理時間 | 明示的な閾値なし（トレースログで記録） | OpenSearchログ |

## 備考

- CacheCleanerはIndicesService内部のprivate staticクラスとして実装されている
- 実装ファイル: `server/src/main/java/org/opensearch/indices/IndicesService.java`（1902行目付近）
- ThreadPool.Names.SAMEを使用してスケジュールされるため、呼び出し元スレッドで実行される
- IndicesRequestCacheの定期クリーンアップとは別の設定（`indices.cache.cleanup_interval`）で管理されるが、同一のデフォルト値（1分）を共有する
