Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E784E17837 for ; Tue, 27 Oct 2015 19:35:35 +0000 (UTC) Received: (qmail 63848 invoked by uid 500); 27 Oct 2015 19:35:32 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 63796 invoked by uid 500); 27 Oct 2015 19:35:32 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 63783 invoked by uid 99); 27 Oct 2015 19:35:32 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 27 Oct 2015 19:35:32 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 9B1AEDFFD9; Tue, 27 Oct 2015 19:35:32 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: kxepal@apache.org To: commits@couchdb.apache.org Date: Tue, 27 Oct 2015 19:35:32 -0000 Message-Id: <0b8cc1add76d4bd6b8be8a8f33ab8fee@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [1/2] couchdb-couch-epi git commit: Add couch_epi:decide/5 Repository: couchdb-couch-epi Updated Branches: refs/heads/master 77dfaf413 -> 807aa3f58 Add couch_epi:decide/5 There are cases when we want to call configured providers until any of them would make a decision. We also would want to be able to find out if any decision has been made so we could call default handler. Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/commit/86531ee4 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/tree/86531ee4 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/diff/86531ee4 Branch: refs/heads/master Commit: 86531ee40193051f1d7572f72eb6b852563cd179 Parents: be34447 Author: ILYA Khlopotov Authored: Fri Oct 9 12:55:41 2015 -0700 Committer: ILYA Khlopotov Committed: Fri Oct 9 15:53:54 2015 -0700 ---------------------------------------------------------------------- README.md | 16 ++++++++ src/couch_epi.erl | 9 ++++- src/couch_epi_functions_gen.erl | 77 +++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/86531ee4/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md index 3f15a62..88390d0 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,22 @@ Notes: - `concurrent` is incompatible with `pipe` +## decide functionality + +There are cases when we want to call configured providers until any of them +would make a decission. We also would want to be able to find out if any +decision has been made so we could call default handler. In order to be able +to do so there is couch_epi:decide/5. Every service which uses this feature +would get either: + + - no_decision + - {decided, Decision :: term()} + +The provider module should return one of the above results. The current logic is +to call all configured providers in order of their definition until we get +`{decided, term()}`. If none of the providers would return this term we would +return `no_decision`. + # couch_epi_plugin behaviour The module implementing behaviour need to export following functions: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/86531ee4/src/couch_epi.erl ---------------------------------------------------------------------- diff --git a/src/couch_epi.erl b/src/couch_epi.erl index 2754261..0ccef90 100644 --- a/src/couch_epi.erl +++ b/src/couch_epi.erl @@ -22,7 +22,7 @@ keys/1, subscribers/1]). %% apply --export([apply/5]). +-export([apply/5, decide/5]). -export([any/5, all/5]). -export([is_configured/3]). @@ -168,3 +168,10 @@ is_configured(Handle, Function, Arity) when Handle /= undefined -> register_service(Plugin, Children) -> couch_epi_sup:plugin_childspecs(Plugin, Children). + +-spec decide(Handle :: handle(), ServiceId :: atom(), Function :: atom(), + Args :: [term()], Opts :: apply_opts()) -> + no_decision | {decided, term()}. + +decide(Handle, ServiceId, Function, Args, Opts) when Handle /= undefined -> + couch_epi_functions_gen:decide(Handle, ServiceId, Function, Args, Opts). http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/86531ee4/src/couch_epi_functions_gen.erl ---------------------------------------------------------------------- diff --git a/src/couch_epi_functions_gen.erl b/src/couch_epi_functions_gen.erl index 4990b60..df1d916 100644 --- a/src/couch_epi_functions_gen.erl +++ b/src/couch_epi_functions_gen.erl @@ -22,7 +22,8 @@ -export([ apply/4, apply/5, - modules/3 + modules/3, + decide/5 ]). -ifdef(TEST). @@ -34,7 +35,8 @@ -record(opts, { ignore_errors = false, pipe = false, - concurrent = false + concurrent = false, + interruptible = false }). get_handle(ServiceId) -> @@ -51,6 +53,15 @@ apply(Handle, _ServiceId, Function, Args, Opts) -> Modules = providers(Handle, Function, length(Args), DispatchOpts), dispatch(Handle, Modules, Function, Args, DispatchOpts). +-spec decide(Handle :: atom(), ServiceId :: atom(), Function :: atom(), + Args :: [term()], Opts :: couch_epi:apply_opts()) -> + no_decision | {decided, term()}. + +decide(Handle, _ServiceId, Function, Args, Opts) -> + DispatchOpts = parse_opts([interruptible|Opts]), + Modules = providers(Handle, Function, length(Args), DispatchOpts), + dispatch(Handle, Modules, Function, Args, DispatchOpts). + %% ------------------------------------------------------------------ %% Codegeneration routines %% ------------------------------------------------------------------ @@ -241,6 +252,9 @@ dispatch(Handle, Modules, Function, Args, lists:foldl(fun(Module, Acc) -> Handle:dispatch(Module, Function, Acc) end, Args, Modules); +dispatch(Handle, Modules, Function, Args, + #opts{interruptible = true}) -> + apply_while(Modules, Handle, Function, Args); dispatch(Handle, Modules, Function, Args, #opts{} = Opts) -> [do_dispatch(Handle, Module, Function, Args, Opts) || Module <- Modules]. @@ -258,6 +272,15 @@ do_dispatch(Handle, Module, Function, Args, do_dispatch(Handle, Module, Function, Args, #opts{}) -> Handle:dispatch(Module, Function, Args). +apply_while([], _Handle, _Function, _Args) -> + no_decision; +apply_while([Module | Modules], Handle, Function, Args) -> + case Handle:dispatch(Module, Function, Args) of + no_decision -> + apply_while(Modules, Handle, Function, Args); + {decided, _Decission} = Result -> + Result + end. parse_opts(Opts) -> parse_opts(Opts, #opts{}). @@ -268,6 +291,8 @@ parse_opts([pipe|Rest], #opts{} = Acc) -> parse_opts(Rest, Acc#opts{pipe = true}); parse_opts([concurrent|Rest], #opts{} = Acc) -> parse_opts(Rest, Acc#opts{concurrent = true}); +parse_opts([interruptible|Rest], #opts{} = Acc) -> + parse_opts(Rest, Acc#opts{interruptible = true}); parse_opts([], Acc) -> Acc. @@ -326,4 +351,52 @@ basic_test() -> ok. +generate_module(Name, Body) -> + Tokens = couch_epi_codegen:scan(Body), + couch_epi_codegen:generate(Name, Tokens). + +decide_module(decide) -> + " + -export([inc/1]). + + inc(A) -> + {decided, A + 1}. + "; +decide_module(no_decision) -> + " + -export([inc/1]). + + inc(_A) -> + no_decision. + ". + +decide_test() -> + ok = generate_module(decide, decide_module(decide)), + ok = generate_module(no_decision, decide_module(no_decision)), + + DecideDef = {foo_app, [{decide, [{inc, 1}]}]}, + NoDecissionDef = {bar_app, [{no_decision, [{inc, 1}]}]}, + + DecideFirstHandle = decide_first_handle, + ok = generate(DecideFirstHandle, [DecideDef, NoDecissionDef]), + ?assertMatch([decide, no_decision], DecideFirstHandle:providers(inc, 1)), + ?assertMatch({decided,4}, decide(DecideFirstHandle, anything, inc, [3], [])), + + DecideSecondHandle = decide_second_handle, + ok = generate(DecideSecondHandle, [NoDecissionDef, DecideDef]), + ?assertMatch([no_decision, decide], DecideSecondHandle:providers(inc, 1)), + ?assertMatch({decided,4}, decide(DecideSecondHandle, anything, inc, [3], [])), + + NoDecissionHandle = no_decision_handle, + ok = generate(NoDecissionHandle, [NoDecissionDef]), + ?assertMatch([no_decision], NoDecissionHandle:providers(inc, 1)), + ?assertMatch(no_decision, decide(NoDecissionHandle, anything, inc, [3], [])), + + NoHandle = no_handle, + ok = generate(NoHandle, []), + ?assertMatch([], NoHandle:providers(inc, 1)), + ?assertMatch(no_decision, decide(NoHandle, anything, inc, [3], [])), + + ok. + -endif.