diff options
| -rw-r--r-- | src/cache_tab.erl | 147 | ||||
| -rw-r--r-- | src/mod_shared_roster_ldap.erl | 2 | 
2 files changed, 96 insertions, 53 deletions
| diff --git a/src/cache_tab.erl b/src/cache_tab.erl index 6140453ca..11b0ea614 100644 --- a/src/cache_tab.erl +++ b/src/cache_tab.erl @@ -53,6 +53,7 @@  		miss = 0,  		procs_num,  		cache_missed, +		lru,  		shrink_size}).  -define(PROCNAME, ?MODULE). @@ -62,6 +63,7 @@  -define(MAX_SIZE, 1000).  -define(WARN, true).  -define(CACHE_MISSED, true). +-define(LRU, true).  -define(LIFETIME, 600). %% 10 minutes  %%==================================================================== @@ -109,7 +111,7 @@ delete(Tab, Key, F) ->  dirty_delete(Tab, Key, F) ->      F(),      ?GEN_SERVER:call( -       get_proc_by_hash(Tab, Key), {dirty_delete, Key}, ?CALL_TIMEOUT). +       get_proc_by_hash(Tab, Key), {cache_delete, Key}, ?CALL_TIMEOUT).  lookup(Tab, Key, F) ->      ?GEN_SERVER:call( @@ -117,20 +119,21 @@ lookup(Tab, Key, F) ->  dirty_lookup(Tab, Key, F) ->      Proc = get_proc_by_hash(Tab, Key), -    case ?GEN_SERVER:call(Proc, {dirty_lookup, Key}, ?CALL_TIMEOUT) of +    case ?GEN_SERVER:call(Proc, {cache_lookup, Key}, ?CALL_TIMEOUT) of  	{ok, '$cached_mismatch'} ->  	    error;  	{ok, Val} ->  	    {ok, Val};  	_ -> -	    case F() of -		{ok, Val} -> -		    ?GEN_SERVER:call( -		       Proc, {dirty_insert, Key, Val}, ?CALL_TIMEOUT), -		    {ok, Val}; -		_ -> -		    error -	    end +	    {Result, NewVal} = case F() of +				   {ok, Val} -> +				       {{ok, Val}, Val}; +				   _ -> +				       {error, '$cached_mismatch'} +			       end, +	    ?GEN_SERVER:call( +	       Proc, {cache_insert, Key, NewVal}, ?CALL_TIMEOUT), +	    Result      end.  insert(Tab, Key, Val, F) -> @@ -140,7 +143,7 @@ insert(Tab, Key, Val, F) ->  dirty_insert(Tab, Key, Val, F) ->      F(),      ?GEN_SERVER:call( -       get_proc_by_hash(Tab, Key), {dirty_insert, Key, Val}, ?CALL_TIMEOUT). +       get_proc_by_hash(Tab, Key), {cache_insert, Key, Val}, ?CALL_TIMEOUT).  info(Tab, Info) ->      case lists:map( @@ -187,8 +190,9 @@ init([Tab, Opts, N, Pid]) ->      {ok, do_setopts(State, Opts)}.  handle_call({lookup, Key, F}, _From, #state{tab = T} = State) -> +    CleanPrio = clean_priority(State#state.life_time),      case treap:lookup(Key, T) of -	{ok, _Prio, Val} -> +	{ok, Prio, Val} when (State#state.lru == true) or (Prio =< CleanPrio) ->  	    Hits = State#state.hits,  	    NewState = treap_update(Key, Val, State#state{hits = Hits + 1}),  	    case Val of @@ -217,50 +221,36 @@ handle_call({lookup, Key, F}, _From, #state{tab = T} = State) ->  		    end  	    end      end; -handle_call({dirty_lookup, Key}, _From, #state{tab = T} = State) -> +handle_call({cache_lookup, Key}, _From, #state{tab = T} = State) -> +    CleanPrio = clean_priority(State#state.life_time),      case treap:lookup(Key, T) of -	{ok, _Prio, Val} -> +	{ok, Prio, Val} when (State#state.lru == true) or (Prio =< CleanPrio) ->  	    Hits = State#state.hits,  	    NewState = treap_update(Key, Val, State#state{hits = Hits + 1}),  	    {reply, {ok, Val}, NewState};  	_ ->  	    Miss = State#state.miss,  	    NewState = State#state{miss = Miss + 1}, -	    if State#state.cache_missed -> -		    {reply, error, -		     treap_insert(Key, '$cached_mismatch', NewState)}; -	       true -> -		    {reply, error, NewState} -	    end +	    {reply, error, NewState}      end;  handle_call({insert, Key, Val, F}, _From, #state{tab = T} = State) ->      case treap:lookup(Key, T) of  	{ok, _Prio, Val} -> -	    {reply, ok, State}; -	Res -> +	    {reply, ok, treap_update(Key, Val, State)}; +	_ ->  	    case catch F() of  		{'EXIT', Reason} ->  		    print_error(insert, [Key, Val], Reason, State),  		    {reply, ok, State};  		_ -> -		    NewState = case Res of -				   {ok, _, _} -> -				       treap_update(Key, Val, State); -				   _ -> -				       treap_insert(Key, Val, State) -			       end, -		    {reply, ok, NewState} +		    {reply, ok, treap_insert(Key, Val, State)}  	    end      end; -handle_call({dirty_insert, Key, Val}, _From, #state{tab = T} = State) -> -    case treap:lookup(Key, T) of -	{ok, _Prio, Val} -> -	    {reply, ok, State}; -	{ok, _, _} -> -	    {reply, ok, treap_update(Key, Val, State)}; -	_ -> -	    {reply, ok, treap_insert(Key, Val, State)} -    end; +handle_call({cache_insert, _, '$cached_mismatch'}, _From, +	    #state{cache_missed = false} = State) -> +    {reply, ok, State}; +handle_call({cache_insert, Key, Val}, _From, State) -> +    {reply, ok, treap_insert(Key, Val, State)};  handle_call({delete, Key, F}, _From, State) ->      NewState = treap_delete(Key, State),      case catch F() of @@ -270,7 +260,7 @@ handle_call({delete, Key, F}, _From, State) ->  	    ok      end,      {reply, ok, NewState}; -handle_call({dirty_delete, Key}, _From, State) -> +handle_call({cache_delete, Key}, _From, State) ->      NewState = treap_delete(Key, State),      {reply, ok, NewState};  handle_call({info, Info}, _From, State) -> @@ -288,6 +278,7 @@ handle_call({info, Info}, _From, State) ->  		   {hits, State#state.hits},  		   {miss, State#state.miss},  		   {cache_missed, State#state.cache_missed}, +		   {lru, State#state.lru},  		   {warn, State#state.warn}];  	      _ ->  		  badarg @@ -372,10 +363,20 @@ do_setopts(#state{procs_num = N} = State, Opts) ->  		      _ ->  			  ?CACHE_MISSED  		  end, +    LRU = case proplists:get_value( +		 lru, Opts, State#state.lru) of +	      false -> +		  false; +	      true -> +		  true; +	      _ -> +		  ?LRU +	  end,      State#state{max_size = MaxSize,  		warn = Warn,  		life_time = LifeTime,  		cache_missed = CacheMissed, +		lru = LRU,  		shrink_size = ShrinkSize}.  get_proc_num() -> @@ -396,15 +397,36 @@ now_priority() ->      {MSec, Sec, USec} = now(),      -((MSec*1000000 + Sec)*1000000 + USec). -treap_update(Key, Val, #state{tab = T} = State) -> -    Priority = now_priority(), -    NewT = treap:insert(Key, Priority, Val, T), -    State#state{tab = NewT}. +clean_priority(LifeTime) -> +    if is_integer(LifeTime) -> +	    now_priority() + LifeTime; +       true -> +	    unlimited +    end. + +treap_update(Key, Val, #state{tab = T, lru = LRU} = State) -> +    if LRU -> +	    Priority = now_priority(), +	    NewT = treap:insert(Key, Priority, Val, T), +	    State#state{tab = NewT}; +       true -> +	    State +    end.  treap_insert(Key, Val, State) ->      State1 = clean_treap(State),      #state{size = Size} = State2 = shrink_treap(State1), -    treap_update(Key, Val, State2#state{size = Size+1}). +    T = State2#state.tab, +    case treap:lookup(Key, T) of +	{ok, _, Val} -> +	    treap_update(Key, Val, State2); +	{ok, _, _} -> +	    NewT = treap:insert(Key, now_priority(), Val, T), +	    State2#state{tab = NewT}; +	_ -> +	    NewT = treap:insert(Key, now_priority(), Val, T), +	    State2#state{tab = NewT, size = Size+1} +    end.  treap_delete(Key, #state{tab = T, size = Size} = State) ->      case treap:lookup(Key, T) of @@ -492,9 +514,9 @@ print_error(Operation, Args, Reason, State) ->  -define(lookup, dirty_lookup).  -define(delete, dirty_delete).  -define(insert, dirty_insert). -%% -define(lookup, lookup). -%% -define(delete, delete). -%% -define(insert, insert). +%%-define(lookup, lookup). +%%-define(delete, delete). +%%-define(insert, insert).  test() ->      LifeTime = 2, @@ -504,7 +526,7 @@ test() ->      check([{"key", "value"}]),      {ok, "value"} = ?lookup(test_tbl, "key", fun() -> error end),      check([{"key", "value"}]), -    io:format("** waiting for ~p seconds to check if cleaner works fine...~n", +    io:format("** waiting for ~p seconds to check if LRU works fine...~n",  	      [LifeTime+1]),      timer:sleep(timer:seconds(LifeTime+1)),      ok = ?insert(test_tbl, "key1", "value1", fun() -> ok end), @@ -531,13 +553,32 @@ test1() ->        end, lists:seq(1, MaxSize*get_proc_num())),      {ok, MaxSize} = info(test_tbl, size),      delete(test_tbl), +    test2(). + +test2() -> +    LifeTime = 2, +    ok = new(test_tbl, [{life_time, LifeTime}, +			{max_size, unlimited}, +			{lru, false}]), +    check([]), +    ok = ?insert(test_tbl, "key", "value", fun() -> ok end), +    {ok, "value"} = ?lookup(test_tbl, "key", fun() -> error end), +    check([{"key", "value"}]), +    io:format("** waiting for ~p seconds to check if non-LRU works fine...~n", +	      [LifeTime+1]), +    timer:sleep(timer:seconds(LifeTime+1)), +    error = ?lookup(test_tbl, "key", fun() -> error end), +    check([{"key", '$cached_mismatch'}]), +    ok = ?insert(test_tbl, "key", "value1", fun() -> ok end), +    check([{"key", "value1"}]), +    delete(test_tbl),      io:format("** testing speed, this may take a while...~n"), -    test2(1000), -    test2(10000), -    test2(100000), -    test2(1000000). +    test3(1000), +    test3(10000), +    test3(100000), +    test3(1000000). -test2(Iter) -> +test3(Iter) ->      ok = new(test_tbl, [{max_size, unlimited}, {life_time, unlimited}]),      L = lists:seq(1, Iter),      T1 = now(), diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index 1f8a5630b..001a5ab94 100644 --- a/src/mod_shared_roster_ldap.erl +++ b/src/mod_shared_roster_ldap.erl @@ -239,9 +239,11 @@ init([Host, Opts]) ->      State = parse_options(Host, Opts),      cache_tab:new(shared_roster_ldap_user,  		  [{max_size, State#state.user_cache_size}, +		   {lru, false}, % We don't need LRU algorithm  		   {life_time, State#state.user_cache_validity}]),      cache_tab:new(shared_roster_ldap_group,  		  [{max_size, State#state.group_cache_size}, +		   {lru, false}, % We don't need LRU algorithm  		   {life_time, State#state.group_cache_validity}]),      ejabberd_hooks:add(roster_get, Host,  		       ?MODULE, get_user_roster, 70), | 
