Created
July 7, 2020 06:25
-
-
Save Xdeon/5676bb037b816b64bf19a7a6992a2bdc to your computer and use it in GitHub Desktop.
frequency server revised
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(frequency). | |
-export([start/0, allocate/0, deallocate/1, stop/0, clear/0, clear_with_print/0, init/0]). | |
start() -> | |
Pid = spawn(?MODULE, init, []), | |
register(?MODULE, Pid), | |
Pid. | |
%% Add clear at beginning of each API call to eliminate unexpected messages in mailbox | |
%% better use combination of erlang:make_ref() and "let it fail" | |
allocate() -> | |
%clear(), | |
?MODULE ! {request, self(), allocate}, | |
client_receive(). | |
deallocate(Freq) -> | |
%clear(), | |
?MODULE ! {request, self(), {deallocate, Freq}}, | |
client_receive(). | |
stop() -> | |
% clear(), | |
?MODULE ! {request, self(), stop}, | |
client_receive(). | |
client_receive() -> | |
receive | |
{reply, Reply} -> Reply | |
after 500 -> | |
{error, timeout} | |
end. | |
%% only clear messages that following protocol defined here instead of any messages | |
clear() -> | |
receive | |
{reply, _} -> clear() | |
after 0 -> ok | |
end. | |
clear_with_print() -> | |
receive | |
{reply, _} = Msg -> | |
io:format("~p~n", [Msg]), | |
clear_with_print() | |
after 0 -> ok | |
end. | |
init() -> | |
Frequencies = {get_frequencies(), []}, | |
loop(Frequencies). | |
get_frequencies() -> | |
[10, 11, 12, 13, 14, 15]. | |
%% uncomment timer:sleep/1 to simulate overloaded server | |
loop(Frequencies) -> | |
receive | |
{request, Pid, allocate} -> | |
% timer:sleep(1000), | |
{NewFrequencies, Reply} = allocate(Frequencies, Pid), | |
Pid ! {reply, Reply}, | |
loop(NewFrequencies); | |
{request, Pid, {deallocate, Freq}} -> | |
% timer:sleep(1000), | |
NewFrequencies = deallocate(Frequencies, Freq), | |
Pid ! {reply, ok}, | |
loop(NewFrequencies); | |
{request, Pid, stop} -> | |
% timer:sleep(1000), | |
Pid ! {reply, stopped} | |
end. | |
allocate({Freqs, Allocated}, Pid) -> | |
case lists:keymember(Pid, 2, Allocated) of | |
true -> {{Freqs, Allocated}, {error, already_allocated}}; | |
false -> do_allocate({Freqs, Allocated}, Pid) | |
end. | |
do_allocate({[], Allocated}, _Pid) -> | |
{{[], Allocated}, {error, no_frequency}}; | |
do_allocate({[Freq|Free], Allocated}, Pid) -> | |
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}. | |
deallocate({Free, Allocated}, Freq) -> | |
case lists:keymember(Freq, 1, Allocated) of | |
true -> | |
{[Freq|Free], lists:keydelete(Freq, 1, Allocated)}; | |
false -> | |
{Free, Allocated} | |
end. | |
% tests | |
-include_lib("eunit/include/eunit.hrl"). | |
frequency_test() -> | |
Freq = start(), | |
% test naming | |
?assertEqual(Freq, whereis(?MODULE)), | |
% test allocate | |
?assertEqual({ok, 10}, allocate()), | |
% test duplicate allocate | |
?assertEqual({error, already_allocated}, allocate()), | |
% test inproper deallocate | |
?assertEqual(ok, deallocate(11)), | |
?assertEqual({error, already_allocated}, allocate()), | |
% test proper deallocate | |
?assertEqual(ok, deallocate(10)), | |
?assertEqual({ok, 10}, allocate()), | |
% test stop | |
?assertEqual(stopped, stop()), | |
ok. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment