Erlang/OTP并发编程实例(二)

来源:互联网 发布:ubuntu 16.04应用商店 编辑:程序博客网 时间:2024/04/30 02:34

第七章 添加了自定义消息流的简单缓存系统

simple_cache.app应用系统元数据

{application, simple_cache,[{description, "A simple cacheing system"},{vsn, "0.1.0"},{modules, [sc_app,sc_sup,sc_element_sup,sc_element,sc_store,sc_event,sc_event_logger,simple_cache]},          %% 此处也可以写少于实际的模块名{registered, [sc_sup, sc_element_sup, sc_event]},%% 感觉此处可以随便写,不影响运行和结果{applications, [kernel, stdlib, sasl]},{mod, {sc_app, []}}]}.

sc_app.erl

-module(sc_app).-behaviour(application).%% ====================================================================%% API functions%% ====================================================================-export([start/2, stop/1]).%% ====================================================================%% Internal functions%% ====================================================================start(_startType, _startArgs) ->sc_store:init(),case sc_sup:start_link() of%% 启动顶层监督者进程{ok, Pid} ->sc_event_logger:add_handler(),%% 添加自定义事件处理器{ok, Pid};Other ->{error, Other}end.stop(_State) ->ok.

sc_element.erl

-module(sc_element).%% ====================================================================%% API functions%% ====================================================================-behaviour(gen_server).-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).-export([start_link/2, create/1, create/2, fetch/1, replace/2, delete/1]).-define(DEF_LEASE_TIME, 60).-record(proState, {value, lease_time, start_time}).%% ====================================================================%% Internal functions%% ====================================================================start_link(Value, LeaseTime) ->gen_server:start_link(?MODULE, [Value, LeaseTime], []).%% ????????create(Value) ->create(Value, ?DEF_LEASE_TIME).create(Value, LeaseTime) ->sc_element_sup:start_child(Value, LeaseTime).%% 注意此处修改为sc_element_supfetch(Pid) ->gen_server:call(Pid, fetch).replace(Pid, Value) ->gen_server:cast(Pid, {replace, Value}).delete(Pid) ->gen_server:cast(Pid, delete).%% ====================================================================%% Extra functions %% ====================================================================%% 判断距离超时还有多少毫秒time_left(_Time, infinity) ->infinity;time_left(StartTime, LeaseTime) ->Now = calendar:local_time(),CurTime = calendar:datetime_to_gregorian_seconds(Now),TimeElapsed = CurTime - StartTime,case LeaseTime - TimeElapsed ofTime when Time =< 0 ->0;Time ->Time * 1000end.%% ====================================================================%% Behavioural functions %% ====================================================================init([Value, LeaseTime]) ->Now = calendar:local_time(),StartTime = calendar:datetime_to_gregorian_seconds(Now),TimeLeft = time_left(StartTime, LeaseTime),{ok, #proState{value = Value, lease_time = LeaseTime, start_time = StartTime}, TimeLeft}.handle_call(fetch, _From, State) ->#proState{value = Value, lease_time = LeaseTime, start_time = StartTime} = State,TimeLeft = time_left(StartTime, LeaseTime),{reply, {ok, Value}, State, TimeLeft}.handle_cast({replace, Value}, State) ->#proState{lease_time = LeaseTime, start_time = StartTime} = State,TimeLeft = time_left(StartTime, LeaseTime),{noreply, State#proState{value = Value}, TimeLeft};handle_cast(delete, State) ->{stop, normal, State}.handle_info(timeout, State) ->{stop, normal, State}.terminate(_Reason, _State) ->sc_store:delete(self()).code_change(_OldVsn, State, _ExtraCondition) ->{ok, State}.

sc_element_sup.erl

-module(sc_element_sup).-behaviour(supervisor).-export([init/1]).%% ====================================================================%% API functions%% ====================================================================-export([start_link/0, start_child/2]).%% ====================================================================%% Behavioural functions %% ====================================================================init([]) ->    AChild = {sc_element,    {sc_element,start_link,[]},      temporary,      brutal_kill,      worker,      [sc_element]},Children = [AChild],Strategy = {simple_one_for_one, 0, 1},    {ok,{Strategy, Children}}.%% ====================================================================%% Internal functions%% ====================================================================start_link() ->supervisor:start_link({local, ?MODULE}, ?MODULE, []).start_child(Value, LeaseTime) ->supervisor:start_child(?MODULE, [Value, LeaseTime]).

sc_event.erl

-module(sc_event).-export([start_link/0, add_handler/2, delete_handler/2, lookup/1, replace/2, create/2, delete/1]).%% ====================================================================%% Internal functions%% ====================================================================start_link() ->gen_event:start_link({local, ?MODULE}).add_handler(Handler, Args) ->gen_event:add_handler(?MODULE, Handler, Args).delete_handler(Handler, Args) ->gen_event:delete_handler(?MODULE, Handler, Args).lookup(Key) ->gen_event:notify(?MODULE, {lookup, Key}).replace(Key, Value) ->gen_event:notify(?MODULE, {replay, {Key, Value}}).create(Key, Value) ->gen_event:notify(?MODULE, {create, {Key, Value}}).delete(Key) ->gen_event:notify(?MODULE, {delete, Key}).

sc_event_logger.erl

-module(sc_event_logger).-behaviour(gen_event).-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).-export([add_handler/0, delete_handler/0]).-record(proState, {}).%% ====================================================================%% Internal functions%% ====================================================================add_handler() ->sc_event:add_handler(?MODULE, []).delete_handler() ->sc_event:delete_handler(?MODULE, []).%% ====================================================================%% Behavioural functions %% ====================================================================init([]) ->{ok, #proState{}}.handle_event({create, {Key, Value}}, State) ->error_logger:info_msg("创建缓存数据(~w, ~w)~n", [Key, Value]),%% 在shell中无法显示中文{ok, State};handle_event({lookup, Key}, State) ->error_logger:info_msg("lookup(~w)~n", [Key]),{ok, State};handle_event({replace, {Key, Value}}, State) ->error_logger:info_msg("replace(~w, ~w)~n", [Key, Value]),{ok, State};handle_event({delete, Key}, State) ->error_logger:info_msg("delete(~w)~n", [Key]),{ok, State}.handle_call(_Request, State) ->Reply = ok,{ok, Reply, State}.handle_info(_Info, State) ->{ok, State}.terminate(_Reason, _State) ->ok.code_change(_OldVsn, State, _ExtraCondition) ->{ok, State}.

sc_store.erl

%% @author Administrator%% @doc @todo Add description to sc_store.-module(sc_store).%% ====================================================================%% API functions%% ====================================================================-export([init/0, lookup/1, insert/2, delete/1]).-define(TABLE_ID, ?MODULE).%% ====================================================================%% Internal functions%% ====================================================================init() ->ets:new(?TABLE_ID, [named_table, public]),ok.lookup(Key) ->case ets:lookup(?TABLE_ID, Key) of[{Key, Pid}] -> {ok, Pid};[] -> {error, not_found}end.insert(Key, Pid) ->ets:insert(?TABLE_ID, {Key, Pid}).delete(Key) ->ets:match_delete(?TABLE_ID, {'_', Key}).

sc_sup.erl

%% @author Administrator%% @doc @todo Add description to sc_sup.-module(sc_sup).-behaviour(supervisor).-export([init/1]).%% ====================================================================%% API functions%% ====================================================================-export([start_link/0, start_child/2]).%% ====================================================================%% Behavioural functions %% ====================================================================init([]) ->    ElementSupervisor = {sc_element_sup,%% 注意此处是sc_element_sup    {sc_element_sup,start_link,[]},%% 注意此处是sc_element_sup,如果还是sc_element则会导致信息不详的错误提示      permanent,%% 重启策略修改了      2000,%% 关闭时间修改了      supervisor,%% 类型修改了      [sc_element]},%% 注意此处是sc_elementEventSupervisor = {sc_event,{sc_event, start_link, []},permanent,2000,worker,[sc_event]},      Children = [ElementSupervisor, EventSupervisor],Strategy = {one_for_one, 4, 3600},    {ok,{Strategy, Children}}.%% ====================================================================%% Internal functions%% ====================================================================start_link() ->supervisor:start_link({local, ?MODULE}, ?MODULE, []).start_child(Value, LeaseTime) ->supervisor:start_child(?MODULE, [Value, LeaseTime]).

simple_cache.erl

%% @author Administrator%% @doc @todo Add description to simple_cache.-module(simple_cache).%% ====================================================================%% API functions%% ====================================================================-export([lookup/1, insert/2, delete/1]).%% ====================================================================%% Internal functions%% ====================================================================lookup(Key) ->try{ok, Pid} = sc_store:lookup(Key),{ok, Value} = sc_element:fetch(Pid),sc_event:lookup(Key),{ok, Value}catch_Class:_Exception ->{error, not_found}end.insert(Key, Value) ->case sc_store:lookup(Key) of{ok, Pid}  -> sc_element:replace(Pid, Value),sc_event:replace(Key, Value);{error, _} -> {ok, Pid} = sc_element:create(Value),sc_store:insert(Key, Pid),sc_event:create(Key, Value)%% 投递自定义的创建事件end.delete(Key) ->case sc_store:lookup(Key) of{ok, Pid} ->sc_element:delete(Pid),sc_event:delete(Key);{error, _Reason} ->okend.


0 0
原创粉丝点击