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

Erlang: ets table does not persist data after gen_server crashes and restarts

我有一个 gen_server 存储对象在 ets 中的位置 table 像这样

-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 ='', 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 table 消失了,我丢失了所有对象数据。我搜索了这个问题,到处都说在 ets table 中存储数据有助于使状态持续存在,但我无法在任何地方找到实现它的代码。 我还尝试在调用 gen_server:start_link 之前创建 ets table 而不是调用 init,但这会阻止 gen_server 在崩溃后完全重新启动。我知道从概念上讲 ets table 应该能够保持状态,但真的希望得到一些帮助来理解它在代码中的工作方式。

ets table 链接到创建它们的进程,这就是为什么如果您在进程终止时在 gen_server 进程中创建 table, table 被摧毁。 如果你想让 table 持续存在,你基本上有 2 个选择:

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