diff --git a/.gitignore b/.gitignore index c6189e7..d266e47 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ doc/edoc-info doc/doc tests/ /erl_cache +/_build +/.erl_cache.plt +/TEST* +/rebar.lock diff --git a/.travis.yml b/.travis.yml index 1aded7a..204d6b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,4 @@ before_install: script: "make get-deps compile test docs" otp_release: - - 17.0 - - R16B03-1 - - R16B02 - - R16B01 - - R15B03 - - R15B02 - - R15B01 + - 23.3.1 diff --git a/Makefile b/Makefile index 668403a..3c30691 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ -REBAR ?= rebar +REBAR ?= rebar3 ifneq ($(wildcard rebar),) - REBAR := ./rebar + REBAR := ./rebar3 endif -.PHONY: clean test docs benchmark docsclean go quick dialyzer +.PHONY: clean test docs docsclean go compile get-deps dialyzer all: get-deps compile @@ -11,36 +11,26 @@ get-deps: $(REBAR) get-deps compile: - $(REBAR) compile - $(REBAR) skip_deps=true xref - -quick: - $(REBAR) skip_deps=true compile - $(REBAR) skip_deps=true xref + $(REBAR) compile xref clean: $(REBAR) clean - rm -f erl_cache + rm -fr _build test: compile - $(REBAR) skip_deps=true eunit + $(REBAR) eunit --cover docs: docsclean - ln -s . doc/doc - $(REBAR) skip_deps=true doc + $(REBAR) edoc docsclean: rm -f doc/*.html doc/*.css doc/erlang.png doc/edoc-info doc/doc go: - erl -name erl_cache -pa deps/*/ebin -pa ebin/ -s erl_cache start ${EXTRA_ARGS} - -dialyzer: - dialyzer -c ebin/ -Wunmatched_returns -Werror_handling -Wrace_conditions + $(REBAR) shell -erl_cache: - REBAR_BENCH=1 $(REBAR) get-deps compile - REBAR_BENCH=1 $(REBAR) escriptize skip_deps=true +.erl_cache.plt: + dialyzer --output_plt $@ --build_plt --apps erts kernel stdlib -benchmark: erl_cache quick - ./erl_cache priv/bench.conf +dialyzer: .erl_cache.plt compile + dialyzer --plt $< -c _build/default/deps/erl_cache/ebin/ -Wunknown -Wunmatched_returns diff --git a/README.md b/README.md index f0ff50f..47e9373 100644 --- a/README.md +++ b/README.md @@ -152,20 +152,3 @@ running out of the configured memory for the cache ets. The memory control mechanism is not accurate and doesn't deal properly with cached large binaries, since the cache ets will only store references to them and it's not possible to figure the exact size of the referenced binaries. - -
-$ make benchmark- -In order to render the results (gnuplot is needed): -
-
-$ ./deps/basho_bench/priv/gp_throughput.sh -- -For full usage guide please consult basho bench -documentation. diff --git a/include/logging.hrl b/include/logging.hrl deleted file mode 100644 index b1b3c4e..0000000 --- a/include/logging.hrl +++ /dev/null @@ -1,11 +0,0 @@ -%%============================================================================ -%% Logging convenience functions -%%============================================================================ - --define(DEBUG(Msg, Args), _ = lager:log(debug, self(), Msg, Args)). --define(INFO(Msg, Args), _ = lager:log(info, self(), Msg, Args)). --define(NOTICE(Msg, Args), _ = lager:log(notice, self(), Msg, Args)). --define(WARNING(Msg, Args), _ = lager:log(warning, self(), Msg, Args)). --define(ERROR(Msg, Args), _ = lager:log(error, self(), Msg, Args)). - - diff --git a/priv/bench.conf b/priv/bench.conf deleted file mode 100644 index b457b79..0000000 --- a/priv/bench.conf +++ /dev/null @@ -1,10 +0,0 @@ -{driver, erl_cache_driver}. - -{duration, 3}. -{report_interval, 3}. - -{concurrent, 128}. -{mode, max}. - -{operations, [{set, 1}, {get, 99}]}. - diff --git a/rebar.config b/rebar.config index ef99315..e19b9f5 100644 --- a/rebar.config +++ b/rebar.config @@ -5,7 +5,6 @@ {cover_print_enabled,true}. {deps,[ - {lager,[],{git,"git://github.com/spilgames/lager.git",{tag,"2.0.3"}}}, {decorator_pt,[],{git,"git://github.com/spilgames/erl-decorator-pt.git",{tag,"1.0.2"}}} ]}. @@ -15,17 +14,4 @@ {eunit_opts,[verbose,{report,{eunit_surefire,[{dir,"."}]}}]}. -{xref_checks,[undefined_function_calls]}. - -{escript_incl_apps, [ - basho_bench, - - % Copied from basho_bench/rebar.config - lager, getopt, bear, folsom, ibrowse, riakc, riak_pb, mochiweb, - protobuffs, velvet, goldrush -]}. - -{erl_opts, [{platform_define, "17|18", 'namespace_types'}, - debug_info, - {src_dirs, [src]}, - {parse_transform, lager_transform}]}. +{erl_opts, [debug_info, {i, "include"}, {src_dirs, [src]}]}. diff --git a/rebar.config.script b/rebar.config.script deleted file mode 100644 index 7f2f18e..0000000 --- a/rebar.config.script +++ /dev/null @@ -1,16 +0,0 @@ -ExtraDeps = [ - {basho_bench, "", {git, "git://github.com/spilgames/basho_bench.git", {tag, "0.1-56-g3d5c35d386f4"}}} -], - -case os:getenv("REBAR_BENCH") of - false -> - CONFIG; - _ -> - C1 = case lists:keysearch(deps, 1, CONFIG) of - {value, {deps, Deps}} -> - NDeps = ExtraDeps ++ Deps, - lists:keyreplace(deps, 1, CONFIG, {deps, NDeps}); - false -> - CONFIG ++ [{deps, ExtraDeps}] - end -end. diff --git a/src/erl_cache.app.src b/src/erl_cache.app.src index 6693fa5..b35d8bf 100644 --- a/src/erl_cache.app.src +++ b/src/erl_cache.app.src @@ -5,8 +5,7 @@ {registered, []}, {applications, [ kernel, - stdlib, - lager + stdlib ]}, {mod, { erl_cache_app, []}}, {env, []} diff --git a/src/erl_cache.erl b/src/erl_cache.erl index afc09ad..fe82d6e 100644 --- a/src/erl_cache.erl +++ b/src/erl_cache.erl @@ -3,12 +3,7 @@ -behaviour(gen_server). -include("erl_cache.hrl"). --include("logging.hrl"). - -%% ================================================================== -%% Escript API -%% ================================================================== --export([main/1]). +-include_lib("kernel/include/logger.hrl"). %% ================================================================== %% API Function Exports @@ -26,11 +21,6 @@ evict/2, evict/3 ]). --ignore_xref([ - {basho_bench, main, 1} -]). - - -type name() :: atom(). %% The identifeir for a cache server -type key() :: term(). %% The identifier for a cache entry -type value() :: term().%% The value associated with a cache key @@ -59,7 +49,6 @@ -type key_generation_module()::atom(). %% A module implementing the erl_cache_key_generator behaviour. --type cache_get_opt()::{wait_for_refresh, wait_for_refresh()}. -type cache_size()::non_neg_integer(). %% Soft limit to the cache size in MB -type cache_server_opt():: @@ -67,6 +56,7 @@ %% innaccurate when working with large binaries! | {mem_check_interval, pos_integer()}. +-type cache_get_opt()::{wait_for_refresh, wait_for_refresh()}. -type cache_set_opt() :: {validity, validity()} | {evict, evict()} | @@ -76,6 +66,7 @@ {is_error_callback, is_error_callback()} | {refresh_callback, refresh_callback()}. -type cache_evict_opt() :: {wait_until_done, wait_until_done()}. +-type decorator_opts()::[cache_get_opt() | cache_set_opt()]. -type cache_opts()::[cache_get_opt() | cache_set_opt() | cache_evict_opt() | {evict_interval, evict_interval()} | cache_server_opt()]. @@ -84,15 +75,16 @@ {miss, non_neg_integer()}. -type cache_stats()::[cache_stat()]. --type config_key()::validity | evict | refresh_callback | wait_for_refresh - | wait_until_done | evict_interval | is_error_callback | error_validity. +-type config_key()::validity | evict | refresh_callback | wait_for_refresh | max_cache_size + | wait_until_done | evict_interval | is_error_callback | error_validity + | mem_check_interval | key_generation. --type callback() :: function() | mfa(). +-type callback() :: function() | {atom(), atom(), [term()]}. -export_type([ name/0, key/0, value/0, validity/0, evict/0, evict_interval/0, refresh_callback/0, cache_stats/0, wait_for_refresh/0, wait_until_done/0, error_validity/0, is_error_callback/0, - cache_size/0, cache_opts/0 + cache_size/0, cache_opts/0, decorator_opts/0 ]). %% ================================================================== @@ -109,13 +101,6 @@ -define(CACHE_MAP, cache_map). -define(SERVER, ?MODULE). - -%% ==================================================================== -%% Escript -%% ==================================================================== -main(Args) -> - basho_bench:main(Args). - %% ==================================================================== %% API %% ==================================================================== @@ -124,7 +109,6 @@ main(Args) -> -spec start() -> ok. %% @end start() -> - ok = lager:start(), ok = application:start(erl_cache). %% @private @@ -162,7 +146,7 @@ set_cache_defaults(Name, CacheOpts) -> end. %% @doc Gets the default value of a cache server option. --spec get_cache_option(name(), cache_opts()) -> term(). +-spec get_cache_option(name(), config_key()) -> term(). %% @end get_cache_option(Name, Opt) -> case ets:lookup(?CACHE_MAP, Name) of @@ -192,7 +176,7 @@ list_cache_servers() -> ets:select(?CACHE_MAP, [{{'$1', '_'}, [], ['$1']}]). %% @doc Gets the value associated with a given key in the cache signaled by the given name. --spec get(name(), key(), [cache_get_opt()]) -> +-spec get(name(), key(), cache_opts()) -> {error, not_found} | {error, invalid_opt_error()} | {ok, value()}. @@ -222,7 +206,7 @@ set(Name, Key, Value) -> %% @doc Sets a cache entry in a cache instance. %% The options passed in this function call will overwrite the default ones for the cache instance %% for any operation related to this specific key. --spec set(name(), key(), value(), [cache_set_opt()]) -> ok | {error, invalid_opt_error()}. +-spec set(name(), key(), value(), cache_opts()) -> ok | {error, invalid_opt_error()}. %% @end set(Name, Key, Value, Opts) -> case validate_opts(Opts, get_name_defaults(Name)) of @@ -281,7 +265,7 @@ handle_call({stop_cache, Name}, _From, #state{}=State) -> Res = case is_cache_server(Name) of true -> ok = erl_cache_server_sup:remove_cache(Name), - ?INFO("Stopping cache server '~p'", [Name]), + ?LOG_INFO("Stopping cache server '~p'", [Name]), true = ets:delete(?CACHE_MAP, Name), ok; false -> @@ -300,7 +284,7 @@ do_start_cache(Name, Opts) -> case validate_opts(Opts, []) of {ok, ValidatedOpts} -> true = ets:insert(?CACHE_MAP, {Name, ValidatedOpts}), - ?INFO("Starting cache server '~p'", [Name]), + ?LOG_INFO("Starting cache server '~p'", [Name]), {ok, _} = erl_cache_server_sup:add_cache(Name), ok; {error, _}=E -> E @@ -449,4 +433,3 @@ get_name_defaults(Name) -> [{Name, Opts}] -> Opts; [] -> undefined end. - diff --git a/src/erl_cache_decorator.erl b/src/erl_cache_decorator.erl index 2e62d59..c833552 100644 --- a/src/erl_cache_decorator.erl +++ b/src/erl_cache_decorator.erl @@ -6,8 +6,9 @@ %% API %% ==================================================================== --spec cache_pt(function(), [term()], {atom(), atom(), erl_cache:name(), erl_cache:cache_opts()}) -> - (fun(() -> term())). +-spec cache_pt(function(), [term()], {atom(), atom(), erl_cache:name(), + [erl_cache:cache_opts()]}) -> + (fun(() -> term())) | no_return(). cache_pt(Fun, Args, {Module, FunctionAtom, Name, Opts}) -> FinalOpts = [{refresh_callback, fun () -> Fun(Args) end} | Opts], Key = case proplists:get_value(key_generation, Opts) of @@ -28,4 +29,3 @@ cache_pt(Fun, Args, {Module, FunctionAtom, Name, Opts}) -> {error, Err} -> throw({error, {cache_pt, Err}}) end. - diff --git a/src/erl_cache_driver.erl b/src/erl_cache_driver.erl deleted file mode 100644 index 4e79285..0000000 --- a/src/erl_cache_driver.erl +++ /dev/null @@ -1,24 +0,0 @@ --module(erl_cache_driver). - --export([new/1, run/4]). - --ignore_xref([ - {basho_bench_config, get, 2} -]). - -new(1) -> - ok = erl_cache:start(), - ok = erl_cache:start_cache(s1, basho_bench_config:get(cache_opts, [])), - {ok, []}; - -new(_) -> - {ok, []}. - -run(get, KeyGen, _ValueGen, State) -> - erl_cache:get(s1, KeyGen()), - {ok, State}; - -run(set, KeyGen, ValueGen, State) -> - erl_cache:set(s1, KeyGen(), ValueGen()), - {ok, State}. - diff --git a/src/erl_cache_server.erl b/src/erl_cache_server.erl index 29e90e8..ea7686f 100644 --- a/src/erl_cache_server.erl +++ b/src/erl_cache_server.erl @@ -3,7 +3,7 @@ -behaviour(gen_server). -include("erl_cache.hrl"). --include("logging.hrl"). +-include_lib("kernel/include/logger.hrl"). %% ================================================================== %% API Function Exports @@ -26,11 +26,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --ifdef(namespace_types). -type stats_dict() :: dict:dict(). --else. --type stats_dict() :: dict(). --endif. -record(state, { @@ -40,16 +36,16 @@ }). -record(cache_entry, { - key::erl_cache:key(), - value::erl_cache:value(), - created::pos_integer(), - validity::pos_integer(), - evict::pos_integer(), - validity_delta::erl_cache:validity(), - error_validity_delta::erl_cache:error_validity(), - evict_delta::erl_cache:evict(), - refresh_callback::erl_cache:refresh_callback(), - is_error_callback::erl_cache:is_error_callback() + key::erl_cache:key() | '_', + value::erl_cache:value() | '_', + created::pos_integer() | '_', + validity::pos_integer() | '_', + evict::pos_integer() | '$1' | '_', + validity_delta::erl_cache:validity() | '_', + error_validity_delta::erl_cache:error_validity() | '_', + evict_delta::erl_cache:evict() | '_', + refresh_callback::erl_cache:refresh_callback() | '_', + is_error_callback::erl_cache:is_error_callback() | '_' }). %% ================================================================== @@ -72,7 +68,7 @@ get(Name, Key, WaitForRefresh) -> gen_server:cast(Name, {increase_stat, overdue}), {ok, Value}; [#cache_entry{evict=Evict, refresh_callback=Cb}=Entry] when Now < Evict, Cb /=undefined -> - ?DEBUG("Refreshing overdue key ~p", [Key]), + ?LOG_DEBUG("Refreshing overdue key ~p", [Key]), gen_server:cast(Name, {increase_stat, overdue}), {ok, NewVal} = refresh(Name, Entry, WaitForRefresh), {ok, NewVal}; @@ -183,7 +179,7 @@ code_change(_OldVsn, State, _Extra) -> %% @private -spec operate_cache(erl_cache:name(), function(), list(), atom(), boolean()) -> ok. operate_cache(Name, Function, Input, Stat, Sync) -> - case Sync of + _ = case Sync of true -> apply(Function, Input); false -> spawn_link(erlang, apply, [Function, Input]) end, @@ -208,7 +204,7 @@ purge_cache(Name) -> {Time, Deleted} = timer:tc( ets, select_delete, [get_table_name(Name), [{#cache_entry{evict='$1', _='_'}, [{'<', '$1', Now}], [true]}]]), - ?INFO("~p cache purged in ~pms", [Name, Time]), + ?LOG_INFO("~p cache purged in ~pms", [Name, Time]), gen_server:cast(Name, {increase_stat, evict, Deleted}), ok. @@ -238,7 +234,7 @@ do_refresh(Name, #cache_entry{key=Key, validity_delta=ValidityDelta, evict_delta Entry#cache_entry{value=NewVal, validity=Now+ValidityDelta, evict=Now+ValidityDelta+EvictDelta}; true -> - ?NOTICE("Error refreshing ~p at ~p: ~p. Disabling auto refresh...", + ?LOG_NOTICE("Error refreshing ~p at ~p: ~p. Disabling auto refresh...", [Key, Name, NewVal]), Entry#cache_entry{refresh_callback=undefined} end, @@ -253,7 +249,7 @@ check_mem_usage(Name) -> CurrentMB = erlang:trunc((CurrentWords * erlang:system_info(wordsize)) / (1024*1024*8)), case MaxMB /= undefined andalso CurrentMB > MaxMB of true -> - ?WARNING("~p exceeded memory limit of ~pMB: ~pMB in use! Forcing eviction...", + ?LOG_WARNING("~p exceeded memory limit of ~pMB: ~pMB in use! Forcing eviction...", [Name, MaxMB, CurrentMB]), purge_cache(Name); false -> ok @@ -263,7 +259,9 @@ check_mem_usage(Name) -> ok. %% @private --spec do_apply(mfa() | function()) -> term(). +-spec do_apply + ({atom(), atom(), [term()]}) -> term(); + (function()) -> term(). do_apply({M, F, A}) when is_atom(M), is_atom(F), is_list(A) -> apply(M, F, A); do_apply(F) when is_function(F) -> @@ -301,4 +299,3 @@ get_table_name(Name) -> -spec to_atom(string()) -> atom(). to_atom(Str) -> try list_to_existing_atom(Str) catch error:badarg -> list_to_atom(Str) end. - diff --git a/src/erl_cache_server_sup.erl b/src/erl_cache_server_sup.erl index 19746c8..b153078 100644 --- a/src/erl_cache_server_sup.erl +++ b/src/erl_cache_server_sup.erl @@ -2,7 +2,7 @@ -behaviour(supervisor). --include("logging.hrl"). +-include_lib("kernel/include/logger.hrl"). %% API -export([start_link/0, add_cache/1, remove_cache/1]). @@ -22,7 +22,7 @@ start_link() -> -spec add_cache(erl_cache:name()) -> {ok, pid()}. add_cache(Name) -> - ?INFO("Adding supervised cache '~p'~n", [Name]), + ?LOG_INFO("Adding supervised cache '~p'~n", [Name]), supervisor:start_child(?MODULE, cache_spec(Name)). -spec remove_cache(erl_cache:name()) -> ok. @@ -52,4 +52,3 @@ init([]) -> -spec cache_spec(erl_cache:name()) -> supervisor:child_spec(). cache_spec(Name) -> {Name, {erl_cache_server, start_link, [Name]}, permanent, 5000, worker, [erl_cache_server]}. - diff --git a/test/erl_cache_eunit.erl b/test/erl_cache_eunit.erl index 2fa20b5..ac3f77c 100644 --- a/test/erl_cache_eunit.erl +++ b/test/erl_cache_eunit.erl @@ -1,7 +1,7 @@ -module(erl_cache_eunit). -include_lib("eunit/include/eunit.hrl"). --include("erl_cache.hrl"). +-include("include/erl_cache.hrl"). -include_lib("decorator_pt/include/decorator_pt.hrl"). -behaviour(erl_cache_key_generator).