You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2015/07/21 15:16:04 UTC

couchdb-couch-epi git commit: The race condition between providers is fixed

Repository: couchdb-couch-epi
Updated Branches:
  refs/heads/master 3d0e6a6b3 -> 822f3a265


The race condition between providers is fixed

In previous design there is a race condition between the time we read the
current definitions in the generated module and the time we compile new
version of it. This race led to overwriting of data of already
configured providers.

This commit fixes the issue by introducing couch_epi_module_keeper
process. This process is named by generated module name and it is
essentially a requests serializer.


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/822f3a26
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/tree/822f3a26
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/diff/822f3a26

Branch: refs/heads/master
Commit: 822f3a265bc45707def9ca10063a43edb5898d16
Parents: 3d0e6a6
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Tue Jul 14 08:27:37 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Fri Jul 17 10:11:25 2015 -0700

----------------------------------------------------------------------
 src/couch_epi_data.erl          |  5 +++
 src/couch_epi_data_gen.erl      |  4 +-
 src/couch_epi_functions.erl     |  5 +++
 src/couch_epi_functions_gen.erl |  4 +-
 src/couch_epi_keeper_sup.erl    | 58 +++++++++++++++++++++++++++
 src/couch_epi_module_keeper.erl | 78 ++++++++++++++++++++++++++++++++++++
 src/couch_epi_sup.erl           |  8 +++-
 7 files changed, 159 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_data.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_data.erl b/src/couch_epi_data.erl
index d421133..680e5f5 100644
--- a/src/couch_epi_data.erl
+++ b/src/couch_epi_data.erl
@@ -53,6 +53,7 @@ childspec(Id, App, EpiKey, Module) ->
     }.
 
 start_link(SubscriberApp, {epi_key, Key}, Module, Options) ->
+    maybe_start_keeper(Key),
     gen_server:start_link(?MODULE, [SubscriberApp, Module, Key, Options], []).
 
 reload(Server) ->
@@ -149,3 +150,7 @@ current(Handle, Subscriber) ->
     catch error:undef ->
         []
     end.
+
+maybe_start_keeper(Key) ->
+    Handle = couch_epi_data_gen:get_handle(Key),
+    couch_epi_module_keeper:maybe_start_keeper(couch_epi_data_gen, Handle).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_data_gen.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_data_gen.erl b/src/couch_epi_data_gen.erl
index 73cf901..75601cf 100644
--- a/src/couch_epi_data_gen.erl
+++ b/src/couch_epi_data_gen.erl
@@ -23,12 +23,14 @@
 -export([by_source/1, by_source/2]).
 -export([keys/1, subscribers/1]).
 
+-export([save/3]).
+
 set(Handle, Source, Data) ->
     case is_updated(Handle, Source, Data) of
         false ->
             ok;
         true ->
-            save(Handle, Source, Data)
+            couch_epi_module_keeper:save(Handle, Source, Data)
     end.
 
 get(Handle) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_functions.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_functions.erl b/src/couch_epi_functions.erl
index 86687a7..09ece2e 100644
--- a/src/couch_epi_functions.erl
+++ b/src/couch_epi_functions.erl
@@ -53,6 +53,7 @@ childspec(Id, App, Key, Module) ->
     }.
 
 start_link(ProviderApp, {epi_key, ServiceId}, {modules, Modules}, Options) ->
+    maybe_start_keeper(ServiceId),
     gen_server:start_link(
         ?MODULE, [ProviderApp, ServiceId, Modules, Options], []).
 
