Pkcs11ex.Slot.Pool (pkcs11ex v0.1.0)

Copy Markdown View Source

Round-robin dispatcher for multi-session slot pools.

A slot configured with session_pool_size: N > 1 runs N independent Pkcs11ex.Slot.Server workers, each holding its own PKCS#11 session. Sign/verify calls round-robin across workers so unrelated requests run concurrently rather than serializing through one mailbox.

When pooling helps

Cloud HSMs (e.g., GCP Cloud HSM via libkmsp11) make every operation a remote call. A single GenServer mailbox + single session means request N+1 waits for request N's network round-trip. With session_pool_size: 4, four signs land on four sessions in parallel — practical 4× lower tail latency for bursty workloads.

When pooling does NOT help and is forbidden

PIN-protected token slots: login state lives on the session, not on the token. With multiple sessions, every worker would need to login independently — fine for pin_callback-driven flows but error-prone for explicit login/2, and the configured-PIN tests across the library all assume one logged-in session per slot.

Cross-field config validation enforces session_pool_size: 1 (the default) for type: :token slots.

Concurrency model

ETS-backed counter (named table, write_concurrency on). Round-robin via :ets.update_counter/4 — atomic, lock-free in the BEAM ETS path. No GenServer round-trip on the hot path; only register/2 (called once at slot startup) holds the GenServer.

Summary

Functions

Returns a specification to start this module under a supervisor.

Returns the next worker index in the range 1..pool_size(slot_ref), using atomic round-robin.

Pool size for slot_ref. Defaults to 1 (single-worker, no pool) when the slot hasn't been registered — keeps the dispatch path uniform for ad-hoc test setups that start a Slot.Server without registering a pool size.

Register a slot's pool size. Idempotent — re-registering with the same size is a no-op; with a different size, overwrites AND logs a warning so a config drift between two startup paths can't slip through silently.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

next_worker_index(slot_ref)

@spec next_worker_index(atom()) :: pos_integer()

Returns the next worker index in the range 1..pool_size(slot_ref), using atomic round-robin.

For pool_size = 1, always returns 1 without touching ETS — the fast path for non-pooled slots.

pool_size(slot_ref)

@spec pool_size(atom()) :: pos_integer()

Pool size for slot_ref. Defaults to 1 (single-worker, no pool) when the slot hasn't been registered — keeps the dispatch path uniform for ad-hoc test setups that start a Slot.Server without registering a pool size.

register(slot_ref, size)

@spec register(atom(), pos_integer()) :: :ok

Register a slot's pool size. Idempotent — re-registering with the same size is a no-op; with a different size, overwrites AND logs a warning so a config drift between two startup paths can't slip through silently.

Called once per slot from Pkcs11ex.SlotSupervisor.init/1.

start_link(opts \\ [])