# 通知設計書 4-sqlite3ConnectionClosed

## 概要

本ドキュメントは、SQLiteの内部関数`sqlite3ConnectionClosed()`の設計について記載する。この関数は、データベース接続クローズ時にブロックリストから接続を削除するクリーンアップ処理を提供し、unlock-notify機能のリソース管理を担う。

### 本通知の処理概要

`sqlite3ConnectionClosed()`は、データベース接続が`sqlite3_close()`によってクローズされる際に呼び出される内部関数である。この関数は、クローズされる接続がunlock-notify機能に関連するすべてのデータ構造から適切に削除されることを保証する。

**業務上の目的・背景**：データベース接続がクローズされる際、その接続がブロックリスト（`sqlite3BlockedList`）に残っていると、無効なポインタ参照やメモリリークの原因となる。また、クローズされる接続を待機している他の接続がある場合、それらに通知を送信してから削除する必要がある。`sqlite3ConnectionClosed()`は、これらのクリーンアップ処理を一括で行い、接続クローズ時のリソース整合性を保証する。

**通知の送信タイミング**：`sqlite3_close()`関数の内部処理中、接続のクリーンアップ処理の一部として呼び出される。具体的には、`main.c`の`sqlite3Close()`関数内で、接続に関連する他のリソース（関数定義、仮想テーブルなど）を解放する前に実行される。

**通知の受信者**：クローズされる接続をpUnlockConnectionとして待機していた接続に対して、登録済みのコールバックが呼び出される（`sqlite3ConnectionUnlocked()`を内部的に呼び出すため）。

**通知内容の概要**：`sqlite3ConnectionUnlocked()`と同様に、コールバック関数にはコンテキストポインタの配列と要素数が渡される。ただし、この関数の主目的はクリーンアップであり、通知はその副作用として実行される。

**期待されるアクション**：コールバックを受け取ったアプリケーションは、クローズされた接続との関連付けが解除されたことを認識する。その後、他のブロッキング接続がある場合は引き続き待機し、ない場合は操作を再試行できる。

## 通知種別

コールバック関数呼び出し（内部的に`sqlite3ConnectionUnlocked()`を呼び出すため） + 内部状態クリーンアップ

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（接続クローズ時に直接呼び出し） |
| 優先度 | 高（リソースクリーンアップのため即座に実行） |
| リトライ | なし |

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

1. `sqlite3ConnectionUnlocked(db)`を呼び出して、この接続を待機していた接続に通知
2. STATIC_MAINミューテックスを取得
3. `removeFromBlockedList(db)`でブロックリストから削除
4. `checkListProperties(db)`でリストの整合性を検証（デバッグビルド時）
5. ミューテックスを解放

## 通知テンプレート

### 関数シグネチャ

```c
void sqlite3ConnectionClosed(sqlite3 *db)
```

| 引数 | 説明 |
|-----|------|
| db | クローズされる接続 |

### 処理内容

```
1. sqlite3ConnectionUnlocked(db)を呼び出し
   - この接続を待機していた接続にコールバック通知
   - この接続をpBlockingConnectionとしていた接続のクリア
2. STATIC_MAINミューテックスを取得
3. removeFromBlockedList(db)でリストから削除
4. checkListProperties(db)で整合性検証（NDEBUGが未定義の場合）
5. ミューテックスを解放
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| db | クローズされる接続 | sqlite3_close()からの引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | sqlite3_close()呼び出し | 常に | 接続クローズ時に必ず実行 |
| API呼び出し | sqlite3_close_v2()呼び出し | 常に | 接続クローズ時に必ず実行 |

### 送信抑止条件

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

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[sqlite3_close呼び出し] --> B[sqlite3Close内部処理]
    B --> C[sqlite3ConnectionClosed呼び出し]
    C --> D[sqlite3ConnectionUnlocked呼び出し]
    D --> E[待機中接続へのコールバック通知]
    E --> F[enterMutex - STATIC_MAINロック取得]
    F --> G[removeFromBlockedList]
    G --> H[checkListProperties - 整合性検証]
    H --> I[leaveMutex - ロック解放]
    I --> J[終了 - 後続クリーンアップへ]
```

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

### 参照テーブル一覧

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

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

| 変数名 | 型 | 操作 | 用途 | 備考 |
|--------|---|------|------|------|
| sqlite3BlockedList | sqlite3* | 参照/更新 | ブロックされた接続のリンクリスト先頭 | エントリ削除時に更新 |

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

| メンバー名 | 型 | 操作 | 用途 |
|-----------|---|------|------|
| pBlockingConnection | sqlite3* | 間接参照（sqlite3ConnectionUnlocked経由） | 他接続からの参照クリア |
| pUnlockConnection | sqlite3* | 間接参照（sqlite3ConnectionUnlocked経由） | 他接続からの参照クリア |
| pNextBlocked | sqlite3* | 更新 | リストからの削除時に更新 |

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（接続クローズ時に即座に呼び出し）

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

