2010-12-03 8 views
1

EDITErlang Dictionnaire chercher accident


J'ai deux modules et causent deux mauvaises erreurs args lors de la récupération du dictionnaire (état gen_server)

Voici le code d'un module

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

Puis set_peer_state qui met en place un dictionnaire de pairs (1 unique pour chaque pair) Le dictionnaire contient le téléchargement et le téléchargement (file d'attente et vitesse) et je l'ajoute à l'état gen_server principal (diction ary) J'ai donc les données principales de torrent dans le dictionnaire principal avec un dictionnaire pour chaque pair stocké par l'id de pair.

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

Cela semble fonctionner jusqu'à présent. Mais quand j'essaye de mettre à jour l'état du torrent, il se bloque lors de l'extraction du dictionnaire.

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;    

et voici les 2 fonctions internes

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

pourrait-il que le passage des données incorrectes aux setters plantage du serveur? Ou l'état se perd-il en cours de route? Cette façon de faire semble désordonnée avec tous les nouveaux dicts à stocker dans l'ancien dict, y a-t-il une meilleure façon de gérer cette structure de données (torrent principal et données pour chaque pair)? Je savais que je pouvais faire les dictionnaires à partir de listes, mais ça me dérangeait au moment où je testais ce module.

Merci

Répondre

4

Votre problème est que l'état n'est pas un dict.

1> dict:fetch(runningCounter, not_a_dict). 
** exception error: {badrecord,dict} 
    in function dict:get_slot/2 
    in call from dict:fetch/2 
+0

Merci. Donc j'utilise State tout au long de mon module. Je pensais que cela a été géré par gen servir de l'état? L'état doit-il être défini dans le serveur gen en tant que dictionnaire? – jarryd

+0

La méthode gen_server: cast ne transmet qu'un message, mais le handle_cast prend le message et l'état. Comment sait-il ce qu'est l'état? Où dois-je définir cet état? Je le fais dans la méthode init qui le configure, mais il ne semble pas qu'il soit disponible dans la méthode handle_cast? Merci – jarryd

+0

Le problème est que vous faites la mauvaise chose quelque part dans votre programme, mais l'erreur n'est pas dans le code que vous avez partagé. L'état est juste une variable, mais ce n'est pas un dictionnaire où vous essayez de l'utiliser, ce qui signifie que vous l'avez incorrectement défini dans un autre endroit. –

1

Comme VOTRE ARGUMENT EST VALIDE suggéré, vous êtes état, à ce point de votre code, n'est pas un dict.

Répondez à vos commentaires, maintenant.

L'état de votre gen_server est mis en place dans la fonction init, où vous revenez: {ok, State}.

Chaque fois que votre gen_server recevez un message, un handle_call ou un handle_cast sont appelés (selon si l'appel est synchrone ou asynchrone). À l'intérieur de ces fonctions, l'état que vous avez défini pendant la phase init peut être mis à jour et transformé en N'IMPORTE QUOI. Vous ne pouvez pas compter sur l'hypothèse que le "type" de votre état initial est le même pendant toute l'exécution de votre serveur.

En d'autres termes, si vous faites quelque chose comme:

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

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

que vous venez de « converti » votre état d'un dict dans un atome et que (l'atome) est ce que vous obtiendrez dans les appels suivants .

Pour ce type d'erreur, l'outil de traçage Erlang dbg est très utile, vous permettant de voir comment les fonctions sont appelées et quels résultats sont renvoyés.Jetez un coup d'oeil à ce court tutoriel pour apprendre à l'utiliser:

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

MISE À JOUR:

Ce que vous devez faire:

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

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

Lorsque la fonction edit_dict est une fonction qui prend un dict et renvoie un dict mis à jour.

+0

Génial. Alors devrais-je créer un nouvel dict = State au début d'une fonction handle_call, handle_cast? Les paires de valeurs clés seront-elles toujours les mêmes ou quel sera le point de l'état si son type change? – jarryd

+0

S'il vous plaît voir la mise à jour –

+0

Merci. Quoi ou comment le dict d'édition fonctionne-t-il? Je ne comprends pas. Est-ce ainsi que gen_servers travaille avec leur état? Kinda est nul. Qu'en est-il de créer un nouveau dict et de fusionner avec lui? Ou l'état n'est-il pas vu comme un dictionnaire? merci – jarryd