Add formatter (#41)

* Add erlfmt
* Apply erlfmt
* Update build-utils
* Switch to Erlang lib pipe
This commit is contained in:
Andrey Fadeev 2020-10-14 12:38:41 +03:00 committed by GitHub
parent 24e3aad9ce
commit 9e11f50e9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 286 deletions

36
Jenkinsfile vendored
View File

@ -9,40 +9,14 @@ def finalHook = {
build('dmt_client', 'docker-host', finalHook) {
checkoutRepo()
runStage('load_builtils') {
withGithubSshCredentials {
sh 'git submodule update --init'
}
}
loadBuildUtils("builtils")
def pipeDefault
def withWsCache
def pipeErlangLib
runStage('load pipeline') {
env.JENKINS_LIB = "builtils/jenkins_lib"
pipeDefault = load("${env.JENKINS_LIB}/pipeDefault.groovy")
withWsCache = load("${env.JENKINS_LIB}/withWsCache.groovy")
}
pipeDefault() {
runStage('compile') {
withGithubPrivkey {
sh 'make wc_compile'
}
}
runStage('lint') {
sh 'make wc_lint'
}
runStage('xref') {
sh 'make wc_xref'
}
runStage('dialyze') {
withWsCache("_build/dialyze/rebar3_23.0.1_plt") {
sh 'make wc_dialyze'
}
}
runStage('test') {
sh "make wdeps_test"
}
env.SH_TOOLS = "builtils/sh"
pipeErlangLib = load("${env.JENKINS_LIB}/pipeErlangLib.groovy")
}
pipeErlangLib.runPipe(true, false, 'dialyze')
}

View File

@ -11,7 +11,7 @@ SERVICE_NAME := dmt_client
# Build image tag to be used
BUILD_IMAGE_TAG := 07d3946f8f005782697de20270ac58cdcd18b011
CALL_ANYWHERE := all submodules rebar-update compile xref lint dialyze check clean distclean
CALL_ANYWHERE := all submodules rebar-update compile xref lint dialyze check clean distclean check_format format
CALL_W_CONTAINER := $(CALL_ANYWHERE) test
all: compile
@ -38,6 +38,12 @@ xref: submodules
lint:
elvis rock
check_format:
$(REBAR) fmt -c
format:
$(REBAR) fmt -w
dialyze: submodules
$(REBAR) as dialyze dialyzer

@ -1 +1 @@
Subproject commit 1aa72677e975fc0604818362c595dcf84d27c4f0
Subproject commit f42e059d9ec93826ba4ad23232eed8ce67bd5486

View File

@ -69,6 +69,12 @@
]}.
{plugins, [
{erlfmt, "0.8.0"}
]}.
{erlfmt, [
{print_width, 120},
{files, "{src,include,test}/*.{hrl,erl}"}
]}.
{pre_hooks, [

View File

@ -2,6 +2,7 @@
%%% @end
-module(dmt_client).
-behaviour(supervisor).
-behaviour(application).
@ -52,15 +53,11 @@
%%% API
-spec checkout(ref()) ->
snapshot() | no_return().
-spec checkout(ref()) -> snapshot() | no_return().
checkout(Reference) ->
checkout(Reference, undefined).
-spec checkout(ref(), transport_opts()) ->
snapshot() | no_return().
-spec checkout(ref(), transport_opts()) -> snapshot() | no_return().
checkout(Reference, Opts) ->
Version = ref_to_version(Reference),
case dmt_client_cache:get(Version, Opts) of
@ -70,15 +67,12 @@ checkout(Reference, Opts) ->
erlang:error(Error)
end.
-spec checkout_object(ref(), object_ref()) ->
dmsl_domain_config_thrift:'VersionedObject'() | no_return().
-spec checkout_object(ref(), object_ref()) -> dmsl_domain_config_thrift:'VersionedObject'() | no_return().
checkout_object(Reference, ObjectReference) ->
checkout_object(Reference, ObjectReference, undefined).
-spec checkout_object(ref(), object_ref(), transport_opts()) ->
dmsl_domain_config_thrift:'VersionedObject'() | no_return().
checkout_object(Reference, ObjectReference, Opts) ->
Version = ref_to_version(Reference),
case dmt_client_cache:get_object(Version, ObjectReference, Opts) of
@ -90,41 +84,29 @@ checkout_object(Reference, ObjectReference, Opts) ->
erlang:throw(#'ObjectNotFound'{})
end.
-spec commit(version(), commit()) ->
version() | no_return().
-spec commit(version(), commit()) -> version() | no_return().
commit(Version, Commit) ->
commit(Version, Commit, undefined).
-spec commit(version(), commit(), transport_opts()) ->
version() | no_return().
-spec commit(version(), commit(), transport_opts()) -> version() | no_return().
commit(Version, Commit, Opts) ->
dmt_client_backend:commit(Version, Commit, Opts).
-spec get_last_version() ->
version().
-spec get_last_version() -> version().
get_last_version() ->
dmt_client_cache:get_last_version().
-spec pull_range(version(), limit()) ->
history() | no_return().
-spec pull_range(version(), limit()) -> history() | no_return().
pull_range(Version, Limit) ->
pull_range(Version, Limit, undefined).
-spec pull_range(version(), limit(), transport_opts()) ->
history() | no_return().
-spec pull_range(version(), limit(), transport_opts()) -> history() | no_return().
pull_range(Version, Limit, Opts) ->
dmt_client_backend:pull_range(Version, Limit, Opts).
%% Health check API
-spec health_check() ->
erl_health:result().
-spec health_check() -> erl_health:result().
health_check() ->
try
_ = dmt_client_cache:get_last_version(),
@ -137,7 +119,6 @@ health_check() ->
%%% Supervisor callbacks
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
init([]) ->
Cache = #{id => dmt_client_cache, start => {dmt_client_cache, start_link, []}, restart => permanent},
{ok, {#{strategy => one_for_one, intensity => 10, period => 60}, [Cache]}}.
@ -145,20 +126,16 @@ init([]) ->
%%% Application callbacks
-spec start(normal, any()) -> {ok, pid()} | {error, any()}.
start(_StartType, _StartArgs) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-spec stop(any()) -> ok.
stop(_State) ->
ok.
%%% Internal functions
-spec ref_to_version(ref()) ->
version().
-spec ref_to_version(ref()) -> version().
ref_to_version({version, Version}) ->
Version;
ref_to_version({head, #'Head'{}}) ->

View File

@ -9,36 +9,30 @@
-spec commit(dmt_client:version(), dmt_client:commit(), dmt_client:transport_opts()) ->
dmt_client:version() | no_return().
commit(Version, Commit, Opts) ->
call('Repository', 'Commit', {Version, Commit}, Opts).
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) ->
dmt_client:snapshot() | no_return().
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) -> dmt_client:snapshot() | no_return().
checkout(Reference, Opts) ->
call('Repository', 'Checkout', {Reference}, Opts).
-spec pull_range(dmt_client:version(), dmt_client:limit(), dmt_client:transport_opts()) ->
dmt_client:history() | no_return().
pull_range(After, Limit, Opts) ->
call('Repository', 'PullRange', {After, Limit}, Opts).
-spec checkout_object(dmt_client:ref(), dmt_client:object_ref(), dmt_client:transport_opts()) ->
dmsl_domain_thrift:'DomainObject'() | no_return().
checkout_object(Reference, ObjectReference, Opts) ->
call('RepositoryClient', 'checkoutObject', {Reference, ObjectReference}, Opts).
call(ServiceName, Function, Args, TransportOpts) ->
Url = get_service_url(ServiceName),
Service = get_service_modname(ServiceName),
Call = {Service, Function, Args},
Opts = #{
url => Url,
event_handler => get_event_handlers(),
event_handler => get_event_handlers(),
transport_opts => ensure_transport_opts(TransportOpts)
},
Context = woody_context:new(),
@ -63,9 +57,7 @@ get_service_module('RepositoryClient') ->
get_event_handlers() ->
genlib_app:env(dmt_client, woody_event_handlers, []).
-spec ensure_transport_opts(dmt_client:transport_opts()) ->
woody_client_thrift_http_transport:transport_options().
-spec ensure_transport_opts(dmt_client:transport_opts()) -> woody_client_thrift_http_transport:transport_options().
ensure_transport_opts(Opts) when is_map(Opts) ->
Opts;
ensure_transport_opts(undefined) ->

View File

@ -10,8 +10,7 @@
-callback commit(dmt_client:version(), dmt_client:commit(), dmt_client:transport_opts()) ->
dmt_client:version() | no_return().
-callback checkout(dmt_client:ref(), dmt_client:transport_opts()) ->
dmt_client:snapshot() | no_return().
-callback checkout(dmt_client:ref(), dmt_client:transport_opts()) -> dmt_client:snapshot() | no_return().
-callback checkout_object(dmt_client:ref(), dmt_client:object_ref(), dmt_client:transport_opts()) ->
dmsl_domain_thrift:'DomainObject'() | no_return().
@ -23,39 +22,30 @@
-spec commit(dmt_client:version(), dmt_client:commit(), dmt_client:transport_opts()) ->
dmt_client:version() | no_return().
commit(Version, Commit, Opts) ->
call(commit, [Version, Commit, Opts]).
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) ->
dmt_client:snapshot() | no_return().
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) -> dmt_client:snapshot() | no_return().
checkout(Reference, Opts) ->
call(checkout, [Reference, Opts]).
-spec checkout_object(dmt_client:ref(), dmt_client:object_ref(), dmt_client:transport_opts()) ->
dmsl_domain_thrift:'DomainObject'() | no_return().
checkout_object(Reference, ObjectReference, Opts) ->
call(checkout_object, [Reference, ObjectReference, Opts]).
-spec pull_range(dmt_client:version(), dmt_client:limit(), dmt_client:transport_opts()) ->
dmt_client:history() | no_return().
pull_range(After, Limit, Opts) ->
call(pull_range, [After, Limit, Opts]).
%%% Internal functions
-spec get_api_module() ->
module().
-spec get_api_module() -> module().
get_api_module() ->
genlib_app:env(dmt_client, api_module, dmt_client_api).
-spec call(atom(), list()) ->
term() | no_return().
-spec call(atom(), list()) -> term() | no_return().
call(Fun, Args) ->
Module = get_api_module(),
erlang:apply(Module, Fun, Args).

View File

@ -1,4 +1,5 @@
-module(dmt_client_cache).
-behaviour(gen_server).
%% API
@ -80,21 +81,16 @@
%%% API
-spec start_link() ->
{ok, pid()} | {error, {already_started, pid()}}.
-spec start_link() -> {ok, pid()} | {error, {already_started, pid()}}.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
-spec get(dmt_client:version()) ->
{ok, dmt_client:snapshot()} | {error, version_not_found | woody_error()}.
-spec get(dmt_client:version()) -> {ok, dmt_client:snapshot()} | {error, version_not_found | woody_error()}.
get(Version) ->
get(Version, undefined).
-spec get(dmt_client:version(), dmt_client:transport_opts()) ->
{ok, dmt_client:snapshot()} | {error, version_not_found | woody_error()}.
get(Version, Opts) ->
case get_snapshot(Version) of
{ok, _Snapshot} = Result ->
@ -105,13 +101,11 @@ get(Version, Opts) ->
-spec get_object(dmt_client:version(), dmt_client:object_ref()) ->
{ok, dmt_client:domain_object()} | {error, version_not_found | object_not_found | woody_error()}.
get_object(Version, ObjectRef) ->
get_object(Version, ObjectRef, undefined).
-spec get_object(dmt_client:version(), dmt_client:object_ref(), dmt_client:transport_opts()) ->
{ok, dmt_client:domain_object()} | {error, version_not_found | object_not_found | woody_error()}.
get_object(Version, ObjectRef, Opts) ->
case do_get_object(Version, ObjectRef) of
{ok, _Object} = Result ->
@ -122,9 +116,7 @@ get_object(Version, ObjectRef, Opts) ->
NotFound
end.
-spec get_last_version() ->
dmt_client:version() | no_return().
-spec get_last_version() -> dmt_client:version() | no_return().
get_last_version() ->
case do_get_last_version() of
{ok, Version} ->
@ -138,24 +130,18 @@ get_last_version() ->
end
end.
-spec update() ->
{ok, dmt_client:version()} | {error, woody_error()}.
-spec update() -> {ok, dmt_client:version()} | {error, woody_error()}.
update() ->
call(update).
%%% gen_server callbacks
-spec init(_) ->
{ok, state(), 0}.
-spec init(_) -> {ok, state(), 0}.
init(_) ->
ok = create_tables(),
{ok, #state{}, 0}.
-spec handle_call(term(), {pid(), term()}, state()) ->
{reply, term(), state()}.
-spec handle_call(term(), {pid(), term()}, state()) -> {reply, term(), state()}.
handle_call({get_object, Version, ObjectRef, Opts}, From, #state{waiters = Waiters} = State) ->
case do_get_object(Version, ObjectRef) of
{ok, _Object} = Result ->
@ -164,29 +150,24 @@ handle_call({get_object, Version, ObjectRef, Opts}, From, #state{waiters = Waite
{reply, NotFound, State};
{error, version_not_found} ->
DispatchFun = dispatch_object(ObjectRef),
NewWaiters = maybe_fetch({version, Version}, From, DispatchFun, Waiters, Opts),
NewWaiters = maybe_fetch({version, Version}, From, DispatchFun, Waiters, Opts),
{noreply, State#state{waiters = NewWaiters}}
end;
handle_call(update, From, State) ->
update_cache(From, State);
handle_call({get_snapshot, Version, Opts}, From, #state{waiters = Waiters} = State) ->
case get_snapshot(Version) of
{ok, _Snapshot} = Result ->
{reply, Result, State};
{error, version_not_found} ->
DispatchFun = fun dispatch_snapshot/2,
NewWaiters = maybe_fetch({version, Version}, From, DispatchFun, Waiters, Opts),
NewWaiters = maybe_fetch({version, Version}, From, DispatchFun, Waiters, Opts),
{noreply, State#state{waiters = NewWaiters}}
end;
handle_call(_Msg, _From, State) ->
{noreply, State}.
-spec handle_cast(term(), state()) ->
{noreply, state()}.
-spec handle_cast(term(), state()) -> {noreply, state()}.
handle_cast({dispatch, Reference, Result}, #state{waiters = Waiters} = State) ->
case Result of
{ok, Snapshot} ->
@ -196,50 +177,36 @@ handle_cast({dispatch, Reference, Result}, #state{waiters = Waiters} = State) ->
end,
_ = [DispatchFun(From, Result) || {From, DispatchFun} <- maps:get(Reference, Waiters, [])],
{noreply, State#state{waiters = maps:remove(Reference, Waiters)}};
handle_cast(_Msg, State) ->
{noreply, State}.
-spec handle_info(term(), state()) ->
{noreply, state()}.
-spec handle_info(term(), state()) -> {noreply, state()}.
handle_info(timeout, State) ->
update_cache(undefined, State);
handle_info(_Msg, State) ->
{noreply, State}.
-spec terminate(term(), state()) ->
ok.
-spec terminate(term(), state()) -> ok.
terminate(_Reason, _State) ->
ok.
-spec code_change(term(), state(), term()) ->
{ok, state()}.
-spec code_change(term(), state(), term()) -> {ok, state()}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%% Internal functions
-spec create_tables() ->
ok.
-spec create_tables() -> ok.
create_tables() ->
?TABLE = ets:new(?TABLE, ?meta_table_opts),
ok.
-spec call(term()) ->
term().
-spec call(term()) -> term().
call(Msg) ->
DefTimeout = application:get_env(dmt_client, cache_server_call_timeout, ?DEFAULT_CALL_TIMEOUT),
call(Msg, DefTimeout).
-spec call(term(), timeout()) ->
term().
-spec call(term(), timeout()) -> term().
call(Msg, Timeout) ->
try
gen_server:call(?SERVER, Msg, Timeout)
@ -248,21 +215,17 @@ call(Msg, Timeout) ->
woody_error:raise(system, {external, resource_unavailable, <<"dmt_client_cache timeout">>})
end.
-spec cast(term()) ->
ok.
-spec cast(term()) -> ok.
cast(Msg) ->
gen_server:cast(?SERVER, Msg).
-spec put_snapshot(dmt_client:snapshot()) ->
ok.
-spec put_snapshot(dmt_client:snapshot()) -> ok.
put_snapshot(#'Snapshot'{version = Version, domain = Domain}) ->
case get_snap(Version) of
{ok, _Snap} ->
ok;
{error, version_not_found} ->
TID = ets:new(?MODULE, ?snapshot_table_opts),
TID = ets:new(?MODULE, ?snapshot_table_opts),
true = put_domain_to_table(TID, Domain),
Snap = #snap{
vsn = Version,
@ -273,9 +236,7 @@ put_snapshot(#'Snapshot'{version = Version, domain = Domain}) ->
cleanup()
end.
-spec put_domain_to_table(ets:tid(), dmt_client:domain()) ->
true.
-spec put_domain_to_table(ets:tid(), dmt_client:domain()) -> true.
put_domain_to_table(TID, Domain) ->
dmt_domain:fold(
fun(Ref, Object, _) ->
@ -285,9 +246,7 @@ put_domain_to_table(TID, Domain) ->
Domain
).
-spec get_snapshot(dmt_client:version()) ->
{ok, dmt_client:snapshot()} | {error, version_not_found}.
-spec get_snapshot(dmt_client:version()) -> {ok, dmt_client:snapshot()} | {error, version_not_found}.
get_snapshot(Version) ->
case get_snap(Version) of
{ok, Snap} ->
@ -296,9 +255,7 @@ get_snapshot(Version) ->
Error
end.
-spec get_snap(dmt_client:version()) ->
{ok, snap()} | {error, version_not_found}.
-spec get_snap(dmt_client:version()) -> {ok, snap()} | {error, version_not_found}.
get_snap(Version) ->
case ets:lookup(?TABLE, Version) of
[Snap] ->
@ -308,15 +265,12 @@ get_snap(Version) ->
{error, version_not_found}
end.
-spec get_all_snaps() ->
[snap()].
-spec get_all_snaps() -> [snap()].
get_all_snaps() ->
ets:tab2list(?TABLE).
-spec do_get_object(dmt_client:version(), dmt_client:object_ref()) ->
{ok, dmt_client:domain_object()} | {error, version_not_found | object_not_found}.
do_get_object(Version, ObjectRef) ->
case get_snap(Version) of
{ok, Snap} ->
@ -327,7 +281,6 @@ do_get_object(Version, ObjectRef) ->
-spec get_object_by_snap(snap(), dmt_client:object_ref()) ->
{ok, dmt_client:domain_object()} | {error, version_not_found | object_not_found}.
get_object_by_snap(#snap{tid = TID}, ObjectRef) ->
try ets:lookup(TID, ObjectRef) of
[#object{obj = Object}] ->
@ -335,13 +288,13 @@ get_object_by_snap(#snap{tid = TID}, ObjectRef) ->
[] ->
{error, object_not_found}
catch
error:badarg -> % table was deleted
% table was deleted
error:badarg ->
{error, version_not_found}
end.
-spec get_object_from_snapshot(dmt_client:object_ref(), dmt_client:snapshot()) ->
{ok, dmt_client:domain_object()} | {error, object_not_found}.
get_object_from_snapshot(ObjectRef, #'Snapshot'{domain = Domain}) ->
case dmt_domain:get_object(ObjectRef, Domain) of
{ok, _Object} = Result ->
@ -350,17 +303,14 @@ get_object_from_snapshot(ObjectRef, #'Snapshot'{domain = Domain}) ->
{error, object_not_found}
end.
-spec update_cache(from() | undefined, state()) ->
{noreply, state()}.
-spec update_cache(from() | undefined, state()) -> {noreply, state()}.
update_cache(From, #state{waiters = Waiters} = State) ->
DispatchFun = fun dispatch_update/2,
NewWaiters = maybe_fetch({head, #'Head'{}}, From, DispatchFun, Waiters, undefined),
NewWaiters = maybe_fetch({head, #'Head'{}}, From, DispatchFun, Waiters, undefined),
{noreply, restart_timer(State#state{waiters = NewWaiters})}.
-spec maybe_fetch(dmt_client:ref(), from() | undefined, dispatch_fun(), waiters(), dmt_client:transport_opts()) ->
waiters().
maybe_fetch(Reference, From, DispatchFun, Waiters, Opts) ->
Prev =
case maps:find(Reference, Waiters) of
@ -372,9 +322,7 @@ maybe_fetch(Reference, From, DispatchFun, Waiters, Opts) ->
end,
Waiters#{Reference => [{From, DispatchFun} | Prev]}.
-spec schedule_fetch(dmt_client:ref(), dmt_client:transport_opts()) ->
pid().
-spec schedule_fetch(dmt_client:ref(), dmt_client:transport_opts()) -> pid().
schedule_fetch(Reference, Opts) ->
proc_lib:spawn_link(
fun() ->
@ -383,9 +331,7 @@ schedule_fetch(Reference, Opts) ->
end
).
-spec fetch(dmt_client:ref(), dmt_client:transport_opts()) ->
fetch_result().
-spec fetch(dmt_client:ref(), dmt_client:transport_opts()) -> fetch_result().
fetch(Reference, Opts) ->
try
Snapshot = do_fetch(Reference, Opts),
@ -397,9 +343,7 @@ fetch(Reference, Opts) ->
{error, Error}
end.
-spec do_fetch(dmt_client:ref(), dmt_client:transport_opts()) ->
dmt_client:snapshot() | no_return().
-spec do_fetch(dmt_client:ref(), dmt_client:transport_opts()) -> dmt_client:snapshot() | no_return().
do_fetch({head, #'Head'{}}, Opts) ->
case latest_snapshot() of
{ok, OldHead} ->
@ -413,18 +357,14 @@ do_fetch({head, #'Head'{}}, Opts) ->
do_fetch(Reference, Opts) ->
dmt_client_backend:checkout(Reference, Opts).
-spec dispatch_snapshot(from() | undefined, fetch_result()) ->
ok.
-spec dispatch_snapshot(from() | undefined, fetch_result()) -> ok.
dispatch_snapshot(undefined, _Result) ->
ok;
dispatch_snapshot(From, Result) ->
_ = gen_server:reply(From, Result),
ok.
-spec dispatch_object(dmt_client:object_ref()) ->
dispatch_fun().
-spec dispatch_object(dmt_client:object_ref()) -> dispatch_fun().
dispatch_object(ObjectRef) ->
fun(From, Result) ->
Reply =
@ -437,9 +377,7 @@ dispatch_object(ObjectRef) ->
gen_server:reply(From, Reply)
end.
-spec dispatch_update(from() | undefined, fetch_result()) ->
ok.
-spec dispatch_update(from() | undefined, fetch_result()) -> ok.
dispatch_update(undefined, _Result) ->
ok;
dispatch_update(From, {ok, #'Snapshot'{version = Version}}) ->
@ -449,9 +387,7 @@ dispatch_update(From, Error) ->
_ = gen_server:reply(From, Error),
ok.
-spec do_get_snapshot(snap()) ->
{ok, dmt_client:snapshot()} | {error, version_not_found}.
-spec do_get_snapshot(snap()) -> {ok, dmt_client:snapshot()} | {error, version_not_found}.
do_get_snapshot(#snap{vsn = Version, tid = TID}) ->
try
Domain = ets:foldl(
@ -464,13 +400,12 @@ do_get_snapshot(#snap{vsn = Version, tid = TID}) ->
),
{ok, #'Snapshot'{version = Version, domain = Domain}}
catch
error:badarg -> % table was deleted due to cleanup process or crash
% table was deleted due to cleanup process or crash
error:badarg ->
{error, version_not_found}
end.
-spec latest_snapshot() ->
{ok, dmt_client:snapshot()} | {error, version_not_found}.
-spec latest_snapshot() -> {ok, dmt_client:snapshot()} | {error, version_not_found}.
latest_snapshot() ->
case do_get_last_version() of
{ok, Version} ->
@ -479,9 +414,7 @@ latest_snapshot() ->
Error
end.
-spec do_get_last_version() ->
{ok, dmt_client:version()} | {error, version_not_found}.
-spec do_get_last_version() -> {ok, dmt_client:version()} | {error, version_not_found}.
do_get_last_version() ->
case ets:last(?TABLE) of
'$end_of_table' ->
@ -490,42 +423,34 @@ do_get_last_version() ->
{ok, Version}
end.
-spec restart_timer(state()) ->
state().
-spec restart_timer(state()) -> state().
restart_timer(State = #state{timer = undefined}) ->
start_timer(State);
restart_timer(State = #state{timer = TimerRef}) ->
_ = erlang:cancel_timer(TimerRef),
start_timer(State#state{timer = undefined}).
-spec start_timer(state()) ->
state().
-spec start_timer(state()) -> state().
start_timer(State = #state{timer = undefined}) ->
Interval = genlib_app:env(dmt_client, cache_update_interval, ?DEFAULT_INTERVAL),
State#state{timer = erlang:send_after(Interval, self(), timeout)}.
-spec cleanup() ->
ok.
-spec cleanup() -> ok.
cleanup() ->
Snaps = get_all_snaps(),
Sorted = lists:keysort(#snap.last_access, Snaps),
{ok, HeadVersion} = do_get_last_version(),
cleanup(Sorted, HeadVersion).
-spec cleanup([snap()], dmt_client:version()) ->
ok.
-spec cleanup([snap()], dmt_client:version()) -> ok.
cleanup([], _HeadVersion) ->
ok;
cleanup(Snaps, HeadVersion) ->
{Elements, Memory} = get_cache_size(),
CacheLimits = genlib_app:env(dmt_client, max_cache_size),
MaxElements = genlib_map:get(elements, CacheLimits, 20),
MaxMemory = genlib_map:get(memory, CacheLimits, 52428800), % 50Mb by default
% 50Mb by default
MaxMemory = genlib_map:get(memory, CacheLimits, 52428800),
case Elements > MaxElements orelse (Elements > 1 andalso Memory > MaxMemory) of
true ->
Tail = remove_earliest(Snaps, HeadVersion),
@ -534,18 +459,14 @@ cleanup(Snaps, HeadVersion) ->
ok
end.
-spec get_cache_size() ->
{non_neg_integer(), non_neg_integer()}.
-spec get_cache_size() -> {non_neg_integer(), non_neg_integer()}.
get_cache_size() ->
WordSize = erlang:system_info(wordsize),
Info = ets:info(?TABLE),
Words = get_snapshot_tables_size(),
Info = ets:info(?TABLE),
Words = get_snapshot_tables_size(),
{proplists:get_value(size, Info), WordSize * Words}.
-spec get_snapshot_tables_size() ->
non_neg_integer().
-spec get_snapshot_tables_size() -> non_neg_integer().
get_snapshot_tables_size() ->
ets:foldl(
fun(#snap{tid = TID}, Words) ->
@ -555,39 +476,29 @@ get_snapshot_tables_size() ->
?TABLE
).
-spec ets_memory(ets:tid()) ->
non_neg_integer().
-spec ets_memory(ets:tid()) -> non_neg_integer().
ets_memory(TID) ->
Info = ets:info(TID),
proplists:get_value(memory, Info).
-spec remove_earliest([snap()], dmt_client:version()) ->
[snap()].
-spec remove_earliest([snap()], dmt_client:version()) -> [snap()].
remove_earliest([#snap{vsn = HeadVersion} | Tail], HeadVersion) ->
Tail;
remove_earliest([Snap | Tail], _HeadVersion) ->
remove_snap(Snap),
Tail.
-spec remove_snap(snap()) ->
ok.
-spec remove_snap(snap()) -> ok.
remove_snap(#snap{tid = TID, vsn = Version}) ->
true = ets:delete(?TABLE, Version),
true = ets:delete(TID),
ok.
-spec update_last_access(dmt_client:version()) ->
boolean().
-spec update_last_access(dmt_client:version()) -> boolean().
update_last_access(Version) ->
ets:update_element(?TABLE, Version, {#snap.last_access, timestamp()}).
-spec timestamp() ->
timestamp().
-spec timestamp() -> timestamp().
timestamp() ->
erlang:monotonic_time(microsecond).
@ -595,14 +506,12 @@ timestamp() ->
-ifdef(TEST).
-spec test() -> % dirty hack for warn_missing_spec
any().
% dirty hack for warn_missing_spec
-spec test() -> any().
-include_lib("eunit/include/eunit.hrl").
-spec cleanup_test() ->
ok.
-spec cleanup_test() -> ok.
cleanup_test() ->
application:set_env(dmt_client, max_cache_size, #{elements => 2, memory => 52428800}),
ok = create_tables(),
@ -619,9 +528,7 @@ cleanup_test() ->
] = get_all_snaps(),
ok.
-spec last_access_test() ->
ok.
-spec last_access_test() -> ok.
last_access_test() ->
application:set_env(dmt_client, max_cache_size, #{elements => 3, memory => 52428800}),
% Tables already created in cleanup_test/0
@ -641,4 +548,5 @@ last_access_test() ->
] = get_all_snaps(),
ok.
-endif. % TEST
% TEST
-endif.

View File

@ -1,4 +1,5 @@
-module(dmt_client_cache_SUITE).
-include_lib("common_test/include/ct.hrl").
-export([all/0]).
@ -31,17 +32,13 @@
%%% Common test callbacks
-spec all() ->
[testcase_or_group()].
-spec all() -> [testcase_or_group()].
all() ->
[
{group, main}
].
-spec groups() ->
[{atom(), list(), [testcase_or_group()]}].
-spec groups() -> [{atom(), list(), [testcase_or_group()]}].
groups() ->
[
{main, [parallel, shuffle], [
@ -57,33 +54,30 @@ groups() ->
{object_not_found, [parallel], lists:duplicate(?tests_count, object_not_found)},
{mixed, [parallel, shuffle],
lists:duplicate(?tests_count, get_snapshot_success) ++
lists:duplicate(?tests_count, snapshot_not_found) ++
lists:duplicate(?tests_count, woody_error) ++
lists:duplicate(?tests_count, object_not_found)
}
lists:duplicate(?tests_count, snapshot_not_found) ++
lists:duplicate(?tests_count, woody_error) ++
lists:duplicate(?tests_count, object_not_found)}
].
-spec init_per_suite(config()) ->
config().
-spec init_per_suite(config()) -> config().
init_per_suite(C) ->
Apps = genlib_app:start_application_with(dmt_client, [
{api_module, ?MODULE},
{cache_update_interval, 5000}, % milliseconds
% milliseconds
{cache_update_interval, 5000},
{max_cache_size, #{
elements => 1,
memory => 2048 % 2Kb
% 2Kb
memory => 2048
}},
{service_urls, #{
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
}}
]),
[{apps, Apps}|C].
-spec end_per_suite(config()) ->
any().
[{apps, Apps} | C].
-spec end_per_suite(config()) -> any().
end_per_suite(C) ->
genlib_app:stop_unload_applications(?config(apps, C)).
@ -91,63 +85,47 @@ end_per_suite(C) ->
-spec commit(dmt_client:version(), dmt_client:commit(), dmt_client:transport_opts()) ->
dmt_client:version() | no_return().
commit(Version, _Commit, _Opts) ->
Version.
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) ->
dmt_client:snapshot() | no_return().
-spec checkout(dmt_client:ref(), dmt_client:transport_opts()) -> dmt_client:snapshot() | no_return().
checkout({version, ?notfound_version}, _Opts) ->
erlang:throw(#'VersionNotFound'{});
checkout({version, ?unavailable_version}, _Opts) ->
woody_error:raise(system, {external, resource_unavailable, <<"test">>});
checkout({version, ?existing_version}, _Opts) ->
timer:sleep(5000),
#'Snapshot'{version = ?existing_version, domain = dmt_domain:new()};
checkout({head, #'Head'{}}, _Opts) ->
timer:sleep(5000),
#'Snapshot'{version = ?existing_version, domain = dmt_domain:new()}.
-spec checkout_object(dmt_client:ref(), dmt_client:object_ref(), dmt_client:transport_opts()) ->
dmsl_domain_thrift:'DomainObject'() | no_return().
checkout_object(_Reference, _ObjectReference, _Opts) ->
erlang:throw(#'ObjectNotFound'{}).
-spec pull_range(dmt_client:version(), dmt_client:limit(), dmt_client:transport_opts()) ->
dmt_client:history() | no_return().
pull_range(_Version, _Limit, _Opts) ->
timer:sleep(5000),
#{}.
%%% Tests
-spec get_snapshot_success(config()) ->
any().
-spec get_snapshot_success(config()) -> any().
get_snapshot_success(_C) ->
{ok, #'Snapshot'{}} = dmt_client_cache:get(?existing_version).
-spec snapshot_not_found(config()) ->
any().
-spec snapshot_not_found(config()) -> any().
snapshot_not_found(_C) ->
{error, version_not_found} = dmt_client_cache:get(1).
-spec woody_error(config()) ->
any().
-spec woody_error(config()) -> any().
woody_error(_C) ->
{error, {woody_error, _}} = dmt_client_cache:get(?unavailable_version).
-spec object_not_found(config()) ->
any().
-spec object_not_found(config()) -> any().
object_not_found(_C) ->
Ref = {category, #'domain_CategoryRef'{id = 1}},
{error, version_not_found} = dmt_client_cache:get_object(?notfound_version, Ref),

View File

@ -1,4 +1,5 @@
-module(dmt_client_tests_SUITE).
-include_lib("common_test/include/ct.hrl").
-export([all/0]).
@ -31,17 +32,19 @@ groups() ->
-spec init_per_suite(term()) -> term().
init_per_suite(C) ->
Apps = genlib_app:start_application_with(dmt_client, [
{cache_update_interval, 5000}, % milliseconds
% milliseconds
{cache_update_interval, 5000},
{max_cache_size, #{
elements => 1,
memory => 2048 % 2Kb
% 2Kb
memory => 2048
}},
{service_urls, #{
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
}}
]),
[{apps, Apps}|C].
[{apps, Apps} | C].
-spec end_per_suite(term()) -> term().
end_per_suite(C) ->