summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriilyak <iilyak@ca.ibm.com>2018-08-08 07:27:37 -0700
committerGitHub <noreply@github.com>2018-08-08 07:27:37 -0700
commitd98e3e1998e8d20bc580d495b82cc3a9b6c82dad (patch)
tree70f0566c42788424260536c2df00856c1bce5576
parent54b2eaac0094c035a6855af3f1e1e0db07b02f93 (diff)
parent7a2a39007284039fb2744aa441fa2fd73af23170 (diff)
downloadcouchdb-d98e3e1998e8d20bc580d495b82cc3a9b6c82dad.tar.gz
Merge pull request #1432 from cloudant/support-callback-module-data-provider
Support callback module data provider
-rw-r--r--src/couch_epi/README.md35
-rw-r--r--src/couch_epi/src/couch_epi_data.erl11
-rw-r--r--src/couch_epi/src/couch_epi_sup.erl5
-rw-r--r--src/couch_epi/test/couch_epi_tests.erl67
4 files changed, 104 insertions, 14 deletions
diff --git a/src/couch_epi/README.md b/src/couch_epi/README.md
index 66421ceb9..368ad9afd 100644
--- a/src/couch_epi/README.md
+++ b/src/couch_epi/README.md
@@ -39,7 +39,8 @@ could add an entry in its implementation of couch_epi_plugin behaviour:
{priv_file, "stats_descriptions.cfg"}, [{interval, 5000}]}
{{couch_stats, descriptions},
{file, "/tmp/extra_stats.cfg"}, [{interval, 5000}]},
- {{couch_stats, descriptions}, {module, my_stats}}
+ {{couch_stats, descriptions}, {static_module, my_stats}},
+ {{couch_stats, descriptions}, {callback_module, my_stats}}
].
When service provider wants to learn about all the installed config data for it to use
@@ -65,6 +66,38 @@ There are also additional functions to get the same data in various formats
- `couch_epi:keys(Handle)` - returns list of configured keys
- `couch_epi:subscribers(Handle)` - return list of known subscribers
+The difference between `static_module` and `callback_module` providers is in how
+couch_epi detects the changes. `static_module` is designed for the cases when you
+have your data hardcoded in the module. For example you might have the following:
+
+```
+-export([data/0]).
+
+data() ->
+ [
+ {[complex, key, 2], [
+ {type, counter},
+ {desc, bar}
+ ]},
+ {[complex, key, 1], [
+ {type, counter},
+ {desc, updated_foo}
+ ]}
+ ].
+```
+
+The changes are detected by relying on `vsn` module attribute. Therefore we
+would notice the change only when data source module is recompiled.
+
+The `callback_module` provider uses the return value from `data/0` to detect
+changes and it is useful for cases when the data term is constructed dynamically.
+For example to cache values of CouchDB config one could use the following:
+
+```
+-export([data/0]).
+data() ->
+ config:get("dreyfus").
+```
# Function dispatch example
diff --git a/src/couch_epi/src/couch_epi_data.erl b/src/couch_epi/src/couch_epi_data.erl
index bbed828bb..2bb09f6cf 100644
--- a/src/couch_epi/src/couch_epi_data.erl
+++ b/src/couch_epi/src/couch_epi_data.erl
@@ -102,12 +102,15 @@ definitions({file, FilePath}) ->
{error, Reason} ->
{error, {FilePath, Reason}}
end;
-definitions({module, Module}) when is_atom(Module) ->
- definitions({module, [Module]});
-definitions({module, Modules}) ->
+definitions({static_module, Module}) when is_atom(Module) ->
+ definitions({static_module, [Module]});
+definitions({static_module, Modules}) ->
Data = lists:append([M:data() || M <- Modules]),
Hash = couch_epi_functions_gen:hash(Modules),
- {ok, Hash, Data}.
+ {ok, Hash, Data};
+definitions({callback_module, Module}) ->
+ Data = Module:data(),
+ {ok, erlang:phash2(Data), Data}.
hash_of_file(FilePath) ->
{ok, Data} = file:read_file(FilePath),
diff --git a/src/couch_epi/src/couch_epi_sup.erl b/src/couch_epi/src/couch_epi_sup.erl
index 31f27d752..509f5a1c2 100644
--- a/src/couch_epi/src/couch_epi_sup.erl
+++ b/src/couch_epi/src/couch_epi_sup.erl
@@ -121,7 +121,8 @@ modules(#couch_epi_spec{kind = services, value = Module}) ->
[Module];
modules(#couch_epi_spec{kind = data_providers, value = Value}) ->
case Value of
- {module, Module} -> [Module];
+ {static_module, Module} -> [Module];
+ {callback_module, Module} -> [Module];
_ -> []
end;
modules(#couch_epi_spec{kind = data_subscriptions, behaviour = Module}) ->
@@ -159,7 +160,7 @@ services() ->
data_providers() ->
[
- {{test_app, descriptions}, {module, ?MODULE}, [{interval, 100}]}
+ {{test_app, descriptions}, {static_module, ?MODULE}, [{interval, 100}]}
].
data_subscriptions() ->
diff --git a/src/couch_epi/test/couch_epi_tests.erl b/src/couch_epi/test/couch_epi_tests.erl
index 79122d75a..042753215 100644
--- a/src/couch_epi/test/couch_epi_tests.erl
+++ b/src/couch_epi/test/couch_epi_tests.erl
@@ -17,7 +17,7 @@
-define(DATA_FILE1, ?ABS_PATH("test/fixtures/app_data1.cfg")).
-define(DATA_FILE2, ?ABS_PATH("test/fixtures/app_data2.cfg")).
--export([notify_cb/4, save/3]).
+-export([notify_cb/4, save/3, get/2]).
-record(ctx, {file, handle, pid, kv, key, modules = []}).
@@ -83,6 +83,14 @@
].
").
+-define(DATA_MODULE3(Name, Kv), "
+ -export([data/0]).
+
+data() ->
+ {ok, Data} = couch_epi_tests:get('" ++ atom_to_list(Kv) ++ "', data),
+ Data.
+").
+
%% ------------------------------------------------------------------
%% couch_epi_plugin behaviour
%% ------------------------------------------------------------------
@@ -175,7 +183,7 @@ setup(data_file) ->
handle = couch_epi:get_handle(Key),
kv = KV,
pid = Pid};
-setup(data_module) ->
+setup(static_data_module) ->
error_logger:tty(false),
Key = {test_app, descriptions},
@@ -183,7 +191,7 @@ setup(data_module) ->
ok = generate_module(provider, ?DATA_MODULE1(provider)),
KV = start_state_storage(),
- ok = start_epi([{provider_epi, plugin_module([KV, {module, provider}])}]),
+ ok = start_epi([{provider_epi, plugin_module([KV, {static_module, provider}])}]),
Pid = whereis(couch_epi:get_handle(Key)),
Handle = couch_epi:get_handle(Key),
@@ -194,6 +202,33 @@ setup(data_module) ->
modules = [Handle, provider],
kv = KV,
pid = Pid};
+setup(callback_data_module) ->
+ error_logger:tty(false),
+
+ Key = {test_app, descriptions},
+
+ KV = start_state_storage(),
+ Value = [
+ {[complex, key, 1], [
+ {type, counter},
+ {desc, foo}
+ ]}
+ ],
+ save(KV, data, Value),
+
+ ok = generate_module(provider, ?DATA_MODULE3(provider, KV)),
+
+ ok = start_epi([{provider_epi, plugin_module([KV, {callback_module, provider}])}]),
+
+ Pid = whereis(couch_epi:get_handle(Key)),
+ Handle = couch_epi:get_handle(Key),
+
+ #ctx{
+ key = Key,
+ handle = Handle,
+ modules = [Handle, provider],
+ kv = KV,
+ pid = Pid};
setup(functions) ->
Key = my_service,
error_logger:tty(false),
@@ -244,7 +279,8 @@ epi_config_update_test_() ->
],
Cases = [
data_file,
- data_module,
+ static_data_module,
+ callback_data_module,
functions
],
{
@@ -264,7 +300,8 @@ epi_data_source_test_() ->
],
Cases = [
data_file,
- data_module
+ static_data_module,
+ callback_data_module
],
{
"epi data API tests",
@@ -305,7 +342,8 @@ epi_providers_order_test_() ->
epi_reload_test_() ->
Cases = [
data_file,
- data_module,
+ static_data_module,
+ callback_data_module,
functions
],
Funs = [
@@ -565,8 +603,21 @@ update(Case, #ctx{pid = Pid, modules = Modules} = Ctx) ->
update_definitions(data_file, #ctx{file = File}) ->
{ok, _} = file:copy(?DATA_FILE2, File),
ok;
-update_definitions(data_module, #ctx{}) ->
+update_definitions(static_data_module, #ctx{}) ->
ok = generate_module(provider, ?DATA_MODULE2(provider));
+update_definitions(callback_data_module, #ctx{kv = Kv}) ->
+ Value = [
+ {[complex, key, 2], [
+ {type, counter},
+ {desc, bar}
+ ]},
+ {[complex, key, 1], [
+ {type, counter},
+ {desc, updated_foo}
+ ]}
+ ],
+ save(Kv, data, Value),
+ ok;
update_definitions(functions, #ctx{}) ->
ok = generate_module(provider1, ?MODULE2(provider1)).
@@ -597,6 +648,8 @@ save(Kv, Key, Value) ->
call(Kv, {set, Key, Value}).
get(#ctx{kv = Kv}, Key) ->
+ call(Kv, {get, Key});
+get(Kv, Key) ->
call(Kv, {get, Key}).
call(Server, Msg) ->