Erlang:ets表在gen_server崩溃并重新启动后不保留数据

kmbjn2e3  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(212)

我有一个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表在概念上应该能够保持状态,但我真的希望在理解它如何在代码中工作方面得到一些帮助。

nwlls2ji

nwlls2ji1#

ets表链接到创建它们的进程,这就是为什么如果您在gen_server进程中创建表,当进程终止时,表将被销毁。如果您希望表持久,基本上有两种选择:

  • 使用ets继承机制:检查ets:give_away/3heir选项以进行表初始化。
  • 保留一个拥有该表的进程,该表不是您的服务器之一。在这种情况下,该表应创建为publicnamed 表,并且不应对表保存进程执行任何操作。该进程的存在只应用于保存该表。这样,您的服务器就可以按名称访问该表。

相关问题