2010-12-03 9 views
1

EDITアーラン辞書フェッチクラッシュ


Iは、2つのモジュールを有し、辞書から(gen_server状態)ここ

をフェッチするときの両方が悪い引数エラーが発生する1つのモジュールからのコードである

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状態(ディクショナリary)だから私はピア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};  

これはこれまでのように動作しているようです。しかしトレントの状態を更新しようとすると、辞書からフェッチするとクラッシュする。

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

は、それがセッターに不正確なデータを渡すと、サーバーがクラッシュすることをだろうか? 途中で状態が失われますか? これを行うこの方法は、古い辞書に保存するすべての新しい辞書では面倒ですが、このデータ構造(各ピアの主なトレントとデータ)を処理するより良い方法はありますか?

私はリストから辞書を作ることができると知っていますが、私はこのモジュールをテストしていた時点で私の心を乱していました。

ありがとうございます。

答えて

4

あなたの問題は、状態が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

ありがとうございました。だから、私は自分のモジュールを通してStateを使います。私はこれが州としてのジェネとして役立ったと思ったのですか?状態を辞書サーバとしてジェネラルサーバに定義する必要がありますか? – jarryd

+0

gen_server:castメソッドはメッセージのみを渡しますが、handle_castはメッセージと状態を取ります。どのような状態が分かっていますか?私はこの状態をどこに設定するのですか?私はそれを設定するinitメソッドで行いますが、handle_castメソッドで利用できるように見えませんか?ありがとう – jarryd

+0

問題はあなたがあなたのプログラムのどこかで間違ったことをやっているということですが、あなたが共有するコードにエラーがありません。状態は単なる変数ですが、それを使用しようとしている辞書ではありません。つまり、別の場所で間違って設定してしまうということです。 –

1

YOUR引数がVALID提案されているように、あなたは状態なら、あなたのコードのその時点では、辞書ではありません。

あなたのコメントにお答えします。

の状態あなたのgen_serverあなたが返すinit関数、で設定されています。呼び出しは同期または非同期である場合{ok, State}.あなたgen_serverがメッセージを受信するたびに、handle_callhandle_castが呼ばれ

が(依存)。これらの関数の中で、initフェーズ中に設定した状態を更新して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/

がUPDATE:あなたが何をすべき

edit_dict機能がとる関数である
init(_Args) -> {ok, dict:new()}. 

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

dictを返し、更新されたdictを返します。

+0

素晴らしいですから、handle_call、handle_cast関数の始めに新しいdict = Stateを作るべきですか?キーの値のペアが同じか、型の変更があった場合の状態のポイントは何ですか? – jarryd

+0

更新を参照してください –

+0

ありがとうございます。編集ディクテーションはどのように動作しますか?理解できません。これはgen_serversがその状態をどのように扱うかです。キンダーは吸う。新しいDICTを作成し、それに状態をマージするのはどうですか?あるいは、状態は辞書として見えないのですか?ありがとう – jarryd