Created
July 4, 2020 00:27
-
-
Save tecnowilliam/0946e57956f22eb3eee15da1e67ce17c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| % Compile: c(frequency_hardened). | |
| -module(frequency_hardened). | |
| -author("William Vargas"). | |
| -version("1.0"). | |
| -export([init/0, start/0, stop/0, allocate/0, deallocate/1, tests/0]). | |
| % Register the server as frequency_hardened | |
| -spec start() -> ?MODULE. | |
| start() -> | |
| register(?MODULE, spawn(?MODULE, init, [])). | |
| % Stop the frequency_hardened server | |
| -spec stop() -> any(). | |
| stop() -> | |
| ?MODULE ! {request, self(), stop}, | |
| io:format("Server stopped~n"), | |
| reply(1000). | |
| % Initialize the server | |
| -spec init() -> any(). | |
| init() -> | |
| process_flag(trap_exit, true), | |
| Frequencies = {get_frequencies(), []}, | |
| io:format("Server started~n"), | |
| loop(Frequencies). | |
| % Get the frequencies | |
| -spec get_frequencies() -> list(integer()). | |
| get_frequencies() -> [10,11,12,13,14,15]. | |
| % Reply/timeout any message | |
| -spec reply(integer()) -> any(). | |
| reply(Timeout) -> | |
| receive | |
| {reply, Reply} -> | |
| io:format("~w~n",[Reply]), | |
| Reply; | |
| _ -> ok | |
| after Timeout -> | |
| clear(), | |
| {error, timeout} | |
| end. | |
| % Clear all the mailbox | |
| -spec clear() -> ok. | |
| clear() -> | |
| receive | |
| _Msg -> clear() | |
| after 0 -> | |
| io:format("Mailbox cleared~n"), | |
| ok | |
| end. | |
| % Process the server messages | |
| -spec loop(list(integer())) -> any(). | |
| loop(Frequencies) -> | |
| io:format("Frequencies: ~w~n", [Frequencies]), | |
| receive | |
| {request, Pid, allocate} -> | |
| {NewFrequencies, Reply} = allocate(Frequencies, Pid), | |
| Pid ! {reply, Reply}, | |
| loop(NewFrequencies); | |
| {request, Pid , {deallocate, Freq}} -> | |
| NewFrequencies = deallocate(Frequencies, Freq), | |
| Pid ! {reply, {deallocate_ok, -Freq}}, | |
| loop(NewFrequencies); | |
| {request, _Pid, overload} -> | |
| timer:sleep(1000), | |
| loop(Frequencies); | |
| {'EXIT', Pid, _Reason} -> | |
| NewFrequencies = exited(Frequencies, Pid), | |
| loop(NewFrequencies); | |
| {request, _Pid, stop} -> | |
| % Pid ! {reply, stopped} | |
| stop() | |
| end. | |
| % Functional interface: allocate | |
| -spec allocate() -> any(). | |
| allocate() -> | |
| ?MODULE ! {request, self(), allocate}, | |
| reply(1000). | |
| % Allocate a frequency | |
| -spec allocate(list(), pid()) -> tuple(). | |
| allocate({[], Allocated}, _Pid) -> | |
| {{[], Allocated}, {allocate_error, no_frequency}}; | |
| allocate({[Freq|Free], Allocated}, Pid) -> | |
| link(Pid), | |
| {{Free, [{Freq, Pid}|Allocated]}, {allocate_ok, Freq}}. | |
| % Functional interface: deallocate | |
| -spec deallocate(integer()) -> any(). | |
| deallocate(Freq) -> | |
| ?MODULE ! {request, self(), {deallocate, Freq}}, | |
| reply(1000). | |
| % Deallocate a frequency | |
| -spec deallocate(tuple(), integer()) -> tuple(). | |
| deallocate({Free, Allocated}, Freq) -> | |
| case lists:keyfind(Freq, 1, Allocated) of | |
| {Freq, Pid} -> | |
| NewAllocated = lists:delete({Freq, Pid}, Allocated), | |
| unlink(Pid), | |
| {[Freq|Free], NewAllocated}; | |
| _ -> | |
| {Free, Allocated} | |
| end. | |
| % Exit from a frequency | |
| -spec exited({list(), list()}, string()) -> tuple(). | |
| exited({Free, Allocated}, Pid) -> | |
| case lists:keysearch(Pid, 2, Allocated) of | |
| {value, {Freq,Pid}} -> | |
| NewAllocated = lists:keydelete(Freq,1,Allocated), | |
| {[Freq|Free],NewAllocated}; | |
| false -> | |
| {Free,Allocated} | |
| end. | |
| % Tests | |
| -spec tests() -> any(). | |
| tests() -> | |
| % Test: Clean mailbox | |
| clear(), | |
| % Test: Start the server | |
| start(), | |
| % Test: Allocate 10,11 and 12 | |
| allocate(), allocate(), allocate(), | |
| % Test: Deallocate 11 | |
| deallocate(11), | |
| % Test: Allocate 11 and 13 | |
| allocate(), allocate(), | |
| % Test: Overloaded server | |
| io:format("Test overloaded server~n"), | |
| ?MODULE ! {request, self(), overload}, | |
| reply(1000). |
This file contains hidden or 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
| % Compile: c(scenario). | |
| -module(scenario). | |
| -author("William Vargas"). | |
| -version("1.0"). | |
| -export([start_server/0, stop_server/0, start_client/0, stop_client/1, client/2, tests/0]). | |
| % Launch the server for the clients | |
| -spec start_server() -> any(). | |
| start_server() -> | |
| frequency_hardened:start(). | |
| % Stop the server for the clients | |
| -spec stop_server() -> any(). | |
| stop_server() -> | |
| whereis(frequency_hardened) ! {request, self(), stop}. | |
| % Start a new client | |
| -spec start_client() -> integer(). | |
| start_client() -> | |
| Client = list_to_atom(lists:flatten(io_lib:format("~p", [rand:uniform(1000)]))), | |
| io:format("New client: ~w~n", [Client]), | |
| register(Client, spawn_link(?MODULE, client, [Client, []])), | |
| Client. | |
| % Stop a client | |
| -spec stop_client(integer()) -> any(). | |
| stop_client(Client) -> | |
| whereis(Client) ! {request, self(), stop}. | |
| % Allocate or desallocate a frequency to the client | |
| -spec send_message(integer(), list()) -> any(). | |
| send_message(Client, Freqs) -> | |
| case rand:uniform(2) of | |
| 1 -> | |
| {allocate_ok, Freq} = frequency_hardened:allocate(), | |
| io:format("Frequency ~w allocated to client ~w.~n", [Freq, Client]), | |
| timer:sleep(2000), | |
| client(Client, [Freq|Freqs]); | |
| 2 -> | |
| Len = length(Freqs), | |
| case Len of | |
| 0 -> | |
| io:format("No frequencies to deallocate by client ~w.~n", [Client]), | |
| timer:sleep(2000), | |
| client(Client, Freqs); | |
| _ -> | |
| Freq = lists:nth(rand:uniform(Len),Freqs), | |
| frequency_hardened:deallocate(Freq), | |
| io:format("Frequency ~w deallocated by client ~w.~n", [Freq, Client]), | |
| timer:sleep(2000), | |
| client(Client, lists:delete(Freq,Freqs)) | |
| end | |
| end. | |
| % Manage the client options | |
| -spec client(integer(), list()) -> any(). | |
| client(Client, Freqs) -> | |
| receive | |
| {request, _Pid, stop} -> | |
| io:format("~w stopped~n", [Client]) | |
| after 0 -> | |
| case is_pid(whereis(frequency_hardened)) of | |
| true -> | |
| send_message(Client, Freqs); | |
| _ -> | |
| io:format("Server is down, retrying... ~n"), | |
| timer:sleep(1000), | |
| client(Client, Freqs) | |
| end | |
| end. | |
| % Tests | |
| -spec tests() -> any(). | |
| tests() -> | |
| % Test: Start the server | |
| start_server(), | |
| % Test: Start a client | |
| Client = start_client(), | |
| % Test: Retry when the server stop | |
| timer:sleep(10000), | |
| stop_server(), | |
| timer:sleep(3000), | |
| start_server(), | |
| timer:sleep(5000), | |
| % Test: Stop the client | |
| stop_client(Client), | |
| % Test: Stop the server | |
| stop_server(). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment