Registry.select guard to find tuple

Hello, I create a Registry for my DynamicSupervisor in my GenServer.

like this:

defp via(id, section, user_id) do
   insert_time =  DateTime.utc_now() |> DateTime.add(3600, :second)
   {:via, Registry, {MishkaContent.Cache.ContentDraftRegistry, id, {section, user_id, insert_time}}}
end

I couldn’t create Registry like this:

 {:via, Registry, {MishkaContent.Cache.ContentDraftRegistry, id, section, user_id, insert_time}}

it shows me this error:

{:error,
 {:function_clause,
  [
    {Registry, :whereis_name,
     [
       {MishkaContent.Cache.ContentDraftRegistry,
        "06da9f9f-880c-4a11-93f8-a0bb401d64b3", "blog_content", "1",
        ~U[2021-09-14 17:40:39.018916Z]}
     ], [file: 'lib/registry.ex', line: 223]},
    {:gen, :start, 6, [file: 'gen.erl', line: 84]},
    {DynamicSupervisor, :start_child, 3,
     [file: 'lib/dynamic_supervisor.ex', line: 693]},
    {DynamicSupervisor, :handle_start_child, 2,
     [file: 'lib/dynamic_supervisor.ex', line: 679]},
    {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 721]},
    {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 750]},
    {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}
  ]}}

Then I am forced to create a tuple, but I have a problem when I want to select this in Registry.select

If I could create this like {:via, Registry, {ContentDraftRegistry, id, section, user_id, insert_time}} , I am able to find it like this:

defp registry_state(user_id) do
  match_all = {:"$1", :"$2", :"$3", :"$4", :"$5"}
  map_result = [%{id: :"$1", pid: :"$2", section: :"$3", user_id: :"$4", time: :"$5"}]
  guards= [{:"==", :"$4", user_id}
  Registry.select(MishkaContent.Cache.ContentDraftRegistry, [{match_all, guards, map_result}])
end

As you see top error which doesn’t let me do this easy, I should search a parameter like this:

guards = [{:"==", :"$3", {section, _user_id, _time}}]

because this is not a pattern it needs _user_id and _time, but I need to skip this and just loads records that their first item is what I need like {"public_info", _user_id, _time}

Please help me to create custom search on Registry

Thanks

You can destructure the tuple in your select.

iex(1)> Registry.start_link(keys: :unique, name: R)
{:ok, #PID<0.112.0>}
iex(2)> Registry.register(R, "id", {_section = "blog_content", _user_id = "1", _insert_time = ~U[2021-09-14 17:40:39.018916Z]})
{:ok, #PID<0.113.0>}
iex(3)> Registry.select(R, [{{:"$1", :"$2", {:"$3", :"$4", :"$5"}}, [{:==, :"$4", "1"}], [%{id: :"$1", pid: :"$2", section: :"$3", user_id: :"$4", time: :"$5"}]}])
[
  %{
    id: "id",
    pid: #PID<0.109.0>,
    section: "blog_content",
    time: ~U[2021-09-14 17:40:39.018916Z],
    user_id: "1"
  }
]

Although depending on the load you expect, select might be not the most efficient approach. In my experience :ets.select is one of the slowest ways to find something in an ets table.

2 Likes