nquic_dispatch (nquic v1.0.0)
View SourceStriped connection dispatch table.
Distributes connection ID mappings across S ETS tables (one per stripe), selected by hashing the DCID. This reduces write contention when many connections register/unregister CIDs concurrently, while maintaining O(1) lookup on the fast path.
Each stripe is an independent ETS set with {read_concurrency, true}
and {write_concurrency, true}. A separate bag table indexed by
owning Pid holds the reverse mapping so reregister/3 can transfer a
single connection's CIDs in O(K) time (K = CIDs of that connection)
instead of O(N) (N = all registered CIDs across stripes).
Also provides atomics-based packet counters for lock-free telemetry.
Summary
Functions
Destroy all stripes. Only call during shutdown.
Look up the listener manager (nquic_listener_mgr) pid published at
listener startup. Returns undefined before the mgr has registered
itself (during the brief boot window of nquic_listener_sup).
Look up the partition supervisor pid published under the given 1-based
index. Returns undefined if the slot is empty (e.g. between a
partition crash and the supervisor's restart).
Return the published partition count, or undefined before
nquic_partitions_sup:init/1 has run.
Add ByteCount to byte counter for receiver I (1-based).
Increment packet count for receiver I (1-based).
Look up the process for a connection ID.
Return the per-listener metrics handle attached to this dispatch, if any.
Create a striped dispatch table with default stripe count (number of schedulers).
Create a striped dispatch table with S stripes.
Create packet counters for N receivers.
Return the distinct owner pids currently registered across all CIDs.
Reads the per-pid reverse index (a bag of {Pid, CID}) and folds it
to a deduplicated pid list. Used only by the listener drain broadcast
(nquic:stop_listener/1,2, mode => cascade); never on the per-packet
path.
Read byte count for receiver I (1-based).
Read packet count for receiver I (1-based).
Register a connection ID to a process.
Re-register all entries pointing to OldPid to NewPid. Walks the per-pid reverse index for OldPid and updates only that connection's CIDs (O(K)), instead of scanning every stripe (O(N)). Used during connection export (accept_ctx) to transfer dispatch entries from the gen_statem to the library-mode owner process.
Publish the listener manager pid. Called from nquic_listener_mgr:init/1
so receivers and protocol-level helpers can route accept/establishment
notifications via nquic_dispatch:get_mgr/1.
Publish a partition supervisor pid under its 1-based index. Each
nquic_server_sup partition calls this from its init/1 (or after
restart) so start_conn_child/3 can route work without a tuple
republish step. Avoids the set_sups tuple write-then-replace loop
that the legacy nquic_listener did on every partition restart.
Publish the total number of partition supervisors. Set once by
nquic_partitions_sup:init/1 before any partition starts so
start_conn_child/3 can hash the DCID into the right slot.
Start a connection child under the partition supervisor selected by hashing the DCID. Resolves the partition pid via two ETS reads (count
Return the total number of registered connection IDs across all stripes.
Remove a connection ID from the dispatch table.
Types
-type counters() :: #counters{ref :: atomics:atomics_ref(), n :: pos_integer()}.
-type t() :: #dispatch{tables :: tuple(), stripes :: pos_integer(), pid_index :: ets:tid(), sups_table :: ets:tid(), metrics :: nquic_metrics:t() | undefined}.
Functions
-spec destroy(t()) -> ok.
Destroy all stripes. Only call during shutdown.
Look up the listener manager (nquic_listener_mgr) pid published at
listener startup. Returns undefined before the mgr has registered
itself (during the brief boot window of nquic_listener_sup).
-spec get_partition(t(), pos_integer()) -> pid() | undefined.
Look up the partition supervisor pid published under the given 1-based
index. Returns undefined if the slot is empty (e.g. between a
partition crash and the supervisor's restart).
-spec get_partition_count(t()) -> pos_integer() | undefined.
Return the published partition count, or undefined before
nquic_partitions_sup:init/1 has run.
-spec inc_bytes(counters(), pos_integer(), non_neg_integer()) -> ok.
Add ByteCount to byte counter for receiver I (1-based).
-spec inc_packets(counters(), pos_integer()) -> ok.
Increment packet count for receiver I (1-based).
Look up the process for a connection ID.
-spec metrics(t()) -> nquic_metrics:t() | undefined.
Return the per-listener metrics handle attached to this dispatch, if any.
-spec new() -> t().
Create a striped dispatch table with default stripe count (number of schedulers).
-spec new(pos_integer()) -> t().
Create a striped dispatch table with S stripes.
-spec new_counters(pos_integer()) -> counters().
Create packet counters for N receivers.
Return the distinct owner pids currently registered across all CIDs.
Reads the per-pid reverse index (a bag of {Pid, CID}) and folds it
to a deduplicated pid list. Used only by the listener drain broadcast
(nquic:stop_listener/1,2, mode => cascade); never on the per-packet
path.
-spec read_bytes(counters(), pos_integer()) -> non_neg_integer().
Read byte count for receiver I (1-based).
-spec read_packets(counters(), pos_integer()) -> non_neg_integer().
Read packet count for receiver I (1-based).
Register a connection ID to a process.
Re-register all entries pointing to OldPid to NewPid. Walks the per-pid reverse index for OldPid and updates only that connection's CIDs (O(K)), instead of scanning every stripe (O(N)). Used during connection export (accept_ctx) to transfer dispatch entries from the gen_statem to the library-mode owner process.
Publish the listener manager pid. Called from nquic_listener_mgr:init/1
so receivers and protocol-level helpers can route accept/establishment
notifications via nquic_dispatch:get_mgr/1.
-spec set_partition(t(), pos_integer(), pid()) -> true.
Publish a partition supervisor pid under its 1-based index. Each
nquic_server_sup partition calls this from its init/1 (or after
restart) so start_conn_child/3 can route work without a tuple
republish step. Avoids the set_sups tuple write-then-replace loop
that the legacy nquic_listener did on every partition restart.
-spec set_partition_count(t(), pos_integer()) -> true.
Publish the total number of partition supervisors. Set once by
nquic_partitions_sup:init/1 before any partition starts so
start_conn_child/3 can hash the DCID into the right slot.
-spec start_conn_child(t(), binary(), map()) -> {ok, pid()} | {ok, pid(), term()} | {error, term()}.
Start a connection child under the partition supervisor selected by hashing the DCID. Resolves the partition pid via two ETS reads (count
- slot), so partition restart is observed immediately without any republish step.
-spec table_size(t()) -> non_neg_integer().
Return the total number of registered connection IDs across all stripes.
Remove a connection ID from the dispatch table.