# 機能設計書 76-ファイルシステム抽象化

## 概要

本ドキュメントは、F#コンパイラにおけるファイルシステム抽象化層の設計を記述する。この抽象化層は、実際のファイルシステムと仮想ファイルシステム（テスト用、IDE統合用など）の両方に対応し、メモリマップドファイルやバイトメモリ操作などの効率的なI/O機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：F#コンパイラは、ソースファイル、アセンブリ、リソースファイルなど多数のファイルを読み書きする必要がある。しかし、テスト環境やIDE統合環境では、実際のファイルシステムではなくメモリ上の仮想ファイルを使用したい場合がある。本機能は、IFileSystemインターフェースを通じてファイルシステム操作を抽象化し、実装を差し替え可能にすることで、テスタビリティと柔軟性を向上させる。また、大規模なアセンブリファイルを効率的に読み込むためのメモリマップドファイル機能も提供する。

**機能の利用シーン**：コンパイル時のソースファイル読み込み、アセンブリメタデータの読み取り、出力ファイルの書き出し、IDE統合でのファイル変更検知、テスト時の仮想ファイルシステム使用など、あらゆるファイルI/O操作で利用される。

**主要な処理内容**：
1. IFileSystemインターフェースによるファイル操作の抽象化
2. DefaultFileSystemによる標準的なファイルシステム実装
3. ByteMemory抽象クラスによるバイト配列/メモリマップドファイルの統一アクセス
4. メモリマップドファイルを使用した大規模ファイルの効率的読み込み
5. ストリーム拡張メソッドによる便利なI/Oユーティリティ
6. グローバルFileSystemフックによる実装の差し替え

**関連システム・外部連携**：System.IO、System.IO.MemoryMappedFiles、System.Buffers.ArrayPoolと連携する。

**権限による制御**：ファイルシステムアクセスはOSレベルの権限に従う。

## 関連画面

本機能はコンパイラ内部機能であり、直接関連する画面は存在しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

ファイルI/O / 抽象化層 / メモリ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filePath | string | Yes | ファイルパス | 不正文字チェック |
| useMemoryMappedFile | bool | No | メモリマップドファイル使用 | - |
| shouldShadowCopy | bool | No | シャドウコピー作成 | - |

### 入力データソース

- ファイルシステム上のファイル
- メモリ上のバイト配列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Stream | Stream | ファイルストリーム |
| ByteMemory | ByteMemory | バイトメモリ抽象 |

### 出力先

- メモリ（読み取り時）
- ファイルシステム（書き込み時）

## 処理フロー

### 処理シーケンス

```
【ファイル読み込み】
1. IFileSystem.OpenFileForReadShim呼び出し
2. FileStream作成
3. メモリマップド使用時:
   a. shouldShadowCopy時: 新規MMF作成→コピー
   b. 通常時: ファイルからMMF作成
4. MemoryMappedStreamラップ
5. Stream返却

【ByteMemory取得】
1. Stream.AsByteMemory()呼び出し
2. MemoryMappedStream時:
   └─ RawByteMemory（ゼロコピー）
3. その他:
   └─ ReadAllBytes→ByteArrayMemory
```

### フローチャート

