# 機能設計書 95-KVStore

## 概要

本ドキュメントは、Apache SparkのKVStore（Key-Value Store）の設計について記述する。アプリケーションデータの永続化とインメモリキャッシュのための統一的なキーバリューストア抽象を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Spark UIやHistory Serverでは、ジョブ・ステージ・タスクなどの実行情報を保存・検索する必要がある。KVStoreは、インメモリ（InMemoryStore）、LevelDB、RocksDBの3つのバックエンドを統一的なインターフェースで利用可能にし、データの永続化とインデックス付きの高速検索を実現する。

**機能の利用シーン**：Spark UIのジョブ履歴表示、History Serverでのアプリケーション情報の永続化、メトリクス・イベントの保存と検索で利用される。

**主要な処理内容**：
1. KVStoreインターフェースによるCRUD操作（read, write, delete, view, count）
2. @KVIndexアノテーションによるフィールドベースのインデックス定義
3. InMemoryStoreによるインメモリデータ管理（ConcurrentHashMap）
4. LevelDB/RocksDBによるディスクベースの永続化
5. KVStoreViewによるソート・フィルタリング・ページネーション付きイテレーション
6. Jacksonベースのシリアライゼーション（KVStoreSerializer）

**関連システム・外部連携**：Spark UI（AppStatusStore）、History Server（FsHistoryProvider）から利用される。LevelDB/RocksDBのネイティブライブラリに依存（永続化ストア使用時）。

**権限による制御**：特になし。KVStoreインスタンスはスレッドセーフ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに本機能に対応する画面定義なし |

## 機能種別

基盤 / データストア

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| klass | Class<T> | Yes | データ型クラス | @KVIndexアノテーション付きクラス |
| naturalKey | Object | Yes（read/delete） | 自然キー（一意識別子） | null不可 |
| value | Object | Yes（write） | 書き込みオブジェクト | - |
| index | String | No | インデックス名 | KVIndexで定義済み |
| indexedValue | Object | No | インデックス値 | - |

### 入力データソース

アプリケーション内部で生成されたデータオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 読み取り結果 | T | readで取得したオブジェクト |
| ビュー | KVStoreView<T> | ソート・フィルタ付きイテレータ |
| カウント | long | 型別またはインデックス別の件数 |
| メタデータ | T | アプリケーション固有メタデータ |

## 処理フロー

### 処理シーケンス

```
1. ストア初期化
   a. InMemoryStore: ConcurrentHashMapの初期化
   b. LevelDB: ネイティブライブラリロード → DB open
   c. RocksDB: ネイティブライブラリロード → DB open

2. write(value)
   a. InMemoryStore:
      - value.getClass()からInstanceListを取得/作成
      - KVTypeInfoで@KVIndexフィールド解析
      - naturalKeyを抽出してConcurrentHashMapに格納
      - parentIndex存在時はparentToChildrenMapも更新
   b. LevelDB/RocksDB:
      - KVStoreSerializerでシリアライズ
      - naturalKeyからDBキー生成
      - DBに書き込み（インデックスも同時更新）

3. read(klass, naturalKey)
   a. InMemoryStore:
      - InstanceList.get(naturalKey) → ConcurrentHashMap.get()
      - 見つからない場合はNoSuchElementException
   b. LevelDB/RocksDB:
      - DBキー生成 → DB.get() → デシリアライズ

4. view(type)
   a. InMemoryStore:
      - InMemoryView生成 → iterator()でソート・フィルタ適用
      - copyElements()でデータコピー → sort → stream filter
   b. LevelDB/RocksDB:
      - DBIteratorでスキャン

5. delete(type, naturalKey)
   a. InMemoryStore:
      - ConcurrentHashMap.remove()
      - parentToChildrenMapからの削除
   b. LevelDB/RocksDB:
      - DB.delete() + インデックス削除

6. removeAllByIndexValues(klass, index, indexValues)
   a. NATURAL_INDEX: 直接キーで削除
   b. naturalParentIndex: parentToChildrenMap利用で効率的削除
   c. その他: 全データスキャンでフィルタ削除
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-95-01 | 自然キー一意性 | 同一型の同一naturalKeyはwrite時に上書き | write()呼び出し時 |
| BR-95-02 | スレッドセーフ | 全操作はスレッドセーフ（ConcurrentHashMap使用） | 常時 |
| BR-95-03 | インデックスソート | view()のイテレーションはインデックスでソート可能 | index指定時 |
| BR-95-04 | 親子関係 | parentIndexにより親子関係に基づくフィルタリングが可能 | @KVIndex(parent=)指定時 |
| BR-95-05 | 自動圧縮 | LevelDB/RocksDB使用時はデータ自動圧縮 | 永続化ストア使用時 |

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| write | KVStoreバックエンド | PUT | オブジェクトとインデックスの書き込み |
| read | KVStoreバックエンド | GET | naturalKeyによるオブジェクト取得 |
| delete | KVStoreバックエンド | DELETE | オブジェクトとインデックスの削除 |
| view | KVStoreバックエンド | SCAN | ソート・フィルタ付きスキャン |
| count | KVStoreバックエンド | COUNT | 件数取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NoSuchElementException | 検索エラー | read()で指定キーが存在しない | キーの存在を事前確認 |
| IOException | DB操作エラー | LevelDB/RocksDB操作失敗 | ストアの再初期化 |
| ReflectiveOperationException | リフレクションエラー | @KVIndexフィールドアクセス失敗 | アノテーション定義確認 |

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

InMemoryStoreでのトランザクション保証はない（ConcurrentHashMapの原子性に依存）。LevelDB/RocksDBはWriteBatchによるアトミック書き込みをサポート。

## パフォーマンス要件

- InMemoryStore: O(1)の読み書き、O(n log n)のview（ソートのため）
- LevelDB/RocksDB: O(log n)の読み書き、O(n)のスキャン
- parentToChildrenMap最適化により、親子関係でのフィルタリングが高速

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

特になし。KVStoreは@Privateアノテーションによりinternal APIとして扱われる。

## 備考

`common/kvstore/` パッケージ配下に実装。LevelDBはSTORE_VERSION=1で管理。

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | KVStore.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStore.java` | **66-135行目**: KVStoreインターフェース。getMetadata/setMetadata/read/write/delete/view/count/removeAllByIndexValues |
| 1-2 | KVIndex.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVIndex.java` | インデックスアノテーション定義。NATURAL_INDEX_NAME、parent、copy属性 |
| 1-3 | KVStoreView.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStoreView.java` | ビュー抽象クラス。index/ascending/first/last/skip/max/parentのフィルタパラメータ |

