fs.erl:
%% Based on code from
%% Erlang Programming
%% Francecso Cesarini and Simon Thompson
%% O'Reilly, 2008
%% http://oreilly.com/catalog/9780596518189/
%% http://www.erlangprogramming.org/
%% (c) Francesco Cesarini and Simon Thompson
-module(fs).
-export([start/0,allocate/0,deallocate/1,stop/0]).
-export([server_init/1, router_init/1, router/2]).
-export([test/0, start_router/1]).
-export([client/2, test_init/0, test2/0]).
%%======== TEST ============
test_init() ->
spawn(fs, test2, []),
testing.
test2() ->
Frequencies = [
[10,11,12,13,14,15], %%The number of sublists in Frequencies
[20,21,22,23,24,25], %%determines the number of servers that will
[30,31,32], %%be started.
[40,41]
],
start_router(Frequencies),
timer:sleep(1000), %Make sure the servers start before
%sending them requests.
Clients =
lists:map(fun(ClientArgs) ->
spawn(fs, client, ClientArgs)
end,
[[1,1000],[2,2000],[3,3000],[4,4000]] ), %%[Id,Sleep]
io:format("Clients: ~w~n", [Clients]),
timer:sleep(10000),
stop().
test() ->
io:format("Client is (~w)~n", [self()]),
Frequencies = [
[10,11,12,13,14,15],
[20,21,22,23,24,25]
],
start_router(Frequencies), %%The number of sublists in Frequencies
%%determines the number of servers that will
%%be started.
loop(14).
loop(0) ->
done_looping;
loop(N) ->
timer:sleep(1000),
io:format("Client (~w) got msg: ~w~n", [self(), allocate()]),
loop(N-1).
%%========== ROUTER ============
start_router(Frequencies) ->
register(router, spawn(fs, router_init, [Frequencies])).
router_init(Frequencies) -> %Frequencies = [ [1,2,3], [10,11] ].
Servers = %% A server is a tuple: {ServerPid, Freqs}
lists:map(fun(Freqs) ->
{
spawn(fs, server_init, [{Freqs, []}] ),
Freqs
} %% => {ServerPid,Freqs}
end,
Frequencies), %% e.g. [ [10,11,12], [20,21,22,23] ]
io:format("Servers: ~lp~n", [Servers]),
router(Servers, []). %% [FreshServers, StaleServers] => All the servers start off as 'Fresh'.
router([], StaleServers) ->
FreshServers = lists:reverse(StaleServers),
router(FreshServers, []);
router( [{FreshServer,_Freqs}=FreshServer_ | FreshServers ]=FreshServers_, StaleServers ) ->
receive
{request, Client, allocate}=Request ->
FreshServer ! Request,
io:format("router: sent allocate request to server (~w) from client (~w)~n",
[FreshServer, Client]),
router(FreshServers, [FreshServer_|StaleServers] );
{request, Client, {deallocate,Freq}}=Request ->
case find_server(Freq, FreshServers_, StaleServers) of
false ->
io:format("router: no servers allocated frequency ~w~n", [Freq]),
Client ! {reply, ok};
TargetServer ->
TargetServer ! Request,
io:format("router: sent {deallocate,~w} request to server (~w) from client (~w)~n",
[Freq,TargetServer,Client])
end,
router(FreshServers_, StaleServers);
{request, Client, stop} ->
stop_servers(FreshServers_, StaleServers),
Client ! stopped
end.
%%First search the FreshServers:
find_server(Freq, [], StaleServers) ->
find_server(Freq, StaleServers); %Then search the StaleServers.
find_server(Freq, [ {FreshServer,Freqs}|FreshServers ], StaleServers) ->
case lists:member(Freq, Freqs) of
false -> find_server(Freq, FreshServers, StaleServers);
true -> FreshServer
end.
%%Search StaleServers:
find_server(_Freq, []) ->
false; %%Couldn't find a server that allocates Freq.
find_server(Freq, [ {StaleServer,Freqs}|StaleServers ] ) ->
case lists:member(Freq, Freqs) of
false -> find_server(Freq, StaleServers);
true -> StaleServer
end.
stop_servers(FreshServers, StaleServers) ->
stop_servers(FreshServers),
stop_servers(StaleServers).
stop_servers([]) ->
servers_stopped;
stop_servers([ {ServerPid,_Freqs}=Server | Servers ]) ->
ServerPid ! {request, self(), stop},
receive
{reply, _Reply} -> ok
end,
io:format("router: sent stop message to server ~w~n", [Server]),
stop_servers(Servers).
%%========= CLIENT ==========
client(Id, Sleep) ->
handle_allocate_response(allocate(), Id, Sleep).
handle_allocate_response({ok, Freq}, Id, Sleep) ->
io:format("client~w(~w): got frequency ~w~n",
[Id, self(), Freq]),
timer:sleep(Sleep),
deallocate(Freq),
io:format("client~w(~w): called deallocate(~w)~n",
[Id, self(), Freq]),
client(Id, Sleep);
handle_allocate_response({error, no_frequency}, Id, Sleep) ->
io:format("client~w(~w): no frequencies available~n",
[Id, self()]),
timer:sleep(500), %Wait small amount of time, then retry.
client(Id, Sleep).
%%======== SERVER ================
start() ->
register(fs,
spawn(fs, server_init, [])).
server_init(Freqs) ->
%%Frequencies = {get_frequencies(), []},
server_loop(Freqs).
%% Hard Coded
%get_frequencies() -> [10,11,12,13,14,15].
%% The Main Loop
server_loop(Freqs) ->
receive
{request, Pid, allocate} ->
{NewFreqs, Reply} = allocate(Freqs, Pid),
Pid ! {reply, Reply},
io:format("server(~w): Sent allocate reply to client(~w)~n",[self(),Pid]),
server_loop(NewFreqs);
{request, Pid , {deallocate, Freq}} ->
NewFreqs = deallocate(Freqs, Freq),
Pid ! {reply, ok},
server_loop(NewFreqs);
{request, Pid, stop} ->
Pid ! {reply, stopped};
Other ->
io:format("server(~w): got Other message ~w~n", [self(), Other])
end.
%% Functional interface
allocate() ->
router ! {request, self(), allocate},
receive
{reply, Reply} -> Reply
end.
deallocate(Freq) ->
router ! {request, self(), {deallocate, Freq}},
receive
{reply, Reply} -> Reply
end.
stop() ->
router ! {request, self(), stop},
receive
{reply, Reply} -> Reply
end.
%% The Internal Help Functions used to allocate and
%% deallocate frequencies.
allocate({[], Allocated}, _Pid) ->
{{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}.
deallocate({Free, Allocated}, Freq) ->
NewAllocated=lists:keydelete(Freq, 1, Allocated),
{[Freq|Free], NewAllocated}.
In the shell:
~/erlang_programs/fl_course2/3week/a6/fs$ ./run.sh
-----Now, do some Erlang for great Good!------
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
-----Now, do some Erlang for great Good!------
Servers: [{<0.33.0>,[10,11,12,13,14,15]},
{<0.34.0>,[20,21,22,23,24,25]},
{<0.35.0>,[30,31,32]},
{<0.36.0>,[40,41]}]
Eshell V6.4 (abort with ^G)
1> Clients: [<0.39.0>,<0.40.0>,<0.41.0>,<0.42.0>]
router: sent allocate request to server (<0.33.0>) from client (<0.39.0>)
server(<0.33.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 10
router: sent allocate request to server (<0.34.0>) from client (<0.40.0>)
server(<0.34.0>): Sent allocate reply to client(<0.40.0>)
router: sent allocate request to server (<0.35.0>) from client (<0.41.0>)
client2(<0.40.0>): got frequency 20
server(<0.35.0>): Sent allocate reply to client(<0.41.0>)
router: sent allocate request to server (<0.36.0>) from client (<0.42.0>)
client3(<0.41.0>): got frequency 30
server(<0.36.0>): Sent allocate reply to client(<0.42.0>)
client4(<0.42.0>): got frequency 40
router: sent {deallocate,10} request to server (<0.33.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(10)
router: sent allocate request to server (<0.33.0>) from client (<0.39.0>)
server(<0.33.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 10
router: sent {deallocate,20} request to server (<0.34.0>) from client (<0.40.0>)
client2(<0.40.0>): called deallocate(20)
router: sent allocate request to server (<0.34.0>) from client (<0.40.0>)
server(<0.34.0>): Sent allocate reply to client(<0.40.0>)
client2(<0.40.0>): got frequency 20
router: sent {deallocate,10} request to server (<0.33.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(10)
router: sent allocate request to server (<0.35.0>) from client (<0.39.0>)
server(<0.35.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 31
router: sent {deallocate,30} request to server (<0.35.0>) from client (<0.41.0>)
client3(<0.41.0>): called deallocate(30)
router: sent allocate request to server (<0.36.0>) from client (<0.41.0>)
server(<0.36.0>): Sent allocate reply to client(<0.41.0>)
client3(<0.41.0>): got frequency 41
router: sent {deallocate,31} request to server (<0.35.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(31)
router: sent allocate request to server (<0.33.0>) from client (<0.39.0>)
server(<0.33.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 10
router: sent {deallocate,40} request to server (<0.36.0>) from client (<0.42.0>)
client4(<0.42.0>): called deallocate(40)
router: sent {deallocate,20} request to server (<0.34.0>) from client (<0.40.0>)
router: sent allocate request to server (<0.34.0>) from client (<0.42.0>)
client2(<0.40.0>): called deallocate(20)
server(<0.34.0>): Sent allocate reply to client(<0.42.0>)
client4(<0.42.0>): got frequency 20
router: sent allocate request to server (<0.35.0>) from client (<0.40.0>)
server(<0.35.0>): Sent allocate reply to client(<0.40.0>)
client2(<0.40.0>): got frequency 31
router: sent {deallocate,10} request to server (<0.33.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(10)
router: sent allocate request to server (<0.36.0>) from client (<0.39.0>)
server(<0.36.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 40
router: sent {deallocate,40} request to server (<0.36.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(40)
router: sent allocate request to server (<0.33.0>) from client (<0.39.0>)
server(<0.33.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 10
router: sent {deallocate,41} request to server (<0.36.0>) from client (<0.41.0>)
client3(<0.41.0>): called deallocate(41)
router: sent allocate request to server (<0.34.0>) from client (<0.41.0>)
server(<0.34.0>): Sent allocate reply to client(<0.41.0>)
client3(<0.41.0>): got frequency 21
router: sent {deallocate,31} request to server (<0.35.0>) from client (<0.40.0>)
client2(<0.40.0>): called deallocate(31)
router: sent allocate request to server (<0.35.0>) from client (<0.40.0>)
server(<0.35.0>): Sent allocate reply to client(<0.40.0>)
client2(<0.40.0>): got frequency 31
router: sent {deallocate,10} request to server (<0.33.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(10)
router: sent allocate request to server (<0.36.0>) from client (<0.39.0>)
server(<0.36.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 41
router: sent {deallocate,41} request to server (<0.36.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(41)
router: sent allocate request to server (<0.33.0>) from client (<0.39.0>)
server(<0.33.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 10
router: sent {deallocate,20} request to server (<0.34.0>) from client (<0.42.0>)
client4(<0.42.0>): called deallocate(20)
router: sent allocate request to server (<0.34.0>) from client (<0.42.0>)
server(<0.34.0>): Sent allocate reply to client(<0.42.0>)
client4(<0.42.0>): got frequency 20
router: sent {deallocate,31} request to server (<0.35.0>) from client (<0.40.0>)
client2(<0.40.0>): called deallocate(31)
router: sent allocate request to server (<0.35.0>) from client (<0.40.0>)
server(<0.35.0>): Sent allocate reply to client(<0.40.0>)
client2(<0.40.0>): got frequency 31
router: sent {deallocate,10} request to server (<0.33.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(10)
router: sent allocate request to server (<0.36.0>) from client (<0.39.0>)
server(<0.36.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 41
router: sent {deallocate,21} request to server (<0.34.0>) from client (<0.41.0>)
client3(<0.41.0>): called deallocate(21)
router: sent allocate request to server (<0.33.0>) from client (<0.41.0>)
server(<0.33.0>): Sent allocate reply to client(<0.41.0>)
client3(<0.41.0>): got frequency 10
router: sent {deallocate,41} request to server (<0.36.0>) from client (<0.39.0>)
client1(<0.39.0>): called deallocate(41)
router: sent allocate request to server (<0.34.0>) from client (<0.39.0>)
server(<0.34.0>): Sent allocate reply to client(<0.39.0>)
client1(<0.39.0>): got frequency 21
router: sent stop message to server {<0.35.0>,[30,31,32]}
router: sent stop message to server {<0.36.0>,[40,41]}
router: sent stop message to server {<0.34.0>,[20,21,22,23,24,25]}
router: sent stop message to server {<0.33.0>,[10,11,12,13,14,15]}
=ERROR REPORT==== 2-May-2017::12:31:56 ===
Error in process <0.40.0> with exit value: {badarg,[{fs,deallocate,1,[{file,"fs.erl"},{line,203}]},{fs,handle_allocate_response,3,[{file,"fs.erl"},{line,149}]}]}
=ERROR REPORT==== 2-May-2017::12:31:56 ===
Error in process <0.39.0> with exit value: {badarg,[{fs,deallocate,1,[{file,"fs.erl"},{line,203}]},{fs,handle_allocate_response,3,[{file,"fs.erl"},{line,149}]}]}
=ERROR REPORT==== 2-May-2017::12:31:58 ===
Error in process <0.41.0> with exit value: {badarg,[{fs,deallocate,1,[{file,"fs.erl"},{line,203}]},{fs,handle_allocate_response,3,[{file,"fs.erl"},{line,149}]}]}
=ERROR REPORT==== 2-May-2017::12:31:58 ===
Error in process <0.42.0> with exit value: {badarg,[{fs,deallocate,1,[{file,"fs.erl"},{line,203}]},{fs,handle_allocate_response,3,[{file,"fs.erl"},{line,149}]}]}
i().
Pid Initial Call Heap Reds Msgs
Registered Current Function Stack
<0.0.0> otp_ring0:start/2 1598 3478 0
init init:boot_loop/2 4
<0.2.0> erlang:apply/2 6772 2816 1
fs:stop/0 7
<0.3.0> erlang:apply/2 2586 141417 0
erl_prim_loader erl_prim_loader:loop/3 6
<0.6.0> gen_event:init_it/6 2586 2655 0
error_logger gen_event:fetch_msg/5 8
<0.7.0> erlang:apply/2 1598 470 0
application_controlle gen_server:loop/6 7
<0.9.0> application_master:init/4 376 44 0
application_master:main_loop/2 6
<0.10.0> application_master:start_it/4 233 69 0
application_master:loop_it/4 5
<0.11.0> supervisor:kernel/1 2586 45786 0
kernel_sup gen_server:loop/6 9
<0.12.0> rpc:init/1 233 35 0
rex gen_server:loop/6 9
<0.13.0> global:init/1 233 52 0
global_name_server gen_server:loop/6 9
<0.14.0> erlang:apply/2 233 19 0
global:loop_the_locker/1 5
<0.15.0> erlang:apply/2 233 3 0
global:loop_the_registrar/0 2
<0.16.0> inet_db:init/1 233 251 0
inet_db gen_server:loop/6 9
<0.17.0> global_group:init/1 233 59 0
global_group gen_server:loop/6 9
<0.18.0> file_server:init/1 233 92 0
file_server_2 gen_server:loop/6 9
<0.19.0> erlang:apply/2 6772 93391 0
code_server code_server:loop/1 3
<0.20.0> supervisor_bridge:standard_error/ 233 41 0
standard_error_sup gen_server:loop/6 9
<0.21.0> erlang:apply/2 233 9 0
standard_error standard_error:server_loop/1 2
<0.22.0> supervisor_bridge:user_sup/1 233 60 0
gen_server:loop/6 9
<0.23.0> user_drv:server/2 987 4501 0
user_drv user_drv:server_loop/5 8
<0.24.0> group:server/3 2586 23953 0
user group:server_loop/3 4
<0.25.0> group:server/3 1598 11715 0
group:server_loop/3 4
<0.26.0> erlang:apply/2 17731 3764 0
shell:shell_rep/4 17
<0.27.0> kernel_config:init/1 233 286 0
gen_server:loop/6 9
<0.28.0> supervisor:kernel/1 233 58 0
kernel_safe_sup gen_server:loop/6 9
<0.37.0> erlang:apply/2 1598 18430 0
c:pinfo/1 50
Total 52403 353454 1
228
ok
2>