mirror of
https://github.com/valitydev/cache.git
synced 2024-11-06 01:45:19 +00:00
add cache select (based on ets select + match spec)
This commit is contained in:
parent
3e078d11b8
commit
da059104f8
7
Makefile
7
Makefile
@ -46,12 +46,7 @@ rebar:
|
||||
chmod ugo+x rebar
|
||||
|
||||
benchmark:
|
||||
$(BB)/basho_bench -N bb@127.0.0.0 -C nocookie -J ${id}@127.0.0.1 priv/${id}.benchmark
|
||||
$(BB)/basho_bench -N bb@127.0.0.0 -C nocookie priv/${id}.benchmark
|
||||
$(BB)/priv/summary.r -i tests/current
|
||||
open tests/current/summary.png
|
||||
|
||||
# benchmark:
|
||||
# $(BB)/basho_bench -N bb@127.0.0.0 -C nocookie -J ${id}@127.0.0.1 priv/${id}.benchmark
|
||||
# $(BB)/priv/summary.r -i tests/current
|
||||
# open tests/current/summary.png
|
||||
|
||||
|
@ -6,14 +6,15 @@
|
||||
%%
|
||||
%% workload
|
||||
{mode, max}.
|
||||
{duration, 5}.
|
||||
{duration, 1}.
|
||||
{concurrent, 10}.
|
||||
{key_generator, {uniform_int, 1000000}}.
|
||||
{value_generator, {fixed_bin, 1000}}.
|
||||
{value_generator, {fixed_bin, 1000}}.
|
||||
|
||||
{operations, [
|
||||
{put, 5}
|
||||
,{get, 5}
|
||||
% ,{select, 1}
|
||||
]}.
|
||||
|
||||
%{cache, {mycache, 'cache@127.0.0.1'}}.
|
||||
|
@ -1,7 +1,7 @@
|
||||
{application, cache,
|
||||
[
|
||||
{description, "in-memory cache"},
|
||||
{vsn, "0.10.0"},
|
||||
{vsn, "0.11.0"},
|
||||
{modules, [
|
||||
cache,
|
||||
cache_bucket,
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
-include("cache.hrl").
|
||||
|
||||
-export([start/0]).
|
||||
-export([
|
||||
start_link/2,
|
||||
drop/1,
|
||||
@ -50,6 +51,8 @@
|
||||
remove_/2,
|
||||
acc/3,
|
||||
acc_/3,
|
||||
select/2,
|
||||
fold/4,
|
||||
% memecached like interface
|
||||
set/3,
|
||||
set/4,
|
||||
@ -79,6 +82,12 @@
|
||||
-type(entity() :: any()).
|
||||
-type(ttl() :: integer()).
|
||||
|
||||
%%
|
||||
%% RnD start application
|
||||
start() ->
|
||||
application:start(pq),
|
||||
application:start(cache).
|
||||
|
||||
%%
|
||||
%% start new cache bucket, accepted options:
|
||||
%% {policy, lru | mru} - cache eviction policy
|
||||
@ -230,6 +239,61 @@ acc(Cache, Key, Val) ->
|
||||
acc_(Cache, Key, Val) ->
|
||||
gen_server:cast(Cache, {acc, Key, Val}).
|
||||
|
||||
%%
|
||||
%% query cache segments using match specification
|
||||
%% e.g.
|
||||
%% -include_lib("stdlib/include/ms_transform.hrl").
|
||||
%% cache:select(cache, ets:fun2ms(fun(X) -> X end)).
|
||||
-spec(select/2 :: (cache(), function() | any()) -> {[any()], any()}).
|
||||
|
||||
select(Cache, {q, [Head|Tail], Req}) ->
|
||||
%% compiled query
|
||||
try
|
||||
case ets:select(Head, Req, ?CONFIG_SELECT) of
|
||||
'$end_of_table' ->
|
||||
select(Cache, {q, Tail, Req});
|
||||
{Result, Query} ->
|
||||
{Result, {q, Tail, Req, Query}}
|
||||
end
|
||||
catch _:badarg ->
|
||||
%% cache segment was evicted
|
||||
select(Cache, {q, Tail, Req})
|
||||
end;
|
||||
|
||||
select(_Cache, {q, [], _}=Req) ->
|
||||
{eof, Req};
|
||||
|
||||
select(Cache, {q, Heap, Req, '$end_of_table'}) ->
|
||||
select(Cache, {q, Heap, Req});
|
||||
|
||||
select(Cache, {q, Heap, Req, Query0}) ->
|
||||
try
|
||||
case ets:select(Query0) of
|
||||
'$end_of_table' ->
|
||||
select(Cache, {q, Heap, Req});
|
||||
{Result, Query} ->
|
||||
{Result, {q, Heap, Req, Query}}
|
||||
end
|
||||
catch _:badarg ->
|
||||
%% cache segment was evicted
|
||||
select(Cache, {q, Heap, Req})
|
||||
end;
|
||||
|
||||
select(Cache, Req) ->
|
||||
select(Cache, {q, lists:reverse(i(Cache, heap)), Req}).
|
||||
|
||||
|
||||
%%
|
||||
%% query cache segments and fold function
|
||||
-spec(fold/4 :: (function(), any(), function(), cache()) -> any()).
|
||||
|
||||
fold(Fun, Acc, Req, Cache) ->
|
||||
case select(Cache, Req) of
|
||||
{eof, _} ->
|
||||
Acc;
|
||||
{List, Query} ->
|
||||
fold(Fun, lists:foldl(Fun, Acc, List), Query, Cache)
|
||||
end.
|
||||
|
||||
%%%----------------------------------------------------------------------------
|
||||
%%%
|
||||
|
@ -14,6 +14,11 @@
|
||||
%% limitations under the License.
|
||||
%%
|
||||
|
||||
%%
|
||||
%% define default select limit
|
||||
-define(CONFIG_SELECT, 1000).
|
||||
|
||||
|
||||
%-define(VERBOSE, true).
|
||||
-ifdef(VERBOSE).
|
||||
-define(DEBUG(Str, Args), error_logger:error_msg(Str, Args)).
|
||||
|
@ -18,6 +18,8 @@
|
||||
-module(cache_benchmark).
|
||||
-author('Dmitry Kolesnikov <dmkolesnikov@gmail.com>').
|
||||
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
-export([new/1, run/4]).
|
||||
|
||||
%%
|
||||
@ -43,7 +45,7 @@ run(put, KeyGen, ValGen, Cache) ->
|
||||
E -> {error, failure(p, Key, E), Cache}
|
||||
end;
|
||||
|
||||
run(get, KeyGen, _ValueGen, Cache) ->
|
||||
run(get, KeyGen, _ValGen, Cache) ->
|
||||
Key = KeyGen(),
|
||||
case (catch cache:get(Cache, Key)) of
|
||||
Val when is_binary(Val) -> {ok, Cache};
|
||||
@ -51,17 +53,28 @@ run(get, KeyGen, _ValueGen, Cache) ->
|
||||
E -> {error, failure(g, Key, E), Cache}
|
||||
end;
|
||||
|
||||
run(remove, KeyGen, _ValueGen, Cache) ->
|
||||
run(remove, KeyGen, _ValGen, Cache) ->
|
||||
Key = KeyGen(),
|
||||
case (catch cache:remove(cache, Key)) of
|
||||
ok -> {ok, Cache};
|
||||
E -> {error, failure(r, Key, E), Cache}
|
||||
end.
|
||||
end;
|
||||
|
||||
run(select, KeyGen, _ValGen, Cache) ->
|
||||
Key0 = KeyGen(),
|
||||
Key1 = KeyGen(),
|
||||
cache:fold(
|
||||
fun(_, Acc) -> Acc + 1 end,
|
||||
0,
|
||||
ets:fun2ms(fun({Key, Val}) when Key > Key0, Key < Key1 -> Key end),
|
||||
cache
|
||||
),
|
||||
{ok, Cache}.
|
||||
|
||||
|
||||
%%
|
||||
local_init() ->
|
||||
case application:start(cache) of
|
||||
case cache:start() of
|
||||
{error, {already_started, _}} ->
|
||||
cache;
|
||||
ok ->
|
||||
|
56
src/cache_bucket_sup.erl
Normal file
56
src/cache_bucket_sup.erl
Normal file
@ -0,0 +1,56 @@
|
||||
%%
|
||||
%% Copyright 2012 Dmitry Kolesnikov, All Rights Reserved
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%
|
||||
%% @description
|
||||
%% root cache supervisor
|
||||
-module(cache_bucket_sup).
|
||||
-behaviour(supervisor).
|
||||
-author('Dmitry Kolesnikov <dmkolesnikov@gmail.com>').
|
||||
-author('Jose Luis Navarro <jlnavarro@gmail.com>').
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
%%
|
||||
-define(CHILD(Type, I), {I, {I, start_link, []}, permanent, 5000, Type, dynamic}).
|
||||
-define(CHILD(Type, I, Args), {I, {I, start_link, Args}, permanent, 5000, Type, dynamic}).
|
||||
-define(CHILD(Type, ID, I, Args), {ID, {I, start_link, Args}, permanent, 5000, Type, dynamic}).
|
||||
|
||||
%% ===================================================================
|
||||
%% API functions
|
||||
%% ===================================================================
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%% ===================================================================
|
||||
%% Supervisor callbacks
|
||||
%% ===================================================================
|
||||
|
||||
init([]) ->
|
||||
{ok,
|
||||
{
|
||||
{one_for_one, 4, 1800},
|
||||
[?CHILD(worker, Name, cache, [Name, Opts]) || {Name, Opts} <- default_cache()]
|
||||
}
|
||||
}.
|
||||
|
||||
%%
|
||||
%% list of default cache specification
|
||||
default_cache() ->
|
||||
proplists:delete(included_applications, application:get_all_env()).
|
@ -26,17 +26,17 @@
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
%%
|
||||
-define(CHILD(Type, I), {I, {I, start_link, []}, permanent, 5000, Type, dynamic}).
|
||||
-define(CHILD(Type, I, Args), {I, {I, start_link, Args}, permanent, 5000, Type, dynamic}).
|
||||
-define(CHILD(Type, ID, I, Args), {ID, {I, start_link, Args}, permanent, 5000, Type, dynamic}).
|
||||
|
||||
%% ===================================================================
|
||||
%% API functions
|
||||
%% ===================================================================
|
||||
|
||||
start_link() ->
|
||||
{ok, Sup} = supervisor:start_link({local, ?MODULE}, ?MODULE, []),
|
||||
lists:foreach(
|
||||
fun default_cache/1,
|
||||
proplists:delete(included_applications, application:get_all_env())
|
||||
),
|
||||
{ok, Sup}.
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%% ===================================================================
|
||||
%% Supervisor callbacks
|
||||
@ -46,15 +46,9 @@ init([]) ->
|
||||
{ok,
|
||||
{
|
||||
{one_for_one, 4, 1800},
|
||||
[]
|
||||
[
|
||||
?CHILD(supervisor, cache_bucket_sup)
|
||||
]
|
||||
}
|
||||
}.
|
||||
|
||||
%%
|
||||
%% create default cache
|
||||
default_cache({Name, Opts}) ->
|
||||
{ok, _} = supervisor:start_child(?MODULE, {
|
||||
Name,
|
||||
{cache, start_link, [Name, Opts]},
|
||||
permanent, 900000, worker, dynamic
|
||||
}).
|
||||
|
Loading…
Reference in New Issue
Block a user