From b5c22a8a96203ad6b656524fe5ecf246a89efb58 Mon Sep 17 00:00:00 2001 From: Nathan Lasseter Date: Fri, 23 Dec 2011 10:11:48 +0000 Subject: Started work on erlbal_n. Changed names to reflect. --- erlbal_n.erl | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ erlbal_n_tests.erl | 44 ++++++++++++++++++++++++++ erlbal_p.erl | 59 +++++++++++++++++++++++++++++++++++ erlbal_p_tests.erl | 44 ++++++++++++++++++++++++++ 4 files changed, 238 insertions(+) create mode 100644 erlbal_n.erl create mode 100644 erlbal_n_tests.erl create mode 100644 erlbal_p.erl create mode 100644 erlbal_p_tests.erl diff --git a/erlbal_n.erl b/erlbal_n.erl new file mode 100644 index 0000000..fba8621 --- /dev/null +++ b/erlbal_n.erl @@ -0,0 +1,91 @@ +-module(erlbal_n). +-export([make_request/2, start_bal/0, stop_bal/1, start_server/5, stop_server/2, list_servers/1]). + +start_server(Balancer, Node, Fun, LoadFun, INITSTATE) when is_function(Fun, 2) andalso is_function(LoadFun, 0) andalso is_list(INITSTATE) -> + PID = spawn(Node, fun() -> server_loop(Fun, LoadFun, INITSTATE) end), + Balancer ! {add_node, PID}. + +stop_server(Balancer, PID) -> + Balancer ! {del_node, PID}, + PID ! die. + +list_servers(Balancer) -> + Balancer ! {list_nodes, self()}, + receive Nodes -> Nodes end. + +server_loop(Fun, LoadFun, STATE) -> + receive + {request, From, Serverlist, ARGS} -> + {Ret, NEWSTATE} = Fun(ARGS, STATE), + From ! Ret, + updatestates(Serverlist, self(), NEWSTATE), + server_loop(Fun, LoadFun, NEWSTATE); + {load, From} -> + From ! LoadFun(), + server_loop(Fun, LoadFun, STATE); + {update, NEWSTATE} -> + server_loop(Fun, LoadFun, NEWSTATE); + die -> + ok + end. + +updatestates([], _, _) -> + ok; +updatestates([H|T], H, NEWSTATE) -> + updatestates(T, H, NEWSTATE); +updatestates([H|T], P, NEWSTATE) -> + H ! {update, NEWSTATE}, + updatestates(T, P, NEWSTATE). + +start_bal() -> + spawn(fun() -> bal_loop([]) end). + +stop_bal(Balancer) -> + Balancer ! die. + +bal_loop(Serverlist) -> + receive + {add_node, PID} -> + bal_loop(Serverlist ++ [PID]); + {del_node, PID} -> + bal_loop(Serverlist -- [PID]); + {list_nodes, From} -> + From ! Serverlist, + bal_loop(Serverlist); + {request, From, ARGS} -> + if + length(Serverlist) > 0 -> + PID = bal_worker(Serverlist), + PID ! {request, From, Serverlist, ARGS}, + bal_loop(Serverlist); + true -> + bal_loop(Serverlist) + end; + die -> + ok + end. + +bal_worker([H|T]) -> + H ! {load, self()}, + receive + N -> + bal_worker(T, N, H) + end. +bal_worker([], _, PID) -> + PID; +bal_worker([H|T], Best, PID) -> + H ! {load, self()}, + receive + N -> + if + N > Best -> + bal_worker(T, N, H); + true -> + bal_worker(T, Best, PID) + end + end. + + +make_request(Balancer, ARGS) when is_list(ARGS)-> + Balancer ! {request, self(), ARGS}, + receive Ret -> Ret end. diff --git a/erlbal_n_tests.erl b/erlbal_n_tests.erl new file mode 100644 index 0000000..91ea5ee --- /dev/null +++ b/erlbal_n_tests.erl @@ -0,0 +1,44 @@ +-module(erlbal_n_tests). +-export([start/1]). + +start(simple) -> + Bal = erlbal_n:start_bal(), + erlbal_n:start_server(Bal, node(), fun(_, _) -> {7, []} end, fun() -> 1000 - length(processes()) end, []), + erlbal_n:start_server(Bal, node(), fun(_, _) -> {7, []} end, fun() -> 1000 - length(processes()) end, []), + 7 = erlbal_n:make_request(Bal, []), + 7 = erlbal_n:make_request(Bal, []), + lists:foreach(fun(X) -> erlbal_n:stop_server(Bal, X) end, erlbal_n:list_servers(Bal)), + erlbal_n:stop_bal(Bal), + ok; + +start(args) -> + Bal = erlbal_n:start_bal(), + erlbal_n:start_server(Bal, node(), fun([X], _) -> {X+1, []} end, fun() -> 1000 - length(processes()) end, []), + erlbal_n:start_server(Bal, node(), fun([X], _) -> {X+1, []} end, fun() -> 1000 - length(processes()) end, []), + 7 = erlbal_n:make_request(Bal, [6]), + 7 = erlbal_n:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_n:stop_server(Bal, X) end, erlbal_n:list_servers(Bal)), + erlbal_n:stop_bal(Bal), + ok; + +start(state) -> + Bal = erlbal_n:start_bal(), + erlbal_n:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S]} end, fun() -> 1000 - length(processes()) end, [1]), + erlbal_n:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S]} end, fun() -> 1000 - length(processes()) end, [1]), + 7 = erlbal_n:make_request(Bal, [6]), + 7 = erlbal_n:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_n:stop_server(Bal, X) end, erlbal_n:list_servers(Bal)), + erlbal_n:stop_bal(Bal), + ok; + +start(complex_state) -> + Bal = erlbal_n:start_bal(), + erlbal_n:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S+1]} end, fun() -> 1000 - length(processes()) end, [1]), + erlbal_n:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S+1]} end, fun() -> 1000 - length(processes()) end, [1]), + 7 = erlbal_n:make_request(Bal, [6]), + 8 = erlbal_n:make_request(Bal, [6]), + 9 = erlbal_n:make_request(Bal, [6]), + 10 = erlbal_n:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_n:stop_server(Bal, X) end, erlbal_n:list_servers(Bal)), + erlbal_n:stop_bal(Bal), + ok. diff --git a/erlbal_p.erl b/erlbal_p.erl new file mode 100644 index 0000000..ed43e0e --- /dev/null +++ b/erlbal_p.erl @@ -0,0 +1,59 @@ +-module(erlbal_p). +-export([make_request/2, start_bal/0, stop_bal/1, start_server/4, stop_server/2, list_servers/1]). + +start_server(Balancer, Node, Fun, INITSTATE) when is_function(Fun, 2) andalso is_list(INITSTATE) -> + PID = spawn(Node, fun() -> server_loop(Fun, INITSTATE) end), + Balancer ! {add_node, PID}. + +stop_server(Balancer, PID) -> + Balancer ! {del_node, PID}, + PID ! die. + +list_servers(Balancer) -> + Balancer ! {list_nodes, self()}, + receive Nodes -> Nodes end. + +server_loop(Fun, STATE) -> + receive + {request, From, ARGS} -> + {Ret, NEWSTATE} = Fun(ARGS, STATE), + From ! Ret, + server_loop(Fun, NEWSTATE); + die -> + ok + end. + +start_bal() -> + spawn(fun() -> bal_loop([], 1) end). + +stop_bal(Balancer) -> + Balancer ! die. + +bal_loop(Serverlist, Nextserver) -> + receive + {add_node, PID} -> + bal_loop(Serverlist ++ [PID], Nextserver); + {del_node, PID} -> + bal_loop(Serverlist -- [PID], Nextserver); + {list_nodes, From} -> + From ! Serverlist, + bal_loop(Serverlist, Nextserver); + {request, From, ARGS} -> + Serv = lists:nth(Nextserver, Serverlist), + Serv ! {request, From, ARGS}, + NS = Nextserver + 1, + SLL = length(Serverlist), + if + NS > SLL -> + bal_loop(Serverlist, 1); + true -> + bal_loop(Serverlist, NS) + end; + die -> + ok + end. + + +make_request(Balancer, ARGS) when is_list(ARGS)-> + Balancer ! {request, self(), ARGS}, + receive Ret -> Ret end. diff --git a/erlbal_p_tests.erl b/erlbal_p_tests.erl new file mode 100644 index 0000000..c3df8f2 --- /dev/null +++ b/erlbal_p_tests.erl @@ -0,0 +1,44 @@ +-module(erlbal_p_tests). +-export([start/1]). + +start(simple) -> + Bal = erlbal_p:start_bal(), + erlbal_p:start_server(Bal, node(), fun(_, _) -> {7, []} end, []), + erlbal_p:start_server(Bal, node(), fun(_, _) -> {8, []} end, []), + 7 = erlbal_p:make_request(Bal, []), + 8 = erlbal_p:make_request(Bal, []), + lists:foreach(fun(X) -> erlbal_p:stop_server(Bal, X) end, erlbal_p:list_servers(Bal)), + erlbal_p:stop_bal(Bal), + ok; + +start(args) -> + Bal = erlbal_p:start_bal(), + erlbal_p:start_server(Bal, node(), fun([X], _) -> {X+1, []} end, []), + erlbal_p:start_server(Bal, node(), fun([X], _) -> {X+2, []} end, []), + 7 = erlbal_p:make_request(Bal, [6]), + 8 = erlbal_p:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_p:stop_server(Bal, X) end, erlbal_p:list_servers(Bal)), + erlbal_p:stop_bal(Bal), + ok; + +start(state) -> + Bal = erlbal_p:start_bal(), + erlbal_p:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S]} end, [1]), + erlbal_p:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S]} end, [10]), + 7 = erlbal_p:make_request(Bal, [6]), + 16 = erlbal_p:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_p:stop_server(Bal, X) end, erlbal_p:list_servers(Bal)), + erlbal_p:stop_bal(Bal), + ok; + +start(complex_state) -> + Bal = erlbal_p:start_bal(), + erlbal_p:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S+1]} end, [1]), + erlbal_p:start_server(Bal, node(), fun([X], [S]) -> Y = X + S, {Y, [S+1]} end, [10]), + 7 = erlbal_p:make_request(Bal, [6]), + 16 = erlbal_p:make_request(Bal, [6]), + 8 = erlbal_p:make_request(Bal, [6]), + 17 = erlbal_p:make_request(Bal, [6]), + lists:foreach(fun(X) -> erlbal_p:stop_server(Bal, X) end, erlbal_p:list_servers(Bal)), + erlbal_p:stop_bal(Bal), + ok. -- cgit v1.2.1