|
@@ -3,9 +3,10 @@
|
|
|
-behaviour(gen_server).
|
|
|
|
|
|
%% API
|
|
|
--export([start_link/0, start_link/1]).
|
|
|
--export([start_work/3, work_finished/1,
|
|
|
- add_node/1, remove_node/1, scavenge/0,
|
|
|
+-export([start/0, start/1, start_link/0, start_link/1]).
|
|
|
+-export([start_work/1, start_work/3, work_finished/1, work_finished/2,
|
|
|
+ available_node/0, add_node/1, remove_node/1, remove_node/2,
|
|
|
+ scavenge/0, scavenge/1,
|
|
|
get_node_queue/0, get_node_list/0]).
|
|
|
|
|
|
%% gen_server callbacks
|
|
@@ -23,6 +24,12 @@
|
|
|
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
|
%% Description: Starts the server
|
|
|
%%--------------------------------------------------------------------
|
|
|
+start() ->
|
|
|
+ start([node()]).
|
|
|
+
|
|
|
+start(Args) ->
|
|
|
+ ebb_work_supv:start_link(Args).
|
|
|
+
|
|
|
start_link() ->
|
|
|
start_link([node()]).
|
|
|
|
|
@@ -37,20 +44,35 @@ start_link(scavenge) ->
|
|
|
start_link(Nodes) ->
|
|
|
gen_server:start_link({local, ?SERVER}, ?MODULE, Nodes, []).
|
|
|
|
|
|
+start_work(Node) ->
|
|
|
+ gen_server:cast(?SERVER, {start_work, Node}).
|
|
|
+
|
|
|
start_work(Func, Args, Receiver) ->
|
|
|
gen_server:call(?SERVER, {start_work, Func, Args, Receiver}).
|
|
|
|
|
|
work_finished(Node) ->
|
|
|
gen_server:cast(?SERVER, {work_finished, Node}).
|
|
|
|
|
|
+work_finished(Root, Node) ->
|
|
|
+ gen_server:cast({?SERVER, Root}, {work_finished, Node}).
|
|
|
+
|
|
|
+available_node() ->
|
|
|
+ gen_server:call(?SERVER, available_node).
|
|
|
+
|
|
|
add_node(Node) ->
|
|
|
gen_server:cast(?SERVER, {add_node, Node}).
|
|
|
|
|
|
remove_node(Node) ->
|
|
|
gen_server:cast(?SERVER, {remove_node, Node}).
|
|
|
|
|
|
+remove_node(Root, Node) ->
|
|
|
+ gen_server:cast({?SERVER, Root}, {remove_node, Node}).
|
|
|
+
|
|
|
scavenge() ->
|
|
|
- gen_server:cast(?SERVER, scavenge).
|
|
|
+ gen_server:cast(?SERVER, {scavenge, world}).
|
|
|
+
|
|
|
+scavenge(Domain) ->
|
|
|
+ gen_server:cast(?SERVER, {scavenge, Domain}).
|
|
|
|
|
|
get_node_queue() ->
|
|
|
gen_server:call(?SERVER, get_node_queue).
|
|
@@ -90,6 +112,10 @@ handle_call({start_work, Func, Args, Receiver}, _From,
|
|
|
{Reply, Queue2} = start_work_from_queue(Func, Args, Receiver, Queue),
|
|
|
State2 = State#state{node_queue=Queue2},
|
|
|
{reply, Reply, State2};
|
|
|
+handle_call(available_node, _From, State = #state{node_queue=Queue}) ->
|
|
|
+ {_Priority, Node, Queue2} = find_available_node(Queue),
|
|
|
+ State2 = State#state{node_queue=Queue2},
|
|
|
+ {reply, Node, State2};
|
|
|
handle_call(get_node_queue, _From, State = #state{node_queue=Queue}) ->
|
|
|
Reply = Queue,
|
|
|
{reply, Reply, State}.
|
|
@@ -100,6 +126,10 @@ handle_call(get_node_queue, _From, State = #state{node_queue=Queue}) ->
|
|
|
%% {stop, Reason, State}
|
|
|
%% Description: Handling cast messages
|
|
|
%%--------------------------------------------------------------------
|
|
|
+handle_cast({start_work, Node}, State = #state{node_queue=Queue}) ->
|
|
|
+ Queue2 = priority_queue:modify_priority(Node, fun(P) -> P+1 end, Queue),
|
|
|
+ State2 = State#state{node_queue=Queue2},
|
|
|
+ {noreply, State2};
|
|
|
handle_cast({work_finished, Node}, State = #state{node_queue=Queue}) ->
|
|
|
Queue2 = priority_queue:modify_priority(Node, fun(P) -> P-1 end, Queue),
|
|
|
State2 = State#state{node_queue=Queue2},
|
|
@@ -112,8 +142,17 @@ handle_cast({remove_node, Node}, State = #state{node_queue=Queue}) ->
|
|
|
Queue2 = priority_queue:delete_value(Node, Queue),
|
|
|
State2 = State#state{node_queue=Queue2},
|
|
|
{noreply, State2};
|
|
|
-handle_cast(scavenge, State = #state{node_queue=Queue}) ->
|
|
|
- World = net_adm:world(),
|
|
|
+handle_cast({scavenge, Domain}, State = #state{node_queue=Queue}) ->
|
|
|
+ World = case Domain of
|
|
|
+ world ->
|
|
|
+ net_adm:world();
|
|
|
+ local ->
|
|
|
+ net_adm:world_list([list_to_atom(net_adm:localhost())]);
|
|
|
+ Hosts when is_list(Hosts) ->
|
|
|
+ net_adm:world_list(Hosts);
|
|
|
+ Host ->
|
|
|
+ net_adm:world_list([Host])
|
|
|
+ end,
|
|
|
Queue2 = new_nodes(World, Queue),
|
|
|
State2 = State#state{node_queue=Queue2},
|
|
|
{noreply, State2}.
|
|
@@ -148,9 +187,17 @@ code_change(_OldVsn, State, _Extra) ->
|
|
|
%%% Internal functions
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
|
|
-start_work_from_queue(Func, Args, Receiver, Queue) ->
|
|
|
+find_available_node(Queue) ->
|
|
|
{Priority, Node, Queue2} = priority_queue:take_minimum(Queue),
|
|
|
- Reply = ebb_worker_bridge:start_link(Node, Func, Args, Receiver),
|
|
|
+ case net_adm:ping(Node) of
|
|
|
+ pong -> {Priority, Node, Queue};
|
|
|
+ pang -> find_available_node(Queue2)
|
|
|
+ end.
|
|
|
+
|
|
|
+start_work_from_queue(Func, Args, Receiver, Queue) ->
|
|
|
+ {Priority, Node, Queue2} = find_available_node(Queue),
|
|
|
+ Reply = ebb_worker_bridge:start_link(
|
|
|
+ Node, Func, Args, Receiver),
|
|
|
case Reply of
|
|
|
{ok, _} ->
|
|
|
Queue3 = priority_queue:insert(Priority+1, Node, Queue2),
|