aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Lasseter <nathan.je.lasseter@googlemail.com>2011-12-23 10:11:48 +0000
committerNathan Lasseter <nathan.je.lasseter@googlemail.com>2011-12-23 10:11:48 +0000
commitb5c22a8a96203ad6b656524fe5ecf246a89efb58 (patch)
treebf098b067149c41fa3a8f46063909927b904fe46
parent2db1bbcde1e0e643a85619a1be350225264d3c10 (diff)
Started work on erlbal_n. Changed names to reflect.erlbal-n
-rw-r--r--erlbal_n.erl91
-rw-r--r--erlbal_n_tests.erl44
-rw-r--r--erlbal_p.erl59
-rw-r--r--erlbal_p_tests.erl44
4 files changed, 238 insertions, 0 deletions
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.