I have a gen_server which stores positions of objects in an ets table like this
-module(my_gen_server).
-record(slot, {position, object}).
-behavior(gen_server).
%% API
-export([start_link/1, init/1, move/2, handle_call/3, handle_cast/2, get/1, delete/1]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
WidthX, HeightY = get_dims(),
ets:new(my_gen_server,[named_table, {keypos, #slot.position}]),
{ok, {WidthX, HeightY}}.
move(Object, {X,Y}) ->
gen_server:call(?MODULE, {move, Object, {X,Y}}).
handle_call({move, Object, {X,Y}}, _From, {WidthX, HeightY}) ->
case add_or_move(Object, X, Y) of
{error, Reason} ->
{reply, {error, Reason}, {WidthX, HeightY}};
_ ->
{reply, ok, {WidthX, HeightY}}
end.
search_object(Object) ->
Pos = ets:match(my_gen_server, #slot{position ='$1', object = Object, _='_'}),
case Pos of
[] -> {error, "Not found"};
_ -> lists:flatten(Pos)
end.
add_or_move(Object, X, Y) ->
Pos = search_object(Object),
case Pos of
{error, _Reason} ->
supervisor:start_child(my_object_sup, [Object, {X, Y}]),
ets:insert(my_gen_server, #slot{position = {X,Y}, object = Object});
_ ->
ets:insert(my_gen_server, #slot{position = {X,Y}, object = Object})
end.
The problem is when a supervisor starts my_gen_server and the process crashes and restarts, the ets table is gone and I lose all my object data. I searched for this problem and everywhere they say that storing data in ets table can help in making the state persist but I cannot find the code to achieve it anywhere.
I also tried creating the ets table before gen_server:start_link is called instead of init, but that prevents the gen_server from restarting at all after crash. I understand that conceptually ets table should be able to persist the state but would really like some help in understanding how it works in code.
etstables are linked to the process that creates them, that's why if you create the table in agen_serverprocess when the process terminates, the table is destroyed. If you want the table to persist, you have basically 2 options:etsinheritance mechanism: Check outets:give_away/3and theheiroption for table initialization.publicand named table and no operation should be performed on the table-holding process. That process should only exist to hold the table. Then, your servers can just access the table by name.