Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding versioning functions

This patch adds two versionning functions, described in the
README.md file. They allow to kind of 'poll' for new versions
of configuration on a given table, without needing to read
the entire table to know if there is new material.

This is especially useful when using the all/1 function to do
further processing somewhere else based on some configuration
data.
  • Loading branch information...
commit b8c43d379665131e424dc3b0e6910400d0302688 1 parent 2fd2e0e
@ferd authored
View
13 README.markdown
@@ -41,6 +41,19 @@ And then start the app. You should then be able to call it as follows:
undefined -> undefined
end.
+While it is possible to have multiple files share the same namespace (the different lists are merged), it isn't recommended to do so unless you can guarantee that all files of the namespace will be reloaded at the same time; otherwise Bertconf will likely just replace the Namespace's table with the content of the lone new file.
+
Since the tag 0.2.0, a new function call is added for users requiring to retrieve entire tables at once. Be aware that in large tables, this can be a bit challenging for the garbage collector, although items are retrieved from the table in batches of 500 to avoid gigantic fetches:
[H|T] = bertconf:all(NameSpace).
+
+Since 0.3.0 there is also a versioning function. It's been our experience that when dealing with larger configuration tables, some indexing or further treatment might wish to be done on the data, especially when joining efforts with the `bertconf:all/1` function.
+
+The versioning function works as below:
+
+ Version = bertconf:version(NameSpace),
+ current = bertconf:version(NameSpace, Version),
+ %% wait for an update of some config data
+ old = bertconf:version(NameSpace, Version).
+
+The 'Version' value is considered to be opaque.
View
2  src/bertconf.app.src
@@ -1,6 +1,6 @@
{application, bertconf,
[{description, "Load configuration from .bert files and load them in ETS tables"},
- {vsn, "0.2.0"},
+ {vsn, "0.3.0"},
{modules, [bertconf, bertconf_sup, bertconf_lib, bertconf_bert_loader]},
{registered, []},
{applications, [kernel, stdlib]},
View
21 src/bertconf.erl
@@ -1,11 +1,15 @@
-module(bertconf).
-behaviour(application).
-export([start/2, stop/1]).
--export([read/2, all/1]).
+-export([read/2, all/1, version/1, version/2]).
-define(TABLE, bertconf_bert_loader).
-define(MATCH_LIMIT, 500).
-include("bertconf.hrl").
+-type namespace() :: term().
+-opaque version() :: {vsn,term()}.
+-export_types([namespace/0, version/0]).
+
%%% APPLICATION CALLBACKS %%%
start(normal, _) ->
bertconf_sup:start_link().
@@ -14,15 +18,30 @@ stop(_) -> ok.
%%% PUBLIC INTERFACE %%%
+-spec read(namespace(), Key::term()) -> undefined | {ok, term()}.
read(NameSpace, Key) ->
case ets:lookup(table(NameSpace), Key) of
[{_Key,Val}] -> {ok, Val};
[] -> undefined
end.
+-spec all(namespace()) -> list().
all(NameSpace) ->
loop_all({table(NameSpace), '_', ?MATCH_LIMIT}).
+%% The version is the table id, which should be swapped on
+%% any update. This is a very scary thing to use, but it works
+%% as long as we use it as an opaque data type.
+-spec version(namespace()) -> version().
+version(NameSpace) -> {vsn, table(NameSpace)}.
+
+-spec version(namespace(), version()) -> current | old.
+version(NameSpace, {vsn, Version}) ->
+ case {table(NameSpace), Version} of
+ {X,X} -> current;
+ _ -> old
+ end.
+
%%% PRIVATE
table(NameSpace) ->
[#tab{id=Tid}] = ets:lookup(?TABLE, NameSpace),
View
4 test/bert_loader_SUITE.erl
@@ -36,7 +36,7 @@ end_per_testcase(_Name, _Config) ->
%% found in a directory.
%% Note: the expected behaviour is that config files are read once as part of the
%% startup procedure.
-read_files_and_tables(Config) ->
+read_files_and_tables(_Config) ->
%% tables would be placement & format, both public and retrievable
%% from an index table by the name of the module. An accessor module
%% should later be created to abstract this away
@@ -49,7 +49,7 @@ read_files_and_tables(Config) ->
%% Only ".bert" files are inspected -- the rest, even if subscribing to
%% the BERT format is not visible in tables
-not_bert_ignored(Config) ->
+not_bert_ignored(_Config) ->
%% A value called 'not_bert' has been inserted in a .not_bert
%% file under the namespace 'format'. If it's found, we failed.
%% This test should pass unless bertconf_lib's suite is also failing.
View
44 test/bertconf_SUITE.erl
@@ -6,9 +6,9 @@
-include_lib("common_test/include/ct.hrl").
-export([all/0, init_per_suite/1, end_per_suite/1,
init_per_testcase/2, end_per_testcase/2]).
--export([access_table/1, all_data/1]).
+-export([access_table/1, all_data/1, table_version/1]).
-all() -> [access_table, all_data].
+all() -> [access_table, all_data, table_version].
init_per_suite(Config) ->
application:load({application, bertconf, []}),
@@ -16,16 +16,23 @@ init_per_suite(Config) ->
end_per_suite(_Config) -> ok.
+init_per_testcase(table_version, Config) ->
+ Data = ?config(data_dir, Config),
+ Priv = ?config(priv_dir, Config),
+ {ok, Files} = file:list_dir(Data),
+ [{ok,_}=file:copy(filename:join(Data,Name), filename:join(Priv,Name)) ||
+ Name <- Files],
+ application:set_env(bertconf, dir, [Priv]),
+ application:set_env(bertconf, delay, 500),
+ %% for some reason, application:start works like shit in here.
+ % application:start(bertconf),
+ {ok, Pid} = bertconf:start(normal, temporary),
+ unlink(Pid),
+ [{kill, Pid} | Config];
init_per_testcase(_Name, Config) ->
- % Data = ?config(data_dir, Config),
- % Priv = ?config(priv_dir, Config),
- % {ok, Files} = file:list_dir(Data),
- % [{ok,_}=file:copy(filename:join(Data,Name), filename:join(Priv,Name)) ||
- % Name <- Files],
application:set_env(bertconf, dir, [?config(data_dir, Config)]),
application:set_env(bertconf, delay, 500),
%% for some reason, application:start works like shit in here.
- % application:start(bertconf),
{ok, Pid} = bertconf:start(normal, temporary),
unlink(Pid),
[{kill, Pid} | Config].
@@ -46,3 +53,24 @@ all_data(_Config) ->
{14611, _},
{14612, _},
{14613, _}] = lists:sort(bertconf:all(placement)).
+
+table_version(Config) ->
+ %% get current table version reference
+ Version = bertconf:version(format),
+ current = bertconf:version(format, Version),
+
+ %% change files
+ Dir = ?config(priv_dir, Config),
+ File = filename:join(Dir, "rtb_state.bert"),
+ {ok, Bin} = file:read_file(File),
+ [{format,L},{placement,_}] = lists:sort(binary_to_term(Bin)),
+ NewList = [{format, [{custom_test_entry, now()}|L]}, {newtable, [{a,b}]}],
+ file:write_file(File, term_to_binary(NewList)),
+
+ %% wait for reload
+ timer:sleep(950),
+
+ old = bertconf:version(format, Version),
+ NewVersion = bertconf:version(format),
+ true = NewVersion =/= Version,
+ current = bertconf:version(format, NewVersion).
Please sign in to comment.
Something went wrong with that request. Please try again.