Skip to content

Instantly share code, notes, and snippets.

@DhavalDalal
Created May 2, 2017 12:19
Show Gist options
  • Save DhavalDalal/01816fbb99b1f7fa17d9f516bb7fff73 to your computer and use it in GitHub Desktop.
Save DhavalDalal/01816fbb99b1f7fa17d9f516bb7fff73 to your computer and use it in GitHub Desktop.
Round-Robin Router
%% 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(frequency).
-export([start/0,allocate/0,deallocate/1,stop/0]).
-export([init/0, worker_init/1]).
%% These are the start functions used to create and
%% initialize the server (supervisor).
start() ->
register(frequency,
spawn(frequency, init, [])).
init() ->
process_flag(trap_exit, true),
loop(0, create_workers([{10, 15}, {20, 25}])).
create_workers(Fs) ->
Servers = lists:map(fun({L, U}) ->
F = lists:seq(L, U),
S = spawn_link(frequency, worker_init, [F]),
{S, F}
end, Fs),
io:format("Servers = ~p~n", [Servers]),
Servers.
loop(RequestNumber, Servers) ->
N = length(Servers),
{Server, _} = lists:nth((RequestNumber rem N) + 1, Servers),
receive
AReq = {request, _Pid, allocate} ->
Server ! AReq,
loop(RequestNumber + 1, Servers);
DReq = {request, Pid, {deallocate, Freq}} ->
case contains_frequency(Freq, Servers) of
{Server, _Fs} ->
Server ! DReq;
false ->
Pid ! {reply, {error, cannot_deallocate}}
end,
loop(RequestNumber + 1, Servers);
{'EXIT', Pid, _Reason} ->
io:format("killed ~p~n", [Pid]),
case contains_server(Pid, Servers) of
{Server, Fs} ->
io:format("Restarting server~n"),
NewServers = [restart_worker(Fs) | lists:keydelete(Pid, 1, Servers)],
io:format("New Servers = ~p~n", [NewServers]),
loop(RequestNumber, NewServers);
false ->
loop(RequestNumber, Servers)
end;
{request, Pid, stop} ->
stop_servers(Servers),
Pid ! {reply, stopped}
end.
restart_worker(Freqs) ->
{spawn_link(frequency, worker_init, [Freqs]), Freqs}.
contains_frequency(F, Servers) ->
case lists:filter(fun({_S, Fs}) ->
lists:member(F, Fs)
end, Servers) of
[] -> false;
[S|_] -> S
end.
contains_server(Pid, Servers) ->
case lists:keysearch(Pid, 1, Servers) of
{value, Value} -> Value;
false -> false
end.
stop_servers([]) -> ok;
stop_servers([{Server, _Fs}|Servers]) ->
Server ! {request, self(), stop},
receive
{reply, stopped} ->
io:format("stopped server: ~p~n", [Server])
end,
stop_servers(Servers).
% start() ->
% register(frequency,
% spawn(frequency, init, [])).
worker_init(Frequencies) ->
worker_loop({Frequencies, []}).
% Hard Coded
% get_frequencies() -> [10,11,12,13,14,15].
%% The Main Loop
worker_loop(Frequencies) ->
receive
{request, Pid, allocate} ->
{NewFrequencies, Reply} = allocate(Frequencies, Pid),
Pid ! {reply, Reply},
worker_loop(NewFrequencies);
{request, Pid, {deallocate, Freq}} ->
NewFrequencies = deallocate(Frequencies, Freq),
Pid ! {reply, ok},
worker_loop(NewFrequencies);
{request, Pid, stop} ->
Pid ! {reply, stopped}
end.
%% Functional interface
allocate() ->
frequency ! {request, self(), allocate},
receive
{reply, Reply} -> Reply
end.
deallocate(Freq) ->
frequency ! {request, self(), {deallocate, Freq}},
receive
{reply, Reply} -> Reply
end.
stop() ->
frequency ! {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}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment