-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathets_table_server.ex
More file actions
114 lines (90 loc) · 2.66 KB
/
Copy pathets_table_server.ex
File metadata and controls
114 lines (90 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
defmodule LiveDebugger.GenServers.EtsTableServer do
@moduledoc """
This gen_server is responsible for managing ETS tables.
"""
use GenServer
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
@ets_table_name :lvdbg_traces
@type table_refs() :: %{pid() => :ets.table()}
## API
@callback table!(pid :: pid()) :: :ets.table()
@callback delete_table!(pid :: pid()) :: :ok
@doc """
Returns ETS table reference.
It creates table if none is associated with given pid
"""
@spec table!(pid :: pid()) :: :ets.table()
def table!(pid) when is_pid(pid) do
impl().table!(pid)
end
@doc """
If table for given `pid` exists it deletes it from ETS.
"""
@spec delete_table!(pid :: pid()) :: :ok
def delete_table!(pid) when is_pid(pid) do
impl().delete_table!(pid)
end
def impl() do
Application.get_env(:live_debugger, :ets_table_server, __MODULE__.Impl)
end
defmodule Impl do
@moduledoc false
@behaviour LiveDebugger.GenServers.EtsTableServer
@server_module LiveDebugger.GenServers.EtsTableServer
@impl true
def table!(pid) do
GenServer.call(@server_module, {:get_or_create_table, pid}, 1000)
end
@impl true
def delete_table!(pid) do
GenServer.call(@server_module, {:delete_table, pid}, 1000)
end
end
## GenServer
@doc false
def start_link(args \\ []) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
@impl true
def init(_args) do
{:ok, %{}}
end
@impl true
def handle_info({:DOWN, _, :process, closed_pid, _}, table_refs) do
{_, table_refs} = delete_ets_table(closed_pid, table_refs)
closed_pid
|> PubSubUtils.process_status_topic()
|> PubSubUtils.broadcast({:process_status, :dead})
{:noreply, table_refs}
end
@impl true
def handle_call({:get_or_create_table, pid}, _from, table_refs) do
case Map.get(table_refs, pid) do
nil ->
ref = create_ets_table()
Process.monitor(pid)
{:reply, ref, Map.put(table_refs, pid, ref)}
ref ->
{:reply, ref, table_refs}
end
end
@impl true
def handle_call({:delete_table, pid}, _from, table_refs) do
{_, table_refs} = delete_ets_table(pid, table_refs)
{:reply, :ok, table_refs}
end
@spec create_ets_table() :: :ets.table()
defp create_ets_table() do
:ets.new(@ets_table_name, [:ordered_set, :public])
end
@spec delete_ets_table(pid(), table_refs()) :: {boolean(), table_refs()}
defp delete_ets_table(pid, table_refs) do
case Map.pop(table_refs, pid) do
{nil, table_refs} ->
{false, table_refs}
{ref, updated_table_refs} ->
:ets.delete(ref)
{true, updated_table_refs}
end
end
end