fix subtle newref decode bug
[fuzed.git] / elibs / resource_manager.erl
blob1d1f6d16b4a241c0e82d61d0711211cc662842a5
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]).
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).
37 %% GEN_SERVER callbacks.
38 init([Generator, Terminator, NumNodes]) ->
39 process_flag(trap_exit, true),
40 Nodes = spawn_nodes(Generator, NumNodes),
41 {ok, #state{generator = Generator, nodecount = NumNodes,
42 nodes = Nodes, terminator = Terminator}}.
44 handle_call(term_hook, _From, State) ->
45 {reply, State#state.term_hook, State};
46 handle_call({term_hook, Hook}, _From, State) when is_function(Hook, 1) ->
47 {reply, State#state.term_hook, State#state{term_hook = Hook}};
48 handle_call(nodecount,_From,State) ->
49 {reply, State#state.nodecount, State};
50 handle_call(nodes, _From, State) ->
51 {reply, State#state.nodes, State}.
53 handle_cast(cycle, State) ->
54 drop_nodes(State#state.terminator, State#state.nodes),
55 {noreply, State#state{nodes=spawn_nodes(State#state.generator, State#state.nodecount)}};
56 handle_cast({change_nodecount, NewCount}, S) when is_number(NewCount) ->
57 Count = S#state.nodecount,
59 NewCount > Count ->
60 {noreply,
61 S#state{nodecount = NewCount,
62 nodes = spawn_nodes(S#state.generator, NewCount - Count) ++ S#state.nodes}};
63 NewCount < Count ->
64 {ToKill, ToKeep} = lists:split(NewCount - Count, S#state.nodes),
65 drop_nodes(S#state.terminator, ToKill),
66 {noreply, S#state{nodecount=NewCount, nodes=ToKeep}};
67 true ->
68 {noreply, S}
69 end.
71 handle_info({'EXIT', Pid, _Reason}, S) ->
72 Term = S#state.terminator,
73 Membership = lists:any(fun(X) -> X =:= Pid end, S#state.nodes),
75 Membership ->
76 Term(Pid),
77 Res = lists:delete(Pid, S#state.nodes),
78 NewNode = spawn_linked_node(S#state.generator),
79 {noreply, S#state{nodes=[NewNode|Res]}};
80 true ->
81 {noreply, S}
82 end;
83 handle_info(Any,S) ->
84 io:format("Got INFO ~p~n", [Any]),
85 {noreply, S}.
87 terminate(_Reason, _State) ->
88 ok.
90 code_change(_OldVsn, State, _Extra) ->
91 {ok, State}.
93 %% Utility functions
95 spawn_linked_node(Generator) ->
96 Node = Generator(),
97 link(Node),
98 Node.
100 spawn_nodes(Generator,NumNodes) ->
101 spawn_nodes(Generator,NumNodes,[]).
103 spawn_nodes(_Generator,0,Acc) -> Acc;
104 spawn_nodes(Generator,NumNodes,Acc) -> spawn_nodes(Generator,NumNodes - 1, [spawn_linked_node(Generator)|Acc]).
106 drop_nodes(Terminator, Nodes) ->
107 Killer = fun(Node) -> unlink(Node), Terminator(Node) end,
108 lists:map(Killer, Nodes).