# 画面設計書 65-ProfileGCエントリ取得（served/getProfileGCEntries）

## 概要

本ドキュメントは、serve-d LSPサーバーのカスタムリクエスト `served/getProfileGCEntries` の画面設計書である。profilegc.logファイルを解析し、GC（ガベージコレクタ）のアロケーション情報をエントリとして返却する。

### 本画面の処理概要

本リクエストは、D言語ランタイムが出力するprofilegc.logのデータを解析し、ソースコードの各行に対応するGCアロケーション情報を返却する機能を提供する。

**業務上の目的・背景**：D言語のプログラムは、GCプロファイリングオプション（`--DRT-gcopt=profile:1`）を使用することで、どのソース行でどれだけのGCアロケーションが発生しているかを記録できる。この情報はパフォーマンスチューニングに不可欠であり、エディタ上でコードレンズとして表示することで開発者がGC負荷の高い箇所を特定できる。本リクエストはそのための全エントリデータを返却する。

**画面へのアクセス方法**：LSPクライアントから `served/getProfileGCEntries` カスタムリクエストを送信することでアクセスする。

**主要な操作・処理内容**：
1. クライアントからリクエストを受信する（パラメータなし）
2. キャッシュされた全profilegc.logのエントリを収集する
3. ProfileGCEntry配列として返却する

**画面遷移**：
- 遷移元：エディタのGCプロファイラ表示UI
- 遷移先：なし（データ返却のみ）

**権限による表示制御**：設定 `d.enableGCProfilerDecorations` が有効な場合にのみ意味を持つが、リクエスト自体は常に応答する。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 70 | ProfileGCエントリ取得 (served/getProfileGCEntries) | 主機能 | profilegc.logファイルを解析しGCアロケーション情報をエントリとして返却する |

## 画面種別

カスタムLSPリクエスト（データ返却型）

## URL/ルーティング

LSPカスタムメソッド: `served/getProfileGCEntries`

## 入出力項目

### リクエストパラメータ

パラメータなし。

### レスポンス

| 項目名 | 型 | 説明 |
|--------|------|------|
| (戻り値) | ProfileGCEntry[] | GCアロケーションエントリの配列 |

### ProfileGCEntry構造

| フィールド名 | 型 | 説明 |
|-------------|------|------|
| bytesAllocated | size_t | アロケーションされたバイト数 |
| allocationCount | size_t | アロケーション回数 |
| type | string | アロケーションの型情報 |
| uri | DocumentUri | ファイルのURI（正規化済み） |
| displayFile | string | 表示用ファイルパス（元のログ記載パス） |
| line | uint | ソースコード上の行番号 |

## 表示項目

クライアント側でGCプロファイリング情報の表示に使用される。コードレンズとして「N bytes allocated / M allocations」形式でエディタ上に表示される。

## イベント仕様

### 1-ProfileGCエントリ取得リクエスト受信

1. クライアントから `served/getProfileGCEntries` リクエストを受信する
2. `profileGCCache.caches` の全エントリを走査する
3. 各キャッシュのentriesを結合して返却する

### 2-profilegc.logキャッシュ更新（バックグラウンド）

以下のイベントでキャッシュが更新される：

- **プロジェクト利用可能時**（`onProfileGCProjectAvailable`）：プロジェクトディレクトリ配下のprofilegc.logを読み込みキャッシュに登録する
- **ファイル変更監視**（`workspace/didChangeWatchedFiles`）：profilegc.logの作成・変更時にキャッシュを更新、削除時にキャッシュをクリアする

### 3-profilegc.logパース処理

1. profilegc.logの内容を行単位で分割する
2. 各行を列（スペース区切り）に分解する
3. 先頭2列からbytesAllocatedとallocationCountを取得する
4. 最後の列からファイル名と行番号（コロン区切り）を取得する
5. 中間部分からtype情報を取得する
6. ファイルパスをURIに正規化してProfileGCEntryを構築する

## データベース更新仕様

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

