# 通知設計書 2-sqlite3ConnectionBlocked

## 概要

本ドキュメントは、SQLiteの内部関数`sqlite3ConnectionBlocked()`の設計について記載する。この関数は、接続がロックされた際に内部的にブロッキング接続情報を記録する機能を提供し、`sqlite3_unlock_notify()` APIの基盤となる。

### 本通知の処理概要

`sqlite3ConnectionBlocked()`は、共有キャッシュモードにおいてデータベース接続がSQLITE_LOCKEDエラーを返す直前に呼び出される内部関数である。この関数は、どの接続がロックを保持しているか（ブロッキング接続）の情報を記録し、後続のunlock-notify処理の準備を行う。

**業務上の目的・背景**：共有キャッシュモードでは、複数のデータベース接続が同一のBtree構造を共有する。ある接続がロックを取得しようとして失敗した場合、どの接続がそのロックを保持しているかを特定する必要がある。この情報がなければ、`sqlite3_unlock_notify()`はどの接続のトランザクション終了を待てばよいか判断できない。`sqlite3ConnectionBlocked()`は、このブロッキング関係を記録する重要な役割を担う。

**通知の送信タイミング**：Btreeレイヤーでロック取得に失敗し、SQLITE_LOCKED_SHAREDCACHEエラーを返す直前に呼び出される。具体的には、`querySharedCacheTableLock()`や`sqlite3BtreeBeginTrans()`関数内で、他の接続がロックを保持していることが検出された時点で実行される。

**通知の受信者**：直接的な受信者はなく、この関数はsqlite3構造体のメンバー（`pBlockingConnection`）を設定するのみである。この情報は後に`sqlite3_unlock_notify()`や`sqlite3ConnectionUnlocked()`によって参照される。

**通知内容の概要**：ブロックされた接続（`db`）と、その原因となったブロッキング接続（`pBlocker`）の関係がsqlite3構造体に記録される。また、必要に応じてグローバルな`sqlite3BlockedList`に接続が追加される。

**期待されるアクション**：この関数自体はアクションを要求しない。記録された情報は、アプリケーションが`sqlite3_unlock_notify()`を呼び出してコールバックを登録する際に使用される。

## 通知種別

内部状態更新（コールバックや外部通知ではなく、内部データ構造の更新）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（呼び出し元から直接呼び出し） |
| 優先度 | 高（ロック情報の即座の記録が必要） |
| リトライ | なし（単純なメモリ操作） |

### 送信先決定ロジック

1. Btreeレイヤーでロック競合を検出
2. ブロッキング接続（ロックを保持している接続）を特定
3. `sqlite3ConnectionBlocked(db, pBlocker)`を呼び出し
4. `db->pBlockingConnection`にブロッキング接続を設定
5. 初めてブロックされる場合、`sqlite3BlockedList`に追加

## 通知テンプレート

### 関数シグネチャ

```c
void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker)
```

| 引数 | 説明 |
|-----|------|
| db | ブロックされた接続（SQLITE_LOCKEDを受け取る接続） |
| pBlocker | ブロッキング接続（ロックを保持している接続） |

### 処理内容

```
1. STATIC_MAINミューテックスを取得
2. dbが初めてブロックされる場合（pBlockingConnection==0 && pUnlockConnection==0）
   - sqlite3BlockedListにdbを追加
3. db->pBlockingConnectionにpBlockerを設定
4. ミューテックスを解放
```

### 添付ファイル

該当なし（内部関数呼び出し）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| db | ブロックされた接続 | 呼び出し元関数の引数 | Yes |
| pBlocker | ブロッキング接続 | Btreeロック情報 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Btree操作 | querySharedCacheTableLock()失敗 | 他接続がロック保持 | テーブルロック取得失敗時（btree.c:371行目） |
| Btree操作 | sqlite3BtreeBeginTrans()失敗 | 他接続が排他ロック保持 | トランザクション開始失敗時（btree.c:3648行目） |
| Btree操作 | 排他ロック競合 | BTS_EXCLUSIVEフラグ設定済み | 排他ロック中の操作（btree.c:354行目） |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| SQLITE_ENABLE_UNLOCK_NOTIFYが未定義 | コンパイルオプションが無効の場合、マクロで空定義に展開 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Btree操作でロック競合検出] --> B{他接続がロック保持?}
    B -->|Yes| C[pBlockerを特定]
    C --> D[sqlite3ConnectionBlocked呼び出し]
    D --> E[enterMutex - STATIC_MAINロック取得]
    E --> F{初めてブロック?}
    F -->|Yes| G[addToBlockedList]
    F -->|No| H[スキップ]
    G --> I[pBlockingConnection設定]
    H --> I
    I --> J[leaveMutex - ロック解放]
    J --> K[SQLITE_LOCKED_SHAREDCACHE返却]
    B -->|No| L[正常処理継続]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（インメモリデータ構造のみ使用）

### グローバル変数参照・更新

| 変数名 | 型 | 操作 | 用途 | 備考 |
|--------|---|------|------|------|
| sqlite3BlockedList | sqlite3* | 参照/更新 | ブロックされた接続のリンクリスト先頭 | STATIC_MAINミューテックスで保護 |

### sqlite3構造体メンバー参照・更新

