Tracks the active log file for each shard.
Uses atomics generation counter + process dictionary cache — ~15ns reads on the hot path. On file rotation, only an ETS re-read (~100ns) happens per caller process. No global GC from persistent_term.put, which matters when the host app has 50K+ LiveView/Channel processes.
Usage
# In Shard init and rotation:
ActiveFile.publish(instance_ctx, shard_index, file_id, file_path, shard_data_path)
# In Router's local-origin write path (hot path):
{file_id, file_path, shard_data_path} = ActiveFile.get(instance_ctx, shard_index)
Summary
Functions
Removes active-file rows for a custom instance.
Returns {file_id, file_path, shard_data_path} for the given shard.
Returns active file metadata for a shard in a specific instance.
Initializes the registry. Called once from Application.start.
Publishes the active file metadata for a shard.
Publishes active file metadata for a shard in a specific instance.
Functions
@spec cleanup_instance(map()) :: :ok
Removes active-file rows for a custom instance.
Called during instance cleanup. The generation bump invalidates process dictionary caches that may still hold paths for the stopped instance.
@spec get(non_neg_integer()) :: {non_neg_integer(), binary(), binary()}
Returns {file_id, file_path, shard_data_path} for the given shard.
~15ns hot path (atomics check + process dictionary cache hit). ~100ns cold (ETS lookup on generation mismatch).
@spec get(map() | nil, non_neg_integer()) :: {non_neg_integer(), binary(), binary()}
Returns active file metadata for a shard in a specific instance.
Prefer this in production paths that already have an Instance context.
@spec init(non_neg_integer()) :: :ok
Initializes the registry. Called once from Application.start.
@spec publish(non_neg_integer(), non_neg_integer(), binary(), binary()) :: :ok
Publishes the active file metadata for a shard.
Called from Shard.init/1 and Shard.maybe_rotate_file/1.
@spec publish(map() | nil, non_neg_integer(), non_neg_integer(), binary(), binary()) :: :ok
Publishes active file metadata for a shard in a specific instance.
The default instance keeps the historical shard-index key for backward
compatibility. Custom instances use {instance_name, shard_index} so
isolated tests and embedded instances cannot overwrite each other.