本リクエストはデータベースへの更新を行わない。インメモリキャッシュからの読み取りのみ。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ProfileGCエントリ取得 | profileGCCache（インメモリ） | SELECT（読み取り） | キャッシュされたエントリを全て返却 |
| profilegc.log変更検出 | profileGCCache（インメモリ） | INSERT/UPDATE/DELETE | ファイル変更に応じてキャッシュを更新 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|--------------|
| d.ext.gcLens | 情報 | コードレンズ表示時 | "{0} bytes allocated / {1} allocations" |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| profilegc.logが存在しない | 空の配列を返却する |
| profilegc.logの読み込みエラー（FileException） | キャッシュから該当URIを削除し、traceログに記録 |
| profilegc.logのパースエラー（Exception） | キャッシュから該当URIを削除し、traceログに記録 |
| 行のフォーマットが不正（列数不足） | 該当行をスキップして処理を継続 |

## 備考

- profilegc.logは `**/profilegc.log` パターンでファイル監視を動的登録する
- キャッシュは `ProfileGCCache` 構造体で管理され、URI単位で `PerDocumentCache` を保持する
- コードレンズとの連携は別途 `provideProfileGCCodeLens` 関数で実装されている（同一ファイル内）
- `d.enableGCProfilerDecorations` 設定が無効の場合、コードレンズは表示されないが、本リクエスト自体は応答する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | profilegc.d | `source/served/workers/profilegc.d` | 行15-22のProfileGCEntry構造体、行24-63のProfileGCCache構造体 |

**読解のコツ**: `ProfileGCCache` は `PerDocumentCache` をURI単位で管理する辞書構造。`PerDocumentCache` がprofilegc.logの実際のパース処理を担当する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | profilegc.d | `source/served/workers/profilegc.d` | `getProfileGCEntries` 関数（行122-129）がエントリーポイント |

**主要処理フロー**:
1. **行122-123**: `@protocolMethod("served/getProfileGCEntries")` で定義。パラメータなし
2. **行125**: `appender!(ProfileGCEntry[])` で結果配列のappenderを作成
3. **行126-127**: `profileGCCache.caches` を走査し全エントリを結合
4. **行128**: `lenses.data` で結果配列を返却

#### Step 3: パース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | profilegc.d | `source/served/workers/profilegc.d` | `PerDocumentCache.process` 関数（行30-62） |

**主要処理フロー**:
- **行33**: `content.lineSplitter` で行単位分割
- **行35-36**: 列分割と列数チェック（5列未満はスキップ）
- **行45-49**: 最後の列からファイル名と行番号を `:` 区切りで解析
- **行50-57**: ProfileGCEntryの構築

#### Step 4: ファイル監視とキャッシュ更新を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | profilegc.d | `source/served/workers/profilegc.d` | `setupProfileGCWatchers`（行131-150）、`onChangeProfileGC`（行158-172） |

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

```
served/getProfileGCEntries リクエスト
    |
    +-- getProfileGCEntries()                    [profilegc.d:123]
           |
           +-- profileGCCache.caches             [グローバルキャッシュ参照]
                  |
                  +-- PerDocumentCache.entries    [パース済みエントリ]

--- キャッシュ更新フロー ---

workspace/didChangeWatchedFiles
    |
    +-- onChangeProfileGC()                      [profilegc.d:159]
           |
           +-- profileGCCache.update()           [profilegc.d:67]
           |      +-- PerDocumentCache.process()  [profilegc.d:30]
           |
           +-- profileGCCache.clear()            [profilegc.d:90]

onProjectAvailable
    |
    +-- onProfileGCProjectAvailable()            [profilegc.d:153]
           +-- profileGCCache.update()
```

### データフロー図

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

profilegc.log --------> PerDocumentCache.process()      --> ProfileGCEntry[]
(ファイル監視)              |                                    |
                           +-- 行分割                            +-- bytesAllocated
                           +-- 列分割                            +-- allocationCount
                           +-- ファイル:行番号解析               +-- type
                           +-- URI正規化                         +-- uri
                                                                 +-- displayFile
(リクエスト)                                                     +-- line
    |
    +-- getProfileGCEntries()
           +-- caches全走査 --> ProfileGCEntry[] 返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| profilegc.d | `source/served/workers/profilegc.d` | ソース | ProfileGCキャッシュ・パース・リクエスト処理・コードレンズ |
| types.d | `source/served/types.d` | ソース | DocumentUri等の共通型定義 |
| extension.d | `source/served/extension.d` | ソース | 設定（enableGCProfilerDecorations）の参照 |
