1%%% This program is free software; you can redistribute it and/or modify 2%%% it under the terms of the GNU General Public License as published by 3%%% the Free Software Foundation; either version 2 of the License, or 4%%% (at your option) any later version. 5%%% 6%%% This program is distributed in the hope that it will be useful, 7%%% but WITHOUT ANY WARRANTY; without even the implied warranty of 8%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9%%% GNU General Public License for more details. 10%%% 11%%% You should have received a copy of the GNU General Public License 12%%% along with this program; if not, write to the Free Software 13%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 14%%% 15%%% In addition, as a special exception, you have the permission to 16%%% link the code of this program with any library released under 17%%% the EPL license and distribute linked combinations including 18%%% the two; the MPL (Mozilla Public License), which EPL (Erlang 19%%% Public License) is based on, is included in this exception. 20 21%%%------------------------------------------------------------------- 22%%% File : ts_session_cache.erl 23%%% Author : Nicolas Niclausse <nniclausse@niclux.org> 24%%% Description : cache sessions request from ts_config_server 25%%% 26%%% Created : 2 Dec 2003 by Nicolas Niclausse <nicolas@niclux.org> 27%%%------------------------------------------------------------------- 28 29 30-module(ts_mon_cache). 31 32-behaviour(gen_server). 33%%-------------------------------------------------------------------- 34%% Include files 35%%-------------------------------------------------------------------- 36 37%%-------------------------------------------------------------------- 38%% External exports 39-export([start/0, add/1, add_match/2, dump/1]). 40 41%% gen_server callbacks 42-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, 43 code_change/3]). 44 45 46-record(state, { 47 stats=[], % cache stats msgs 48 transactions=[], % cache transaction stats msgs 49 pages=[], % cache pages stats msgs 50 requests=[], % cache requests stats msgs 51 connections=[], % cache connect stats msgs 52 match=[], % cache match logs 53 protocol=[], % cache dump=protocol data 54 sum % cache sum stats msgs 55 }). 56 57 58-include("ts_config.hrl"). 59 60%%==================================================================== 61%% External functions 62%%==================================================================== 63%%-------------------------------------------------------------------- 64%% Function: start_link/0 65%% Description: Starts the server 66%%-------------------------------------------------------------------- 67start() -> 68 ?LOG("Starting~n",?INFO), 69 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 70 71%%-------------------------------------------------------------------- 72%% Function: add/1 73%% Description: Add stats data. Will be accumulated sent periodically 74%% to ts_mon 75%%-------------------------------------------------------------------- 76add(Data) -> 77 gen_server:cast(?MODULE, {add, Data}). 78 79%% @spec add_match(Data::list(),{UserId::integer(),SessionId::integer(),RequestId::integer(), 80%% TimeStamp::tuple(),Transactions::list(),Name::atom()}) -> ok; 81%% (Data::list(),{UserId::integer(),SessionId::integer(),RequestId::integer(), 82%% TimeStamp::tuple(),Bin::list(),Transactions::list(),Name::atom()}) -> ok. 83add_match(Data,{UserId,SessionId,RequestId,Tr,Name}) -> 84 add_match(Data,{UserId,SessionId,RequestId,[],Tr,Name}); 85add_match(Data,{UserId,SessionId,RequestId,Bin,Tr,Name}) -> 86 TimeStamp=?TIMESTAMP, 87 add_match(Data,{UserId,SessionId,RequestId,TimeStamp,Bin,Tr,Name}); 88add_match(Data=[Head|_],{UserId,SessionId,RequestId,TimeStamp,Bin,Tr,Name}) -> 89 put(last_match,Head), 90 gen_server:cast(?MODULE, {add_match, Data, {UserId,SessionId,RequestId,TimeStamp,Bin,Tr,Name}}). 91 92 93%% @spec dump({Type, Who, What}) -> ok @end 94dump({none, _, _}) -> skip; 95dump({_Type, Who, What}) -> 96 gen_server:cast(?MODULE, {dump, Who, ?TIMESTAMP, What}). 97 98%%==================================================================== 99%% Server functions 100%%==================================================================== 101 102%%-------------------------------------------------------------------- 103%% Function: init/1 104%% Description: Initiates the server 105%% Returns: {ok, State} | 106%% {ok, State, Timeout} | 107%% ignore | 108%% {stop, Reason} 109%%-------------------------------------------------------------------- 110init([]) -> 111 erlang:start_timer(?CACHE_DUMP_STATS_INTERVAL, self(), dump_stats ), 112 {ok, #state{sum=dict:new()}}. 113 114%%-------------------------------------------------------------------- 115%% Function: handle_call/3 116%% Description: Handling call messages 117%% Returns: {reply, Reply, State} | 118%% {reply, Reply, State, Timeout} | 119%% {noreply, State} | 120%% {noreply, State, Timeout} | 121%% {stop, Reason, Reply, State} | (terminate/2 is called) 122%% {stop, Reason, State} (terminate/2 is called) 123%%-------------------------------------------------------------------- 124handle_call(_Request, _From, State) -> 125 Reply = ok, 126 {reply, Reply, State}. 127 128%%-------------------------------------------------------------------- 129%% Function: handle_cast/2 130%% Description: Handling cast messages 131%% Returns: {noreply, State} | 132%% {noreply, State, Timeout} | 133%% {stop, Reason, State} (terminate/2 is called) 134%%-------------------------------------------------------------------- 135handle_cast({add, Data}, State) when is_list(Data) -> 136 LastState = lists:foldl(fun(NewData,NewState)-> 137 update_stats(NewData,NewState) 138 end, State, Data), 139 {noreply, LastState }; 140handle_cast({add, Data}, State) when is_tuple(Data) -> 141 {noreply,update_stats(Data, State)}; 142handle_cast({add_match, Data=[First|_Tail],{UserId,SessionId,RequestId,TimeStamp,Bin,Tr,Name}}, 143 State=#state{stats=List, match=MatchList})-> 144 NewMatchList=lists:append([{UserId,SessionId,RequestId,TimeStamp,First, Bin, Tr,Name}], MatchList), 145 {noreply, State#state{stats = lists:append(Data, List), match = NewMatchList}}; 146 147handle_cast({dump, Who, When, What}, State=#state{protocol=Cache}) -> 148 Log = io_lib:format("~w;~w;~s~n",[ts_utils:time2sec_hires(When),Who,What]), 149 {noreply, State#state{protocol=[Log|Cache]}}; 150 151handle_cast(_Msg, State) -> 152 {noreply, State}. 153 154%%-------------------------------------------------------------------- 155%% Function: handle_info/2 156%% Description: Handling all non call/cast messages 157%% Returns: {noreply, State} | 158%% {noreply, State, Timeout} | 159%% {stop, Reason, State} (terminate/2 is called) 160%%-------------------------------------------------------------------- 161handle_info({timeout, _Ref, dump_stats}, State =#state{protocol=ProtocolData, stats= Stats, match=MatchList}) -> 162 Fun = fun(Key,Val, Acc) -> [{sum,Key,Val}| Acc] end, 163 NewStats=dict:fold(Fun, Stats, State#state.sum), 164 ts_stats_mon:add(NewStats), 165 ts_stats_mon:add(State#state.requests,request), 166 ts_stats_mon:add(State#state.connections,connect), 167 ts_stats_mon:add(State#state.transactions,transaction), 168 ts_stats_mon:add(State#state.pages,page), 169 ts_mon:dump({cached, list_to_binary(lists:reverse(ProtocolData))}), 170 ts_match_logger:add(MatchList), 171 erlang:start_timer(?CACHE_DUMP_STATS_INTERVAL, self(), dump_stats ), 172 {noreply, State#state{protocol=[],stats=[],match=[],pages=[],requests=[],transactions=[],connections=[],sum=dict:new()}}; 173 174handle_info(_Info, State) -> 175 {noreply, State}. 176 177%%-------------------------------------------------------------------- 178%% Function: terminate/2 179%% Description: Shutdown the server 180%% Returns: any (ignored by gen_server) 181%%-------------------------------------------------------------------- 182terminate(Reason, _State) -> 183 ?LOGF("Die ! (~p)~n",[Reason],?ERR), 184 ok. 185 186%%-------------------------------------------------------------------- 187%% Func: code_change/3 188%% Purpose: Convert process state when code is changed 189%% Returns: {ok, NewState} 190%%-------------------------------------------------------------------- 191code_change(_OldVsn, State, _Extra) -> 192 {ok, State}. 193 194 195update_stats({sample, request, Val}, State=#state{requests=L}) -> 196 State#state{requests=lists:append([Val],L)}; 197 198update_stats({sample, page, Val}, State=#state{pages=L}) -> 199 State#state{pages=lists:append([Val],L)}; 200 201update_stats({sample, connect, Val}, State=#state{connections=L}) -> 202 State#state{connections=lists:append([Val],L)}; 203 204update_stats(S={sample, _Type, _}, State=#state{transactions=L}) -> 205 State#state{transactions=lists:append([S],L)}; 206 207update_stats({sum, Type, Val}, State=#state{sum=Sum}) -> 208 NewSum=dict:update_counter(Type,Val,Sum), 209 State#state{sum=NewSum}; 210update_stats({count, Type}, State=#state{sum=Sum}) -> 211 NewSum=dict:update_counter(Type,1,Sum), 212 State#state{sum=NewSum}; 213update_stats(Data, State=#state{stats=L}) when is_tuple(Data)-> 214 State#state{stats=lists:append([Data],L)}. 215 216 217