diff --git a/Jenkinsfile b/Jenkinsfile index 0da0b51..c537ed8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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') } diff --git a/Makefile b/Makefile index f9ab18a..ae8812a 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/builtils b/builtils index 1aa7267..f42e059 160000 --- a/builtils +++ b/builtils @@ -1 +1 @@ -Subproject commit 1aa72677e975fc0604818362c595dcf84d27c4f0 +Subproject commit f42e059d9ec93826ba4ad23232eed8ce67bd5486 diff --git a/rebar.config b/rebar.config index 0bfd5ff..6c96063 100644 --- a/rebar.config +++ b/rebar.config @@ -69,6 +69,12 @@ ]}. {plugins, [ + {erlfmt, "0.8.0"} +]}. + +{erlfmt, [ + {print_width, 120}, + {files, "{src,include,test}/*.{hrl,erl}"} ]}. {pre_hooks, [ diff --git a/src/dmt_client.erl b/src/dmt_client.erl index 67c3ce4..44ad002 100644 --- a/src/dmt_client.erl +++ b/src/dmt_client.erl @@ -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'{}}) -> diff --git a/src/dmt_client_api.erl b/src/dmt_client_api.erl index 2ee452d..c3a7cf1 100644 --- a/src/dmt_client_api.erl +++ b/src/dmt_client_api.erl @@ -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) -> diff --git a/src/dmt_client_backend.erl b/src/dmt_client_backend.erl index 374b101..b85a53c 100644 --- a/src/dmt_client_backend.erl +++ b/src/dmt_client_backend.erl @@ -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). diff --git a/src/dmt_client_cache.erl b/src/dmt_client_cache.erl index bb3af50..e7e894e 100644 --- a/src/dmt_client_cache.erl +++ b/src/dmt_client_cache.erl @@ -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. diff --git a/test/dmt_client_cache_SUITE.erl b/test/dmt_client_cache_SUITE.erl index d90a1ec..ff49525 100644 --- a/test/dmt_client_cache_SUITE.erl +++ b/test/dmt_client_cache_SUITE.erl @@ -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), diff --git a/test/dmt_client_tests_SUITE.erl b/test/dmt_client_tests_SUITE.erl index 237e1d8..626d3bd 100644 --- a/test/dmt_client_tests_SUITE.erl +++ b/test/dmt_client_tests_SUITE.erl @@ -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) ->