| メンバー名 | 型 | 操作 | 用途 |
|-----------|---|------|------|
| pBlockingConnection | sqlite3* | 更新 | ブロッキング接続を設定 |
| pUnlockConnection | sqlite3* | 参照 | リストへの追加判定に使用 |
| pNextBlocked | sqlite3* | 更新（間接） | addToBlockedList()で設定 |

### 更新テーブル一覧

該当なし（インメモリデータ構造のみ使用）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| なし | - | この関数はエラーを返さない（void型） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（ロック競合発生時に即座に呼び出し）

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

- SQLITE_MUTEX_STATIC_MAINミューテックスでグローバルデータ構造を保護
- マルチスレッド環境での競合を防止
- 接続間の情報漏洩はない（ポインタの記録のみ）

## 備考

- SQLITE_ENABLE_UNLOCK_NOTIFYコンパイルオプションが必要
- 未定義の場合は空のマクロ`#define sqlite3ConnectionBlocked(x,y)`に展開される
- notify.cで実装されているが、btree.cから呼び出される
- この関数はsqlite3_unlock_notify()の基盤機能を提供する

---

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

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

### 推奨読解順序

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

まず、ブロッキング関係を記録するためのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sqliteInt.h | `src/sqliteInt.h` | sqlite3構造体のunlock-notify関連メンバー（1790-1803行目） |

**読解のコツ**: `pBlockingConnection`がこの関数で設定される主要なメンバー。`pUnlockConnection`は既存の登録状態を確認するために参照される。

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

処理の起点となる内部関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notify.c | `src/notify.c` | sqlite3ConnectionBlocked()関数（201-208行目）の実装 |

**主要処理フロー**:
1. **202行**: enterMutex()でSTATIC_MAINミューテックス取得
2. **203行**: 初めてブロックされるかの判定（pBlockingConnection==0 && pUnlockConnection==0）
3. **204行**: addToBlockedList(db)でグローバルリストに追加
4. **206行**: db->pBlockingConnection = pBlocker で関係を記録
5. **207行**: leaveMutex()でミューテックス解放

#### Step 3: 呼び出し元を理解する

この関数がどこから呼び出されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | btree.c | `src/btree.c` | querySharedCacheTableLock()内での呼び出し（354, 371行目） |
| 3-2 | btree.c | `src/btree.c` | sqlite3BtreeBeginTrans()内での呼び出し（3648行目） |

**主要処理フロー（btree.c:354行目）**:
```c
if( pBt->pWriter!=p && (pBt->btsFlags & BTS_EXCLUSIVE)!=0 ){
  sqlite3ConnectionBlocked(p->db, pBt->pWriter->db);
  return SQLITE_LOCKED_SHAREDCACHE;
}
```
- 排他ロック（BTS_EXCLUSIVE）を保持している接続が存在する場合

**主要処理フロー（btree.c:371行目）**:
```c
if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){
  sqlite3ConnectionBlocked(p->db, pIter->pBtree->db);
  ...
}
```
- 特定テーブルのロックが競合している場合

**主要処理フロー（btree.c:3648行目）**:
```c
if( pBlock ){
  sqlite3ConnectionBlocked(p->db, pBlock);
  rc = SQLITE_LOCKED_SHAREDCACHE;
  ...
}
```
- トランザクション開始時にブロッキング接続が検出された場合

#### Step 4: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | notify.c | `src/notify.c` | addToBlockedList()（98-108行目） |
| 4-2 | notify.c | `src/notify.c` | enterMutex()/leaveMutex()（113-125行目） |

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

```
btree.c: querySharedCacheTableLock() または sqlite3BtreeBeginTrans()
    |
    +-- [ロック競合検出]
    |
    +-- sqlite3ConnectionBlocked(db, pBlocker)  [notify.c:201]
            |
            +-- enterMutex()  [notify.c:113]
            |       +-- sqlite3_mutex_enter(SQLITE_MUTEX_STATIC_MAIN)
            |       +-- checkListProperties(0)
            |
            +-- [条件判定: pBlockingConnection==0 && pUnlockConnection==0]
            |       |
            |       +-- addToBlockedList(db)  [notify.c:98]
            |               +-- [同一xUnlockNotifyでグループ化]
            |               +-- db->pNextBlocked設定
            |
            +-- db->pBlockingConnection = pBlocker
            |
            +-- leaveMutex()  [notify.c:121]
                    +-- checkListProperties(0)
                    +-- sqlite3_mutex_leave(SQLITE_MUTEX_STATIC_MAIN)
```

### データフロー図

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

Btreeロック競合検出   --->  sqlite3ConnectionBlocked()
sqlite3 *db          --->       |
sqlite3 *pBlocker    --->       v
                         [ミューテックス取得]
                                |
                                v
                         [sqlite3BlockedListに追加]  --->  グローバルリスト更新
                                |
                                v
                         [pBlockingConnection設定]  --->  db構造体更新
                                |
                                v
                         [ミューテックス解放]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notify.c | `src/notify.c` | ソース | sqlite3ConnectionBlocked()の実装 |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | sqlite3構造体定義、関数プロトタイプ |
| btree.c | `src/btree.c` | ソース | 呼び出し元（ロック競合検出） |
| btreeInt.h | `src/btreeInt.h` | ヘッダー | Btree内部構造定義 |
