实现资源探测
-record(state.
(target_resource_types,
local_resource tuples,
found_resource_tuples)).
定义了3个字段:target_resource_types就是上述的“需求”列表,所需资源的类型的列表;local_resource_tuples则是“供给”列表,这张列表以资源元组的形式保存着本地节点上的所有资源;found_resource_tuples用于缓存探测到的可以需求的资源实例。
-module(resource_discovery).
-author("chen").
-behaviour(gen_server).
%% API
-export([
start_link/0,
add_target_resource_type/1,
fetch_resources/1,
trade_resources/0,
add_local_resource/2]).
-export([init/1, handle_cast/2, handle_call/3]).
-define(SERVER, ?MODULE).
-record(state, {
target_resource_types,
local_resource_tuples,
found_resource_tuples
}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
{ok, #state{target_resource_types = [],
local_resource_tuples = dict:new(),
found_resource_tuples = dict:new()}}.
add_target_resource_type(Type) ->
gen_server:cast(?SERVER, {add_target_resource_type, Type}).
add_local_resource(Type, Instance) ->
gen_server:cast(?SERVER, {add_local_resource, {Type, Instance}}).
trade_resources() ->
gen_server:cast(?SERVER, trade_resources).
fetch_resources(Type) ->
gen_server:call(?SERVER, {fetch_resources, Type}).
handle_cast({add_target_resource_type, Type}, State) ->
TargetTypes = State#state.target_resource_types,
NewTargetTypes = [Type | lists:delete(Type, TargetTypes)],
{noreply, State#state{target_resource_types = NewTargetTypes}};
handle_cast({add_local_resource, {Type, Instance}}, State) ->
ResourceTuples = State#state.local_resource_tuples,
NewResourceTuples = add_resource(Type, Instance, ResourceTuples),
{noreply, State#state{local_resource_tuples = NewResourceTuples}};
handle_cast({trade_resources, {ReplyTo, Remotes}},
#state{local_resource_tuples = Locals,
target_resource_types = TargetTypes,
found_resource_tuples = OldFound} = State) ->
FilteredRemotes = resources_for_types(TargetTypes, Remotes),
NewFound = add_resources(FilteredRemotes, OldFound),
case ReplyTo of
noreply ->
ok;
_ ->
gen_server:cast({?SERVER, ReplyTo},
{trade_resources, {noreply, Locals}})
end,
{noreply, State#state{found_resource_tuples = NewFound}};
handle_cast(trade_resources, State) ->
ResourceTuples = State#state.local_resource_tuples,
AllNodes = [node() | nodes()],
lists:foreach(
fun(Node) ->
gen_server:cast({?SERVER, Node}, {trade_resources, {node(), ResourceTuples}})
end,
AllNodes),
{noreply, state}.
add_resource(Type, Resource, ResourceTuples) ->
case dict:find(Type, ResourceTuples) of
{ok, ResourceList} ->
NewList = [Resource | lists:delete(Resource, ResourceList)],
dict:store(Type, NewList, ResourceTuples);
error ->
dict:store(Type, [Resource], ResourceTuples)
end.
handle_call({fetch_resources, Type}, _From, State) ->
{reply, dict:find(Type, State#state.found_resource_tuples), State}.
add_resources([{Type, Resource} | T], ResourceTuples) ->
add_resources(T, add_resource(Type, Resource, ResourceTuples));
add_resources([], ResourceTuples) ->
ResourceTuples.
resources_for_types(Types, ResourceTuples) ->
Fun =
fun(Type, Acc) ->
case dict:find(Type, ResourceTuples) of
{ok, List} ->
[{Type, Instance} || Instance <- List] ++ Acc;
error
->
Acc
end
end,
lists:foldl(Fun, [], Types).
首先,从服务器状态中提取当前所有目标资源的类型。然后,将接收到的资源类型加入当前
的列表。。
trade_resources消息会促使本地节点上的资源探测服务器异步地向Erlang集群内所
有互联节点上的资源探测服务器发起广播(也包括本地节点自身,这种对称性使你无须额外的代
码便可以更新本地的资源匹配情况。)这些广播消息的格式为{trade_resources,[ReplyTo,Resources]},其中ReplyTo是发送方所处节点的节点名(由node()给出)Resources是一个数据结构(一个dict),内含发送方打算公布的所有资源元组。