Erlang Словарь выборки аварии - PullRequest
1 голос
/ 03 декабря 2010

РЕДАКТИРОВАТЬ


У меня два модуля, и оба вызывают ошибки args при извлечении из словаря (состояние gen_server)

Вот код из одного модуля

init([ChunkSize, RunningCounter]) ->    
D0 = dict:new(),
D1 = dict:store(chunkSize, ChunkSize, D0),
D2 = dict:store(torrentUploadSpeed, 0, D1),
D3 = dict:store(torrentDownloadSpeed, 0, D2),
TorrentDownloadQueue = queue:new(),
TorrentUploadQueue = queue:new(),
D4 = dict:store(torrentDownloadQueue, TorrentDownloadQueue, D3),
D5 = dict:store(torrentUploadQueue, TorrentUploadQueue, D4),
D6 = dict:store(runningCounter, RunningCounter, D5),
{ok, D6}.

Затем я устанавливаю set_peer_state, который устанавливает одноранговый словарь (по 1 уникальному для каждого однорангового узла). Словарь содержит загрузку и выгрузку (очередь и скорость), и я добавляю это в основное состояние gen_server (словарь). Итак, у меня есть основные данные торрентав главном словаре со словарем для каждого пира, сохраненным идентификатором пира.

set_peer_state(Id) ->
    gen_server:cast(?SERVER, {setPeerState, Id}).

handle_cast({setPeerState, Id}, State) ->
io:format("In the Set Peer State ~p~n", [dict:fetch(runningCounter, State)]),
Id0 = dict:new(), 
PeerDownloadQueue = queue:new(),
PeerUploadQueue = queue:new(),
Id1 = dict:store(peerDownloadQueue, PeerDownloadQueue, Id0),
Id2 = dict:store(peerUploadQueue, PeerUploadQueue, Id1),
Id3 = dict:store(peerDownloadSpeed, 0, Id2),
Id4 = dict:store(peerUploadSpeed, 0, Id3),
D = dict:store(Id, Id4, State),
    {noreply, D};       

Это, кажется, работает до сих пор.Но когда я пытаюсь обновить состояние торрента, происходит сбой при извлечении из словаря.

handle_cast({updateTorrentDownloadState, Time}, State) ->
% fetch the counter for the speed calculation and queue length
RunningCounter  = dict:fetch(runningCounter, State),
% Fetch the Torrents download queue
TorrentDownloadQueue = dict:fetch(torrentDownloadQueue, State),
io:format("The fetched queue is  ~p~n", [dict:fetch(torrentDownloadQueue, State)]),
% Add the item to the queue (main torrent upload queue)
TorrentDownloadQueue2 = queue:in(Time, TorrentDownloadQueue),
% Get the lenght of the downloadQueue
TorrentDownloadQueueLength = queue:len(TorrentDownloadQueue2),
% If the queue is larger than the running counter remove item 
if
    TorrentDownloadQueueLength >= RunningCounter ->
        % Remove item from the queue
        TorrentDownloadQueue3 = queue:drop(TorrentDownloadQueue2),
        update_torrent_download(TorrentDownloadQueue3, State);

    TorrentDownloadQueueLength < RunningCounter ->
        update_torrent_download(TorrentDownloadQueue2, State)
    end;            

и вот две внутренние функции

update_torrent_download(TorrentDownloadQueue, State) ->
    % Store the queue to the new torrent dict
    State2  = dict:store(torrentDownLoadQueue, TorrentDownloadQueue, State),
    Speed = calculate_speed(TorrentDownloadQueue, State2),
    State3 = dict:store(torrentDownloadSpeed, Speed, State2),
        {noreply, State3}.

calculate_speed(Queue, State) ->
List = queue:to_list(Queue),
Sum = lists:sum(List),
Count = queue:len(Queue),
ChunkSize = dict:fetch(chunkSize, State),
Speed = (Count * ChunkSize) div Sum,
    {ok, Speed}.

Может быть, передача неправильных данных установщикам приведет к сбою сервера?Или государство теряется по пути?Этот способ выглядит запутанным со всеми новыми диктами для хранения в старом, есть ли лучший способ обработать эту структуру данных (основной торрент и данные для каждого узла)?

Я знаю, что мог бы сделатьсловари из списков, но в тот момент, когда я тестировал этот модуль, это мешало мне.

Спасибо

Ответы [ 2 ]

4 голосов
/ 03 декабря 2010

Ваша проблема в том, что государство не является диктатом.

1> dict:fetch(runningCounter, not_a_dict).
** exception error: {badrecord,dict}
     in function  dict:get_slot/2
     in call from dict:fetch/2
1 голос
/ 03 декабря 2010

Поскольку ваш аргумент недействителен, вы утверждаете, что в этот момент ваш код не является диктатом.

Отвечаю на ваши комментарии, сейчас.

Состояние вашего gen_server устанавливается в функции инициализации, где вы возвращаете: {ok, State}.

Каждый раз, когда ваш gen_server получает сообщение, вызывается handle_call или handle_cast (в зависимости от того, является ли вызов синхронным или асинхронным). Внутри этих функций состояние, которое вы установили на этапе инициализации, может быть обновлено и преобразовано в НИЧЕГО. Вы не можете полагаться на предположение, что «тип» вашего исходного состояния одинаков во время всего выполнения вашего сервера.

Другими словами, если вы делаете что-то вроде:

init(_Args) -> {ok, dict:new()}.

handle_call(_Request, _From, State) ->
  {ok, completely_new_state}.

вы только что «преобразовали» свое состояние из дикта в атом, и это (атом) - это то, что вы получите при последующих вызовах.

Для такого рода ошибок очень полезен инструмент трассировки Erlang dbg, позволяющий увидеть, как вызываются функции и какие результаты возвращаются. Посмотрите этот короткий урок, чтобы узнать, как его использовать:

http://aloiroberto.wordpress.com/2009/02/23/tracing-erlang-functions/

UPDATE:

Что вы должны сделать:

init(_Args) -> {ok, dict:new()}.

handle_call(_Request, _From, State) ->
  NewState = edit_dict(State),
  {ok, NewState}.

Где функция edit_dict - это функция, которая принимает dict и возвращает обновленный dict.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...