我有一个gen_server,它在ets表中存储对象的位置,如下所示
-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.
问题是当一个管理员启动my_gen_server
时,进程崩溃并重新启动,ets表消失了,我丢失了所有的对象数据。我搜索了这个问题,到处都有人说在ets表中存储数据可以帮助保持状态,但我在任何地方都找不到实现它的代码。我还尝试在调用gen_server:start_link
而不是init之前创建ets表。但这会阻止gen_server在崩溃后重新启动。我理解ets表在概念上应该能够保持状态,但我真的希望在理解它如何在代码中工作方面得到一些帮助。
1条答案
按热度按时间nwlls2ji1#
ets
表链接到创建它们的进程,这就是为什么如果您在gen_server
进程中创建表,当进程终止时,表将被销毁。如果您希望表持久,基本上有两种选择:ets
继承机制:检查ets:give_away/3
和heir
选项以进行表初始化。public
和 named 表,并且不应对表保存进程执行任何操作。该进程的存在只应用于保存该表。这样,您的服务器就可以按名称访问该表。