You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@couchdb.apache.org by rn...@apache.org on 2015/06/25 11:38:58 UTC
[6/6] couchdb-couch-epi git commit: Add couch_epi_data
Add couch_epi_data
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/59bbd8ee
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/tree/59bbd8ee
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/diff/59bbd8ee
Branch: refs/heads/master
Commit: 59bbd8eefbf2d7dc881e6a8b2911a84966be88a4
Parents: 32ba6e7
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Jun 24 13:52:59 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Wed Jun 24 15:13:50 2015 -0700
----------------------------------------------------------------------
src/couch_epi_data.erl | 151 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 151 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch-epi/blob/59bbd8ee/src/couch_epi_data.erl
----------------------------------------------------------------------
diff --git a/src/couch_epi_data.erl b/src/couch_epi_data.erl
new file mode 100644
index 0000000..d421133
--- /dev/null
+++ b/src/couch_epi_data.erl
@@ -0,0 +1,151 @@
+% 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_data).
+
+-behaviour(gen_server).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([childspec/4]).
+-export([start_link/4, reload/1]).
+-export([wait/1, 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, {
+ subscriber, module, key, hash, handle,
+ initialized = false, pending = []}).
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+childspec(Id, App, EpiKey, Module) ->
+ {
+ Id,
+ {?MODULE, start_link, [
+ App,
+ EpiKey,
+ Module,
+ []
+ ]},
+ permanent,
+ 5000,
+ worker,
+ [Module]
+ }.
+
+start_link(SubscriberApp, {epi_key, Key}, Module, Options) ->
+ gen_server:start_link(?MODULE, [SubscriberApp, Module, Key, Options], []).
+
+reload(Server) ->
+ gen_server:call(Server, reload).
+
+wait(Server) ->
+ gen_server:call(Server, wait).
+
+stop(Server) ->
+ catch gen_server:call(Server, stop).
+
+%% ------------------------------------------------------------------
+%% gen_server Function Definitions
+%% ------------------------------------------------------------------
+
+init([Subscriber, Module, Key, _Options]) ->
+ gen_server:cast(self(), init),
+ {ok, #state{
+ subscriber = Subscriber,
+ module = Module,
+ key = Key,
+ handle = couch_epi_data_gen:get_handle(Key)}}.
+
+handle_call(wait, _From, #state{initialized = true} = State) ->
+ {reply, ok, State};
+handle_call(wait, From, #state{pending = Pending} = State) ->
+ {noreply, State#state{pending = [From | Pending]}};
+handle_call(reload, _From, State) ->
+ {Res, NewState} = reload_if_updated(State),
+ {reply, Res, NewState};
+handle_call(stop, _From, State) ->
+ {stop, normal, State};
+handle_call(_Request, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(init, #state{pending = Pending} = State) ->
+ {_, NewState} = reload_if_updated(State),
+ [gen_server:reply(Client, ok) || Client <- Pending],
+ {noreply, NewState#state{initialized = true, pending = []}};
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {_, NewState} = reload_if_updated(State),
+ {ok, NewState}.
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+reload_if_updated(#state{hash = OldHash, module = Module} = State) ->
+ case couch_epi_functions_gen:hash([Module]) of
+ OldHash ->
+ {ok, State};
+ Hash ->
+ safe_set(Hash, State)
+ end.
+
+safe_set(Hash, #state{} = State) ->
+ #state{
+ handle = Handle,
+ subscriber = Subscriber,
+ module = Module,
+ key = Key} = State,
+ try
+ Data = get_from_module(Module),
+ OldData = current(Handle, Subscriber),
+ ok = couch_epi_data_gen:set(Handle, Subscriber, Data),
+ couch_epi_server:notify(Subscriber, Key, {data, OldData}, {data, Data}),
+ {ok, State#state{hash = Hash}}
+ catch Class:Reason ->
+ {{Class, Reason}, State}
+ end.
+
+get_from_module(Module) ->
+ try
+ Module:data()
+ catch
+ error:undef -> []
+ end.
+
+current(Handle, Subscriber) ->
+ try
+ case couch_epi_data_gen:by_source(Handle, Subscriber) of
+ undefined -> [];
+ Data -> Data
+ end
+ catch error:undef ->
+ []
+ end.