# `SuperCache.Cluster.ThreePhaseCommit`
[🔗](https://github.com/ohhi-vn/super_cache/blob/main/lib/cluster/three_phase_commit.ex#L1)

Three-phase commit (3PC) coordinator.

Every `commit/2` call records a latency sample and increments either
the `:committed` or `:aborted` counter (plus per-phase failure counters
on abort) via `SuperCache.Cluster.Stats.record_tpc/2`.  These are
visible in `SuperCache.Cluster.Stats.three_phase_commit/0`.

## Coordinator contract

`commit/2` **must be called from the partition's primary node**.
The Router enforces this for all writes that go through
`SuperCache.Cluster.Router`.  If `commit/2` is called from a non-primary
node (e.g. in a direct test), `apply_local/2` will write to the wrong
node's ETS table and the primary will be left without data.

## ops fallback in handle_commit

`phase_commit/4` passes the full `ops` list to every replica alongside
the `txn_id`.  `handle_commit/3` uses the locally registered ops first
(set by `handle_prepare/3`); if the TxnRegistry entry is absent — due to
a prepare message being lost or a race during startup — it falls back to
the coordinator-supplied ops so the write still completes rather than
being silently skipped.

# `op`

```elixir
@type op() ::
  {:put, tuple()}
  | {:delete, any()}
  | {:delete_match, tuple()}
  | {:delete_all, nil}
```

# `op_list`

```elixir
@type op_list() :: [op()]
```

# `txn_id`

```elixir
@type txn_id() :: binary()
```

# `commit`

```elixir
@spec commit(non_neg_integer(), op_list()) :: :ok | {:error, term()}
```

# `recover`

```elixir
@spec recover() :: :ok
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