- SQLITE_MUTEX_STATIC_MAINミューテックスでグローバルデータ構造を保護
- 接続クローズ後の無効ポインタ参照を防止
- `checkListProperties(db)`でdbへの参照が残っていないことを検証（デバッグビルド時）

## 備考

- SQLITE_ENABLE_UNLOCK_NOTIFYコンパイルオプションが必要
- notify.cで実装され、main.cのsqlite3Close()から呼び出される
- `sqlite3ConnectionUnlocked()`を内部的に呼び出すため、待機中接続への通知も同時に行われる
- 接続クローズ時のクリーンアップ処理の一部として必ず実行される

---

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

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

### 推奨読解順序

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

まず、クリーンアップ対象となるデータ構造を理解する。

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

**読解のコツ**: `pNextBlocked`がリンクリストの構造を形成。`removeFromBlockedList()`はこのポインタを操作してリストから削除する。

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

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

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

**主要処理フロー**:
1. **329行**: `sqlite3ConnectionUnlocked(db)`呼び出し - 待機中接続への通知
2. **330行**: `enterMutex()` - STATIC_MAINミューテックス取得
3. **331行**: `removeFromBlockedList(db)` - リストからの削除
4. **332行**: `checkListProperties(db)` - 整合性検証（dbへの参照がないことを確認）
5. **333行**: `leaveMutex()` - ミューテックス解放

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | main.c | `src/main.c` | sqlite3Close()内での呼び出し（1406-1409行目） |

**主要処理フロー（main.c:1406-1409行目）**:
```c
/* Tell the code in notify.c that the connection no longer holds any
** locks and does not require any further unlock-notify callbacks.
*/
sqlite3ConnectionClosed(db);
```
- 接続がロックを保持しておらず、unlock-notifyコールバックも不要であることをnotify.cに通知

#### Step 4: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | notify.c | `src/notify.c` | sqlite3ConnectionUnlocked()（229-322行目）- 内部呼び出し |
| 4-2 | notify.c | `src/notify.c` | removeFromBlockedList()（83-92行目） |
| 4-3 | notify.c | `src/notify.c` | checkListProperties()（57-74行目）- デバッグ検証 |

**removeFromBlockedList()の処理フロー（83-92行目）**:
```c
static void removeFromBlockedList(sqlite3 *db){
  sqlite3 **pp;
  assertMutexHeld();
  for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){
    if( *pp==db ){
      *pp = (*pp)->pNextBlocked;
      break;
    }
  }
}
```
- リンクリストをスキャンし、該当するエントリを削除

**checkListProperties(db)の検証内容（デバッグビルド時）**:
- リスト内の全エントリで`pUnlockConnection!=db`かつ`pBlockingConnection!=db`であることを確認
- これにより、クローズされる接続への参照が残っていないことを保証

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

```
main.c: sqlite3_close() または sqlite3_close_v2()
    |
    +-- sqlite3Close()  [main.c]
            |
            +-- [様々なクリーンアップ処理...]
            |
            +-- sqlite3ConnectionClosed(db)  [notify.c:328]
                    |
                    +-- sqlite3ConnectionUnlocked(db)  [notify.c:329]
                    |       |
                    |       +-- [待機中接続へのコールバック通知]
                    |       +-- [pBlockingConnection/pUnlockConnectionのクリア]
                    |
                    +-- enterMutex()  [notify.c:330]
                    |
                    +-- removeFromBlockedList(db)  [notify.c:331]
                    |       |
                    |       +-- [sqlite3BlockedListからdbを削除]
                    |
                    +-- checkListProperties(db)  [notify.c:332]
                    |       |
                    |       +-- [dbへの参照がないことを検証]
                    |
                    +-- leaveMutex()  [notify.c:333]
```

### データフロー図

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

sqlite3_close(db)    --->  sqlite3Close()
                               |
                               v
                     sqlite3ConnectionClosed(db)
                               |
                               +--- sqlite3ConnectionUnlocked(db)
                               |       |
                               |       +---> 待機中接続へのコールバック
                               |       +---> 内部状態クリア
                               |
                               +--- removeFromBlockedList(db)
                               |       |
                               |       +---> sqlite3BlockedList更新
                               |
                               +--- checkListProperties(db)
                                       |
                                       +---> 整合性検証結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notify.c | `src/notify.c` | ソース | sqlite3ConnectionClosed()の実装 |
| sqliteInt.h | `src/sqliteInt.h` | ヘッダー | sqlite3構造体定義、関数プロトタイプ |
| main.c | `src/main.c` | ソース | 呼び出し元（sqlite3Close関数） |
