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

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

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_sup

fetch(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 of
		Time when Time =< 0 ->	0;
		Time 				->	Time * 1000
	end.

%% ====================================================================
%% 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_element
	EventSupervisor = {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} ->
			ok
	end.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值