```mermaid
flowchart TD
    A[OpenFileForReadShim] --> B[FileStream作成]
    B --> C{useMemoryMappedFile?}
    C -->|No| D[FileStream返却]
    C -->|Yes| E{shouldShadowCopy?}
    E -->|Yes| F[新規MMF作成]
    F --> G[FileStreamからコピー]
    G --> H[MemoryMappedStream作成]
    E -->|No| I[ファイルからMMF作成]
    I --> H
    H --> J[MemoryMappedStream返却]

    K[AsByteMemory] --> L{MemoryMappedStream?}
    L -->|Yes| M[RawByteMemory作成]
    L -->|No| N[ReadAllBytes]
    N --> O[ByteArrayMemory作成]
    M --> P[ByteMemory返却]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-76-01 | グローバルフック | FileSystem変数で実装を差し替え可能 | 常時 |
| BR-76-02 | メモリマップ条件 | 大規模バイナリファイルにMMFを推奨 | useMemoryMappedFile=true時 |
| BR-76-03 | シャドウコピー | ファイルロック回避のためコピー作成 | shouldShadowCopy=true時 |
| BR-76-04 | 安定ファイル判定 | Reference Assemblies/packages等は安定とみなす | IsStableFileHeuristic |
| BR-76-05 | 不正文字検査 | パスに不正文字があれば例外 | checkPathForIllegalChars |

### 計算ロジック

- パス不正文字チェック: `Path.GetInvalidPathChars()`との照合

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IllegalFileNameChar | 例外 | パスに不正文字含有 | パス修正を要求 |
| ArgumentOutOfRangeException | 例外 | 無効なオフセット/長さ | パラメータ検証 |
| IOException | 例外 | ファイルアクセスエラー | リトライまたは報告 |
| ObjectDisposedException | 例外 | 破棄済みバッファ使用 | 使用パターン修正 |

### リトライ仕様

GetReaderメソッドは、ファイルロック時に最大60回（50ms間隔）リトライ可能。

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

本機能はトランザクション管理を必要としない。

## パフォーマンス要件

- メモリマップドファイルによる大規模ファイルのゼロコピー読み込み
- ArrayPoolを使用したバッファ再利用（ByteBuffer）
- WeakReferenceによるByteStorageのキャッシュ管理

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

- ファイルパスの不正文字検証
- Assembly.UnsafeLoadFromの使用に注意（信頼されたファイルのみ）
- メモリマップドファイルハンドルの適切な解放

## 備考

- Experimental属性が付与されたAPIは将来変更の可能性あり
- F#コンパイラサービス（FCS）での使用を想定した設計

---

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

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

### 推奨読解順序

#### Step 1: インターフェース定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FileSystem.fs | `src/Compiler/Utilities/FileSystem.fs` | IFileSystem、IAssemblyLoaderインターフェース |

**主要処理フロー**:
- **449-454行目**: IAssemblyLoader - アセンブリロードの抽象化
- **466-512行目**: IFileSystem - ファイルシステム操作の抽象化
- **867行目**: グローバルFileSystem変数

**読解のコツ**: `Shim`サフィックスは.NETのSystem.IOメソッドのラッパーであることを示す。

#### Step 2: メモリ抽象化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FileSystem.fs | `src/Compiler/Utilities/FileSystem.fs` | ByteMemory抽象クラス |

**主要処理フロー**:
- **51-64行目**: ByteMemory抽象クラス - バイトメモリの統一インターフェース
- **68-153行目**: ByteArrayMemory - byte[]ベースの実装
- **212-320行目**: RawByteMemory - ネイティブポインタベースの実装
- **322-352行目**: ReadOnlyByteMemory - 読み取り専用ラッパー

#### Step 3: デフォルト実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FileSystem.fs | `src/Compiler/Utilities/FileSystem.fs` | DefaultFileSystemクラス |

**主要処理フロー**:
- **516-754行目**: DefaultFileSystem - 標準ファイルシステム実装
- **520-567行目**: OpenFileForReadShim - メモリマップドファイル対応読み込み
- **569-576行目**: OpenFileForWriteShim - ファイル書き込み
- **698-710行目**: IsStableFileHeuristic - 安定ファイル判定

#### Step 4: ストリーム拡張を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FileSystem.fs | `src/Compiler/Utilities/FileSystem.fs` | StreamExtensions |

**主要処理フロー**:
- **755-863行目**: StreamExtensions - ストリームの便利メソッド
- **776-803行目**: GetReader - リトライ付きStreamReader取得
- **845-862行目**: AsByteMemory - ストリームからByteMemoryへ変換

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

```
呼び出し元（コンパイラ各モジュール）
    │
    └─ FileSystem（グローバル変数）
           │
           ├─ IFileSystem.OpenFileForReadShim
           │      │
           │      ├─ FileStream
           │      │
           │      └─ MemoryMappedFile.CreateFromFile
           │             │
           │             └─ MemoryMappedStream
           │
           ├─ IFileSystem.OpenFileForWriteShim
           │      └─ FileStream
           │
           └─ Stream.AsByteMemory()（拡張メソッド）
                  │
                  ├─ RawByteMemory（MMF時）
                  │
                  └─ ByteArrayMemory（その他）
```

### データフロー図

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

ファイルパス ───────────▶ OpenFileForReadShim ───────────────▶ Stream
                               │
                               ├─ FileStream
                               │
                               └─ MemoryMappedFile
                                      │
                                      └─ MemoryMappedStream

Stream ─────────────────▶ AsByteMemory ──────────────────────▶ ByteMemory
                               │
                               ├─ RawByteMemory（ゼロコピー）
                               │
                               └─ ByteArrayMemory（コピー）

ByteMemory ─────────────▶ ReadBytes / Slice / ToArray ────────▶ byte[]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FileSystem.fs | `src/Compiler/Utilities/FileSystem.fs` | ソース | ファイルシステム抽象化の主実装 |
| FileSystem.fsi | `src/Compiler/Utilities/FileSystem.fsi` | シグネチャ | 公開APIの定義 |
| prim-lexing.fs | `src/Compiler/Facilities/prim-lexing.fs` | ソース | レキサーでのByteMemory使用 |
| AbstractIL.ILBinaryReader.fs | `src/Compiler/AbstractIL/` | ソース | アセンブリ読み込みでのByteMemory使用 |
