# 帳票設計書 21-PIT Segments Report

## 概要

本ドキュメントは、OpenSearch の Cat API エンドポイント `GET /_cat/pit_segments` によって出力される PIT Segments Report の設計仕様を定義する。Point-in-Time (PIT) に関連するLuceneセグメント情報をテキストテーブル形式で出力する帳票である。

### 本帳票の処理概要

PIT Segments Report は、OpenSearch の Point-in-Time (PIT) 機能で保持されているセグメント情報を一覧形式で出力する帳票である。

**業務上の目的・背景**：Point-in-Time (PIT) は検索の一貫性を保つためにインデックスの特定時点のスナップショットを保持する機能であり、運用上これらの PIT が保持するセグメント情報を確認する必要がある。PIT が保持するセグメント数やサイズは、メモリ消費やディスク使用量に直接影響するため、クラスタのリソース管理において重要な監視対象となる。本帳票は、PIT に紐づくセグメントの詳細情報を可視化することで、PIT の適切な管理とクラスタリソースの最適化を支援する。

**帳票の利用シーン**：PIT を使用した長時間実行される検索処理のデバッグ時、PIT が保持するセグメントのリソース消費量を調査する場面、古い PIT が不要なセグメントを保持していないかの確認、クラスタのメモリ・ディスク使用量が想定以上に増加した場合の原因調査時に利用される。

**主要な出力内容**：
1. インデックス名、シャード番号、プライマリ/レプリカの区別
2. セグメント名、世代番号、ドキュメント数、削除済みドキュメント数
3. セグメントサイズ、メモリ使用量
4. コミット済み・検索可能フラグ、Luceneバージョン、コンパウンドフラグ
5. ノードのIPアドレスとID

**帳票の出力タイミング**：ユーザーが REST API エンドポイント `GET /_cat/pit_segments` または `GET /_cat/pit_segments/_all` を呼び出した時点でリアルタイムに生成される。リクエストボディで特定の PIT ID を指定することも可能である。

**帳票の利用者**：OpenSearch クラスタの運用管理者、SRE エンジニア、検索機能の開発者

## 帳票種別

一覧表（テキストテーブル形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 166 | Cat PIT セグメント | `GET /_cat/pit_segments` | REST API 呼び出し |
| 166 | Cat PIT セグメント（全件） | `GET /_cat/pit_segments/_all` | REST API 呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（プレーンテキストテーブル / JSON） |
| 用紙サイズ | N/A（API レスポンス） |
| 向き | N/A |
| ファイル名 | N/A（HTTP レスポンスボディ） |
| 出力方法 | HTTP レスポンス |
| 文字コード | UTF-8 |

### テキストテーブル固有設定

| 項目 | 内容 |
|-----|------|
| ヘッダー表示 | `v` パラメータで制御（デフォルト: 非表示） |
| カラム選択 | `h` パラメータで表示カラムを指定可能 |
| ソート | `s` パラメータでソートカラムを指定可能 |
| フォーマット | `format` パラメータで text/json/yaml 等を指定可能 |
| ヘルプ | `help` パラメータで各カラムの説明を表示 |

## 帳票レイアウト

### レイアウト概要

