修改
我有两个模块,从字典中获取时都会导致错误的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状态(字典)所以我有主要的torrent数据在主词典中,包含由对等ID存储的每个对等词的字典。
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};
到目前为止这似乎有效。但是当我尝试更新torrent状态时,它会从字典中获取时崩溃。
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;
以下是2个内部函数
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}.
将不正确的数据传递给setter是否会导致服务器崩溃? 或者国家在途中迷路了吗? 这样做的方式看起来很乱,所有新的dicts存储在旧的dict中,是否有更好的方法来处理这个数据结构(每个对等体的主要torrent和数据)?
我知道我可以从列表中创建字典,但是在我测试这个模块时,我的想法一直在弄乱。
由于
答案 0 :(得分:4)
你的问题是国家不是一个字面。
1> dict:fetch(runningCounter, not_a_dict).
** exception error: {badrecord,dict}
in function dict:get_slot/2
in call from dict:fetch/2
答案 1 :(得分:1)
由于你提出的论点是有效的,你在代码的那一点上陈述的并不是一个字典。
现在回答你的意见。
您的gen_server
的状态是在init函数中设置的,您返回的位置为:{ok, State}.
每次gen_server
收到消息时,都会调用handle_call
或handle_cast
(具体取决于呼叫是同步还是异步)。在这些函数中,您可以更新在初始阶段设置的状态并将其转换为ANYTHING。您不能依赖于在整个服务器执行期间初始状态的“类型”相同的假设。
换句话说,如果您执行以下操作:
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/
更新:
你应该做什么:
init(_Args) -> {ok, dict:new()}.
handle_call(_Request, _From, State) ->
NewState = edit_dict(State),
{ok, NewState}.
edit_dict函数是一个接受dict并返回更新的dict的函数。