From 4f3364a76d5952af49fef3c8abfe241837de5efa Mon Sep 17 00:00:00 2001 From: lsowen Date: Tue, 4 Dec 2012 21:36:44 -0500 Subject: [PATCH] Much cleaner, but not working, because I have a circular loop --- src/ezic.erl | 30 +++--- src/ezic_date.erl | 2 +- src/ezic_db.erl | 214 +++++++++++++++++--------------------- src/ezic_db_ets.erl | 174 +++++++++++++++---------------- src/ezic_db_ets_admin.erl | 137 ------------------------ src/ezic_db_mnesia.erl | 145 ++++++++++++++++++++++++++ src/ezic_flatten.erl | 15 ++- src/ezic_rule.erl | 2 +- src/ezic_sup.erl | 2 +- src/ezic_zone.erl | 3 +- 10 files changed, 353 insertions(+), 371 deletions(-) delete mode 100644 src/ezic_db_ets_admin.erl create mode 100644 src/ezic_db_mnesia.erl diff --git a/src/ezic.erl b/src/ezic.erl index 6a4f12c..53e4780 100644 --- a/src/ezic.erl +++ b/src/ezic.erl @@ -36,7 +36,7 @@ localtime(TzName) -> utc_to_local(UTCDatetime, TzName) -> NormalDatetime= ezic_date:normalize(UTCDatetime, u), - #flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db_ets:flatzone(NormalDatetime, TzName), + #flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db:flatzone(NormalDatetime, TzName), ezic_date:add_offset( ezic_date:add_offset( @@ -47,7 +47,7 @@ utc_to_local(UTCDatetime, TzName) -> local_to_utc(LocalDatetime, TzName) -> NormalDatetime= ezic_date:normalize(LocalDatetime, w), - #flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db_ets:flatzone(NormalDatetime, TzName), + #flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db:flatzone(NormalDatetime, TzName), ezic_date:add_offset( ezic_date:add_offset( @@ -84,7 +84,7 @@ dev() -> % ezic_flatten:flatten_all_zones(Zones), application:start(ezic), - ezic_db_ets:flatzone({{2010,11,17}, #tztime{time={23,42,0}}}, "America/Los_Angeles"), + ezic_db:flatzone({{2010,11,17}, #tztime{time={23,42,0}}}, "America/Los_Angeles"), ok. @@ -94,8 +94,8 @@ zf() -> reflatten() -> - ezic_db_ets:wipe(flatzone), - ezic_db_ets:flatten(). + ezic_db:wipe(flatzone), + ezic_db:flatten(). @@ -113,20 +113,20 @@ test() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -current_as_of_utc(UTCDatetime, TzName) -> - CZone= ezic_zone:current_as_of_utc(UTCDatetime, TzName), - RuleName= CZone#zone.rule, - Rules= ezic_db_ets:rules(RuleName), - CRule= ezic_rule:current_as_of_utc(UTCDatetime, Rules), - {ok, CZone, CRule}. +%current_as_of_utc(UTCDatetime, TzName) -> +% CZone= ezic_zone:current_as_of_utc(UTCDatetime, TzName), +% RuleName= CZone#zone.rule, +% Rules= ezic_db:rules(RuleName), +% CRule= ezic_rule:current_as_of_utc(UTCDatetime, Rules), +% {ok, CZone, CRule}. %%current_as_of_local(Datetime, TzName) -> %% not_done. -time_offset(Zone, Rule) -> - OffsetSec= ezic_zone:offset_sec(Zone), - DSTSec= ezic_rule:dst_sec(Rule), - OffsetSec + DSTSec. +%time_offset(Zone, Rule) -> +% OffsetSec= ezic_zone:offset_sec(Zone), +% DSTSec= ezic_rule:dst_sec(Rule), +% OffsetSec + DSTSec. diff --git a/src/ezic_date.erl b/src/ezic_date.erl index a6f0b86..40a4836 100644 --- a/src/ezic_date.erl +++ b/src/ezic_date.erl @@ -251,7 +251,7 @@ when is_integer(Y1), is_integer(Y2) compare({Date1, #tztime{time=Time1, flag=F}} , {Date2, #tztime{time=Time2, flag=F}}) -> - Date1 =< Date2 orelse Time1 =< time2; + Date1 =< Date2 orelse Time1 =< Time2; compare(X,Y) -> erlang:error(bad_dates, [X,Y]). diff --git a/src/ezic_db.erl b/src/ezic_db.erl index f319ca2..55d0116 100644 --- a/src/ezic_db.erl +++ b/src/ezic_db.erl @@ -1,149 +1,125 @@ -module(ezic_db). -include("include/ezic.hrl"). --include_lib("stdlib/include/qlc.hrl"). -include_lib("eunit/include/eunit.hrl"). +-behaviour(gen_server). + -export([ zones/1 , rules/1 , flatzone/2 + %, insert/2 + , get_all/1 + , insert_all/1 + , wipe/1 + , flatten/0 ]). -export([ - wipe/0 - , wipe/1 - , init/0 - , insert_all/1 - , get_all/1 - ]). + start_link/0 + , init/1 + , code_change/3 + , handle_call/3 + , handle_cast/2 + , handle_info/2 + , terminate/2 + ]). --define(create(Record), - {atomic, ok} = mnesia:create_table(Record, - [{type, bag} - , {disc_copies, [node()]} - , {attributes, record_info(fields, Record)} - ])). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PUBLIC API +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% READ - db reading methods -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +zones(TzName) -> + gen_server:call(?MODULE, {zones, TzName}). +rules(TzName) -> + gen_server:call(?MODULE, {rules, TzName}). -% retrieve all zones by name -zones(Name) -> - F = fun()-> - Q = qlc:q([Z || Z=#zone{name=N} <- mnesia:table(zone), N=:=Name]), - qlc:e(Q) - end, - {atomic, Zones}= mnesia:transaction(F), - Zones. - -% retrieve all rules by name -rules(Name) -> - F = fun()-> - Q = qlc:q([R || R=#rule{name=N} <- mnesia:table(rule), N=:=Name]), - qlc:e(Q) - end, - {atomic, Rules}= mnesia:transaction(F), - Rules. - -% get all records from table -get_all(Tab) when is_atom(Tab) -> - F = fun() -> - Q = qlc:q([R || R<- mnesia:table(Tab)]), - qlc:e(Q) - end, - {atomic, Ret}= mnesia:transaction(F), - Ret. -%% get a flatzone for a specific date -%% Date :: {date(), #tztime{}} -%% returns #flatzone{} -%% or throws either error: -%% * {ambiguous_zone, [Z1,Z2,...]} -%% * {no_zone} flatzone(Date, TzName) -> - %% @todo validate Date - F = fun()-> - Q = qlc:q( - [Fz || Fz=#flatzone{tzname=N} <- mnesia:table(flatzone) - , N=:=TzName - , ezic_flatten:contains_date(Fz, Date)]), - qlc:e(Q) - end, - {atomic, FlatZones}= mnesia:transaction(F), - - case length(FlatZones) of - 1 -> - hd(FlatZones); - 2 -> - erlang:error(ambiguous_zone, FlatZones); - 0 -> - erlang:error(no_zone); - _ -> - erlang:error(should_not_happen, {FlatZones, Date, TzName}) - end. - + gen_server:call(?MODULE, {flatzone, Date, TzName}). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% ADMIN - initialization and administration methods -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% initialize the db -init() -> - create_tabs(mnesia:create_schema([node()])), - mnesia:wait_for_tables([rule, zone, link, leap, flatzone], 3000). - - -% WARNING: deletes all db files -wipe() -> - mnesia:stop(), - mnesia:delete_schema([node()]). - - - -% WARNING: deletes all entries in table Tab -wipe(Tab) -> - mnesia:transaction( - fun()-> - mnesia:delete(Tab, '_', write) - end). - - - -create_tabs(ok) -> - mnesia:start(), - - ?create(rule), - ?create(zone), - ?create(link), - ?create(leap), - ?create(flatzone), - - ok; -create_tabs({error, {_, {already_exists,_}}}) -> - mnesia:start(), - ok; -create_tabs(E) -> - ?debugVal(E). +get_all(Tab) -> + gen_server:call(?MODULE, {all, Tab}). insert_all(Records) -> - mnesia:transaction( - fun() -> - lists:foreach( - fun(R)-> mnesia:write(R) end, - Records) - end). - + gen_server:call(?MODULE, {insert_all, Records}). +%wipe() -> +% gen_server:call(?MODULE, {wipe}). +wipe(Tab) -> + gen_server:call(?MODULE, {wipe, Tab}). + + +flatten() -> + gen_server:call(?MODULE, {flatten}). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% GEN_SERVER +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +init(_) -> + ezic_db_ets:init(), + {ok, []}. + +%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%% DB Lookup +%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +handle_call({zones, Name}, _, State) -> + Matches= ezic_db_ets:zones(Name), + {reply, Matches, State}; +handle_call({rules, Name}, _, State) -> + Matches= ezic_db_ets:rules(Name), + {reply, Matches, State}; +handle_call({all, Tab}, _, State) -> + Matches= ezic_db_ets:get_all(Tab), + {reply, Matches, State}; +handle_call({flatzone, Date, Name}, _, State) -> + Result= ezic_db_ets:flatzone(Date, Name), + {reply, Result, State}; +handle_call({insert_all, Records}, _, State) -> + ezic_db_ets:insert_all(Records), + {noreply, State}; +handle_call({wipe, Tab}, _, State) -> + Result= ezic_db_ets:wipe(Tab), + {reply, Result, State}; +handle_call({flatten}, _, State) -> + Result= ezic_flatten:flatten(), + {reply, Result, State}; +handle_call(_, _, State) -> + {noreply, State}. + + +%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%% Other gen_server +%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +code_change(_, State, _) -> + {ok, State}. + + +handle_cast(_, State) -> + {noreply, State}. + +handle_info(_, State) -> + {noreply, State}. + +terminate(_, _State) -> + ok. diff --git a/src/ezic_db_ets.erl b/src/ezic_db_ets.erl index dd1d32c..928dc01 100644 --- a/src/ezic_db_ets.erl +++ b/src/ezic_db_ets.erl @@ -2,54 +2,57 @@ -include("include/ezic.hrl"). -include_lib("eunit/include/eunit.hrl"). --behaviour(gen_server). - +-define(DB_FILENAME, "db.e2f"). -export([ - zones/1 + init/0 + , zones/1 , rules/1 , flatzone/2 - , all/1 - %, insert_all/1 + %, insert/2 + , get_all/1 + , insert_all/1 , wipe/1 - , flatten/0 ]). - --export([ - start_link/0 - , init/1 - , code_change/3 - , handle_call/3 - , handle_cast/2 - , handle_info/2 - , terminate/2 - ]). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % PUBLIC API %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% zones(TzName) -> - gen_server:call(?MODULE, {zones, TzName}). + ets:select(zone, [{#zone{name=TzName, _='_'}, [], ['$_']}]). rules(TzName) -> - gen_server:call(?MODULE, {rules, TzName}). + ets:select(rule, [{#rule{name=TzName, _='_'}, [], ['$_']}]). flatzone(Date, TzName) -> - gen_server:call(?MODULE, {flatzone, Date, TzName}). + FlatZones= ets:select(flatzone, ezic_flatten:ms(Date, TzName)), + case length(FlatZones) of + 1 -> + hd(FlatZones); + 2 -> + erlang:error(ambiguous_zone, FlatZones); + 0 -> + erlang:error(no_zone); + _ -> + erlang:error(should_not_happen, {FlatZones, Date, TzName}) + end. -all(Tab) -> - gen_server:call(?MODULE, {all, Tab}). +get_all(Tab) -> + ets:lookup(Tab, Tab). -%insert_all(Records) -> -% gen_server:call(?MODULE, {insert_all, Records}). +insert_all(Records) -> + Zones= [ZI || ZI <- Records, ZI = #zone{}], + ets:insert(zone, Zones), + Rules= [RI || RI <- Records, RI = #rule{}], + ets:insert(rule, Rules), + FlatZones= [FZ || FZ <- Records, FZ = #flatzone{}], + ets:insert(flatzone, FlatZones). %wipe() -> @@ -57,81 +60,78 @@ all(Tab) -> wipe(Tab) -> - gen_server:call(?MODULE, {wipe, Tab}). + ets:delete(Tab, Tab). -flatten() -> - gen_server:call(?MODULE, {flatten}). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% GEN_SERVER -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -init(_) -> - ezic_db_ets_admin:init(). +init() -> + {ok, DbDir}= application:get_env(db_dir), + Filename= filename:join(DbDir, ?DB_FILENAME), + case db_sane(Filename) of + true -> load_tabfile(Filename); + false -> create_tables(Filename) + end, + {ok, []}. %%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -%% DB Lookup +%% Private functions for initializing ets %%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -handle_call({zones, Name}, _, State) -> - Matches= ets:select(zone, [{#zone{name=Name, _='_'}, [], ['$_']}]), - {reply, Matches, State}; -handle_call({rules, Name}, _, State) -> - Matches= ets:select(rule, [{#rule{name=Name, _='_'}, [], ['$_']}]), - {reply, Matches, State}; -handle_call({all, Tab}, _, State) -> - Matches= ets:lookup(Tab, Tab), - {reply, Matches, State}; -handle_call({flatzone, Date, Name}, _, State) -> - FlatZones= ets:select(flatzone, ezic_flatten:ms(Date, Name)), - Result= case length(FlatZones) of - 1 -> - hd(FlatZones); - 2 -> - erlang:error(ambiguous_zone, FlatZones); - 0 -> - erlang:error(no_zone); - _ -> - erlang:error(should_not_happen, {FlatZones, Date, Name}) - end, - {reply, Result, State}; -%handle_call({insert_all, Records}, _, Ets) -> -% Result= ets:insert(Ets, Records), -% {reply, Result, Ets}; -%handle_call({wipe}, _, Ets) -> -% Result= ets:delete(Ets), -% {reply, Result, Ets}; -handle_call({wipe, Tab}, _, State) -> - Result= ets:delete(Tab, Tab), - {reply, Result, State}; -handle_call({flatten}, _, State) -> - Result= ezic_flatten:flatten(), - {reply, Result, State}; -handle_call(_, _, State) -> - {noreply, State}. +%% -> true if table exists +db_sane(Filename) -> + %% @todo ensure data is present for each record type. + + case ets:tabfile_info(Filename) of + {ok, _} -> true; + {error, _} -> false + end. + -%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -%% Other gen_server -%%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%% creates the dets table and populates it. +create_tables(Filename) -> + {ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()), + ets:new(zone, [duplicate_bag, named_table]), + true = ets:insert(zone, Zones), -code_change(_, State, _) -> - {ok, State}. + ets:new(rule, [duplicate_bag, named_table]), + true = ets:insert(rule, Rules), + ets:new(flatzone, [duplicate_bag, named_table]), + io:format("~p~n", [Rules]), + ezic_flatten:flatten(), -handle_cast(_, State) -> - {noreply, State}. + % combine into one ets + Ets= ets:new(ezic_db_ets, [duplicate_bag]), + ets:insert(Ets, ets:lookup(zone, zone)), + ets:insert(Ets, ets:lookup(rule, rule)), + ets:insert(Ets, ets:lookup(flatzone, flatzone)), -handle_info(_, State) -> - {noreply, State}. + % save to disk + ets:tab2file(Ets, Filename), + + ets:delete(Ets), -terminate(_, State) -> + ok. + + + +%% loads or creates the dets table. +load_tabfile(Filename) -> + {ok, Ets}= ets:file2tab(Filename), + + Zones= ets:lookup(Ets, zone), + ets:new(zone, [duplicate_bag, named_table]), + ets:insert(zone, Zones), + + Rules= ets:lookup(Ets, rule), + ets:new(rule, [duplicate_bag, named_table]), + ets:insert(rule, Rules), + + FlatZones= ets:lookup(Ets, flatzone), + ets:new(flatzone, [duplicate_bag, named_table]), + ets:insert(flatzone, FlatZones), + + ets:delete(Ets), ok. diff --git a/src/ezic_db_ets_admin.erl b/src/ezic_db_ets_admin.erl deleted file mode 100644 index 163ef2c..0000000 --- a/src/ezic_db_ets_admin.erl +++ /dev/null @@ -1,137 +0,0 @@ --module(ezic_db_ets_admin). --include("include/ezic.hrl"). --include_lib("eunit/include/eunit.hrl"). - --define(TABS, [rule, zone, leap, flatzone]). --define(DB_FILENAME, "db.e2f"). --define(DETS_OPTS, []). --define(ETS_OPTS, [named_table]). - - - - - --export([ - init/0 - , wipe/0 - , insert_all/1 - , wipe/1 - ]). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% ADMIN API -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% Entire DB -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -%% if dets tables exist, -%% load stored tables -%% else -%% create all ets tables as named tables -%% load data -init() -> - {ok, DbDir}= application:get_env(db_dir), - Filename= filename:join(DbDir, ?DB_FILENAME), - case db_sane(Filename) of - true -> load_tabfile(Filename); - false -> create_tables(Filename) - end, - {ok, []}. - - -% erases all data -wipe() -> - not_done. - - -% inserts all records into the appropriate db -insert_all(Record) -> - not_done. - - - -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% Single Table -%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -% erases date for one table -wipe(Tab) -> - ezic_db_ets:wipe(Tab). - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% PRIVATE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%% -> true if table exists -db_sane(Filename) -> - %% @todo ensure data is present for each record type. - - case ets:tabfile_info(Filename) of - {ok, _} -> true; - {error, _} -> false - end. - - - -%% creates the dets table and populates it. -create_tables(Filename) -> - {ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()), - - ets:new(zone, [duplicate_bag, named_table]), - ets:insert(zone, Zones), - - ets:new(rule, [duplicate_bag, named_table]), - ets:insert(rule, Rules), - - ets:new(flatzone, [duplicate_bag, named_table]), - ezic_flatten:flatten(), - - % combine into one ets - Ets= ets:new(ezic_db_ets, [duplicate_bag]), - ets:insert(Ets, ets:lookup(zone, zone)), - ets:insert(Ets, ets:lookup(rule, rule)), - ets:insert(Ets, ets:lookup(flatzone, flatzone)), - - % save to disk - ets:tab2file(Ets, Filename), - - ets:delete(Ets), - - ok. - - - -%% loads or creates the dets table. -load_tabfile(Filename) -> - {ok, Ets}= ets:file2tab(Filename), - - Zones= ets:lookup(Ets, zone), - ets:new(zone, [duplicate_bag, named_table]), - ets:insert(zone, Zones), - - Rules= ets:lookup(Ets, rule), - ets:new(rule, [duplicate_bag, named_table]), - ets:insert(rule, Rules), - - FlatZones= ets:lookup(Ets, flatzone), - ets:new(flatzone, [duplicate_bag, named_table]), - ets:insert(flatzone, FlatZones), - - ets:delete(Ets), - ok. - - - -%% takes a populated dets table and converts it to an ets table. -ets_from_dets(Dets) -> - Ets= ets:new(tzdb, ?ETS_OPTS), - dets:to_ets(Dets, Ets). diff --git a/src/ezic_db_mnesia.erl b/src/ezic_db_mnesia.erl new file mode 100644 index 0000000..3666a14 --- /dev/null +++ b/src/ezic_db_mnesia.erl @@ -0,0 +1,145 @@ +-module(ezic_db_mnesia). +-include("include/ezic.hrl"). +-include_lib("stdlib/include/qlc.hrl"). +-include_lib("eunit/include/eunit.hrl"). + + +-export([ + init/0 + , zones/1 + , rules/1 + , flatzone/2 + %, insert/2 + , get_all/1 + , insert_all/1 + , wipe/1 + ]). + +-define(create(Record), + {atomic, ok} = mnesia:create_table(Record, + [{type, bag} + , {disc_copies, [node()]} + , {attributes, record_info(fields, Record)} + ])). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% READ - db reading methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +% retrieve all zones by name +zones(Name) -> + F = fun()-> + Q = qlc:q([Z || Z=#zone{name=N} <- mnesia:table(zone), N=:=Name]), + qlc:e(Q) + end, + {atomic, Zones}= mnesia:transaction(F), + Zones. + +% retrieve all rules by name +rules(Name) -> + F = fun()-> + Q = qlc:q([R || R=#rule{name=N} <- mnesia:table(rule), N=:=Name]), + qlc:e(Q) + end, + {atomic, Rules}= mnesia:transaction(F), + Rules. + +% get all records from table +get_all(Tab) when is_atom(Tab) -> + F = fun() -> + Q = qlc:q([R || R<- mnesia:table(Tab)]), + qlc:e(Q) + end, + {atomic, Ret}= mnesia:transaction(F), + Ret. + +%% get a flatzone for a specific date +%% Date :: {date(), #tztime{}} +%% returns #flatzone{} +%% or throws either error: +%% * {ambiguous_zone, [Z1,Z2,...]} +%% * {no_zone} +flatzone(Date, TzName) -> + %% @todo validate Date + F = fun()-> + Q = qlc:q( + [Fz || Fz=#flatzone{tzname=N} <- mnesia:table(flatzone) + , N=:=TzName + , ezic_flatten:contains_date(Fz, Date)]), + qlc:e(Q) + end, + {atomic, FlatZones}= mnesia:transaction(F), + + case length(FlatZones) of + 1 -> + hd(FlatZones); + 2 -> + erlang:error(ambiguous_zone, FlatZones); + 0 -> + erlang:error(no_zone); + _ -> + erlang:error(should_not_happen, {FlatZones, Date, TzName}) + end. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% ADMIN - initialization and administration methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% initialize the db +init() -> + create_tabs(mnesia:create_schema([node()])), + mnesia:wait_for_tables([rule, zone, link, leap, flatzone], 3000). + + +% WARNING: deletes all db files +%wipe() -> +% mnesia:stop(), +% mnesia:delete_schema([node()]). + + + +% WARNING: deletes all entries in table Tab +wipe(Tab) -> + mnesia:transaction( + fun()-> + mnesia:delete(Tab, '_', write) + end). + + + +create_tabs(ok) -> + mnesia:start(), + + ?create(rule), + ?create(zone), + ?create(link), + ?create(leap), + ?create(flatzone), + + {ok, Zones, Rules, _, _} = ezic_record:separate(ezic_loader:load()), + insert_all(Zones), + insert_all(Rules), + ezic_flatten:flatten(), + + ok; +create_tabs({error, {_, {already_exists,_}}}) -> + mnesia:start(), + ok; +create_tabs(E) -> + ?debugVal(E). + + +insert_all(Records) -> + mnesia:transaction( + fun() -> + lists:foreach( + fun(R)-> mnesia:write(R) end, + Records) + end). diff --git a/src/ezic_flatten.erl b/src/ezic_flatten.erl index c94cb38..5e74b6f 100644 --- a/src/ezic_flatten.erl +++ b/src/ezic_flatten.erl @@ -1,6 +1,5 @@ -module(ezic_flatten). -include("include/ezic.hrl"). --define(NODEBUG, true). -include_lib("eunit/include/eunit.hrl"). @@ -22,7 +21,7 @@ flatten() -> - AllZones= ets:lookup(zone, zone), + AllZones= ezic_db:get_all(zone), flatten_all_zones(AllZones), done. @@ -45,7 +44,7 @@ ms(Date, Name) -> {D, #tztime{time=T, flag=F}}=Date, - SDate= {D,T}, + %SDate= {D,T}, DComp= {{{D},{T}}}, G= ms_guards(F, DComp), @@ -82,22 +81,22 @@ flatten_all_zones([Z1|_]= AllZones) -> {CurrentZones, RestZones}= ezic_zone:split_by_name(Z1, AllZones), Flats= flatten_zone_set(CurrentZones), - ets:insert(flatzone, Flats), + ezic_db:insert_all(Flats), flatten_all_zones(RestZones). -contains_date2(FlatZone=#flatzone{utc_from=From, utc_to=To}, {Dt,#tztime{time=T, flag=F}}) +contains_date2(#flatzone{utc_from=From, utc_to=To}, {Dt,#tztime{time=T, flag=F}}) when F=:= u; F=:= g; F=:=z -> Date={Dt, T}, ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To); -contains_date2(FlatZone=#flatzone{std_from=From, std_to=To}, {Dt,#tztime{time=T, flag=s}}) -> +contains_date2(#flatzone{std_from=From, std_to=To}, {Dt,#tztime{time=T, flag=s}}) -> Date={Dt, T}, ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To); -contains_date2(FlatZone=#flatzone{wall_from=From, wall_to=To}, {Dt,#tztime{time=T, flag=F}}) +contains_date2(#flatzone{wall_from=From, wall_to=To}, {Dt,#tztime{time=T, flag=F}}) when F=:=w; F=:=undefined -> Date={Dt, T}, ezic_date:compare(From, Date) andalso ezic_date:compare(Date, To). @@ -141,7 +140,7 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset} %% we gather all rules that _may_ apply - Rules= ets:select(rule, [{#rule{name=RuleName, _='_'}, [], ['$_']}]), + Rules= ezic_db:rules(RuleName), ?debugVal(FromTime), diff --git a/src/ezic_rule.erl b/src/ezic_rule.erl index 1710d95..7f51d7c 100644 --- a/src/ezic_rule.erl +++ b/src/ezic_rule.erl @@ -58,7 +58,7 @@ years(#rule{from=From, to=To}) -> %% calculation stops after a fixed year, configurable above. years_after(Y, {F,M}) when M=:=max; M=:=maximum -> {erlang:max(Y,F), M}; -years_after(Y, {From, To}) when Y > To -> +years_after(Y, {_From, To}) when Y > To -> none; years_after(Y, {From, To}) -> {erlang:max(Y,From), To}. diff --git a/src/ezic_sup.erl b/src/ezic_sup.erl index fd9711f..b1c9542 100644 --- a/src/ezic_sup.erl +++ b/src/ezic_sup.erl @@ -40,7 +40,7 @@ start_link(_) -> %% specifications. %%-------------------------------------------------------------------- init(_) -> - EzicDb = {ezic_db_ets,{ezic_db_ets, start_link, []}, + EzicDb = {ezic_db,{ezic_db, start_link, []}, permanent,2000,worker,[ezic_db_ets]}, {ok,{{one_for_all,3,30}, [EzicDb]}}. diff --git a/src/ezic_zone.erl b/src/ezic_zone.erl index df61374..b2a93ce 100644 --- a/src/ezic_zone.erl +++ b/src/ezic_zone.erl @@ -1,6 +1,5 @@ -module(ezic_zone). -include("include/ezic.hrl"). --define(NODEBUG, true). -include_lib("eunit/include/eunit.hrl"). -export([ @@ -42,7 +41,7 @@ current(TzName) -> current_as_of_utc(erlang:universaltime(), TzName). current_as_of_utc(UTCDatetime, TzName) -> - Zones= ezic_db_ets:zones(TzName), + Zones= ezic_db:zones(TzName), get_zone_utc(UTCDatetime, Zones).