文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

今天的Erlang Thursday继续介绍 ets 模块以及ETS的概况。

上次我们看到ETS表在其父进程崩溃的时候被删除了,那么问题来了,我们怎么能够在其父进程崩溃的时候依然保持ETS表活着呢?

为解决这个问题,我们将研究函数 ets:give_away/3 以及在创建表的时候指定的参数 heir 。

首先我们创建一个函数,它将代表一个进程,而我们可以将表的所有权赋予它的。这个函数只是等待消息而且永远不超时。

第 1 段(可获 1.24 积分)
Fun = fun() -> receive after infinity -> ok end end.
% #Fun<erl_eval.20.54118792>

现在我们创建一个运行该函数的进程。

Process = spawn(Fun).
% <0.53.0>

然后我们创建一个新的ETS表,

Table = ets:new(table, []).
% 20498

并且将它赋予我们刚刚创建的进程。

ets:give_away(Table, Process, []).
% true

我查看表信息可以看到表的所有者是我们创建的进程,因为这个进程的PID和表消息里的所有者元组的PID一样。

ets:info(Table).
% [{read_concurrency,false},
%  {write_concurrency,false},
%  {compressed,false},
%  {memory,305},
%  {owner,<0.53.0>},
%  {heir,none},
%  {name,table},
%  {size,0},
%  {node,nonode@nohost},
%  {named_table,false},
%  {type,set},
%  {keypos,1},
%  {protection,protected}]

 

第 2 段(可获 0.8 积分)

现在我们已经进行了所谓的所有权转移,那么是时候将原来的所有者进程也就是我们当前的shell进程崩溃掉。

1 = 2.
% ** exception error: no match of right hand side value 2
self().
% <0.58.0>

我们检查我们创建的进程是否还活着,绝大多数情况下应该是活着的。

is_process_alive(Process).
% true

在检查表的信息,看看它是否还活着。

ets:info(Table).
% [{read_concurrency,false},
%  {write_concurrency,false},
%  {compressed,false},
%  {memory,305},
%  {owner,<0.53.0>},
%  {heir,none},
%  {name,table},
%  {size,0},
%  {node,nonode@nohost},
%  {named_table,false},
%  {type,set},
%  {keypos,1},
%  {protection,protected}]

 

第 3 段(可获 0.83 积分)

它依然还活着!!!我们已经转移了所有权,所以如果我们自己的进程崩溃的话,ETS表依然是活着的。

是时候杀掉那个进程了。

exit(Process, "Because").
% true
is_process_alive(Process).
% false

然后表就消失了...

ets:info(Table).
% undefined

这一次,让我们在创建一个ETS表的时候用 heir 选项,来利用ETS表的所有权转移给一个继承人的魔法。

在这次场景里,当所有者进程死掉的时候shell将是继承人。

TableWithHeir = ets:new(table, [{heir, self(), "something went wrong"}]).
% 24594

 

第 4 段(可获 0.9 积分)

我们创建一个新的进程,然后将ETS表的所有权赋予这个新的进程。

Process2 = spawn(Fun).
% <0.71.0>
ets:give_away(TableWithHeir, Process2, []).
% true

我们检查表的信息,我们可以看到表的所有者是新的进程,而它的继承人是我们当前的shell进程。

self().
% <0.58.0>
ets:info(TableWithHeir).
% [{read_concurrency,false},
%  {write_concurrency,false},
%  {compressed,false},
%  {memory,349},
%  {owner,<0.71.0>},
%  {heir,<0.58.0>},
%  {name,table},
%  {size,0},
%  {node,nonode@nohost},
%  {named_table,false},
%  {type,set},
%  {keypos,1},
%  {protection,protected}]

 

第 5 段(可获 0.54 积分)

现在再次杀掉所有者进程了......

exit(Process2, "Because").
% true
is_process_alive(Process2).
% false

我们在检查表的信息,我们可以看到当前的shell进程既是所有者又是继承人。

ets:info(TableWithHeir).
% [{read_concurrency,false},
%  {write_concurrency,false},
%  {compressed,false},
%  {memory,349},
%  {owner,<0.58.0>},
%  {heir,<0.58.0>},
%  {name,table},
%  {size,0},
%  {node,nonode@nohost},
%  {named_table,false},
%  {type,set},
%  {keypos,1},
%  {protection,protected}]

我们创建一个新的进程,然后我们把表转移给它。

第 6 段(可获 0.55 积分)
Process3 = spawn(Fun).
% <0.78.0>
ets:give_away(TableWithHeir, Process3, []).
% true

所有者变成了新的进程,我们当前的shell进程依然是继承人。

ets:info(TableWithHeir).
% [{read_concurrency,false},
%  {write_concurrency,false},
%  {compressed,false},
%  {memory,349},
%  {owner,<0.78.0>},
%  {heir,<0.58.0>},
%  {name,table},
%  {size,0},
%  {node,nonode@nohost},
%  {named_table,false},
%  {type,set},
%  {keypos,1},
%  {protection,protected}]

通过利用指定继承人的能力,同时用 ets:give_away/3 函数,我们可以帮助ETS表长生不死。

第 7 段(可获 0.45 积分)

一种可能利用的方式是,我们有一个监督进程,它创建一个“继承人”进程,然后创建一个子进程,这个子进程拥有ETS表,如果这个子进程死掉,它将转移所有权给继承人进程。直到新的所有者进程被重新创建,然后继承人进程便可以将ETS表的所有权转移给这个新创建的进程。

第 8 段(可获 0.89 积分)

文章评论