1defmodule Phoenix.PubSub.GC do 2 @moduledoc """ 3 A garbage collector process that cleans up the table used 4 by `Phoenix.PubSub.Local`. 5 """ 6 7 use GenServer 8 9 @doc """ 10 Starts the server. 11 12 * `server_name` - The name to register the server under 13 * `table_name` - The name of the local table 14 15 """ 16 def start_link(server_name, local_name) do 17 GenServer.start_link(__MODULE__, {server_name, local_name}, name: server_name) 18 end 19 20 @doc """ 21 Force table clean up because the given pid is down asynchronously. 22 23 * `gc_server` - The registered server name or pid 24 * `pid` - The subscriber pid 25 26 ## Examples 27 28 iex> down(:gc_server, self()) 29 :ok 30 31 """ 32 def down(gc_server, pid) when is_atom(gc_server) do 33 GenServer.cast(gc_server, {:down, pid}) 34 end 35 36 def init({server_name, local_name}) do 37 {:ok, %{topics: local_name, pids: server_name}} 38 end 39 40 def handle_call({:subscription, pid}, _from, state) do 41 {:reply, subscription(state.pids, pid), state} 42 end 43 44 def handle_cast({:down, pid}, state) do 45 try do 46 topics = :ets.lookup_element(state.pids, pid, 2) 47 for topic <- topics do 48 true = :ets.match_delete(state.topics, {topic, {pid, :_}}) 49 end 50 true = :ets.match_delete(state.pids, {pid, :_}) 51 catch 52 :error, :badarg -> :badarg 53 end 54 55 {:noreply, state} 56 end 57 58 defp subscription(pids_table, pid) do 59 try do 60 :ets.lookup_element(pids_table, pid, 2) 61 catch 62 :error, :badarg -> [] 63 end 64 end 65end 66