@@ -148,3 +149,7 @@ safe_remove(#state{} = State) ->
     catch Class:Reason ->
         {{Class, Reason}, State}
     end.
+
+maybe_start_keeper(ServiceId) ->
+    Handle = couch_epi_functions_gen:get_handle(ServiceId),
+    couch_epi_module_keeper:maybe_start_keeper(couch_epi_functions_gen, Handle).

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_functions_gen.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_functions_gen.erl b/src/couch_epi_functions_gen.erl
index b62fbb5..a08573c 100644
--- a/src/couch_epi_functions_gen.erl
+++ b/src/couch_epi_functions_gen.erl
@@ -14,6 +14,8 @@
 
 -export([add/3, remove/3, get_handle/1, hash/1, apply/4, apply/5]).
 
+-export([save/3]).
+
 -ifdef(TEST).
 
 -export([foo/2, bar/0]).
@@ -32,7 +34,7 @@ add(Handle, Source, Modules) ->
         false ->
             ok;
         true ->
-            save(Handle, Source, Modules)
+            couch_epi_module_keeper:save(Handle, Source, Modules)
     end.
 
 remove(Handle, Source, Modules) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_keeper_sup.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_keeper_sup.erl b/src/couch_epi_keeper_sup.erl
new file mode 100644
index 0000000..c342d68
--- /dev/null
+++ b/src/couch_epi_keeper_sup.erl
@@ -0,0 +1,58 @@
+% 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.
+
+-module(couch_epi_keeper_sup).
+
+-behaviour(supervisor).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([start_link/0]).
+
+-export([start_child/2, terminate_child/1]).
+
+%% ------------------------------------------------------------------
+%% supervisor Function Exports
+%% ------------------------------------------------------------------
+
+-export([init/1]).
+
+%% Helper macro for declaring children of supervisor
+-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+
+%% ===================================================================
+%% API functions
+%% ===================================================================
+
+start_link() ->
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+start_child(Codegen, Module) ->
+    supervisor:start_child(?MODULE, [Codegen, Module]).
+
+terminate_child(undefined) -> ok;
+terminate_child(Child) when is_atom(Child) ->
+    terminate_child(whereis(Child));
+terminate_child(ChildPid) ->
+    supervisor:terminate_child(?MODULE, ChildPid).
+
+%% ===================================================================
+%% Supervisor callbacks
+%% ===================================================================
+
+init([]) ->
+    Children = [
+        ?CHILD(couch_epi_module_keeper, worker)
+    ],
+    {ok, { {simple_one_for_one, 5, 10}, Children} }.

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_module_keeper.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_module_keeper.erl b/src/couch_epi_module_keeper.erl
new file mode 100644
index 0000000..f538cf5
--- /dev/null
+++ b/src/couch_epi_module_keeper.erl
@@ -0,0 +1,78 @@
+% 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.
+
+-module(couch_epi_module_keeper).
+
+-behaviour(gen_server).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([maybe_start_keeper/2]).
+-export([start_link/2, save/3]).
+-export([stop/1]).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Exports
+%% ------------------------------------------------------------------
+
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+         terminate/2, code_change/3]).
+
+-record(state, {codegen, module}).
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+maybe_start_keeper(Codegen, Module) ->
+    catch couch_epi_keeper_sup:start_child(Codegen, Module).
+
+start_link(Codegen, Module) ->
+    gen_server:start_link({local, Module}, ?MODULE, [Codegen, Module], []).
+
+stop(Server) ->
+    catch gen_server:call(Server, stop).
+
+save(Server, Source, Config) ->
+    gen_server:call(Server, {save, Source, Config}).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Definitions
+%% ------------------------------------------------------------------
+
+init([Codegen, Module]) ->
+    {ok, #state{codegen = Codegen, module = Module}}.
+
+handle_call({save, Source, Config}, _From, State) ->
+    #state{codegen = Codegen, module = Module} = State,
+    Reply = Codegen:save(Module, Source, Config),
+    {reply, Reply, State};
+handle_call(_Request, _From, State) ->
+    {reply, ok, State}.
+
+handle_cast(_Msg, State) ->
+    {noreply, State}.
+
+handle_info(_Info, State) ->
+    {noreply, State}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/822f3a26/src/couch_epi_sup.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_sup.erl b/src/couch_epi_sup.erl
index 5e44d1b..3c35d2d 100644
--- a/src/couch_epi_sup.erl
+++ b/src/couch_epi_sup.erl
@@ -22,6 +22,8 @@
 
 %% Helper macro for declaring children of supervisor
 -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+-define(SUP(I, A),
+        {I, {I, start_link, A}, permanent, infinity, supervisor, [I]}).
 
 %% ===================================================================
 %% API functions
@@ -35,4 +37,8 @@ start_link() ->
 %% ===================================================================
 
 init([]) ->
-    {ok, { {one_for_one, 5, 10}, [?CHILD(couch_epi_server, worker)]} }.
+    Children = [
+        ?CHILD(couch_epi_server, worker),
+        ?SUP(couch_epi_keeper_sup, [])
+    ],
+    {ok, { {one_for_one, 5, 10}, Children} }.