Erlang/ets: reset ets table after getting a “bad a

2020-03-24 03:22发布

I've been learning how to use ets, but one thing that has bothered me is that, occasionally*, ets:match throws a bad argument… And, from them on, all subsequent calls (even calls which previously worked) also throw a bad argument:

> ets:match(Tid, { [$r | '$1'] }, 1).
% this match works...
% Then, at some point, this comes up:
** exception error: bad argument
     in function  ets:match/3
        called as ets:match(24589,{[114|'$1']},1)
% And from then on, matches stop working:
> ets:match(Tid, { [$r | '$1'] }, 1).
** exception error: bad argument
     in function  ets:match/3
        called as ets:match(24589,{[114|'$1']},1)

Is there any way to "reset" the ets system so that I can query it (ie, from the shell) again?

*: I haven't been able to reproduce the problem… But it happens fairly often while I'm trying to do "other things".

标签: erlang ets
2条回答
劫难
2楼-- · 2020-03-24 04:04

Although I'm not 100% sure, this thread seems to answer your question. It appears that you're observing this behaviour in the shell. If so, two facts are interacting in a confusing way:

  1. An ets table is deleted as soon as its owning process dies.
  2. The erlang shell dies whenver it receives an exception and is silently restarted.

So, when you get the first exception, the current shell process dies causing the ets table to be deleted, and then a new shell process is started for you. Now, when you try another ets:match, it fails because the table no longer exists.

查看更多
可以哭但决不认输i
3楼-- · 2020-03-24 04:16

Dale already told you what happens. You can confirm that by calling self() in the shell every now and then.

As a quick workaround you can spawn another process to create a public table for you. Then that table won't die along with your shell.

1> self().
<0.32.0>    % shell's Pid

2> spawn(fun() -> ets:new(my_table, [named_table, public]), receive X -> ok end end).
<0.35.0>    % the spawned process's Pid

3> ets:insert(my_table, {a, b}).
true

Now make an exception and check that the table indeed survived.

4> 1/0.
** exception error: bad argument in an arithmetic expression
     in operator  '/'/2
        called as 1 / 0
5> self().
<0.38.0>   % shell's reborn, with a different Pid

6> ets:insert(my_table, {c, d}).
true
7> ets:tab2list(my_table).
[{c,d},{a,b}]    % table did survive the shell restart

To delete the table, just send something to your spawned process:

8> pid(0,35,0) ! bye_bye.
bye_bye
9> ets:info(my_table).   
undefined
查看更多
登录 后发表回答