# 機能設計書 32-同期的書き込み試行

## 概要

本ドキュメントは、libuvにおける同期的書き込み試行機能（uv_try_write()/uv_try_write2()）の設計仕様を記述する。ストリームへの書き込みをキューイングせず即座に試行し、書き込めたバイト数を返す。

### 本機能の処理概要

**業務上の目的・背景**：非同期書き込み（uv_write）ではリクエストの初期化、キューイング、バッファコピーなどのオーバーヘッドが発生する。低レイテンシが求められるシーンや、OSバッファに余裕がある場合にデータを即座に送出したい場合には、同期的に書き込みを試行する手段が有効である。uv_try_write()は書き込みリクエストを作成せず、直接writev()システムコールを呼び出すことで、この軽量な書き込みパスを提供する。

**機能の利用シーン**：TCPサーバーで小さなレスポンスを即座に返したい場合、キューが空であることが期待できるケースでオーバーヘッドを削減したい場合、書き込み可能かどうかを事前にプローブしたい場合に使用される。

**主要な処理内容**：
1. 書き込みキューの状態チェック（接続中または既存キューイングデータがある場合はUV_EAGAIN）
2. 事前バリデーション（uv__check_before_write）
3. writev()またはsendmsg()を直接呼び出し
4. 書き込めたバイト数または負のエラーコードを返却

**関連システム・外部連携**：OSのwritev()/sendmsg()システムコール。

**権限による制御**：特になし。ストリームがUV_HANDLE_WRITABLEフラグを持っていない場合はUV_EPIPEを返す。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ストリーム | 主機能 | uv_try_write()/uv_try_write2()による同期的書き込み試行のAPI定義 |

## 機能種別

データ送信処理（同期I/O試行）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stream | uv_stream_t* | Yes | 書き込み先ストリーム（TCP/パイプ/TTY） | UV_TCP, UV_NAMED_PIPE, UV_TTYのいずれか |
| bufs | const uv_buf_t[] | Yes | 書き込みデータバッファ配列 | 1以上1048576以下の要素数 |
| nbufs | unsigned int | Yes | バッファ配列の要素数 | 1 <= nbufs <= 1024*1024 |
| send_handle | uv_stream_t* | No（uv_try_write2のみ） | IPC経由で送信するハンドル | NULLでない場合、ストリームがIPCパイプであること |

### 入力データソース

アプリケーションコードからの直接呼び出し。バッファデータは呼び出し元が管理する。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 正値: 書き込めたバイト数、負値: エラーコード |

### 出力先

成功時はOSのソケット/パイプバッファに直接書き込まれる。コールバックは存在しない。

## 処理フロー

### 処理シーケンス

```
1. uv_try_write()が呼ばれる
   └─ uv_try_write2(stream, bufs, nbufs, NULL)に委譲

2. 接続中またはキューイング済みデータの存在チェック
   └─ connect_req != NULL || write_queue_size != 0 → UV_EAGAIN

3. uv__check_before_write()による事前バリデーション
   ├─ ストリーム型チェック
   ├─ バッファ数チェック
   ├─ FD有効性チェック
   └─ 書き込み可能フラグチェック

4. uv__try_write()で直接書き込み試行
   ├─ writev()を実行（通常書き込み）
   └─ sendmsg()を実行（ハンドル送信時）

5. 結果を返却
   ├─ 正値: 書き込んだバイト数
   ├─ UV_EAGAIN: バッファが一杯で書き込み不可
   └─ 負のエラーコード: その他のエラー
```

### フローチャート

