Created
July 14, 2020 06:42
-
-
Save Xdeon/9d5ba3a739deee0453637ceefb42c3e7 to your computer and use it in GitHub Desktop.
frequency server scaling up with front-end router
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_front). | |
-export([start/0, allocate/0, deallocate/1, stop/0]). | |
-export([init/0]). | |
%% API | |
allocate() -> | |
send_receive(allocate). | |
deallocate(Freq) -> | |
send_receive({deallocate, Freq}). | |
stop() -> | |
send_receive(stop). | |
send_receive(Info) -> | |
try frequency ! {request, self(), Info} of | |
_ -> | |
receive | |
{reply, Reply} -> Reply | |
after 500 -> | |
erlang:error(timeout) | |
end | |
catch error:badarg -> | |
erlang:error(serverdown) | |
end. | |
start() -> | |
register(frequency, spawn(?MODULE, init, [])). | |
%% Internal functions | |
init() -> | |
erlang:process_flag(trap_exit, true), | |
Servers = lists:map(fun({Id, Free}) -> | |
Pid = frequency_shard:start(Free), | |
link(Pid), | |
{Id, Pid} end, get_frequencies()), | |
%io:format("start servers: ~p~n", [Servers]), | |
loop(Servers). | |
get_frequencies() -> | |
[{freq1, [10,11,12,13,14,15]}, | |
{freq2, [20,21,22,23,24,25]}]. | |
loop(Servers) -> | |
receive | |
{request, _, _}=Req -> | |
case handle_request(Req, Servers) of | |
ok -> ok; | |
NewServers -> loop(NewServers) | |
end; | |
{'EXIT', Pid, _Reason} -> | |
loop(handle_exited(Pid, Servers)) | |
end. | |
% round robin for allocate request | |
handle_request({request, Pid, allocate}, [{Id, S}|T]) -> | |
S ! {request, Pid, allocate}, | |
T ++ [{Id, S}]; | |
% dedicated routing for deallocate request | |
handle_request({request, Pid, {deallocate, Freq}}, Servers) -> | |
case freq_shard(Freq) of | |
{ok, Id} -> | |
S = proplists:get_value(Id, Servers), | |
S ! {request, Pid, {deallocate, Freq}}; | |
{error, _}=Error -> | |
Pid ! {reply, Error} | |
end, | |
Servers; | |
% stop all servers and the front itself | |
handle_request({request, Pid, stop}, Servers) -> | |
terminate(Servers), | |
Pid ! {reply, stopped}, | |
ok. | |
% restart crashed server | |
handle_exited(Pid, Servers) -> | |
case lists:keytake(Pid, 2, Servers) of | |
{value, {Id, Pid}, Rest} -> | |
New = frequency_shard:start(proplists:get_value(Id, get_frequencies())), | |
link(New), | |
[{Id, New}|Rest]; | |
false -> | |
Servers | |
end. | |
% clean up for termination | |
terminate([]) -> | |
ok; | |
terminate([{_, S}|T]) -> | |
_ = frequency_shard:stop(S), | |
terminate(T). | |
% find appropriate server for given frequency | |
freq_shard(Freq) -> | |
case lists:filter(fun({_, Free}) -> | |
lists:member(Freq, Free) end, get_frequencies()) of | |
[{Id, _}] -> {ok, Id}; | |
[] -> {error, illegal_frequency} | |
end. | |
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
%% 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_shard). | |
-export([start/1, allocate/1, deallocate/2, stop/1]). | |
-export([init/1]). | |
%% These are the start functions used to create and | |
%% initialize the server. | |
start(Free) -> | |
spawn(?MODULE, init, [Free]). | |
init(Free) -> | |
Frequencies = {Free, []}, | |
loop(Frequencies). | |
%% The Main Loop | |
loop(Frequencies) -> | |
receive | |
{request, Pid, allocate} -> | |
{NewFrequencies, Reply} = handle_allocate(Frequencies, Pid), | |
Pid ! {reply, Reply}, | |
loop(NewFrequencies); | |
{request, Pid , {deallocate, Freq}} -> | |
NewFrequencies = handle_deallocate(Frequencies, Freq), | |
Pid ! {reply, ok}, | |
loop(NewFrequencies); | |
{request, Pid, stop} -> | |
Pid ! {reply, stopped} | |
end. | |
%% Functional interface | |
allocate(Pid) -> | |
Pid ! {request, self(), allocate}, | |
receive | |
{reply, Reply} -> Reply | |
end. | |
deallocate(Pid, Freq) -> | |
Pid ! {request, self(), {deallocate, Freq}}, | |
receive | |
{reply, Reply} -> Reply | |
end. | |
stop(Pid) -> | |
Pid ! {request, self(), stop}, | |
receive | |
{reply, Reply} -> Reply | |
end. | |
%% The Internal Help Functions used to allocate and | |
%% deallocate frequencies. | |
handle_allocate({[], Allocated}, _Pid) -> | |
{{[], Allocated}, {error, no_frequency}}; | |
handle_allocate({[Freq|Free], Allocated}, Pid) -> | |
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}. | |
handle_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