yaws 1.73 compatibility
[fuzed.git] / elibs / resource_manager.erl
blob1190c9154f5238648fbbfceb78011e8f68ac85aa
1 %%%-------------------------------------------------------------------
2 %%% File : /Users/dfayram/Projects/concilium/elibs/resource_manager.erl
3 %%% Author : David Fayram
4 %%%-------------------------------------------------------------------
5 -module(resource_manager).
6 -behaviour(gen_server).
8 %% API exports
9 -export([start_link/3, start/3,nodes/0,nodecount/0,change_nodecount/1,cycle/0,cycle/1]).
11 %% gen_server callback exports
12 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
13 terminate/2, code_change/3]).
15 %% Erlang records are ugly.
16 -record(state, {generator = fun() -> undefined end,
17 terminator = fun(_) -> undefined end,
18 nodecount = 1,
19 nodes = [],
20 term_hook = fun(_) -> undefined end
21 }).
23 %% External call functions
25 % Note the local server, one of these should run on every
26 % node serving up rails responders.
27 start_link(Generator, Terminator, NumNodes) ->
28 gen_server:start_link({local, ?MODULE}, ?MODULE, [Generator, Terminator, NumNodes], []).
29 start(Generator, Terminator, NumNodes) ->
30 gen_server:start({local, ?MODULE}, ?MODULE, [Generator, Terminator, NumNodes], []).
32 nodes() -> gen_server:call(?MODULE, nodes).
33 nodecount() -> gen_server:call(?MODULE, nodecount).
34 change_nodecount(NewNodecount) -> gen_server:cast(?MODULE, {change_nodecount, NewNodecount}).
35 cycle() -> gen_server:cast(?MODULE, cycle).
36 cycle(Node) -> gen_server:cast({?MODULE, Node}, cycle).
38 %% GEN_SERVER callbacks.
39 init([Generator, Terminator, NumNodes]) ->
40 process_flag(trap_exit, true),
41 Nodes = spawn_nodes(Generator, NumNodes),
42 {ok, #state{generator = Generator, nodecount = NumNodes,
43 nodes = Nodes, terminator = Terminator}}.
45 handle_call(term_hook, _From, State) ->
46 {reply, State#state.term_hook, State};
47 handle_call({term_hook, Hook}, _From, State) when is_function(Hook, 1) ->
48 {reply, State#state.term_hook, State#state{term_hook = Hook}};
49 handle_call(nodecount,_From,State) ->
50 {reply, State#state.nodecount, State};
51 handle_call(nodes, _From, State) ->
52 {reply, State#state.nodes, State}.
54 handle_cast(cycle, State) ->
55 drop_nodes(State#state.terminator, State#state.nodes),
56 {noreply, State#state{nodes=spawn_nodes(State#state.generator, State#state.nodecount)}};
57 handle_cast({change_nodecount, NewCount}, S) when is_number(NewCount) ->
58 Count = S#state.nodecount,
60 NewCount > Count ->
61 {noreply,
62 S#state{nodecount = NewCount,
63 nodes = spawn_nodes(S#state.generator, NewCount - Count) ++ S#state.nodes}};
64 NewCount < Count ->
65 {ToKill, ToKeep} = lists:split(NewCount - Count, S#state.nodes),
66 drop_nodes(S#state.terminator, ToKill),
67 {noreply, S#state{nodecount=NewCount, nodes=ToKeep}};
68 true ->
69 {noreply, S}
70 end.
72 handle_info({'EXIT', Pid, _Reason}, S) ->
73 Term = S#state.terminator,
74 Membership = lists:any(fun(X) -> X =:= Pid end, S#state.nodes),
76 Membership ->
77 Term(Pid),
78 Res = lists:delete(Pid, S#state.nodes),
79 NewNode = spawn_linked_node(S#state.generator),
80 {noreply, S#state{nodes=[NewNode|Res]}};
81 true ->
82 {noreply, S}
83 end;
84 handle_info(Any,S) ->
85 io:format("Got INFO ~p~n", [Any]),
86 {noreply, S}.
88 terminate(_Reason, _State) ->
89 ok.
91 code_change(_OldVsn, State, _Extra) ->
92 {ok, State}.
94 %% Utility functions
96 spawn_linked_node(Generator) ->
97 Node = Generator(),
98 link(Node),
99 Node.
101 spawn_nodes(Generator,NumNodes) ->
102 spawn_nodes(Generator,NumNodes,[]).
104 spawn_nodes(_Generator,0,Acc) -> Acc;
105 spawn_nodes(Generator,NumNodes,Acc) -> spawn_nodes(Generator,NumNodes - 1, [spawn_linked_node(Generator)|Acc]).
107 drop_nodes(Terminator, Nodes) ->
108 Killer = fun(Node) -> unlink(Node), Terminator(Node) end,
109 lists:map(Killer, Nodes).