Node-level semaphore that limits concurrent merge operations.
Only one shard merge may run at a time across the entire node. This prevents merge I/O from multiple shards competing for the same NVMe bandwidth and PCIe bus, which would cause both merges to run slower than a single sequential merge.
The semaphore uses a simple acquire/release model backed by a GenServer. The caller must release the semaphore after the merge completes (or fails). To guard against callers that crash without releasing, the semaphore monitors the acquiring process and auto-releases on DOWN.
Usage
case Ferricstore.Merge.Semaphore.acquire(shard_index) do
:ok ->
try do
do_merge(...)
after
Ferricstore.Merge.Semaphore.release(shard_index)
end
{:busy, holder_shard} ->
# Another shard is merging, try later.
:ok
end
Summary
Functions
Attempts to acquire the merge semaphore for the given shard.
Returns a specification to start this module under a supervisor.
Releases the merge semaphore. Must be called by the same shard that acquired it.
Starts the merge semaphore GenServer.
Returns the current state of the semaphore for observability.
Types
@type state() :: %{ holder: {non_neg_integer(), pid()} | nil, monitor_ref: reference() | nil }
Functions
@spec acquire(non_neg_integer(), GenServer.server()) :: :ok | {:busy, non_neg_integer()}
Attempts to acquire the merge semaphore for the given shard.
Returns :ok if the semaphore was acquired, or {:busy, holder_shard_index}
if another shard currently holds it.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec release(non_neg_integer(), GenServer.server()) :: :ok | {:error, :not_holder}
Releases the merge semaphore. Must be called by the same shard that acquired it.
Returns :ok on success, or {:error, :not_holder} if the caller is not
the current holder.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the merge semaphore GenServer.
@spec status(GenServer.server()) :: :free | {:held, non_neg_integer()}
Returns the current state of the semaphore for observability.
Returns {:held, shard_index} if a merge is in progress, or :free.