Why does ets delete my tables rudely? - erlang

After lookup a nonexistent table(t3) in ets, all the user-created tables(t1 and t2) will be deleted. Is it a bug or just a wierd feature of ets?
Here is the code in Eshell.
Eshell V5.9.1 (abort with ^G)
1> ets:new(t1, [named_table]).
t1
2> ets:new(t2, [named_table]).
t2
3> ets:all().
[t2,t1,8207,4110,13,file_io_servers,inet_hosts_file_byaddr,
inet_hosts_file_byname,inet_hosts_byaddr,inet_hosts_byname,
inet_cache,inet_db,global_pid_ids,global_pid_names,
global_names_ext,global_names,global_locks,ac_tab]
4> ets:insert(t1, {1,2}).
true
5> ets:lookup(t1, 1).
[{1,2}]
6> ets:lookup(t2, 1).
[]
7> ets:all().
[t2,t1,8207,4110,13,file_io_servers,inet_hosts_file_byaddr,
inet_hosts_file_byname,inet_hosts_byaddr,inet_hosts_byname,
inet_cache,inet_db,global_pid_ids,global_pid_names,
global_names_ext,global_names,global_locks,ac_tab]
8> ets:lookup(t3, 1).
** exception error: bad argument
in function ets:lookup/2
called as ets:lookup(t3,1)
9> ets:all().
[8207,4110,13,file_io_servers,inet_hosts_file_byaddr,
inet_hosts_file_byname,inet_hosts_byaddr,inet_hosts_byname,
inet_cache,inet_db,global_pid_ids,global_pid_names,
global_names_ext,global_names,global_locks,ac_tab]
10>
Anyone who can tell me what's the problem here?

You lookuup in a table that does not exist, so you get an error that "crash" your shell. A new shell is launch an it looks transparent, except that the ets that belonged to the first shell are deleted.

Related

How to copy an Erlang digraph?

How do I copy an Erlang digraph? There doesn't seem to be a copy function in the docs. Do I have to build a copy manually?
I'm coding in Elixir.
The best way I can see to copy an entire digraph is to use the digraph_utils:subgraph/2 with Vertices = digraph:vertices(Digraph).
Test:
Creating A->B graph in Digraph, copying it to Digraph2 and checking that it is a different graph by adding "C" vertex only to Digraph2.
1> Digraph = digraph:new().
{digraph,16400,20497,24594,true}
2> digraph:add_vertex(Digraph,"A").
"A"
3> digraph:add_vertex(Digraph,"B").
"B"
4> digraph:add_edge(Digraph,"A","B").
['$e'|0]
5> Digraph2 = digraph_utils:subgraph(Digraph, digraph:vertices(Digraph)).
{digraph,28691,32788,36885,true}
6> digraph:add_vertex(Digraph2, "C").
"C"
7> digraph:vertices(Digraph).
["B","A"]
8> digraph:vertices(Digraph2).
["C","B","A"]

Variables bind once in Erlang

Edit: I changed the title of this question, as it wasn't useful in light of the n00b mistake I had made. The remainder is unchanged, and serves as a cautionary tale!
I am using Erlang OTP version 17.4. Consider the following Erlang shell session where I am experimenting with the trap_exit process flag as explained in "Learn You Some Erlang:Errors and Processes".
First, I set the trap_exit flag to convert exit signals in linked processes to regular messages:
Eshell V6.2 (abort with ^G)
1> process_flag(trap_exit, true).
false
Then I spawn a linked process and terminate it immediately with a call to exit/2:
2> exit(spawn_link(fun() -> timer:sleep(50000) end), kill).
true
Then I read the converted exit message:
3> receive X -> X end.
{'EXIT',<0.61.0>,killed}
All looking good so far, just like the book describes. Now, just for fun, I spawn_link and terminate another process:
4> exit(spawn_link(fun() -> timer:sleep(5000) end), kill).
true
And try to read the converted exit message:
5> receive X -> X end.
At this point the shell hangs. My question is why does the behaviour change on the second go around and where did the exit message go?
Your second receive X -> X end. already has X bound; it is attempting to receive a message exactly matching the one you already saw. Since the pid is going to be different, the message will never match. So it hangs, waiting for one that does match.
You need to f(X) first.

give local pid and node name, how to convert to remote pid?

