# バッチ設計書 1-AsyncTranslogFSync

## 概要

本ドキュメントは、OpenSearchのインデックスサービスにおけるトランザクションログ（translog）の非同期fsync処理バッチの設計を記載する。

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

AsyncTranslogFSyncは、インデックスごとに割り当てられた全シャードのトランザクションログを定期的にfsync（ディスクへの書き込み同期）するバッチタスクである。

**業務上の目的・背景**：OpenSearchではドキュメントの書き込み操作がトランザクションログに記録されるが、トランザクションログの耐久性設定が`ASYNC`の場合、書き込み操作ごとにfsyncを行わず、定期的にバッチでfsyncすることでI/Oパフォーマンスを向上させる。ノード障害時のデータ損失リスクとパフォーマンスのトレードオフを管理するために本バッチが必要となる。

**バッチの実行タイミング**：インデックスごとに`index.translog.sync_interval`（デフォルト5秒）の間隔で定期実行される。IndexServiceの初期化時にスケジューリングが開始される。

**主要な処理内容**：
1. トランザクションログの耐久性設定が`ASYNC`であるか確認する
2. インデックス内の全シャードを走査する
3. 各シャードについて`isSyncNeeded()`で同期が必要か判定する
4. 同期が必要なシャードに対して`sync()`を実行し、トランザクションログをディスクにfsyncする

**前後の処理との関連**：本タスクはIndexServiceの初期化時（コンストラクタまたは設定更新時）に生成・開始される。AsyncTrimTranslogTask（No.5）によるトランスログのトリム処理の前提として、トランスログがディスクに同期されている必要がある。

**影響範囲**：対象インデックスの全シャードのトランザクションログファイルに影響する。fsyncの遅延はASYNC耐久性モード時のデータ損失リスクに直結する。

## バッチ種別

データ同期処理（トランザクションログのディスク書き込み同期）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 定期実行（デフォルト5秒間隔） |
| 実行時刻 | インデックスのライフサイクルに依存（常時） |
| 実行曜日 | 該当なし（常時稼働） |
| 実行日 | 該当なし（常時稼働） |
| トリガー | タイマーベースの定期スケジュール（AbstractAsyncTask） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| IndexServiceが未クローズ | `indexService.closed.get() == false`であること |
| インデックスがOPEN状態 | `IndexMetadata.State.OPEN`であること |
| トランスログ耐久性がASYNC | `indexSettings.getTranslogDurability() == Translog.Durability.ASYNC`であること |

### 実行可否判定

BaseAsyncTaskの`mustReschedule()`メソッドにより、IndexServiceがクローズされておらず、かつインデックスメタデータの状態がOPENである場合のみ再スケジューリングされる。実際のfsync処理は`maybeFSyncTranslogs()`内でトランスログ耐久性がASYNCの場合のみ実行される。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| index.translog.sync_interval | TimeValue | No | 5s | fsyncの実行間隔 |
| index.translog.durability | Enum | No | REQUEST | トランスログの耐久性モード（REQUESTまたはASYNC） |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| IndexServiceのシャードマップ | インメモリ | 対象インデックスに属する全シャード |
| 各シャードのTranslog | ディスクファイル | トランザクションログデータ |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| トランザクションログファイル | ディスクファイル | fsyncによりバッファからディスクへ書き込み同期される |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | translog-N.tlog（Nはgeneration番号） |
| 出力先 | 各シャードのtranslogディレクトリ |
| 文字コード | バイナリ形式 |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. タイマーによる定期起動
   └─ AbstractAsyncTaskにより指定間隔で起動
2. トランスログ耐久性チェック
   └─ indexSettings.getTranslogDurability()がASYNCか確認
3. シャード走査
   └─ indexService.shards.values()で全シャードをイテレーション
4. 同期必要性判定
   └─ shard.isSyncNeeded()でfsyncが必要か判定
5. fsync実行
   └─ shard.sync()を呼び出してトランスログをディスクに同期
6. 次回スケジュール
   └─ mustReschedule()がtrueの場合、同一間隔で再スケジュール
```

### フローチャート

```mermaid
flowchart TD
    A[タイマー起動] --> B{トランスログ耐久性 == ASYNC?}
    B -->|No| G[処理スキップ]
    B -->|Yes| C[全シャード走査開始]
    C --> D{次のシャードあり?}
    D -->|No| H[処理終了・再スケジュール]
    D -->|Yes| E{isSyncNeeded?}
    E -->|No| D
    E -->|Yes| F[shard.sync 実行]
    F --> D
    G --> H
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| translog fsync | トランザクションログファイル | WRITE(fsync) | メモリバッファの内容をディスクに同期書き込み |

### テーブル別操作詳細

#### トランザクションログファイル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| fsync | トランスログファイル全体 | バッファ済み未同期データをディスクに書き込み | OSレベルのfsyncシステムコール |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | AlreadyClosedException | シャードが既にクローズされている | 例外をキャッチして処理を継続（次のシャードへ） |
| - | IOException | fsync実行時のI/Oエラー | 警告ログを出力して処理を継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 明示的なリトライなし（次回スケジュール実行で再試行される） |
| リトライ間隔 | index.translog.sync_interval（デフォルト5秒） |
| リトライ対象エラー | IOException（次回実行時に自動的に再試行） |

### 障害時対応

fsyncに失敗した場合、警告ログが出力され、次回のスケジュール実行時に再度fsyncが試行される。継続的なI/Oエラーが発生する場合はディスクの健全性を確認する必要がある。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | シャード単位（各シャードのfsyncは独立） |
| コミットタイミング | fsync実行時（シャードごとに即時） |
| ロールバック条件 | 該当なし（fsyncは冪等操作） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | インデックス内のシャード数に依存 |
| 目標処理時間 | sync_interval内に完了すること |
| メモリ使用量上限 | 追加メモリ使用なし（既存バッファのfsyncのみ） |

## 排他制御

同一インデックスに対するAsyncTranslogFSyncタスクは1つのみ存在する。タスクの更新時（`updateIfNeeded`）は新しいインターバルを設定するだけで、タスク自体の再作成は行わない。各シャードのsync()は内部でシャードレベルのロックを使用する。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 警告ログ | fsync失敗時 | "failed to sync translog" + 例外情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| fsyncエラー | 継続的なIOException発生 | OpenSearchログ（WARN） |

## 備考

- 本タスクはFLUSHスレッドプールで実行される
- `index.translog.durability`が`REQUEST`（デフォルト）の場合、書き込み操作ごとに同期fsyncが行われるため、本バッチによるfsyncは実行されない
- インターバルの動的更新が可能で、設定変更時に`updateIfNeeded()`が呼ばれる
- ソースコード: `server/src/main/java/org/opensearch/index/IndexService.java` (AsyncTranslogFSync内部クラス)
