I am trying to create a simple Erlang process with the access to ETS module.
My source code includes:
Process creation:
start_message_channel() ->
Table = ets:new(messages, [ordered_set, named_table]),
Channel = spawn(?MODULE, channel, []),
{Channel, {table, Table}}.
Process logic:
channel() ->
receive
{Sender, {send_message, {Message, Table}}} ->
ets:insert(Table, {message, Message}),
Sender ! {self(), {status, success}};
{Sender, {receive_message, Table}} ->
{message, Message} = ets:first(Table),
Sender ! {self(), {status, {success, Message}}};
_ ->
throw(incorrect_protocol_exception)
end.
Communication with process
send_message_to_message_channel({Channel, {table, Table}}, Message) ->
Channel ! {self(), {send_message, {Message, Table}}},
receive
{Channel, {status, success}} ->
io:format("Message sent!~n");
{Channel, {status, failure}} ->
io:format("Message failed to send!~n");
_ ->
throw(incorrect_protocol_exception)
end.
receive_message_from_message_channel({Channel, {table, Table}}) ->
Channel ! {self(), {receive_message, Table}},
receive
{Channel, {status, {success, Message}}} ->
io:format(Message);
{Channel, {status, failure}} ->
io:format("Message failed to receive!~n");
_ ->
throw(incorrect_protocol_exception)
end.
While executing function calls in Erlang terminal, I am getting error:
1> cd("C:/Users/dauma").
C:/Users/dauma
ok
2> c(message_channel).
{ok,message_channel}
3> Object = message_channel:start_message_channel().
{<0.59.0>,{table,messages}}
4> message_channel:send_message_to_message_channel(Object, "Hello World!").
=ERROR REPORT==== 19-May-2016::11:09:27 ===
Error in process <0.59.0> with exit value:
{badarg,[{ets,insert,[messages,"Hello World!"],[]},
{message_channel,channel,0,
[{file,"message_channel.erl"},{line,35}]}]}
Could anyone tell me, where might be the problem?
ETS tables are owned by an Erlang process, and have access controls. By default the table is protected and can only be written to by the process that owns it, though it can be read from other processes.
If you want to read and write from a different process, use public.
Table = ets:new(messages, [ordered_set, named_table, public])
You can also use private, which means that only the owning process can read and write.
Per the documentation:
publicAny process may read or write to the table.protectedThe owner process can read and write to the table. Other processes can only read the table. This is the default setting for the access rights.privateOnly the owner process can read or write to the table.
In your example, you create the table in one process (the one calling start_message_channel), and then you attempt to call ets:insert from a different process: spawn(?MODULE, channel, []) creates a new process, with channel as its entry point.
Because your table is not marked as public, the call to ets:insert from the other process fails with badarg.
Per the documentation, again:
In general, the functions below will exit with reason
badargif any argument is of the wrong format, if the table identifier is invalid or if the operation is denied due to table access rights (protectedorprivate).
Side note: if you use named_table, the value returned from ets:new is the table name, so you can do this:
-define(TABLE, messages).
% later...
?TABLE = ets:new(?TABLE, [named_table, ordered_set, protected])
...and you don't need to store the returned value in state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With