# 機能設計書 104-oids

## 概要

本ドキュメントは、Nim標準ライブラリの`oids`モジュールの機能設計を記述する。このモジュールは、グローバルに一意なオブジェクトID（OID）の生成機能を提供する。

### 本機能の処理概要

`oids`モジュールは、タイムスタンプ、乱数（fuzz）、およびアトミックカウンタを組み合わせて、分散システムでも衝突しないグローバルユニークIDを生成する。MongoDBのObjectIDに類似した設計となっている。

**業務上の目的・背景**：分散システムやマイクロサービスアーキテクチャにおいて、中央集権的なID発番サービスなしでグローバルに一意なIDを生成する必要がある。OIDは、タイムスタンプベースでソート可能であり、生成時刻の情報も含むため、ドキュメントストアやイベントソーシングなどで有用である。

**機能の利用シーン**：データベースのプライマリキー生成、分散システムでのトランザクションID、ファイルやオブジェクトの一意識別子、ログのトレースIDなど。

**主要な処理内容**：
1. グローバルユニークなOIDの生成（`genOid`）
2. 16進数文字列からOIDへの変換（`parseOid`）
3. OIDから16進数文字列への変換（`$`演算子）
4. OIDから生成時刻の抽出（`generatedTime`）
5. OIDの等値比較とハッシュ生成

**関連システム・外部連携**：特になし。

**権限による制御**：権限による制御は存在しない。

## 関連画面

本モジュールは標準ライブラリであり、特定の画面との関連はない。

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

## 機能種別

ID生成 / ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| str | cstring | Yes | パース対象の24文字16進数文字列 | 有効な16進数文字 |

### 入力データソース

プログラムコードからの直接呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Oid | object | 生成されたOID（time, fuzz, count） |
| string | string | 24文字の16進数文字列表現 |
| Time | Time | OID生成時のタイムスタンプ |
| Hash | Hash | ハッシュテーブル用ハッシュ値 |

### 出力先

呼び出し元への戻り値。

## 処理フロー

### 処理シーケンス

