-module(mnesia_test). -compile(export_all). -define(TABLE_START_TIMEOUT, 900 * 1000). -record(retry_db, { address, next_retry, failed_reason, attempts }). init() -> init([node()]). init(NodeList) -> init(NodeList, NodeList, 10). init(NodeList, FragNodes, NFrags) -> case NodeList of [NodeDesc | _Rest] when is_tuple(NodeDesc) -> mnesia_create_tables(NodeList, FragNodes, NFrags); _ -> case mnesia:create_schema(NodeList) of ok -> StartFun = fun(NodeName) -> rpc:call(NodeName, mnesia, start, []) end, lists:map(StartFun, NodeList), mnesia_create_tables([{disc_copies, NodeList}], FragNodes, NFrags); {error, {_Node1, {already_exists, _Node2}}} -> mnesia_create_tables([{disc_copies, NodeList}], FragNodes, NFrags); {error, Reason} -> error_logger:error_report(["Mnesia create_schema error: ", Reason]), {error, Reason} end end. start() -> io:fwrite("Starting mnesia~n"), mnesia:start(). mnesia_create_tables(_NodeList, FragNodes, NFrags) -> case mnesia:start() of ok -> error_logger:error_report(["Mnesia started ok"]), FragsProps = [{node_pool, FragNodes}, {n_fragments, NFrags}, {n_disc_copies, 1}], mnesia:create_table(retry_db, [{frag_properties, FragsProps}, {index, [next_retry]}, {record_name, retry_db}, {attributes, record_info(fields, retry_db)}]), ok; {error, Reason} -> error_logger:error_report(["Mnesia start error: ", Reason]), {error, Reason} end. %% %% %% Retry DB management %% %% Save an address %% mnesia_test:save_retry(123456, 1000, 1, 1). save_retry(DA, NextRetry, FailureReason, Attempts) -> RetryRec = #retry_db{ address = DA, next_retry = NextRetry, failed_reason = FailureReason, attempts = Attempts }, save_record_frag(retry_db, RetryRec). save_retry(RetryRec) -> save_record_frag(retry_db, RetryRec). %% %% Read all read_all_retry() -> Pattern = #retry_db{_='_'}, pattern_match_frag_dirty(retry_db, Pattern). %% %% Read an address to retry using select_frag_dirty read_retry_by_time1(RetryTime) -> MatchHead = #retry_db{address = '$1', next_retry = '$2', failed_reason = '$3', attempts = '$4', _='_'}, Guard = [{'<', '$2', RetryTime}], Result = ['$$'], MatchSpec = [{MatchHead, Guard, Result}], select_frag_dirty(retry_db, MatchSpec). %% %% Read an address to retry using select_with_limit_frag_dirty read_retry_by_time2(RetryTime) -> MatchHead = #retry_db{address = '$1', next_retry = '$2', failed_reason = '$3', attempts = '$4', _='_'}, Guard = [{'<', '$2', RetryTime}], Result = ['$$'], MatchSpec = [{MatchHead, Guard, Result}], select_with_limit_frag_dirty(retry_db, MatchSpec, 1000). %% %% Read an address to retry using select_with_limit_frag_dirty read_retry_by_time3(RetryTime) -> MatchHead = #retry_db{address = '$1', next_retry = '$2', failed_reason = '$3', attempts = '$4', _='_'}, Guard = [{'<', '$2', RetryTime}], Result = ['$$'], MatchSpec = [{MatchHead, Guard, Result}], case select_with_limit_frag_dirty(retry_db, MatchSpec, 1000) of '$end_of_table' -> io:fwrite("End of table~n"); {ok, Res, Cont} -> io:fwrite("Result: ~p~n", [Res]), read_retry_in_cont(Cont) end. read_retry_in_cont(Cont) -> case select_in_cont_frag_dirty(Cont) of '$end_of_table' -> io:fwrite("End of table~n"); {ok, Res, NewCont} -> io:fwrite("Result: ~p~n", [Res]), read_retry_in_cont(NewCont) end. %% %% Delete an Address del_retry(Address) -> delete_frag(retry_db, Address). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 %% %% Generic functions handling Fragmented Table requests %% %% Save a Record save_record_frag_dirty(Db, Record) -> save_record_frag(async_dirty, Db, Record). save_record_frag(Db, Record) -> save_record_frag(transaction, Db, Record). save_record_frag(Context, Db, Record) -> DelFun = fun() -> mnesia:write(Db, Record, write) end, case catch mnesia:activity(Context, DelFun, [], mnesia_frag) of ok -> ok; Other -> io:fwrite("DB save_record_frag: ~p~n", [Other]), {error, Other} end. %% %% Read a Record read_frag_dirty(Db, Key) -> read_frag(async_dirty,Db, Key). read_frag(Db, Key) -> read_frag(transaction, Db, Key). read_frag(Context, Db, Key) -> ReadFun = fun() -> mnesia:read(Db, Key, read) end, case catch mnesia:activity(Context, ReadFun, [], mnesia_frag) of Result when is_list(Result) -> {ok, Result}; Other -> io:fwrite("DB read_frag: ~p~n", [Other]), {error, Other} end. %% %% Dirty Delete a Record delete_frag_dirty(Db, Key) -> delete_frag(async_dirty, Db, Key). delete_frag(Db, Key) -> delete_frag(transaction, Db, Key). delete_frag(Context, Db, Key) -> DelFun = fun() -> mnesia:delete(Db, Key, write) end, case catch mnesia:activity(Context, DelFun, [], mnesia_frag) of ok -> ok; Other -> io:fwrite("DB delete_frag: ~p~n", [Other]), {error, aborted} end. %% %% Read by Pattern pattern_match_frag_dirty(Db, Pattern) -> pattern_match_frag(async_dirty, Db, Pattern). pattern_match_frag(Db, Pattern) -> pattern_match_frag(transaction, Db, Pattern). pattern_match_frag(Context, Db, Pattern) -> PattMatchFun = fun() -> mnesia:match_object(Db, Pattern, read) end, case catch mnesia:activity(Context, PattMatchFun, [], mnesia_frag) of Result when is_list(Result) -> {ok, Result}; Other -> io:fwrite("DB pattern_match_frag: ~p~n", [Other]), {error, Other} end. %% %% Select Records select_frag_dirty(Db, MatchSpec) -> select_frag(async_dirty, Db, MatchSpec). select_frag(Db, MatchSpec) -> select_frag(transaction, Db, MatchSpec). select_frag(Context, Db, MatchSpec) -> SelFun = fun() -> mnesia:select(Db, MatchSpec, read) end, case catch mnesia:activity(Context, SelFun, [], mnesia_frag) of Result when is_list(Result) -> {ok, Result}; Other -> {error, Other} end. %% %% Select Records with a Limit select_with_limit_frag_dirty(Db, MatchSpec, NObjects) -> select_with_limit_frag(async_dirty, Db, MatchSpec, NObjects). select_with_limit_frag(Db, MatchSpec, NObjects) -> select_with_limit_frag(transaction, Db, MatchSpec, NObjects). select_with_limit_frag(Context, Db, MatchSpec, NObjects) -> SelFun = fun() -> mnesia:select(Db, MatchSpec, NObjects, read) end, case catch mnesia:activity(Context, SelFun, [], mnesia_frag) of {Result, Cont} when is_list(Result) -> {ok, Result, Cont}; '$end_of_table' -> '$end_of_table'; Other -> {error, Other} end. %% %% Select Records in Cont select_in_cont_frag_dirty(Cont) -> select_in_cont_frag(async_dirty, Cont). select_in_cont_frag(Cont) -> select_in_cont_frag(transaction, Cont). select_in_cont_frag(Context, Cont) -> SelFun = fun() -> mnesia:select(Cont) end, case catch mnesia:activity(Context, SelFun, [], mnesia_frag) of {Result, NewCont} when is_list(Result) -> {ok, Result, NewCont}; '$end_of_table' -> '$end_of_table'; Other -> {error, Other} end.