Erlang ETS ошибка вставки/2

Я пытаюсь создать простой процесс Erlang с доступом к модулю ETS.

Мой исходный код включает в себя:

  1. Создание процесса:

    start_message_channel() ->
        Table = ets:new(messages, [ordered_set, named_table]),
        Channel = spawn(?MODULE, channel, []),
        {Channel, {table, Table}}.
    
  2. Логика процесса:

    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.
    
  3. Связь с процессом

    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.
    

При выполнении вызовов функций в терминале Erlang я получаю сообщение об ошибке:

    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}]}]}

Может ли кто-нибудь сказать мне, где может быть проблема?


person Daumantas Versockas    schedule 19.05.2016    source источник


Ответы (1)


Таблицы ETS принадлежат процессу Erlang и имеют контроль доступа. По умолчанию таблица имеет номер protected и может быть записана только процессом, которому она принадлежит, хотя она может быть прочитана из других процессов.

Если вы хотите читать и писать из другого процесса, используйте public.

Table = ets:new(messages, [ordered_set, named_table, public])

Вы также можете использовать private, что означает, что только процесс-владелец может читать и писать.

Согласно документации:

  • public Любой процесс может читать или писать в таблицу.
  • protected Процесс-владелец может читать и писать в таблицу. Другие процессы могут только читать таблицу. Это настройка прав доступа по умолчанию.
  • private Только процесс-владелец может читать или писать в таблицу.

В вашем примере вы создаете таблицу в одном процессе (тот, который вызывает start_message_channel), а затем пытаетесь вызвать ets:insert из другого процесса: spawn(?MODULE, channel, []) создает новый процесс с channel в качестве точки входа.

Поскольку ваша таблица не помечена как public, вызов ets:insert из другого процесса завершится ошибкой с badarg.

Согласно документации, опять же:

Как правило, приведенные ниже функции завершатся с причиной badarg, если какой-либо аргумент имеет неправильный формат, если идентификатор таблицы недействителен или если операция запрещена из-за прав доступа к таблице (protected или private).


Примечание: если вы используете named_table, значение, возвращаемое из ets:new, является именем таблицы, поэтому вы можете сделать это:

-define(TABLE, messages).

% later...
?TABLE = ets:new(?TABLE, [named_table, ordered_set, protected])

... и вам не нужно хранить возвращаемое значение в состоянии.

person Roger Lipscombe    schedule 19.05.2016
comment
Спасибо за ваш ответ! После небольших изменений, которые вы предложили, все работает как шарм! Для лучшего понимания, не могли бы вы сказать, что в моем примере тот же процесс, который создал таблицу, не обновляет ее? - person Daumantas Versockas; 19.05.2016
comment
Вы создаете таблицу в #1, а затем запускаете процесс для запуска канала/0. Это процесс, выполняющий вставку, поэтому конфиденциальность не работает. - person Derek Brown; 19.05.2016
comment
Да, но по умолчанию protected. - person rvirding; 19.05.2016
comment
@rvirding, правда (я никогда не могу вспомнить, поэтому стараюсь быть откровенным); обновил мой ответ. - person Roger Lipscombe; 19.05.2016