```mermaid
flowchart TD
    A[uv_try_write/uv_try_write2 呼び出し] --> B{接続中 or キューに既存データ?}
    B -->|Yes| C[UV_EAGAIN 返却]
    B -->|No| D[uv__check_before_write]
    D -->|エラー| E[エラーコード返却]
    D -->|OK| F[uv__try_write 実行]
    F --> G{結果}
    G -->|n >= 0| H[書き込みバイト数を返却]
    G -->|EAGAIN/EWOULDBLOCK| I[UV_EAGAIN 返却]
    G -->|その他エラー| J[エラーコード返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-32-01 | キュー空必須 | 書き込みキューが空でなければUV_EAGAINを返す | 常時 |
| BR-32-02 | 接続完了必須 | connect_reqが進行中の場合はUV_EAGAINを返す | 常時 |
| BR-32-03 | 部分書き込み | 全データを書き込めない場合もエラーではなく書き込んだバイト数を返す | 常時 |
| BR-32-04 | コールバックなし | 結果は戻り値で返され、コールバックは使用しない | 常時 |

### 計算ロジック

戻り値が正の場合、書き込めたバイト数を返す。呼び出し元は残りのデータについてuv_write()で非同期書き込みを行う必要がある。

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

該当なし。

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

該当なし。

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EAGAIN | 一時エラー | 接続中、キューにデータあり、OSバッファが一杯 | 後でuv_write()で非同期書き込み |
| UV_EINVAL | 入力エラー | 不正なストリーム型、バッファ数が範囲外 | パラメータを修正 |
| UV_EBADF | 状態エラー | FDが無効 | ストリームの状態を確認 |
| UV_EPIPE | 状態エラー | ストリームが書き込み不可 | 再接続 |
| UV_ECONNRESET | 接続エラー | macOSでのEPROTOTYPEエラー変換 | 接続の再確立 |

### リトライ仕様

UV_EAGAINが返された場合はuv_write()で非同期書き込みにフォールバックすることが推奨される。libuv内部での自動リトライは行われない。

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

該当なし。部分書き込みが発生する可能性があるため、呼び出し元で残りデータの管理が必要。

## パフォーマンス要件

- リクエストオブジェクトの初期化やキューイングを省略し、直接システムコールを呼び出すことで最小レイテンシを実現
- ヒープアロケーション不要
- バッファコピー不要

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

- バッファ数の上限チェック（1024*1024）で符号変換バグを防止
- ストリームのクローズ中チェック

## 備考

- uv_try_write()はuv_try_write2()のsend_handle=NULL呼び出しとして実装されている
- Unix実装ではuv_try_write2()がsend_handleに対応しているが、Windows実装ではsend_handle!=NULLの場合UV_EAGAINを返す
- 部分書き込みが発生した場合、残りのデータについてはuv_write()を使用する必要がある

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **561-567行目**: uv_try_write()とuv_try_write2()のAPI宣言。戻り値が書き込みバイト数またはエラーコード |

**読解のコツ**: uv_try_write()はuv_write_tリクエストを使用しない。戻り値で即座に結果が返されるため、コールバックパターンとは異なる同期的なインターフェースである。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stream.c | `src/unix/stream.c` | **1422-1426行目**: uv_try_write()の実装。uv_try_write2()にsend_handle=NULLで委譲 |
| 2-2 | stream.c | `src/unix/stream.c` | **1429-1444行目**: uv_try_write2()の本体実装 |

**主要処理フロー**:
1. **1436-1437行目**: connect_reqまたはwrite_queue_sizeが非ゼロの場合UV_EAGAIN
2. **1439-1441行目**: uv__check_before_write()によるバリデーション
3. **1443行目**: uv__try_write()で直接書き込み実行

#### Step 3: 書き込み実行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stream.c | `src/unix/stream.c` | **753-837行目**: uv__try_write()の実装 |

**主要処理フロー**:
- **766-767行目**: uv_buf_tをiovec*にキャスト
- **769-773行目**: IOV_MAX制限の適用
- **779-809行目**: send_handleがある場合はsendmsg()
- **810-813行目**: send_handleがない場合はuv__writev()（write/writev）
- **816-817行目**: 成功時は書き込みバイト数を返却
- **819-820行目**: EAGAIN/EWOULDBLOCK/ENOBUFSはUV_EAGAINに変換

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

```
uv_try_write(stream, bufs, nbufs)
    └─ uv_try_write2(stream, bufs, nbufs, NULL)
           ├─ 接続中/キュー非空チェック → UV_EAGAIN
           ├─ uv__check_before_write(stream, nbufs, NULL)
           └─ uv__try_write(stream, bufs, nbufs, send_handle)
                  ├─ uv__writev(fd, iov, iovcnt)  [通常書き込み]
                  │      ├─ write(fd, base, len)   [nbufs==1]
                  │      └─ writev(fd, iov, n)     [nbufs>1]
                  └─ sendmsg(fd, &msg, 0)          [ハンドル送信]
```

### データフロー図

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

uv_buf_t bufs[]  ───▶ uv_try_write2()              ───▶ 書き込みバイト数(int)
                       │                                  または UV_EAGAIN
                       ├─ キュー/接続状態チェック
                       ├─ バリデーション
                       └─ uv__try_write()
                              │
                              └─ writev()/sendmsg() ───▶ OSバッファ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_try_write/uv_try_write2のAPI宣言 |
| stream.c | `src/unix/stream.c` | ソース | Unix環境での同期書き込み試行実装 |
| stream.c | `src/win/stream.c` | ソース | Windows環境での同期書き込み試行実装 |
| uv-common.h | `src/uv-common.h` | ヘッダ | 内部共通定義 |
| internal.h | `src/unix/internal.h` | ヘッダ | Unix内部関数宣言 |