Cat API 標準のテキストテーブル形式であり、1行が1セグメントに対応する。ヘッダー行はオプションで表示可能。

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ [ヘッダー行（v=trueの場合）]                                                   │
│ index  shard  prirep  ip  segment  generation  docs.count  ...              │
├─────────────────────────────────────────────────────────────────────────────┤
│ [明細行（セグメントごとに1行）]                                                  │
│ my-idx  0      p      10.0.0.1  _0  0  1000  0  50kb  0b  true  true  ...  │
│ my-idx  0      r      10.0.0.2  _0  0  1000  0  50kb  0b  true  true  ...  │
└─────────────────────────────────────────────────────────────────────────────┘
```

### ヘッダー部

ヘッダーは `v=true` パラメータ指定時のみ表示される。

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | index | インデックス名 | ShardRouting.getIndexName() | 文字列 | 可変 |
| 2 | shard | シャード番号 | ShardRouting.getId() | 整数 | 可変 |
| 3 | prirep | プライマリ(p)/レプリカ(r) | ShardRouting.primary() | p/r | 可変 |
| 4 | ip | ノードIPアドレス | DiscoveryNodes.get(nodeId).getHostAddress() | IPアドレス | 可変 |
| 5 | id | ノードID | ShardRouting.currentNodeId() | 文字列 | 可変（デフォルト非表示） |
| 6 | segment | セグメント名 | Segment.getName() | 文字列 | 可変 |
| 7 | generation | セグメント世代番号 | Segment.getGeneration() | 整数（右寄せ） | 可変 |
| 8 | docs.count | セグメント内ドキュメント数 | Segment.getNumDocs() | 整数（右寄せ） | 可変 |
| 9 | docs.deleted | 削除済みドキュメント数 | Segment.getDeletedDocs() | 整数（右寄せ） | 可変 |
| 10 | size | セグメントサイズ | Segment.getSize() | バイト数（右寄せ） | 可変 |
| 11 | size.memory | セグメントメモリ使用量 | 固定値: 0L | バイト数（右寄せ） | 可変 |
| 12 | committed | コミット済みフラグ | Segment.isCommitted() | true/false | 可変 |
| 13 | searchable | 検索可能フラグ | Segment.isSearch() | true/false | 可変 |
| 14 | version | Luceneバージョン | Segment.getVersion() | バージョン文字列 | 可変 |
| 15 | compound | コンパウンドフラグ | Segment.isCompound() | true/false | 可変 |

### フッター部

フッター部は存在しない。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| PIT ID | 特定のPIT IDを指定して絞り込み（リクエストボディの `pit_id` フィールド） | No（`_all` エンドポイント使用時は不要） |
| `_all` 指定 | `/_cat/pit_segments/_all` で全PITのセグメントを取得 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | インデックス名 | 昇順（デフォルト: インデックス順に反復） |
| 2 | シャード番号 | 昇順 |

### 改ページ条件

改ページは発生しない（API レスポンスとして全件を一度に返却）。

## データベース参照仕様

### 参照テーブル一覧

本帳票はRDBMSを使用せず、OpenSearchクラスタの内部状態から情報を取得する。

| データソース | 用途 | 取得方法 |
|-----------|------|---------|
| PitReaderContext | PIT が保持するセグメント情報の取得 | SearchService.getPitReaderContext() |
| DiscoveryNodes | ノードのIPアドレス等の情報取得 | ClusterState から取得 |
| PitService | PIT一覧の取得（`_all` 指定時） | PitService.getAllPits() |

### データソース別参照項目詳細

#### PitReaderContext

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| getSegments() | セグメント一覧（segment, generation, docs.count等） | PIT IDからSearchContextIdを復号し、シャード単位で取得 | nullの場合は空リスト |
| getShardRouting() | index, shard, prirep | 同上 | シャードルーティング情報 |

#### SearchContextId

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| shards() | シャード一覧 | PIT IDをdecodeして取得 | SearchContextIdForNode のマップ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| prirep | ShardRouting.primary() ? "p" : "r" | N/A | プライマリかレプリカかの判定 |
| size.memory | 固定値 0L | N/A | 現在の実装では常に0を返す |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[REST リクエスト受信] --> B{_all エンドポイント?}
    B -->|Yes| C[PitSegmentsRequest に _all を設定]
    B -->|No| D[リクエストボディから pit_id を解析]
    C --> E[PitSegmentsAction を実行]
    D --> E
    E --> F{_all リクエスト?}
    F -->|Yes| G[PitService.getAllPits で全PIT ID取得]
    F -->|No| H[指定されたPIT IDを使用]
    G --> I[PIT IDからシャード一覧を構築]
    H --> I
    I --> J[各シャードで shardOperation 実行]
    J --> K[PitReaderContext からセグメント情報取得]
    K --> L[IndicesSegmentResponse 生成]
    L --> M[Table にセグメントデータを格納]
    M --> N[RestTable.buildResponse でテキスト変換]
    N --> O[HTTP レスポンス返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| リクエスト解析エラー | リクエストボディのJSON解析に失敗 | "Failed to parse request body" | リクエストボディのJSON形式を確認 |
| バリデーションエラー | pit_id が未指定（`_all`でもない場合） | "no pit ids specified" | PIT IDを指定するか `_all` エンドポイントを使用 |
| 不正なパラメータ | 未知のJSONフィールドが含まれる | "Unknown parameter [x] in request body..." | リクエストボディに `pit_id` のみを含める |
| 不正なpit_id値 | pit_id配列に非値トークンが含まれる | "pit_id array element should only contain PIT identifier" | pit_id に文字列値のみを指定 |
| クラスタブロック | METADATA_READ レベルのブロック発生中 | ClusterBlockException | ブロック解除を待つ |
| PIT コンテキスト消失 | 指定されたPITが既に削除済み | 空のセグメントリストを返却（エラーにはならない） | PITが有効であることを確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | PIT数 x シャード数 x セグメント数（数十～数千件） |
| 目標出力時間 | クラスタ内ブロードキャスト通信に依存（通常数秒以内） |
| 同時出力数上限 | RESTスレッドプールの上限に依存 |

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

- PIT セグメント情報へのアクセスは `indices:monitor/point_in_time/segments` アクション権限に基づいて制御される
- `allowSystemIndexAccessByDefault()` が `true` に設定されており、システムインデックスのPITセグメント情報にもアクセス可能
- 個人情報は含まれないが、クラスタのインフラ情報（IPアドレス、インデックス名等）が出力されるため、適切なアクセス制御が必要

## 備考

- `size.memory` カラムは現在の実装では常に `0` を返す（行131、RestPitSegmentsAction.java の `table.addCell(0L)`）
- PIT は Point-in-Time の略で、検索の一貫性を保つための機能である（OpenSearch 2.3.0 以降で利用可能）
- `_all` エンドポイントを使用すると、クラスタ内の全PIT のセグメント情報を一括取得できる

---

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

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

### 推奨読解順序

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

PIT セグメント情報の中心的なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PitSegmentsRequest.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/PitSegmentsRequest.java` | リクエストの構造。pitIds リスト、verbose フラグ、fromXContent() によるJSON解析処理（行93-124） |
| 1-2 | PitSegmentsAction.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/PitSegmentsAction.java` | アクション定義。NAME = "indices:monitor/point_in_time/segments"（行19） |
| 1-3 | IndicesSegmentResponse.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/IndicesSegmentResponse.java` | レスポンスの構造。IndexSegments / IndexShardSegments / ShardSegments の階層構造 |

