# 通知設計書 11-DirectoryWatcher WatchedDirRemoved

## 概要

本ドキュメントは、clangのDirectoryWatcherコンポーネントにおける`WatchedDirRemoved`イベント通知の設計仕様を記述する。監視対象ディレクトリ自体が削除された際にクライアントへ通知するイベントメカニズムである。

### 本通知の処理概要

DirectoryWatcher WatchedDirRemovedは、ファイルシステム監視機能において監視対象のディレクトリ自体が削除された場合に発生する重要な通知イベントである。

**業務上の目的・背景**：IDE、言語サーバー（clangd等）、ビルドシステムなどのツールでは、ソースコードディレクトリやコンパイルデータベースのディレクトリを継続的に監視している。監視対象ディレクトリが削除された場合、ツールは状態を適切にリセットし、ユーザーに警告を表示したり、関連するキャッシュを無効化する必要がある。この通知により、ツールはディレクトリ削除を検知し、適切なエラーハンドリングやリソースクリーンアップを実行できる。

**通知の送信タイミング**：OSカーネルからのファイルシステムイベント（Linuxではinotifyの`IN_DELETE_SELF`または`IN_MOVE_SELF`、macOSではFSEventsの`kFSEventStreamEventFlagItemRemoved`）を受信した際に送信される。監視対象ディレクトリが削除、移動、またはリネームされた場合にトリガーされる。

**通知の受信者**：DirectoryWatcherインスタンスを作成した際に登録されたReceiverコールバック関数が受信者となる。通常は、ClangTooling、clangd、その他のLLVMツールチェーンのコンポーネントがReceiverを登録する。

**通知内容の概要**：`DirectoryWatcher::Event`構造体として通知される。`EventKind`は`WatchedDirRemoved`、`Filename`は空文字列（ディレクトリ自体に関するイベントのため）である。この通知の直後には必ず`WatcherGotInvalidated`通知も送信される。

**期待されるアクション**：受信者はこの通知を受け取った後、DirectoryWatcherインスタンスを破棄し、必要に応じて新しいディレクトリパスで再作成する必要がある。また、関連するキャッシュの無効化、ユーザーへの警告表示、エラーログの記録などを行うべきである。

## 通知種別

イベントコールバック（C++関数オブジェクト）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（イベントキュー経由） |
| 優先度 | 高（Watcher無効化を伴うため） |
| リトライ | なし（一度限りのイベント） |

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

DirectoryWatcher::create()で登録されたReceiverコールバック関数に対して通知される。Receiverは`std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)>`型であり、Eventsの配列とIsInitialフラグを受け取る。

## 通知テンプレート

### イベント通知の場合

| 項目 | 内容 |
|-----|------|
| イベント種別 | `DirectoryWatcher::Event::EventKind::WatchedDirRemoved` |
| Filename | 空文字列 `""` |
| IsInitial | `false`（実行時イベント） |

### 本文テンプレート

```cpp
DirectoryWatcher::Event{
    DirectoryWatcher::Event::EventKind::WatchedDirRemoved,
    ""  // Filename is empty for directory-level events
}
```

### 添付ファイル

該当なし（プログラムイベントのため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Kind | イベント種別 | `EventKind::WatchedDirRemoved`固定 | Yes |
| Filename | ファイル名 | 空文字列固定 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| OSイベント（Linux） | inotify `IN_DELETE_SELF` | 監視ディレクトリの削除 | ディレクトリ自身が削除された |
| OSイベント（Linux） | inotify `IN_MOVE_SELF` | 監視ディレクトリの移動 | ディレクトリ自身が移動またはリネームされた |
| OSイベント（macOS） | FSEvents `kFSEventStreamEventFlagItemRemoved` | 監視ディレクトリの削除 | パスが監視対象ディレクトリと一致 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| サブディレクトリの削除 | 監視対象はフラットディレクトリのみ。サブディレクトリの削除ではこのイベントは発生しない |
| 既にWatcherが無効化済み | WatcherGotInvalidatedが既に送信されている場合は送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[OSからファイルシステムイベント受信] --> B{イベント種別判定}
    B -->|IN_DELETE_SELF/IN_MOVE_SELF| C[WatchedDirRemovedイベント生成]
    B -->|その他| D[別のイベント処理へ]
    C --> E[イベントキューにプッシュ]
    E --> F[WatcherGotInvalidatedイベント生成]
    F --> G[StopWork呼び出し]
    G --> H[Receiverコールバック実行]
    H --> I[処理完了]
