# `dgen_backend`
[🔗](https://github.com/foundationdb-beam/dgen/blob/main/src/dgen_backend.erl#L1)

Behaviour defining the storage backend for dgen.

A backend must implement all required callbacks to provide:

- **Transactions.** Serializable read-write transactions over the keyspace.
- **Key-value operations.** Get, set, clear, range reads, and atomic adds.
- **Watches.** Notifications when a key changes.
- **Versionstamps.** Unique, globally ordered write stamps, used for FIFO queuing.
- **Directory layer.** Tuple-key packing, range calculation, and namespace isolation.

The default backend is `dgen_erlfdb`, which delegates to FoundationDB via the
`erlfdb` library.

We look forward to changing the backend interface to support other systems.

## Configuring the backend

Set the `backend` application env before starting dgen:

```erlang
application:set_env(dgen, backend, my_backend).
```

Or in `config.exs`:

```elixir
config :dgen, backend: MyBackend
```

## Implementing a backend

A backend module must implement this behaviour. Every watch and future operation
must return a `{dgen_future, Ref, BackendData}` tuple. `Ref` is a reference, and
the backend later sends `{Ref, ready}` to the watching process.

## Types

Backends define opaque types for database handles, transaction handles,
directory handles, and futures. The dgen core treats these as opaque terms
and only passes them back into backend callbacks.

*This documentation is LLM-generated. See the AI disclosure in `README.md`.*

# `db`

```erlang
-type db() :: term().
```

# `dir`

```erlang
-type dir() :: term().
```

# `future`

```erlang
-type future() :: term().
```

# `key`

```erlang
-type key() :: binary().
```

# `tenant`

```erlang
-type tenant() :: {db() | tx(), dir()}.
```

# `tuple_key`

```erlang
-type tuple_key() :: tuple().
```

# `tx`

```erlang
-type tx() :: term().
```

# `versionstamp`

```erlang
-type versionstamp() :: term().
```

# `add`

```erlang
-callback add(Tx :: tx(), Key :: key(), Value :: integer()) -> ok.
```

# `add_read_conflict_key`

```erlang
-callback add_read_conflict_key(Tx :: tx(), Key :: key()) -> ok.
```

# `clear_range`

```erlang
-callback clear_range(Tx :: tx(), StartKey :: key(), EndKey :: key()) -> ok.
```

# `commit`

```erlang
-callback commit(Tx :: tx()) -> future().
```

# `create_transaction`

```erlang
-callback create_transaction(Db :: db()) -> tx().
```

# `dir_create`

```erlang
-callback dir_create(Db :: db(), Dir :: dir(), Name :: term()) -> dir().
```

# `dir_pack`

```erlang
-callback dir_pack(Dir :: dir(), TupleKey :: tuple_key()) -> key().
```

# `dir_pack_vs`

```erlang
-callback dir_pack_vs(Dir :: dir(), TupleKey :: tuple_key()) -> key().
```

# `dir_range`

```erlang
-callback dir_range(Dir :: dir(), TupleKey :: tuple_key()) -> {key(), key()}.
```

# `dir_remove`

```erlang
-callback dir_remove(Db :: db(), Dir :: dir(), Name :: term()) -> ok.
```

# `dir_unpack`

```erlang
-callback dir_unpack(Dir :: dir(), PackedKey :: key()) -> tuple_key().
```

# `error_code`

```erlang
-callback error_code(Reason :: term()) -> integer() | error.
```

# `get`

```erlang
-callback get(Tx :: tx(), Key :: key()) -> future().
```

# `get_committed_version`

```erlang
-callback get_committed_version(Tx :: tx()) -> integer().
```

# `get_next_tx_id`

```erlang
-callback get_next_tx_id(Tx :: tx()) -> non_neg_integer().
```

# `get_range`

```erlang
-callback get_range(Tx :: tx(), StartKey :: key(), EndKey :: key(), Opts :: list()) -> [{key(), binary()}].
```

# `get_read_version`

```erlang
-callback get_read_version(Tx :: tx()) -> future().
```

# `get_versionstamp`

```erlang
-callback get_versionstamp(Tx :: tx()) -> future().
```

# `is_transaction`

```erlang
-callback is_transaction(Handle :: db() | tx()) -> boolean().
```

# `key_strinc`

```erlang
-callback key_strinc(Key :: key()) -> key().
```

# `on_error`

```erlang
-callback on_error(Tx :: tx(), ErrorCode :: integer()) -> future().
```

# `sandbox_open`
*optional* 

```erlang
-callback sandbox_open(Name :: term(), DirName :: term()) -> tenant().
```

# `set`

```erlang
-callback set(Tx :: tx(), Key :: key(), Value :: binary()) -> ok.
```

# `set_read_version`

```erlang
-callback set_read_version(Tx :: tx(), Version :: integer()) -> ok.
```

# `set_versionstamped_key`

```erlang
-callback set_versionstamped_key(Tx :: tx(), Key :: key(), Value :: binary()) -> ok.
```

# `set_versionstamped_value`

```erlang
-callback set_versionstamped_value(Tx :: tx(), Key :: key(), Value :: binary()) -> ok.
```

# `transactional`

```erlang
-callback transactional(Db :: db(), Fun :: fun((Tx :: tx()) -> Result)) -> Result when Result :: term().
```

# `wait`

```erlang
-callback wait(Future :: future()) -> term().
```

# `wait_for_all`

```erlang
-callback wait_for_all(Futures :: [future()]) -> [term()].
```

# `watch`

```erlang
-callback watch(Tx :: tx(), Key :: key()) -> future().
```

# `watch`

```erlang
-callback watch(Tx :: tx(), Key :: key(), Opts :: list()) -> future().
```

# `transactional`

```erlang
-spec transactional(tenant(), fun((tenant()) -> Result)) -> Result when Result :: term().
```

Runs `Fun` inside a transaction if `Handle` is a database handle,
or calls `Fun` directly if `Handle` is already a transaction.

---

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