Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions lib/elixir/lib/registry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ defmodule Registry do
| {:partitions, pos_integer}
| {:listeners, [atom]}
| {:compressed, boolean}
| {:spawn_opt, [Process.spawn_opt()]}
| {:meta, [{meta_key, meta_value}]}

@typedoc """
Expand Down Expand Up @@ -360,6 +361,9 @@ defmodule Registry do
crashes. Messages sent to listeners are of type `t:listener_message/0`.
* `:compressed` - turns on compression for registry's keys ETS tables, reducing
memory usage at the cost of additional CPU usage. Defaults to `false`.
* `:spawn_opt` - a list of options passed to the registry's partition
processes on spawn. See `Process.spawn/2` for the full list of options.
Defaults to `[]`.
* `:meta` - a keyword list of metadata to be attached to the registry.

For `:duplicate` registries, you can specify the partitioning strategy
Expand Down Expand Up @@ -439,6 +443,13 @@ defmodule Registry do
"expected :compressed to be a boolean, got: #{inspect(compressed)}"
end

spawn_opt = Keyword.get(options, :spawn_opt, [])

if not is_list(spawn_opt) do
raise ArgumentError,
"expected :spawn_opt to be a list, got: #{inspect(spawn_opt)}"
end

# The @info format must be kept in sync with Registry.Partition optimization.
entries = [
{@all_info, {kind, partitions, nil, nil, listeners}},
Expand All @@ -451,7 +462,8 @@ defmodule Registry do
partitions,
listeners,
entries,
compressed
compressed,
spawn_opt
)
end

Expand Down Expand Up @@ -1776,20 +1788,23 @@ defmodule Registry.Supervisor do
@moduledoc false
use Supervisor

def start_link(kind, registry, partitions, listeners, entries, compressed) do
arg = {kind, registry, partitions, listeners, entries, compressed}
def start_link(kind, registry, partitions, listeners, entries, compressed, spawn_opt) do
arg = {kind, registry, partitions, listeners, entries, compressed, spawn_opt}
Supervisor.start_link(__MODULE__, arg, name: registry)
end

def init({kind, registry, partitions, listeners, entries, compressed}) do
def init({kind, registry, partitions, listeners, entries, compressed, spawn_opt}) do
^registry = :ets.new(registry, [:set, :public, :named_table, read_concurrency: true])
true = :ets.insert(registry, entries)

children =
for i <- 0..(partitions - 1) do
key_partition = Registry.Partition.key_name(registry, i)
pid_partition = Registry.Partition.pid_name(registry, i)
arg = {kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed}

arg =
{kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed,
spawn_opt}
Comment thread
josevalim marked this conversation as resolved.
Resolved

%{
id: pid_partition,
Expand Down Expand Up @@ -1844,7 +1859,10 @@ defmodule Registry.Partition do
The process is only responsible for linking and cleaning up when processes crash.
"""
def start_link(registry, arg) do
GenServer.start_link(__MODULE__, arg, name: registry)
{_kind, _registry, _i, _partitions, _key_partition, _pid_partition, _listeners, _compressed,
spawn_opt} = arg

GenServer.start_link(__MODULE__, arg, name: registry, spawn_opt: spawn_opt)
end

@doc """
Expand All @@ -1862,7 +1880,10 @@ defmodule Registry.Partition do

## Callbacks

def init({kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed}) do
def init(
{kind, registry, i, partitions, key_partition, pid_partition, listeners, compressed,
_spawn_opt}
) do
Process.flag(:trap_exit, true)

key_ets = init_key_ets(kind, key_partition, compressed)
Expand Down
21 changes: 21 additions & 0 deletions lib/elixir/test/elixir/registry_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ Code.require_file("test_helper.exs", __DIR__)
defmodule Registry.CommonTest do
use ExUnit.Case, async: true
doctest Registry, except: [:moduledoc]

test "raises on invalid :spawn_opt option" do
assert_raise ArgumentError, ~r/expected :spawn_opt to be a list/, fn ->
Registry.start_link(keys: :unique, name: :invalid_spawn_opt, spawn_opt: :oops)
end
end

test "partitions are spawned with the given :spawn_opt" do
{:ok, _} =
Registry.start_link(
keys: :unique,
name: __MODULE__.OffHeap,
partitions: 4,
spawn_opt: [message_queue_data: :off_heap]
)

for i <- 0..3 do
{partition, _} = :ets.lookup_element(__MODULE__.OffHeap, i, 3)
assert {:message_queue_data, :off_heap} = Process.info(partition, :message_queue_data)
end
end
end

defmodule Registry.Test do
Expand Down