```

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

### 参照テーブル一覧

該当なし（ファイルシステム監視のためDBは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| イベント処理中のエラー | Receiverコールバック内で例外発生 | Watcherは継続動作せず、WatcherGotInvalidatedが送信される |
| キュー操作エラー | EventQueueへのプッシュ失敗 | StopWorkが呼び出され、Watcherは無効化 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

24時間常時（ファイルシステムイベント発生時に即時送信）

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

- ファイルシステムのアクセス権限に依存する
- 監視対象ディレクトリへの読み取りアクセス権が必要
- シンボリックリンクの解決にはrealpath()が使用される（macOS実装）
- ファイルディスクリプタはFD_CLOEXEC/O_CLOEXECフラグで保護

## 備考

- WatchedDirRemovedの後には必ずWatcherGotInvalidatedが送信される
- macOS実装ではFSEventsのイベント結合により、削除の前に重複したModifiedイベントが発生する可能性がある
- Linux実装ではinotifyを使用、macOS実装ではFSEventsを使用
- Windows実装も存在するが、別ファイルで実装されている

---

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

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

### 推奨読解順序

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

まず、イベントデータ構造とEventKind列挙型を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | DirectoryWatcher.h | `clang/include/clang/DirectoryWatcher/DirectoryWatcher.h` | Event構造体とEventKind列挙型の定義（行66-100）。WatchedDirRemovedの意味と用途を確認 |

**読解のコツ**: EventKind列挙型は4種類のイベント（Removed, Modified, WatchedDirRemoved, WatcherGotInvalidated）を定義している。行72-90のコメントで各イベントの意味が詳細に説明されている。

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

処理の起点となるDirectoryWatcher::create()関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DirectoryWatcher.h | `clang/include/clang/DirectoryWatcher/DirectoryWatcher.h` | create()静的メソッドの宣言（行106-111）。Receiverコールバックの登録方法を確認 |

**主要処理フロー**:
1. **行106-111**: create()メソッドがPath、Receiver、WaitForInitialSyncを受け取りDirectoryWatcherを生成
2. **行108-110**: Receiver関数の型は`std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)>`

#### Step 3: Linux実装の処理フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DirectoryWatcher-linux.cpp | `clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp` | Linux固有のinotify実装。WatchedDirRemovedの生成箇所（行258-261）を確認 |

**主要処理フロー**:
- **行171-273**: InotifyPollingLoop()でinotifyイベントを処理
- **行258-261**: `IN_DELETE_SELF`または`IN_MOVE_SELF`イベント受信時にWatchedDirRemovedをキューにプッシュし、StopWork()を呼び出す
- **行164-168**: StopWork()でWatcherGotInvalidatedをキューにプッシュ

#### Step 4: macOS実装の処理フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | DirectoryWatcher-mac.cpp | `clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp` | macOS固有のFSEvents実装。WatchedDirRemovedの生成箇所（行124-131）を確認 |

**主要処理フロー**:
- **行105-158**: eventStreamCallback()でFSEventsイベントを処理
- **行121-131**: ディレクトリ（非ファイル）に対するItemRemovedフラグ受信時、パスが監視対象と一致すればWatchedDirRemovedとWatcherGotInvalidatedを生成

#### Step 5: テストコードで動作を確認する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | DirectoryWatcherTest.cpp | `clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp` | DeleteWatchedDirテスト（行419-440）でWatchedDirRemovedの期待動作を確認 |

**主要処理フロー**:
- **行422-425**: 期待されるイベントとしてWatchedDirRemovedとWatcherGotInvalidatedを設定
- **行437**: remove_directories()で監視ディレクトリを削除してイベントをトリガー

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

```
DirectoryWatcher::create()
    │
    ├─ [Linux] DirectoryWatcherLinux constructor
    │      ├─ inotify_init1() / inotify_add_watch()
    │      ├─ InotifyPollingThread (InotifyPollingLoop)
    │      │      └─ Queue.push_back(WatchedDirRemoved)
    │      │             └─ StopWork()
    │      │                    └─ Queue.push_back(WatcherGotInvalidated)
    │      └─ EventsReceivingThread (EventReceivingLoop)
    │             └─ Receiver(Event)
    │
    └─ [macOS] DirectoryWatcherMac constructor
           ├─ createFSEventStream()
           ├─ FSEventStreamSetDispatchQueue()
           ├─ eventStreamCallback()
           │      └─ Events.emplace_back(WatchedDirRemoved)
           │             └─ Events.emplace_back(WatcherGotInvalidated)
           └─ Receiver(Events)
```

### データフロー図

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

OSイベント              イベント判定・変換                 コールバック
─────────────────────────────────────────────────────────────────────

[Linux]
IN_DELETE_SELF ───────▶ InotifyPollingLoop ──▶ EventQueue ──▶ Receiver()
IN_MOVE_SELF                   │
                               ▼
                         WatchedDirRemoved
                         + WatcherGotInvalidated

[macOS]
kFSEventStreamEventFlagItemRemoved ───▶ eventStreamCallback ──▶ Receiver()
                                               │
                                               ▼
                                         WatchedDirRemoved
                                         + WatcherGotInvalidated
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DirectoryWatcher.h | `clang/include/clang/DirectoryWatcher/DirectoryWatcher.h` | ヘッダー | Event構造体・DirectoryWatcherクラス定義 |
| DirectoryWatcher-linux.cpp | `clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp` | ソース | Linux (inotify) 実装 |
| DirectoryWatcher-mac.cpp | `clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp` | ソース | macOS (FSEvents) 実装 |
| DirectoryWatcher-windows.cpp | `clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp` | ソース | Windows実装 |
| DirectoryScanner.cpp | `clang/lib/DirectoryWatcher/DirectoryScanner.cpp` | ソース | ディレクトリスキャン補助機能 |
| DirectoryScanner.h | `clang/lib/DirectoryWatcher/DirectoryScanner.h` | ヘッダー | ディレクトリスキャン補助機能定義 |
| DirectoryWatcherTest.cpp | `clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp` | テスト | ユニットテスト |