A remote pid registers its "local pid" and "its node" name has been registered into mnesia table. If another node's pid fetch the above "local pid<0.xxx.xxx>" and node name, how to convert to remote pid<xxx.xxx.xxx>.
I don't really see WHY you have to do anything special at all. Here I will create a mnesia table running on l#renat and r#renat and write and read pids from the respective nodes and show their is no need to "convert" the pid as Erlang's distribution mechanism automatically take care of it. It will be a bit long to get it all working.
First on node l#renat we connect or the other node and create our mnesia schema:
Eshell V5.9.1 (abort with ^G)
(l#renat)1> net_adm:ping(r#renat).
pong
(l#renat)3> mnesia:create_schema([node()|nodes()]).
ok
(l#renat)5> mnesia:start().
ok
On node r#renat we have just started mnesia:
Eshell V5.9.1 (abort with ^G)
(r#renat)1> mnesia:start().
ok
On node l#renat we then create a table and insert an entry containing a local (to l#renat) pid:
(l#renat)6> mnesia:create_table(local, [{attributes,[node,pid]},{ram_copies,[node()|nodes()]}]).
{atomic,ok}
(l#renat)8> mnesia:transaction(fun () -> mnesia:write({local,node(),self()}) end).
{atomic,ok}
Note that I have not defined the records but am explicitly reading/writing the record tuples. You can do that, but it is best to use records. Now on node r#renat we can read the same record:
(r#renat)10> {atomic,[Lr]} = mnesia:transaction(fun () -> mnesia:read(local, l#renat) end).
{atomic,[{local,l#renat,<5893.37.0>}]}
(r#renat)11> node(element(3, Lr)).
l#renat
(r#renat)12> mnesia:transaction(fun () -> mnesia:write({local,node(),self()}) end).
{atomic,ok}
and we see that the pid refers to a process on another node(), node l#renat. We have then added a record to the table containing a local (to r#renat) pid. If we then read that record on node l#renat we see that it contains a pid of a process on node r#renat:
(l#renat)13> {atomic,[Rp]} = mnesia:transaction(fun () -> mnesia:read(local, r#renat) end).
{atomic,[{local,r#renat,<6007.85.0>}]}
(l#renat)14> node(element(3,Rp)).
r#renat
So we see that a "conversion" is not necessary.
In fact any form of "conversion" is in fact totally meaningless. A pid refers to a specific process on a specific node so trying to convert it has no meaning. It is an atomic data type. And even if you could convert it you have no idea of what process it would actually refer to, if any.

erlang ets select strange behaviour

I have a strange behaviour in erlang with ets:select.
I achieve a correct select statement (4 and 5 below), then I make an error in my statement (6 below), and then I try again the same statement as in 4 and 5, and it does not work any longer.
What is happening ? any idea ?
Erlang R14B01 (erts-5.8.2) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]
Eshell V5.8.2 (abort with ^G)
1> Tab = ets:new(x, [private]).
16400
2> ets:insert(Tab, {c, "rhino"}).
true
3> ets:insert(Tab, {a, "lion"}).
true
4> ets:select(Tab,[{{'$1','$2'},[],['$1', '$2']}]).
["rhino","lion"]
5> ets:select(Tab,[{{'$1','$2'},[],['$1', '$2']}]).
["rhino","lion"]
6> ets:select(Tab,[{{'$1','$2'},[],['$1', '$2', '$3']}]).
** exception error: bad argument
in function ets:select/2
called as ets:select(16400,[{{'$1','$2'},[],['$1','$2','$3']}])
7> ets:select(Tab,[{{'$1','$2'},[],['$1', '$2']}]).
** exception error: bad argument
in function ets:select/2
called as ets:select(16400,[{{'$1','$2'},[],['$1','$2']}])
Has my ets table been destroyed ? Would it be a bug of ets ?
Thank you.
The shell process has created the ETS table and is the owner of it. When the owner process dies the ETS table is automatically deleted.
So when you get an exception at 6, the shell process dies so the ETS table is deleted.
Making it private also means that no other process can access it (so even if the table was persisted the new shell wouldn't be able to access it), but in this case it is even worse as the table has been deleted.
(too big to leave as a comment to thanosQR's correct answer)
if you'd like the table to survive an exception in the shell, you can give it away to another process. for example:
1> Pid = spawn(fun () -> receive foo -> ok end end). % sit and wait for 'foo' message
<0.62.0>
2> Tab = ets:new(x, [public]). % Tab must be public if you plan to give it away and still have access
24593
3> ets:give_away(Tab, Pid, []).
true
4> ets:insert(Tab, {a,1}).
true
5> ets:tab2list(Tab).
[{a,1}]
6> 3=4.
** exception error: no match of right hand side value 4
7> ets:tab2list(Tab). % Tab survives exception
[{a,1}]
8> Pid ! foo. % cause owning process to exit
foo
9> ets:tab2list(Tab). % Tab is now gone
** exception error: bad argument
in function ets:match_object/2
called as ets:match_object(24593,'_')
in call from ets:tab2list/1 (ets.erl, line 323)

dets example importing data

got a problem with dets:to_ets/2
Could somebody point me to an example online? Ive looked at the man pages but I couldnt see any example usage. Couldn't find anything on google..
My problem seems to be with the actual dets:to_ets() function itself, not the creating of the dets. I have tested that on it's own and it's fine.
You should create ETS table before use to_ets/2 function on it. The existing objects of the Ets table are kept unless overwritten. Do you have any {error, Reason} tuples in the result?
a quick example of dets:to_ets/2.
1> dets:open_file(d, [{file, "/tmp/d"}, {type, set}]).
{ok,d}
2> dets:insert(d, {a, 1}).
ok
3> dets:insert(d, {b, 2}).
ok
4> ets:new(e, [named_table, set]).
e
5> dets:to_ets(d, e).
e
6> ets:tab2list(e).
[{b,2},{a,1}]

Resources