```
1. OID生成 (genOid)
   └─ 現在時刻を取得
   └─ アトミックカウンタをインクリメント
   └─ time, fuzz, countをビッグエンディアンで格納

2. 文字列化 ($)
   └─ 12バイトを24文字の16進数に変換

3. パース (parseOid)
   └─ 24文字の16進数を12バイトにデコード
   └─ Oidオブジェクトとして復元

4. 生成時刻抽出 (generatedTime)
   └─ ビッグエンディアンのtimeフィールドをデコード
   └─ Timeオブジェクトとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: genOid] --> B[現在時刻取得]
    B --> C[アトミックカウンタ++]
    C --> D[bigEndian64でtime格納]
    D --> E[fuzz設定]
    E --> F[bigEndian32でcount格納]
    F --> G[Oid返却]
    G --> H[終了]

    I[開始: parseOid] --> J[24文字の16進数を処理]
    J --> K[2文字ずつ1バイトに変換]
    K --> L[Oidオブジェクト構築]
    L --> H

    M[開始: $] --> N[12バイトを取得]
    N --> O[各バイトを2桁16進数に変換]
    O --> P[24文字文字列生成]
    P --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 一意性保証 | time + fuzz + countの組み合わせで一意性を保証 | genOid呼び出し時 |
| BR-02 | タイムスタンプ順序 | 同一プロセス内では生成順にソート可能 | 常時 |
| BR-03 | 初期化 | 最初のgenOid呼び出し時にinitRand実行 | 初回呼び出し時 |
| BR-04 | アトミック操作 | カウンタはアトミックにインクリメント | 常時 |

### 計算ロジック

**OID構造（16バイト）**:
- `time`: int64 - Unixタイムスタンプ（ビッグエンディアン）
- `fuzz`: int32 - 乱数値（プロセス識別用）
- `count`: int32 - アトミックカウンタ（ビッグエンディアン）

**初期化処理**:
```nim
let t = getTime().toUnix
var seed = initRand(t)
var incr: int = seed.rand(int.high)
let fuzz = cast[int32](seed.rand(high(int)))
```

**生成処理**:
```nim
var time = getTime().toUnix
var i = cast[int32](atomicInc(incr))
bigEndian64(addr result.time, addr(time))
result.fuzz = fuzz
bigEndian32(addr result.count, addr(i))
```

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

本モジュールはデータベース操作を行わない（ただし生成されたOIDはDB主キーとして使用可能）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | parseOidに無効な16進数文字 | 正しい16進数文字列を入力 |

### リトライ仕様

リトライは不要。

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

トランザクション管理は不要。

## パフォーマンス要件

- OID生成: O(1)
- アトミック操作によりスレッドセーフ
- 文字列変換: O(1)

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

- OIDには生成時刻が含まれるため、推測可能
- セキュリティトークンとしての使用には不適切（予測可能性がある）

## 備考

- 24文字の16進数文字列として表現
- MongoDBのObjectIDと類似した設計

---

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

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

### 推奨読解順序

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

Oid型の内部構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | oids.nim | `lib/pure/oids.nim` | 23-27行目: Oid型定義（time, fuzz, count） |
| 1-2 | oids.nim | `lib/pure/oids.nim` | 17行目: 依存モジュール（hashes, times, endians, random） |

**読解のコツ**: Oid型は3つのフィールド（time: int64, fuzz: int32, count: int32）を持つシンプルなobject。ただし、実際のバイト表現ではビッグエンディアンが使用される。

#### Step 2: 初期化処理を理解する

モジュール初期化時の乱数シード設定を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | oids.nim | `lib/pure/oids.nim` | 69-76行目: 初期化処理 |

**主要処理フロー**:
- **70行目**: 現在のUnixタイムスタンプを取得
- **73行目**: タイムスタンプをシードに乱数生成器を初期化
- **74行目**: カウンタの初期値を乱数で設定
- **76行目**: fuzz値を乱数で設定

#### Step 3: OID生成処理を理解する

genOid関数の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | oids.nim | `lib/pure/oids.nim` | 79-85行目: genOidテンプレート |
| 3-2 | oids.nim | `lib/pure/oids.nim` | 87-94行目: genOid関数 |

**主要処理フロー**:
- **80行目**: 現在時刻を取得
- **81行目**: アトミックインクリメントでカウンタ増加
- **83行目**: bigEndian64でtimeフィールドを設定
- **84行目**: fuzzフィールドを設定
- **85行目**: bigEndian32でcountフィールドを設定

#### Step 4: 文字列変換を理解する

OIDと文字列の相互変換を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | oids.nim | `lib/pure/oids.nim` | 42-43行目: hexbyte関数 |
| 4-2 | oids.nim | `lib/pure/oids.nim` | 45-52行目: parseOid関数 |
| 4-3 | oids.nim | `lib/pure/oids.nim` | 54-67行目: `$`演算子 |

**主要処理フロー**:
- **48-52行目**: parseOidは2文字ずつ16進数としてデコード
- **61-67行目**: `$`は各バイトを2桁の16進数に変換

#### Step 5: ユーティリティ関数を理解する

等値比較、ハッシュ、時刻抽出を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | oids.nim | `lib/pure/oids.nim` | 29-32行目: `==`演算子 |
| 5-2 | oids.nim | `lib/pure/oids.nim` | 34-40行目: hash関数 |
| 5-3 | oids.nim | `lib/pure/oids.nim` | 96-101行目: generatedTime関数 |

**主要処理フロー**:
- **31-32行目**: 3フィールド全ての比較で等値判定
- **36-40行目**: ハッシュは3フィールドを!&で合成
- **98-101行目**: bigEndian64でtimeをデコードしTimeに変換

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

```
oids.nim
    │
    ├─ Oid型定義
    │      └─ object {time: int64, fuzz: int32, count: int32}
    │
    ├─ 初期化（モジュールロード時）
    │      ├─ getTime().toUnix
    │      ├─ initRand
    │      └─ rand (fuzz, incr初期値)
    │
    ├─ 生成
    │      └─ genOid ─── atomicInc ─── bigEndian64/32
    │
    ├─ 変換
    │      ├─ parseOid ─── hexbyte
    │      └─ `$`
    │
    └─ ユーティリティ
           ├─ `==`
           ├─ hash
           └─ generatedTime ─── bigEndian64 ─── fromUnix
```

### データフロー図

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

(初回genOid呼び出し)
getTime() ──────────────▶ initRand ────────────────▶ seed
                              │
                              ├─▶ incr (カウンタ初期値)
                              └─▶ fuzz (乱数値)

(genOid呼び出し毎)
getTime() ──────────────▶ genOid ──────────────────▶ Oid
atomicInc(incr) ────────┘

Oid ────────────────────▶ `$` ─────────────────────▶ "24文字16進数"
                              │
                              └─▶ バイト→16進数変換

"24文字16進数" ─────────▶ parseOid ─────────────────▶ Oid
                              │
                              └─▶ hexbyte (2文字→1バイト)

Oid ────────────────────▶ generatedTime ───────────▶ Time
                              │
                              └─▶ bigEndian64 + fromUnix
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| oids.nim | `lib/pure/oids.nim` | ソース | メインモジュール、全機能の実装 |
| hashes.nim | `lib/pure/hashes.nim` | 依存 | hash関数、!&, !$演算子 |
| times.nim | `lib/pure/times.nim` | 依存 | getTime, toUnix, fromUnix |
| endians.nim | `lib/pure/endians.nim` | 依存 | bigEndian64, bigEndian32 |
| random.nim | `lib/pure/random.nim` | 依存 | initRand, rand |
| decode_helpers.nim | `lib/std/private/decode_helpers.nim` | 依存 | handleHexChar |
| sysatomics.nim | `lib/std/sysatomics.nim` | 依存 | atomicInc |