**読解のコツ**: PitSegmentsRequest は BroadcastRequest を継承しており、クラスタ全ノードに対するブロードキャスト操作の基盤となっている。

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

REST リクエストを受け取り、内部アクションへ変換する処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestPitSegmentsAction.java | `server/src/main/java/org/opensearch/rest/action/cat/RestPitSegmentsAction.java` | REST ハンドラ。routes()（行48-49）でエンドポイント定義、doCatRequest()（行63-88）でリクエスト処理 |
| 2-2 | AbstractCatAction.java | `server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java` | Cat API の基底クラス。prepareRequest()（行68-91）で help パラメータ処理 |

**主要処理フロー**:
1. **行49**: `GET /_cat/pit_segments` と `GET /_cat/pit_segments/_all` の2つのルートを登録
2. **行63-88**: `doCatRequest()` でリクエストパスに `_all` が含まれるかを判定し、PitSegmentsRequest を構築
3. **行66-78**: `_all` でない場合はリクエストボディから `pit_id` を解析
4. **行80-87**: `PitSegmentsAction.INSTANCE` を実行し、レスポンスを Table に変換

#### Step 3: Transport層の処理を理解する

PIT セグメント情報の実際の収集処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TransportPitSegmentsAction.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/TransportPitSegmentsAction.java` | Transport アクション。doExecute()（行100-109）で `_all` 判定、shards()（行131-160）でシャード一覧構築、shardOperation()（行212-222）でセグメント取得 |

**主要処理フロー**:
- **行100-109**: `doExecute()` で `_all` リクエストの場合は PitService.getAllPits() で全PIT IDを取得
- **行131-160**: `shards()` でPIT IDをデコードし、各シャードの PitAwareShardRouting を構築
- **行212-222**: `shardOperation()` で SearchService.getPitReaderContext() からセグメント情報を取得

#### Step 4: テーブル構築処理を理解する

取得したセグメント情報をテキストテーブルに変換する処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | RestPitSegmentsAction.java | `server/src/main/java/org/opensearch/rest/action/cat/RestPitSegmentsAction.java` | getTableWithHeader()（行97-117）でカラム定義、buildTable()（行119-154）でデータ行を構築 |

**主要処理フロー**:
- **行97-117**: `getTableWithHeader()` で15カラムのテーブルヘッダーを定義（alias, desc, default 表示設定含む）
- **行119-154**: `buildTable()` で IndexSegments を3重ループで走査し、各セグメントの情報をテーブル行に追加
- **行141**: `size.memory` は固定値 `0L` が設定される

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

```
RestPitSegmentsAction.doCatRequest()                    [行63]
    |
    +-- PitSegmentsRequest 構築                          [行65-78]
    |   +-- fromXContent() で pit_id 解析               [行71-75]
    |
    +-- client.execute(PitSegmentsAction.INSTANCE, ...)  [行80]
        |
        +-- TransportPitSegmentsAction.doExecute()       [行100]
            |
            +-- (if _all) PitService.getAllPits()         [行102]
            |
            +-- shards() -- PIT IDデコード & ShardRouting構築 [行131]
            |
            +-- shardOperation()                          [行212]
                |
                +-- SearchService.getPitReaderContext()    [行217]
                |
                +-- PitReaderContext.getSegments()         [行221]
        |
        +-- newResponse() -- IndicesSegmentResponse生成   [行178]
    |
    +-- buildTable() -- Table構築                         [行84]
    |
    +-- RestTable.buildResponse() -- テキスト変換          [行85]