**読解のコツ**: KVStoreインターフェースのJavadoc（28-64行目）を先に読み、自動キー管理とインデックスの仕組みを理解する。

#### Step 2: インメモリ実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | InMemoryStore.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/InMemoryStore.java` | 本機能の参照実装 |

**主要処理フロー**:
- **44-47行目**: フィールド定義。metadata、InMemoryLists（ConcurrentHashMap<Class, InstanceList>）
- **80-87行目**: read()。InstanceList.get()で取得、見つからなければNoSuchElementException
- **90-92行目**: write()。InMemoryLists.write()でInstanceList生成/格納
- **145-163行目**: InMemoryLists内部クラス。型ごとのInstanceListをConcurrentHashMapで管理
- **172-338行目**: InstanceList内部クラス。KVTypeInfoでリフレクション管理、ConcurrentHashMap<Comparable, T>でデータ格納、parentToChildrenMapで親子関係管理
- **231-261行目**: countingRemoveAllByIndexValues。NATURAL_INDEX/parentIndex/一般インデックスで分岐最適化
- **340-450行目**: InMemoryView内部クラス。iterator()でソート・フィルタ・ページネーション実装

#### Step 3: 永続化実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LevelDB.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/LevelDB.java` | **46-60行目**: LevelDB実装のフィールド定義。STORE_VERSION, STORE_VERSION_KEY, METADATA_KEY, TYPE_ALIASES_KEY |
| 3-2 | RocksDB.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/RocksDB.java` | **43-60行目**: RocksDB実装。LevelDBと同等のインターフェース |

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

```
KVStore (インターフェース)
    |
    +-- InMemoryStore
    |     +-- InMemoryLists
    |     |     +-- ConcurrentHashMap<Class, InstanceList>
    |     +-- InstanceList
    |     |     +-- KVTypeInfo [リフレクション]
    |     |     +-- ConcurrentHashMap<Comparable, T> [データ]
    |     |     +-- parentToChildrenMap [親子関係]
    |     +-- InMemoryView
    |           +-- iterator() --> sort --> filter --> stream
    |
    +-- LevelDB
    |     +-- JniDBFactory / DB
    |     +-- KVStoreSerializer [Jackson]
    |     +-- WriteBatch [アトミック書き込み]
    |
    +-- RocksDB
          +-- org.rocksdb.RocksDB
          +-- KVStoreSerializer [Jackson]
```

### データフロー図

```
[アプリケーション]            [KVStore API]              [バックエンド]

AppStatusStore    ──>    write(obj)         ──>    InMemoryStore / LevelDB / RocksDB
                 ──>    read(Class, key)   ──>
                 ──>    view(Class)        ──>    InstanceList / DBIterator
                 ──>    count(Class)       ──>
                 ──>    delete(Class, key) ──>

FsHistoryProvider ──>   LevelDB.open()     ──>    LevelDB / RocksDB (ディスク)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| KVStore.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStore.java` | ソース | KVStoreインターフェース |
| InMemoryStore.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/InMemoryStore.java` | ソース | インメモリ実装 |
| LevelDB.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/LevelDB.java` | ソース | LevelDB永続化実装 |
| RocksDB.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/RocksDB.java` | ソース | RocksDB永続化実装 |
| KVIndex.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVIndex.java` | ソース | インデックスアノテーション |
| KVStoreView.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStoreView.java` | ソース | ビュー抽象クラス |
| KVStoreIterator.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStoreIterator.java` | ソース | イテレータインターフェース |
| KVStoreSerializer.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVStoreSerializer.java` | ソース | Jacksonシリアライザ |
| KVTypeInfo.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/KVTypeInfo.java` | ソース | 型情報・リフレクション管理 |
| ArrayWrappers.java | `common/kvstore/src/main/java/org/apache/spark/util/kvstore/ArrayWrappers.java` | ソース | 配列ラッパー（Comparable対応） |
