Erlang:在 gen_server 崩溃并重新启动后,ets 表不会保留数据
我有一个 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 表应该能够持久保存状态,但确实需要一些帮助来理解它在代码中的工作原理。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ets
表链接到创建它们的进程,这就是为什么如果您在gen_server
进程中创建表,当进程终止时,该表将被销毁。如果您希望该表持续存在,您基本上有 2 个选择:
ets
继承机制:查看ets:give_away/3
和用于表初始化的heir
选项。公共
和命名表,并且不应在表持有进程上执行任何操作。该进程应该只存在来保存表。然后,您的服务器就可以按名称访问该表。ets
tables are linked to the process that creates them, that's why if you create the table in agen_server
process when the process terminates, the table is destroyed.If you want the table to persist, you have basically 2 options:
ets
inheritance mechanism: Check outets:give_away/3
and theheir
option for table initialization.public
and 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.