```

### データフロー図

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

REST Request            --> RestPitSegmentsAction           --> PitSegmentsRequest
(GET /_cat/pit_segments)        |
                                v
PIT ID (リクエストボディ)  --> TransportPitSegmentsAction     --> ShardsIterator
                                |
                                v
SearchService           --> shardOperation()                --> ShardSegments[]
(PitReaderContext)              |
                                v
DiscoveryNodes          --> buildTable()                    --> Table
(ノード情報)                    |
                                v
                           RestTable.buildResponse()        --> HTTP Response
                                                               (text/json/yaml)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RestPitSegmentsAction.java | `server/src/main/java/org/opensearch/rest/action/cat/RestPitSegmentsAction.java` | ソース | REST ハンドラ（エントリーポイント） |
| AbstractCatAction.java | `server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java` | ソース | Cat API 基底クラス |
| PitSegmentsAction.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/PitSegmentsAction.java` | ソース | アクション定義 |
| PitSegmentsRequest.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/PitSegmentsRequest.java` | ソース | リクエストモデル |
| TransportPitSegmentsAction.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/TransportPitSegmentsAction.java` | ソース | Transport アクション（メイン処理） |
| IndicesSegmentResponse.java | `server/src/main/java/org/opensearch/action/admin/indices/segments/IndicesSegmentResponse.java` | ソース | レスポンスモデル |
| ActionModule.java | `server/src/main/java/org/opensearch/action/ActionModule.java` | ソース | アクション登録 |
| TransportPitSegmentsActionTests.java | `server/src/test/java/org/opensearch/action/admin/indices/segments/TransportPitSegmentsActionTests.java` | テスト | Transport アクションのユニットテスト |
