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

Shared helpers for distributed read/write operations.

Extracts common patterns used across `SuperCache.KeyValue`, `SuperCache.Queue`,
`SuperCache.Stack`, and `SuperCache.Struct` for:

- Determining cluster mode (`distributed?/0`)
- Applying writes with replication (`apply_write/3`)
- Routing writes to the primary node (`route_write/4`)
- Routing reads with `:local`/`:primary`/`:quorum` modes (`route_read/5`)
- Checking local partition ownership (`has_partition?/1`)
- Reading from the primary node (`read_primary/4`)
- Reading with quorum consensus (`read_quorum/4`)

## Quorum reads

Quorum reads use `Task.async` with early termination — as soon as a majority
of replicas agree on a result, remaining tasks are killed. This is more
efficient than `Task.async_stream` which always waits for all tasks to
complete before computing consensus.

# `apply_write`

```elixir
@spec apply_write(non_neg_integer(), term(),
  put: term(),
  delete: term(),
  delete_match: term(),
  delete_all: term()
) :: :ok | {:error, term()}
```

Applies a batch of write operations with the configured replication strategy.

- **Strong replication** (`:strong`): delegates to `ThreePhaseCommit.commit/2`
  for atomic distributed commits via the WAL-based 3PC protocol.
- **Async / sync replication**: applies each operation to local storage first,
  then replicates to replica nodes via `Replicator`.

## Operations

Each operation is a tuple:

| Operation                   | Description                          |
|-----------------------------|--------------------------------------|
| `{:put, record}`           | Insert or update a record            |
| `{:delete, key}`           | Delete a record by key               |
| `{:delete_match, pattern}` | Delete records matching a pattern    |
| `{:delete_all, _}`         | Delete all records in the partition  |

## Returns

- `:ok` on success
- `{:error, reason}` when 3PC commit fails (strong mode only)

# `distributed?`

```elixir
@spec distributed?() :: boolean()
```

Returns `true` when the cluster is running in distributed mode.

Inlined by the compiler for hot-path performance.

# `has_partition?`

```elixir
@spec has_partition?(non_neg_integer()) :: boolean()
```

Returns `true` if the current node holds a replica (primary or secondary)
for the given partition index.

# `read_primary`

```elixir
@spec read_primary(module(), atom(), [term()], non_neg_integer()) :: term()
```

Reads from the primary replica for the given partition.

If the current node is the primary, the function is applied locally.
Otherwise, an `:erpc.call` is made to the primary node.

# `read_quorum`

```elixir
@spec read_quorum(module(), atom(), [term()], non_neg_integer()) :: term()
```

Reads from all replicas and returns the result that achieves quorum (majority).

Uses `Task.async` with early termination: as soon as a majority of replicas
agree on a result, remaining tasks are killed immediately. This avoids waiting
for slow replicas once quorum is satisfied.

If no result reaches quorum, falls back to the primary node's result.

# `route_read`

```elixir
@spec route_read(module(), atom(), [term()], non_neg_integer(), keyword()) :: term()
```

Routes a read operation according to the requested read mode.

## Read modes

- `:local`   — read from the local node. If the local node does **not** hold a
  replica, automatically escalates to `:primary`.
- `:primary` — read from the primary replica.
- `:quorum`  — read from all replicas and return the majority result.

## Parameters

- `caller`        — the module that owns the function being called
- `fun`           — the function name (atom)
- `args`          — the function arguments (list)
- `partition_idx` — the partition index
- `opts`          — keyword list, supports `:read_mode` (default `:local`)

## Returns

The return value of the called function.

# `route_write`

```elixir
@spec route_write(module(), atom(), [term()], non_neg_integer()) :: term()
```

Routes a write operation to the primary replica for the given partition.

If the current node is the primary, the function is applied locally.
Otherwise, an `:erpc.call` is made to the primary node.

## Parameters

- `caller`        — the module that owns the function being called (replaces `__MODULE__`)
- `fun`           — the function name (atom)
- `args`          — the function arguments (list)
- `partition_idx` — the partition index used to look up the primary node

## Returns

The return value of the called function, or raises on `:erpc` failure.

---

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