The simplest possible example of using :ets.give.away to save a table if the table owner’s process crashes.
Add genservers to the supervisor’s tree
{UsersEtsTableBackup, []},
{UsersEtsTable, []}
UsersEtsTableBackup - is needed only to create a table and transfer the table and the rights to use it to the working process and also gets the table back if the working process crashes
defmodule UsersEtsTableBackup do
use GenServer
######## Client API #########################################################
def give_me_ets(data), do: GenServer.call(__MODULE__, data)
######## Server callbacks ###################################################
def start_link([]), do: GenServer.start_link(__MODULE__, [], name: __MODULE__)
def init(state) do
with :undefined <- :ets.whereis(:users) do
:ets.new(:users, [:set, :protected, :named_table, {:heir, self(), {}}])
else
_ -> UsersEtsTable.set_me_heir(:set_me_heir)
end
{:ok, state}
end
#############################################################################
def handle_call(:give_me_ets, {pid, _}, state) do
:ets.give_away(:users, pid, {})
{:reply, :ok, state}
end
def handle_call(_, _from, state) do
{:reply, :ok, state}
end
#############################################################################
def handle_cast(_, state) do
{:noreply, state}
end
#############################################################################
def handle_info({:"ETS-TRANSFER", :users, _, {}}, state) do
{:noreply, state}
end
def handle_info(_, state) do
{:noreply, state}
end
#############################################################################
end
UsersEtsTable - work process, gets the table and rights from UsersEtsTableBackup and works with it
defmodule UsersEtsTable do
use GenServer
######## Client API #########################################################
def set_me_heir(data), do: GenServer.call(__MODULE__, data)
######## Server callbacks ###################################################
def start_link([]), do: GenServer.start_link(__MODULE__, [], name: __MODULE__)
def init(state), do: {:ok, state, {:continue, :give_me_ets}}
#############################################################################
def handle_call(:set_me_heir, {pid, _}, state) do
:ets.setopts(:users, {:heir, pid, {}})
{:reply, :ok, state}
end
def handle_call(_, _from, state) do
{:reply, :ok, state}
end
#############################################################################
def handle_cast(_, state) do
{:noreply, state}
end
#############################################################################
def handle_continue(:give_me_ets, state) do
UsersEtsTableBackup.give_me_ets(:give_me_ets)
{:noreply, state}
end
def handle_continue(_, state) do
{:noreply, state}
end
#############################################################################
def handle_info({:"ETS-TRANSFER", :users, _, {}}, state) do
{:noreply, state}
end
def handle_info(_, state) do
{:noreply, state}
end
#############################################################################
end