Skip to content

Commit 203cb4b

Browse files
committed
Add Registry.values/3
1 parent 8ff5c76 commit 203cb4b

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

lib/elixir/lib/registry.ex

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,64 @@ defmodule Registry do
731731
acc
732732
end
733733

734+
@doc """
735+
Reads the values for the given `key` for `pid` in `registry`.
736+
737+
For unique registries, it is either an empty list or a list
738+
with a single element. For duplicate registries, it is a list
739+
with zero, one, or multiple elements.
740+
741+
## Examples
742+
743+
In the example below we register the current process and look it up
744+
both from itself and other processes:
745+
746+
iex> Registry.start_link(keys: :unique, name: Registry.UniqueLookupTest)
747+
iex> Registry.values(Registry.UniqueLookupTest, "hello", self())
748+
[]
749+
iex> {:ok, _} = Registry.register(Registry.UniqueLookupTest, "hello", :world)
750+
iex> Registry.values(Registry.UniqueLookupTest, "hello", self())
751+
[:world]
752+
iex> Task.async(fn -> Registry.values(Registry.UniqueLookupTest, "hello", self()) end) |> Task.await()
753+
[]
754+
iex> parent = self()
755+
iex> Task.async(fn -> Registry.values(Registry.UniqueLookupTest, "hello", parent) end) |> Task.await()
756+
[:world]
757+
758+
The same applies to duplicate registries:
759+
760+
iex> Registry.start_link(keys: :duplicate, name: Registry.DuplicateLookupTest)
761+
iex> Registry.values(Registry.DuplicateLookupTest, "hello", self())
762+
[]
763+
iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, "hello", :world)
764+
iex> Registry.values(Registry.DuplicateLookupTest, "hello", self())
765+
[:world]
766+
iex> {:ok, _} = Registry.register(Registry.DuplicateLookupTest, "hello", :another)
767+
iex> Enum.sort(Registry.values(Registry.DuplicateLookupTest, "hello", self()))
768+
[:another, :world]
769+
770+
"""
771+
@doc since: "1.12.0"
772+
@spec values(registry, key, pid) :: [value]
773+
def values(registry, key, pid) when is_atom(registry) do
774+
case key_info!(registry) do
775+
{:unique, partitions, key_ets} ->
776+
key_ets = key_ets || key_ets!(registry, key, partitions)
777+
778+
case safe_lookup_second(key_ets, key) do
779+
{^pid, value} ->
780+
[value]
781+
782+
_ ->
783+
[]
784+
end
785+
786+
{:duplicate, partitions, key_ets} ->
787+
key_ets = key_ets || key_ets!(registry, pid, partitions)
788+
for {^pid, value} <- safe_lookup_second(key_ets, key), do: value
789+
end
790+
end
791+
734792
@doc """
735793
Unregisters all entries for the given `key` associated to the current
736794
process in `registry`.

lib/elixir/test/elixir/registry_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ defmodule RegistryTest do
3636
{:ok, pid} = Registry.register(registry, "hello", :value)
3737
assert is_pid(pid)
3838
assert Registry.keys(registry, self()) == ["hello"]
39+
assert Registry.values(registry, "hello", self()) == [:value]
3940

4041
assert {:error, {:already_registered, pid}} = Registry.register(registry, "hello", :value)
4142
assert pid == self()
4243
assert Registry.keys(registry, self()) == ["hello"]
44+
assert Registry.values(registry, "hello", self()) == [:value]
4345

4446
{:ok, pid} = Registry.register(registry, "world", :value)
4547
assert is_pid(pid)
@@ -49,11 +51,15 @@ defmodule RegistryTest do
4951
test "has unique registrations across processes", %{registry: registry} do
5052
{_, task} = register_task(registry, "hello", :value)
5153
Process.link(Process.whereis(registry))
54+
assert Registry.keys(registry, task) == ["hello"]
55+
assert Registry.values(registry, "hello", task) == [:value]
5256

5357
assert {:error, {:already_registered, ^task}} =
5458
Registry.register(registry, "hello", :recent)
5559

5660
assert Registry.keys(registry, self()) == []
61+
assert Registry.values(registry, "hello", self()) == []
62+
5763
{:links, links} = Process.info(self(), :links)
5864
assert Process.whereis(registry) in links
5965
end
@@ -433,16 +439,30 @@ defmodule RegistryTest do
433439
{:ok, pid} = Registry.register(registry, "hello", :value)
434440
assert is_pid(pid)
435441
assert Registry.keys(registry, self()) == ["hello"]
442+
assert Registry.values(registry, "hello", self()) == [:value]
436443

437444
assert {:ok, pid} = Registry.register(registry, "hello", :value)
438445
assert is_pid(pid)
439446
assert Registry.keys(registry, self()) == ["hello", "hello"]
447+
assert Registry.values(registry, "hello", self()) == [:value, :value]
440448

441449
{:ok, pid} = Registry.register(registry, "world", :value)
442450
assert is_pid(pid)
443451
assert Registry.keys(registry, self()) |> Enum.sort() == ["hello", "hello", "world"]
444452
end
445453

454+
test "has duplicate registrations across processes", %{registry: registry} do
455+
{_, task} = register_task(registry, "hello", :world)
456+
assert Registry.keys(registry, self()) == []
457+
assert Registry.keys(registry, task) == ["hello"]
458+
assert Registry.values(registry, "hello", self()) == []
459+
assert Registry.values(registry, "hello", task) == [:world]
460+
461+
assert {:ok, _pid} = Registry.register(registry, "hello", :value)
462+
assert Registry.keys(registry, self()) == ["hello"]
463+
assert Registry.values(registry, "hello", self()) == [:value]
464+
end
465+
446466
test "compares using matches", %{registry: registry} do
447467
{:ok, _} = Registry.register(registry, 1.0, :value)
448468
{:ok, _} = Registry.register(registry, 1, :value)

0 commit comments

Comments
 (0)