diff options
Diffstat (limited to 'lib/mnesia')
26 files changed, 1820 insertions, 1513 deletions
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile index f2e581f9d3..1ac5760510 100644 --- a/lib/mnesia/doc/src/Makefile +++ b/lib/mnesia/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 19ec70118f..20133cb6cb 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -813,6 +813,21 @@ mnesia:change_table_copy_type(person, node(), disc_copies) </p> </item> <item> + <p><c>{storage_properties, [{Backend, Properties}]</c>. + Forwards additional properties to the backend storage. + <c>Backend</c> can currently be <c>ets</c> or <c>dets</c> and + <c>Properties</c> is a list of options sent to the backend storage + during table creation. <c>Properties</c> may not contain properties + already used by mnesia such as <c>type</c> or <c>named_table</c>. + </p> + <p>For example:</p> + <code type="none"> +mnesia:create_table(table, [{ram_copies, [node()]}, {disc_only_copies, nodes()}, + {storage_properties, + [{ets, [compressed]}, {dets, [{auto_save, 5000}]} ]}]) + </code> + </item> + <item> <p><c>{type, Type}</c>, where <c>Type</c> must be either of the atoms <c>set</c>, <c>ordered_set</c> or <c>bag</c>. The default value is <c>set</c>. In a diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 1bb80f8fe3..a300fcc12d 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -38,7 +38,61 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.5.1</title> + <section><title>Mnesia 4.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Reduce calls to phash in key_to_frag_number</p> + <p> + Original code calls phash 1..2 times, based on which + fragment the hashed key targets and how many fragments + exist. New code always calls phash only once.</p> + <p> + Add mnesia_frag_hash test (Thanks to Philip Robinson)</p> + <p> + Own Id: OTP-9722</p> + </item> + <item> + <p> + Fixed a sticky lock bug which caused mnesia:read(Tab, + Key, write) return undefined.</p> + <p> + Own Id: OTP-9786</p> + </item> + <item> + <p> + Use the synchronous log_terms instead of alog_terms in + mnesia_log:ets2dcd()</p> + <p> + This avoids the situation where mnesia could dump a very + large ets table in its entirety into the message queue of + the disk_log process, causing memory blowup and choking + the disk logger. (Thanks to Richard Carlsson)</p> + <p> + Own Id: OTP-9804</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Implemented a new option to mnesia:create_table/2 which + allows the user to assign 'ets' and 'dets' options not + available in mnesia.</p> + <p> + Own Id: OTP-8970</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.5.1</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src index e0954ad206..304a15242f 100644 --- a/lib/mnesia/src/mnesia.appup.src +++ b/lib/mnesia/src/mnesia.appup.src @@ -1,14 +1,16 @@ %% -*- erlang -*- {"%VSN%", [ - {"4.5", [{restart_application, mnesia}]}, + {"4.5.1", [{restart_application, mnesia}]}, + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, {"4.4.16", [{restart_application, mnesia}]} ], [ - {"4.5", [{restart_application, mnesia}]}, + {"4.5.1", [{restart_application, mnesia}]}, + {"4.5", [{restart_application, mnesia}]}, {"4.4.19", [{restart_application, mnesia}]}, {"4.4.18", [{restart_application, mnesia}]}, {"4.4.17", [{restart_application, mnesia}]}, diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 980a9c6213..3d30debc53 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -27,7 +27,7 @@ %% Start, stop and debugging start/0, start/1, stop/0, % Not for public use set_debug_level/1, lkill/0, kill/0, % Not for public use - ms/0, + ms/0, change_config/2, %% Activity mgt @@ -40,14 +40,14 @@ %% Access within an activity - Lock acquisition lock/2, lock/4, lock_table/2, - read_lock_table/1, + read_lock_table/1, write_lock_table/1, %% Access within an activity - Updates - write/1, s_write/1, write/3, write/5, - delete/1, s_delete/1, delete/3, delete/5, - delete_object/1, s_delete_object/1, delete_object/3, delete_object/5, - + write/1, s_write/1, write/3, write/5, + delete/1, s_delete/1, delete/3, delete/5, + delete_object/1, s_delete_object/1, delete_object/3, delete_object/5, + %% Access within an activity - Reads read/1, read/2, wread/1, read/3, read/5, match_object/1, match_object/3, match_object/5, @@ -58,9 +58,9 @@ first/1, next/2, last/1, prev/2, first/3, next/4, last/3, prev/4, - %% Iterators within an activity + %% Iterators within an activity foldl/3, foldl/4, foldr/3, foldr/4, - + %% Dirty access regardless of activities - Updates dirty_write/1, dirty_write/2, dirty_delete/1, dirty_delete/2, @@ -72,8 +72,8 @@ dirty_select/2, dirty_match_object/1, dirty_match_object/2, dirty_all_keys/1, dirty_index_match_object/2, dirty_index_match_object/3, - dirty_index_read/3, dirty_slot/2, - dirty_first/1, dirty_next/2, dirty_last/1, dirty_prev/2, + dirty_index_read/3, dirty_slot/2, + dirty_first/1, dirty_next/2, dirty_last/1, dirty_prev/2, %% Info table_info/2, table_info/4, schema/0, schema/1, @@ -102,7 +102,7 @@ dump_tables/1, wait_for_tables/2, force_load_table/1, change_table_access_mode/2, change_table_load_order/2, set_master_nodes/1, set_master_nodes/2, - + %% Misc admin dump_log/0, subscribe/1, unsubscribe/1, report_event/1, @@ -112,7 +112,7 @@ %% Textfile access load_textfile/1, dump_to_textfile/1, - + %% QLC functions table/1, table/2, @@ -137,20 +137,20 @@ -define(DEFAULT_ACCESS, ?MODULE). -%% Select +%% Select -define(PATTERN_TO_OBJECT_MATCH_SPEC(Pat), [{Pat,[],['$_']}]). -define(PATTERN_TO_BINDINGS_MATCH_SPEC(Pat), [{Pat,[],['$$']}]). - + %% Local function in order to avoid external function call val(Var) -> case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); + {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); Value -> Value end. is_dollar_digits(Var) -> case atom_to_list(Var) of - [$$ | Digs] -> + [$$ | Digs] -> is_digits(Digs); _ -> false @@ -166,13 +166,13 @@ is_digits([Dig | Tail]) -> is_digits([]) -> true. -has_var(X) when is_atom(X) -> - if - X == '_' -> +has_var(X) when is_atom(X) -> + if + X == '_' -> true; - is_atom(X) -> + is_atom(X) -> is_dollar_digits(X); - true -> + true -> false end; has_var(X) when is_tuple(X) -> @@ -196,9 +196,9 @@ e_has_var(X, Pos) -> start() -> {Time , Res} = timer:tc(application, start, [?APPLICATION, temporary]), - + Secs = Time div 1000000, - case Res of + case Res of ok -> verbose("Mnesia started, ~p seconds~n",[ Secs]), ok; @@ -243,10 +243,10 @@ change_config(extra_db_nodes, Ns) when is_list(Ns) -> mnesia_controller:connect_nodes(Ns); change_config(dc_dump_limit, N) when is_number(N), N > 0 -> case mnesia_lib:is_running() of - yes -> + yes -> mnesia_lib:set(dc_dump_limit, N), {ok, N}; - _ -> + _ -> {error, {not_started, ?APPLICATION}} end; change_config(BadKey, _BadVal) -> @@ -255,7 +255,7 @@ change_config(BadKey, _BadVal) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Debugging -set_debug_level(Level) -> +set_debug_level(Level) -> mnesia_subscr:set_debug_level(Level). lkill() -> @@ -274,9 +274,9 @@ ms() -> mnesia_controller, mnesia_dumper, mnesia_loader, - mnesia_frag, - mnesia_frag_hash, - mnesia_frag_old_hash, + mnesia_frag, + mnesia_frag_hash, + mnesia_frag_old_hash, mnesia_index, mnesia_kernel_sup, mnesia_late_loader, @@ -295,9 +295,9 @@ ms() -> %% Keep these last in the list, so %% mnesia_sup kills these last - mnesia_monitor, + mnesia_monitor, mnesia_event - ]. + ]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -305,7 +305,7 @@ ms() -> -spec abort(_) -> no_return(). -abort(Reason) -> +abort(Reason) -> exit({aborted, Reason}). is_transaction() -> @@ -339,7 +339,7 @@ sync_transaction(Fun, Args, Retries) -> transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, sync). -transaction(State, Fun, Args, Retries, Mod, Kind) +transaction(State, Fun, Args, Retries, Mod, Kind) when is_function(Fun), is_list(Args), Retries == infinity, is_atom(Mod) -> mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind); transaction(State, Fun, Args, Retries, Mod, Kind) @@ -348,7 +348,7 @@ transaction(State, Fun, Args, Retries, Mod, Kind) transaction(_State, Fun, Args, Retries, Mod, _Kind) -> {aborted, {badarg, Fun, Args, Retries, Mod}}. -non_transaction(State, Fun, Args, ActivityKind, Mod) +non_transaction(State, Fun, Args, ActivityKind, Mod) when is_function(Fun), is_list(Args), is_atom(Mod) -> mnesia_tm:non_transaction(State, Fun, Args, ActivityKind, Mod); non_transaction(_State, Fun, Args, _ActivityKind, _Mod) -> @@ -394,7 +394,7 @@ wrap_trans(State, Fun, Args, Retries, Mod, Kind) -> {atomic, GoodRes} -> GoodRes; BadRes -> exit(BadRes) end. - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Access within an activity - lock acquisition @@ -507,13 +507,13 @@ good_global_nodes(Nodes) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Access within an activity - updates -write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> +write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), write(Tab, Val, write); write(Val) -> abort({bad_type, Val}). -s_write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> +s_write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), write(Tab, Val, sticky_write). @@ -561,7 +561,7 @@ write_to_store(Tab, Store, Oid, Val) -> _ -> ?ets_delete(Store, Oid), ?ets_insert(Store, {Oid, Val, write}) - end, + end, ok; {'EXIT', _} -> abort({no_exists, Tab}); @@ -611,7 +611,7 @@ delete(Tid, Ts, Tab, Key, LockKind) ok; Protocol -> do_dirty_delete(Protocol, Tab, Key) - end; + end; delete(_Tid, _Ts, Tab, _Key, _LockKind) -> abort({bad_type, Tab}). @@ -640,7 +640,7 @@ delete_object(Tab, Val, LockKind) -> delete_object(Tid, Ts, Tab, Val, LockKind) when is_atom(Tab), Tab /= schema, is_tuple(Val), tuple_size(Val) > 2 -> case has_var(Val) of - false -> + false -> do_delete_object(Tid, Ts, Tab, Val, LockKind); true -> abort({bad_type, Tab, Val}) @@ -665,7 +665,7 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) -> abort({bad_type, Tab, LockKind}) end, case val({Tab, setorbag}) of - bag -> + bag -> ?ets_match_delete(Store, {Oid, Val, '_'}), ?ets_insert(Store, {Oid, Val, delete_object}); _ -> @@ -731,7 +731,7 @@ read(Tid, Ts, Tab, Key, LockKind) add_written(?ets_lookup(Store, Oid), Tab, Objs); _Protocol -> dirty_read(Tab, Key) - end; + end; read(_Tid, _Ts, Tab, _Key, _LockKind) -> abort({bad_type, Tab}). @@ -744,7 +744,7 @@ first(Tab) -> _ -> abort(no_transaction) end. - + first(Tid, Ts, Tab) when is_atom(Tab), Tab /= schema -> case element(1, Tid) of @@ -845,9 +845,9 @@ prev(_Tid, _Ts,Tab,_) -> stored_keys(Tab,'$end_of_table',Prev,Ts,Op,Type) -> case ts_keys(Ts#tidstore.store,Tab,Op,Type,[]) of [] -> '$end_of_table'; - Keys when Type == ordered_set-> + Keys when Type == ordered_set-> get_ordered_tskey(Prev,Keys,Op); - Keys -> + Keys -> get_next_tskey(Prev,Keys,Tab) end; stored_keys(Tab,{'EXIT',{aborted,R={badarg,[Tab,Key]}}}, @@ -858,7 +858,7 @@ stored_keys(Tab,{'EXIT',{aborted,R={badarg,[Tab,Key]}}}, Ops -> case lists:last(Ops) of [delete] -> abort(R); - _ -> + _ -> case ts_keys(Store,Tab,Op,Type,[]) of [] -> '$end_of_table'; Keys -> get_next_tskey(Key,Keys,Tab) @@ -869,14 +869,14 @@ stored_keys(_,{'EXIT',{aborted,R}},_,_,_,_) -> abort(R); stored_keys(Tab,Key,Prev,#tidstore{store=Store},Op,ordered_set) -> case ?ets_match(Store, {{Tab, Key}, '_', '$1'}) of - [] -> + [] -> Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]), get_ordered_tskey(Prev,Keys,Op); Ops -> case lists:last(Ops) of [delete] -> mnesia:Op(Tab,Key); - _ -> + _ -> Keys = ts_keys(Store,Tab,Op,ordered_set,[Key]), get_ordered_tskey(Prev,Keys,Op) end @@ -898,7 +898,7 @@ get_ordered_tskey(Prev, [_|R],Op) -> get_ordered_tskey(Prev,R,Op); get_ordered_tskey(_, [],_) -> '$end_of_table'. get_next_tskey(Key,Keys,Tab) -> - Next = + Next = if Key == '$end_of_table' -> hd(Keys); true -> case lists:dropwhile(fun(A) -> A /= Key end, Keys) of @@ -912,7 +912,7 @@ get_next_tskey(Key,Keys,Tab) -> _ -> %% Really slow anybody got another solution?? case dirty_read(Tab, Next) of [] -> Next; - _ -> + _ -> %% Updated value we already returned this key get_next_tskey(Next,Keys,Tab) end @@ -921,7 +921,7 @@ get_next_tskey(Key,Keys,Tab) -> ts_keys(Store, Tab, Op, Type, Def) -> All = ?ets_match(Store, {{Tab,'$1'},'_','$2'}), Keys = ts_keys_1(All, Def), - if + if Type == ordered_set, Op == prev -> lists:reverse(lists:sort(Keys)); Type == ordered_set -> @@ -947,7 +947,7 @@ ts_keys_1([], Acc) -> %%%%%%%%%%%%%%%%%%%%% -%% Iterators +%% Iterators foldl(Fun, Acc, Tab) -> foldl(Fun, Acc, Tab, read). @@ -968,7 +968,7 @@ foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) -> close_iteration(Res, Tab). do_foldl(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) -> - lists:foldl(fun(Key, Acc) -> + lists:foldl(fun(Key, Acc) -> lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)) end, RAcc, Stored); do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key -> @@ -983,7 +983,7 @@ do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key -> NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), {_, Tid, Ts} = get(mnesia_activity_state), do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]); -do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag +do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), NewStored = ordsets:del_element(Key, Stored), {_, Tid, Ts} = get(mnesia_activity_state), @@ -1003,8 +1003,8 @@ foldr(Fun, Acc, Tab, LockKind) when is_function(Fun) -> foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) -> {Type, TempPrev} = init_iteration(ActivityId, Opaque, Tab, LockKind), - Prev = - if + Prev = + if Type == ordered_set -> lists:reverse(TempPrev); true -> %% Order doesn't matter for set and bag @@ -1014,7 +1014,7 @@ foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) -> close_iteration(Res, Tab). do_foldr(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) -> - lists:foldl(fun(Key, Acc) -> + lists:foldl(fun(Key, Acc) -> lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)) end, RAcc, Stored); do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key -> @@ -1029,7 +1029,7 @@ do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key -> NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), {_, Tid, Ts} = get(mnesia_activity_state), do_foldr(Tid, Ts, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]); -do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag +do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), NewStored = ordsets:del_element(Key, Stored), {_, Tid, Ts} = get(mnesia_activity_state), @@ -1037,25 +1037,25 @@ do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag init_iteration(ActivityId, Opaque, Tab, LockKind) -> lock(ActivityId, Opaque, {table, Tab}, LockKind), - Type = val({Tab, setorbag}), + Type = val({Tab, setorbag}), Previous = add_previous(ActivityId, Opaque, Type, Tab), St = val({Tab, storage_type}), - if - St == unknown -> + if + St == unknown -> ignore; true -> mnesia_lib:db_fixtable(St, Tab, true) - end, + end, {Type, Previous}. close_iteration(Res, Tab) -> case val({Tab, storage_type}) of - unknown -> + unknown -> ignore; - St -> + St -> mnesia_lib:db_fixtable(St, Tab, false) end, - case Res of + case Res of {'EXIT', {aborted, What}} -> abort(What); {'EXIT', What} -> @@ -1074,7 +1074,7 @@ add_previous(_Tid, Ts, _Type, Tab) -> %% it is correct with respect to what this particular transaction %% has already written, deleted .... etc -add_written([], _Tab, Objs) -> +add_written([], _Tab, Objs) -> Objs; % standard normal fast case add_written(Written, Tab, Objs) -> case val({Tab, setorbag}) of @@ -1093,7 +1093,7 @@ add_written_to_set(Ws) -> add_written_to_bag([{_, Val, write} | Tail], Objs, Ack) -> add_written_to_bag(Tail, lists:delete(Val, Objs), [Val | Ack]); -add_written_to_bag([], Objs, Ack) -> +add_written_to_bag([], Objs, Ack) -> Objs ++ lists:reverse(Ack); %% Oldest write first as in ets add_written_to_bag([{_, _ , delete} | Tail], _Objs, _Ack) -> %% This transaction just deleted all objects @@ -1118,7 +1118,7 @@ match_object(Tab, Pat, LockKind) -> abort(no_transaction) end. -match_object(Tid, Ts, Tab, Pat, LockKind) +match_object(Tid, Ts, Tab, Pat, LockKind) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> case element(1, Tid) of ets -> @@ -1142,11 +1142,11 @@ add_written_match(S, Pat, Tab, Objs) -> add_match(Ops, Objs, val({Tab, setorbag})). find_ops(S, Tab, Pat) -> - GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']}, + GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']}, {{{Tab, '_'}, '_', delete}, [], ['$_']}, {{{Tab, '_'}, Pat, delete_object}, [], ['$_']}], ets:select(S, GetWritten). - + add_match([], Objs, _Type) -> Objs; add_match(Written, Objs, ordered_set) -> @@ -1162,13 +1162,13 @@ add_match([{Oid, Val, write}|R], Objs, set) -> add_match(R, [Val | deloid(Oid,Objs)],set). %% For ordered_set only !! -add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc) +add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc) when Key > element(2, Obj) -> add_ordered_match(Written, Objs, [Obj|Acc]); -add_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_], Acc) +add_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_], Acc) when Key < element(2, Obj) -> add_ordered_match(Rest, [Val|Objs],Acc); -add_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc) +add_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc) when Key < element(2, Obj) -> add_ordered_match(Rest,Objs,Acc); %% Greater than last object @@ -1176,7 +1176,7 @@ add_ordered_match([{_, Val, write}|Rest], [], Acc) -> add_ordered_match(Rest, [Val], Acc); add_ordered_match([_|Rest], [], Acc) -> add_ordered_match(Rest, [], Acc); -%% Keys are equal from here +%% Keys are equal from here add_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) -> add_ordered_match(Rest, [Val|Objs], Acc); add_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) -> @@ -1207,7 +1207,7 @@ add_sel_match([Op={Oid, _, delete}|R], Objs, Type, Acc) -> end; add_sel_match([Op = {_Oid, Val, delete_object}|R], Objs, Type, Acc) -> case lists:delete(Val, Objs) of - Objs -> + Objs -> add_sel_match(R, Objs, Type, [Op|Acc]); NewObjs when Type == set -> add_sel_match(R, NewObjs, Type, Acc); @@ -1224,26 +1224,26 @@ add_sel_match([Op={Oid={_,Key}, Val, write}|R], Objs, bag, Acc) -> end; add_sel_match([Op={Oid, Val, write}|R], Objs, set, Acc) -> case deloid(Oid,Objs) of - Objs -> + Objs -> add_sel_match(R, Objs,set, [Op|Acc]); NewObjs -> add_sel_match(R, [Val | NewObjs],set, Acc) end. %% For ordered_set only !! -add_sel_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs],Acc) +add_sel_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs],Acc) when Key > element(2, Obj) -> add_sel_ordered_match(Written, Objs, [Obj|Acc]); -add_sel_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_],Acc) +add_sel_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_],Acc) when Key < element(2, Obj) -> add_sel_ordered_match(Rest,[Val|Objs],Acc); -add_sel_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc) +add_sel_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc) when Key < element(2, Obj) -> add_sel_ordered_match(Rest,Objs,Acc); %% Greater than last object add_sel_ordered_match(Ops1, [], Acc) -> {lists:reverse(Acc), Ops1}; -%% Keys are equal from here +%% Keys are equal from here add_sel_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) -> add_sel_ordered_match(Rest, [Val|Objs], Acc); add_sel_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) -> @@ -1264,11 +1264,11 @@ deloid(Oid, [H | T]) -> [H | deloid(Oid, T)]. %%%%%%%%%%%%%%%%%% -% select +% select select(Tab, Pat) -> select(Tab, Pat, read). -select(Tab, Pat, LockKind) +select(Tab, Pat, LockKind) when is_atom(Tab), Tab /= schema, is_list(Pat) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1293,13 +1293,13 @@ fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, SelectFun) -> select_lock(Tid,Ts,LockKind,Spec,Tab), Store = Ts#tidstore.store, Written = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}), - case Written of - [] -> + case Written of + [] -> %% Nothing changed in the table during this transaction, %% Simple case get results from [d]ets SelectFun(Spec); - _ -> - %% Hard (slow case) records added or deleted earlier + _ -> + %% Hard (slow case) records added or deleted earlier %% in the transaction, have to cope with that. Type = val({Tab, setorbag}), FixedSpec = get_record_pattern(Spec), @@ -1326,7 +1326,7 @@ select_lock(Tid,Ts,LockKind,Spec,Tab) -> end. %% Breakable Select -select(Tab, Pat, NObjects, LockKind) +select(Tab, Pat, NObjects, LockKind) when is_atom(Tab), Tab /= schema, is_list(Pat), is_integer(NObjects) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1356,26 +1356,26 @@ fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, Init, NObjects, Node, Storage) select_lock(Tid,Ts,LockKind,Spec,Tab), Store = Ts#tidstore.store, do_fixtable(Tab, Store), - - Written0 = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}), - case Written0 of - [] -> + + Written0 = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}), + case Written0 of + [] -> %% Nothing changed in the table during this transaction, %% Simple case get results from [d]ets select_state(Init(Spec),Def); - _ -> - %% Hard (slow case) records added or deleted earlier + _ -> + %% Hard (slow case) records added or deleted earlier %% in the transaction, have to cope with that. Type = val({Tab, setorbag}), - Written = + Written = if Type == ordered_set -> %% Sort stable lists:keysort(1,Written0); - true -> + true -> Written0 end, FixedSpec = get_record_pattern(Spec), CMS = ets:match_spec_compile(Spec), - trans_select(Init(FixedSpec), + trans_select(Init(FixedSpec), Def#mnesia_select{written=Written,spec=CMS,type=Type, orig=FixedSpec}) end; _Protocol -> @@ -1394,7 +1394,7 @@ select(Cont) -> select_cont(_Tid,_Ts,'$end_of_table') -> '$end_of_table'; -select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid,cont=Cont, orig=Ms}) +select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid,cont=Cont, orig=Ms}) when element(1,Tid) == ets -> case Cont of '$end_of_table' -> '$end_of_table'; @@ -1415,7 +1415,7 @@ trans_select('$end_of_table', #mnesia_select{written=Written0,spec=CMS,type=Type trans_select({TabRecs,Cont}, State = #mnesia_select{written=Written0,spec=CMS,type=Type}) -> {FixedRes,Written} = add_sel_match(Written0, TabRecs, Type), select_state({ets:match_spec_run(FixedRes, CMS),Cont}, - State#mnesia_select{written=Written}). + State#mnesia_select{written=Written}). select_state({Matches, Cont}, MS) -> {Matches, MS#mnesia_select{cont=Cont}}; @@ -1433,9 +1433,9 @@ all_keys(Tab) -> Mod:all_keys(Tid, Ts, Tab, read); _ -> abort(no_transaction) - end. + end. -all_keys(Tid, Ts, Tab, LockKind) +all_keys(Tid, Ts, Tab, LockKind) when is_atom(Tab), Tab /= schema -> Pat0 = val({Tab, wild_pattern}), Pat = setelement(2, Pat0, '$1'), @@ -1446,7 +1446,7 @@ all_keys(Tid, Ts, Tab, LockKind) _ -> Keys end; -all_keys(_Tid, _Ts, Tab, _LockKind) -> +all_keys(_Tid, _Ts, Tab, _LockKind) -> abort({bad_type, Tab}). index_match_object(Pat, Attr) when is_tuple(Pat), tuple_size(Pat) > 2 -> @@ -1465,7 +1465,7 @@ index_match_object(Tab, Pat, Attr, LockKind) -> abort(no_transaction) end. -index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind) +index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> case element(1, Tid) of ets -> @@ -1501,7 +1501,7 @@ index_read(Tab, Key, Attr) -> abort(no_transaction) end. -index_read(Tid, Ts, Tab, Key, Attr, LockKind) +index_read(Tid, Ts, Tab, Key, Attr, LockKind) when is_atom(Tab), Tab /= schema -> case element(1, Tid) of ets -> @@ -1536,7 +1536,7 @@ dirty_write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> dirty_write(Tab, Val); dirty_write(Val) -> abort({bad_type, Val}). - + dirty_write(Tab, Val) -> do_dirty_write(async_dirty, Tab, Val). @@ -1562,7 +1562,7 @@ dirty_delete(Oid) -> dirty_delete(Tab, Key) -> do_dirty_delete(async_dirty, Tab, Key). - + do_dirty_delete(SyncMode, Tab, Key) when is_atom(Tab), Tab /= schema -> Oid = {Tab, Key}, mnesia_tm:dirty(SyncMode, {Oid, Oid, delete}); @@ -1582,7 +1582,7 @@ do_dirty_delete_object(SyncMode, Tab, Val) when is_atom(Tab), Tab /= schema, is_tuple(Val), tuple_size(Val) > 2 -> Oid = {Tab, element(2, Val)}, case has_var(Val) of - false -> + false -> mnesia_tm:dirty(SyncMode, {Oid, Val, delete_object}); true -> abort({bad_type, Tab, Val}) @@ -1600,7 +1600,7 @@ dirty_update_counter(Counter, _Incr) -> dirty_update_counter(Tab, Key, Incr) -> do_dirty_update_counter(async_dirty, Tab, Key, Incr). - + do_dirty_update_counter(SyncMode, Tab, Key, Incr) when is_atom(Tab), Tab /= schema, is_integer(Incr) -> case ?catch_val({Tab, record_validation}) of @@ -1638,7 +1638,7 @@ dirty_match_object(Pat) when is_tuple(Pat), tuple_size(Pat) > 2 -> dirty_match_object(Tab, Pat); dirty_match_object(Pat) -> abort({bad_type, Pat}). - + dirty_match_object(Tab, Pat) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> dirty_rpc(Tab, ?MODULE, remote_dirty_match_object, [Tab, Pat]); @@ -1697,8 +1697,8 @@ remote_dirty_select(Tab, [{HeadPat,_, _}] = Spec, [Pos | Tail]) %% Returns the records without applying the match spec %% The actual filtering is handled by the caller CMS = ets:match_spec_compile(Spec), - case val({Tab, setorbag}) of - ordered_set -> + case val({Tab, setorbag}) of + ordered_set -> ets:match_spec_run(lists:sort(Recs), CMS); _ -> ets:match_spec_run(Recs, CMS) @@ -1730,14 +1730,14 @@ dirty_all_keys(Tab) when is_atom(Tab), Tab /= schema -> end; dirty_all_keys(Tab) -> abort({bad_type, Tab}). - + dirty_index_match_object(Pat, Attr) when is_tuple(Pat), tuple_size(Pat) > 2 -> Tab = element(1, Pat), dirty_index_match_object(Tab, Pat, Attr); dirty_index_match_object(Pat, _Attr) -> abort({bad_type, Pat}). -dirty_index_match_object(Tab, Pat, Attr) +dirty_index_match_object(Tab, Pat, Attr) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> case mnesia_schema:attr_tab_to_pos(Tab, Attr) of Pos when Pos =< tuple_size(Pat) -> @@ -1752,7 +1752,7 @@ dirty_index_match_object(Tab, Pat, Attr) [Tab, Pat, Pos]); true -> abort({bad_type, Tab, Attr, Elem}) - end + end end; BadPos -> abort({bad_type, Tab, BadPos}) @@ -1810,7 +1810,7 @@ do_dirty_rpc(Tab, Node, M, F, Args) -> %% Sync with mnesia_monitor try sys:get_status(mnesia_monitor) catch _:_ -> ok end, case mnesia_controller:call({check_w2r, Node, Tab}) of % Sync - NewNode when NewNode =:= Node -> + NewNode when NewNode =:= Node -> ErrorTag = mnesia_lib:dirty_rpc_error_tag(Reason), mnesia:abort({ErrorTag, Args}); NewNode -> @@ -1821,9 +1821,9 @@ do_dirty_rpc(Tab, Node, M, F, Args) -> %% to acquire the lock on the NewNode. %% In this context we do neither know %% the kind or granularity of the lock. - %% --> Abort the transaction + %% --> Abort the transaction mnesia:abort({node_not_running, Node}); - {error, {node_not_running, _}} -> + {error, {node_not_running, _}} -> %% Mnesia is stopping mnesia:abort({no_exists, Args}); _ -> @@ -1858,21 +1858,21 @@ table_info(_Tid, _Ts, Tab, Item) -> any_table_info(Tab, Item). -any_table_info(Tab, Item) when is_atom(Tab) -> +any_table_info(Tab, Item) when is_atom(Tab) -> case Item of master_nodes -> mnesia_recover:get_master_nodes(Tab); -% checkpoints -> +% checkpoints -> % case ?catch_val({Tab, commit_work}) of % [{checkpoints, List} | _] -> List; % No_chk when is_list(No_chk) -> []; % Else -> info_reply(Else, Tab, Item) % end; - size -> + size -> raw_table_info(Tab, Item); memory -> raw_table_info(Tab, Item); - type -> + type -> case ?catch_val({Tab, setorbag}) of {'EXIT', _} -> abort({no_exists, Tab, Item}); @@ -1885,8 +1885,8 @@ any_table_info(Tab, Item) when is_atom(Tab) -> abort({no_exists, Tab, Item}); Props -> lists:map(fun({setorbag, Type}) -> {type, Type}; - (Prop) -> Prop end, - Props) + (Prop) -> Prop end, + Props) end; name -> Tab; @@ -1927,14 +1927,14 @@ bad_info_reply(_Tab, memory) -> 0; bad_info_reply(Tab, Item) -> abort({no_exists, Tab, Item}). %% Raw info about all tables -schema() -> +schema() -> mnesia_schema:info(). %% Raw info about one tables -schema(Tab) -> +schema(Tab) -> mnesia_schema:info(Tab). -error_description(Err) -> +error_description(Err) -> mnesia_lib:error_desc(Err). info() -> @@ -1951,18 +1951,18 @@ info() -> io:format( "---> Processes waiting for locks <--- ~n", []), lists:foreach(fun({Oid, Op, _Pid, Tid, OwnerTid}) -> io:format("Tid ~p waits for ~p lock " - "on oid ~p owned by ~p ~n", + "on oid ~p owned by ~p ~n", [Tid, Op, Oid, OwnerTid]) end, Queued), mnesia_tm:display_info(group_leader(), TmInfo), - + Pat = {'_', unclear, '_'}, Uncertain = ets:match_object(mnesia_decision, Pat), io:format( "---> Uncertain transactions <--- ~n", []), lists:foreach(fun({Tid, _, Nodes}) -> io:format("Tid ~w waits for decision " - "from ~w~n", + "from ~w~n", [Tid, Nodes]) end, Uncertain), @@ -2023,15 +2023,15 @@ display_tab_info() -> io:format("master node tables = ~p~n", [lists:sort(MasterTabs)]), Tabs = system_info(tables), - + {Unknown, Ram, Disc, DiscOnly} = lists:foldl(fun storage_count/2, {[], [], [], []}, Tabs), - + io:format("remote = ~p~n", [lists:sort(Unknown)]), io:format("ram_copies = ~p~n", [lists:sort(Ram)]), io:format("disc_copies = ~p~n", [lists:sort(Disc)]), io:format("disc_only_copies = ~p~n", [lists:sort(DiscOnly)]), - + Rfoldl = fun(T, Acc) -> Rpat = case val({T, access_mode}) of @@ -2041,7 +2041,7 @@ display_tab_info() -> table_info(T, where_to_commit) end, case lists:keysearch(Rpat, 1, Acc) of - {value, {_Rpat, Rtabs}} -> + {value, {_Rpat, Rtabs}} -> lists:keyreplace(Rpat, 1, Acc, {Rpat, [T | Rtabs]}); false -> [{Rpat, [T]} | Acc] @@ -2161,20 +2161,20 @@ system_info2(fallback_activated) -> system_info2(version) -> case ?catch_val(version) of - {'EXIT', _} -> + {'EXIT', _} -> Apps = application:loaded_applications(), case lists:keysearch(?APPLICATION, 1, Apps) of {value, {_Name, _Desc, Version}} -> Version; false -> %% Ensure that it does not match - {mnesia_not_loaded, node(), now()} + {mnesia_not_loaded, node(), now()} end; Version -> Version end; -system_info2(access_module) -> mnesia_monitor:get_env(access_module); +system_info2(access_module) -> mnesia_monitor:get_env(access_module); system_info2(auto_repair) -> mnesia_monitor:get_env(auto_repair); system_info2(is_running) -> mnesia_lib:is_running(); system_info2(backup_module) -> mnesia_monitor:get_env(backup_module); @@ -2183,7 +2183,7 @@ system_info2(debug) -> mnesia_monitor:get_env(debug); system_info2(dump_log_load_regulation) -> mnesia_monitor:get_env(dump_log_load_regulation); system_info2(dump_log_write_threshold) -> mnesia_monitor:get_env(dump_log_write_threshold); system_info2(dump_log_time_threshold) -> mnesia_monitor:get_env(dump_log_time_threshold); -system_info2(dump_log_update_in_place) -> +system_info2(dump_log_update_in_place) -> mnesia_monitor:get_env(dump_log_update_in_place); system_info2(max_wait_for_decision) -> mnesia_monitor:get_env(max_wait_for_decision); system_info2(embedded_mnemosyne) -> mnesia_monitor:get_env(embedded_mnemosyne); @@ -2204,9 +2204,9 @@ system_info2(transaction_failures) -> mnesia_lib:read_counter(trans_failures); system_info2(transaction_commits) -> mnesia_lib:read_counter(trans_commits); system_info2(transaction_restarts) -> mnesia_lib:read_counter(trans_restarts); system_info2(transaction_log_writes) -> mnesia_dumper:get_log_writes(); -system_info2(core_dir) -> mnesia_monitor:get_env(core_dir); -system_info2(no_table_loaders) -> mnesia_monitor:get_env(no_table_loaders); -system_info2(dc_dump_limit) -> mnesia_monitor:get_env(dc_dump_limit); +system_info2(core_dir) -> mnesia_monitor:get_env(core_dir); +system_info2(no_table_loaders) -> mnesia_monitor:get_env(no_table_loaders); +system_info2(dc_dump_limit) -> mnesia_monitor:get_env(dc_dump_limit); system_info2(send_compressed) -> mnesia_monitor:get_env(send_compressed); system_info2(Item) -> exit({badarg, Item}). @@ -2281,7 +2281,7 @@ system_info_items(no) -> core_dir, version ]. - + system_info() -> IsRunning = mnesia_lib:is_running(), case IsRunning of @@ -2308,62 +2308,62 @@ load_mnesia_or_abort() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Database mgt -create_schema(Ns) -> +create_schema(Ns) -> mnesia_bup:create_schema(Ns). -delete_schema(Ns) -> +delete_schema(Ns) -> mnesia_schema:delete_schema(Ns). -backup(Opaque) -> +backup(Opaque) -> mnesia_log:backup(Opaque). -backup(Opaque, Mod) -> +backup(Opaque, Mod) -> mnesia_log:backup(Opaque, Mod). -traverse_backup(S, T, Fun, Acc) -> +traverse_backup(S, T, Fun, Acc) -> mnesia_bup:traverse_backup(S, T, Fun, Acc). -traverse_backup(S, SM, T, TM, F, A) -> +traverse_backup(S, SM, T, TM, F, A) -> mnesia_bup:traverse_backup(S, SM, T, TM, F, A). -install_fallback(Opaque) -> +install_fallback(Opaque) -> mnesia_bup:install_fallback(Opaque). -install_fallback(Opaque, Mod) -> +install_fallback(Opaque, Mod) -> mnesia_bup:install_fallback(Opaque, Mod). -uninstall_fallback() -> +uninstall_fallback() -> mnesia_bup:uninstall_fallback(). -uninstall_fallback(Args) -> +uninstall_fallback(Args) -> mnesia_bup:uninstall_fallback(Args). -activate_checkpoint(Args) -> +activate_checkpoint(Args) -> mnesia_checkpoint:activate(Args). -deactivate_checkpoint(Name) -> +deactivate_checkpoint(Name) -> mnesia_checkpoint:deactivate(Name). -backup_checkpoint(Name, Opaque) -> +backup_checkpoint(Name, Opaque) -> mnesia_log:backup_checkpoint(Name, Opaque). -backup_checkpoint(Name, Opaque, Mod) -> +backup_checkpoint(Name, Opaque, Mod) -> mnesia_log:backup_checkpoint(Name, Opaque, Mod). -restore(Opaque, Args) -> +restore(Opaque, Args) -> mnesia_schema:restore(Opaque, Args). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt -create_table(Arg) -> +create_table(Arg) -> mnesia_schema:create_table(Arg). -create_table(Name, Arg) when is_list(Arg) -> +create_table(Name, Arg) when is_list(Arg) -> mnesia_schema:create_table([{name, Name}| Arg]); create_table(Name, Arg) -> {aborted, badarg, Name, Arg}. -delete_table(Tab) -> +delete_table(Tab) -> mnesia_schema:delete_table(Tab). add_table_copy(Tab, N, S) -> @@ -2371,38 +2371,38 @@ add_table_copy(Tab, N, S) -> del_table_copy(Tab, N) -> mnesia_schema:del_table_copy(Tab, N). -move_table_copy(Tab, From, To) -> +move_table_copy(Tab, From, To) -> mnesia_schema:move_table(Tab, From, To). -add_table_index(Tab, Ix) -> +add_table_index(Tab, Ix) -> mnesia_schema:add_table_index(Tab, Ix). -del_table_index(Tab, Ix) -> +del_table_index(Tab, Ix) -> mnesia_schema:del_table_index(Tab, Ix). -transform_table(Tab, Fun, NewA) -> +transform_table(Tab, Fun, NewA) -> case catch val({Tab, record_name}) of - {'EXIT', Reason} -> + {'EXIT', Reason} -> mnesia:abort(Reason); - OldRN -> + OldRN -> mnesia_schema:transform_table(Tab, Fun, NewA, OldRN) end. -transform_table(Tab, Fun, NewA, NewRN) -> +transform_table(Tab, Fun, NewA, NewRN) -> mnesia_schema:transform_table(Tab, Fun, NewA, NewRN). change_table_copy_type(T, N, S) -> mnesia_schema:change_table_copy_type(T, N, S). clear_table(Tab) -> - case get(mnesia_activity_state) of + case get(mnesia_activity_state) of State = {Mod, Tid, _Ts} when element(1, Tid) =/= tid -> transaction(State, fun() -> do_clear_table(Tab) end, [], infinity, Mod, sync); - undefined -> + undefined -> transaction(undefined, fun() -> do_clear_table(Tab) end, [], infinity, ?DEFAULT_ACCESS, sync); _ -> %% Not allowed for clear_table mnesia:abort({aborted, nested_transaction}) end. - + do_clear_table(Tab) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -2415,7 +2415,7 @@ do_clear_table(Tab) -> clear_table(Tid, Ts, Tab, Obj) when element(1, Tid) =:= tid -> Store = Ts#tidstore.store, - mnesia_locker:wlock_table(Tid, Store, Tab), + mnesia_locker:wlock_table(Tid, Store, Tab), Oid = {Tab, '_'}, ?ets_insert(Store, {Oid, Obj, clear_table}), ok. @@ -2423,26 +2423,26 @@ clear_table(Tid, Ts, Tab, Obj) when element(1, Tid) =:= tid -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - user properties -read_table_property(Tab, PropKey) -> +read_table_property(Tab, PropKey) -> val({Tab, user_property, PropKey}). -write_table_property(Tab, Prop) -> +write_table_property(Tab, Prop) -> mnesia_schema:write_table_property(Tab, Prop). -delete_table_property(Tab, PropKey) -> +delete_table_property(Tab, PropKey) -> mnesia_schema:delete_table_property(Tab, PropKey). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - user properties -change_table_frag(Tab, FragProp) -> +change_table_frag(Tab, FragProp) -> mnesia_schema:change_table_frag(Tab, FragProp). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - table load %% Dump a ram table to disc -dump_tables(Tabs) -> +dump_tables(Tabs) -> mnesia_schema:dump_tables(Tabs). %% allow the user to wait for some tables to be loaded @@ -2455,10 +2455,10 @@ force_load_table(Tab) -> Other -> Other end. -change_table_access_mode(T, Access) -> +change_table_access_mode(T, Access) -> mnesia_schema:change_table_access_mode(T, Access). -change_table_load_order(T, O) -> +change_table_load_order(T, O) -> mnesia_schema:change_table_load_order(T, O). change_table_majority(T, M) -> @@ -2471,13 +2471,13 @@ set_master_nodes(Nodes) when is_list(Nodes) -> yes -> CsPat = {{'_', cstruct}, '_'}, Cstructs0 = ?ets_match_object(mnesia_gvar, CsPat), - Cstructs = [Cs || {_, Cs} <- Cstructs0], + Cstructs = [Cs || {_, Cs} <- Cstructs0], log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning); _NotRunning -> case UseDir of true -> mnesia_lib:lock_table(schema), - Res = + Res = case mnesia_schema:read_cstructs_from_disc() of {ok, Cstructs} -> log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning); @@ -2497,7 +2497,7 @@ log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning) -> Fun = fun(Cs) -> Copies = mnesia_lib:copy_holders(Cs), Valid = mnesia_lib:intersect(Nodes, Copies), - {Cs#cstruct.name, Valid} + {Cs#cstruct.name, Valid} end, Args = lists:map(Fun, Cstructs), mnesia_recover:log_master_nodes(Args, UseDir, IsRunning). @@ -2523,7 +2523,7 @@ set_master_nodes(Tab, Nodes) when is_list(Nodes) -> case UseDir of true -> mnesia_lib:lock_table(schema), - Res = + Res = case mnesia_schema:read_cstructs_from_disc() of {ok, Cstructs} -> case lists:keysearch(Tab, 2, Cstructs) of @@ -2553,7 +2553,7 @@ set_master_nodes(Tab, Nodes) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Misc admin -dump_log() -> +dump_log() -> mnesia_controller:sync_dump_log(user). subscribe(What) -> @@ -2568,10 +2568,10 @@ report_event(Event) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Snmp -snmp_open_table(Tab, Us) -> +snmp_open_table(Tab, Us) -> mnesia_schema:add_snmp(Tab, Us). -snmp_close_table(Tab) -> +snmp_close_table(Tab) -> mnesia_schema:del_snmp(Tab). snmp_get_row(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) -> @@ -2583,26 +2583,26 @@ snmp_get_row(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) SnmpType = val({Tab,snmp}), Fix = fun({{_,Key},Row,Op}, Res) -> case mnesia_snmp_hook:key_to_oid(Tab,Key,SnmpType) of - RowIndex -> + RowIndex -> case Op of write -> {ok, Row}; _ -> undefined end; - _ -> + _ -> Res end end, lists:foldl(Fix, undefined, Ops); Key -> case Mod:read(Tid, Ts, Tab, Key, read) of - [Row] -> + [Row] -> {ok, Row}; - _ -> + _ -> undefined end end; - _ -> + _ -> dirty_rpc(Tab, mnesia_snmp_hook, get_row, [Tab, RowIndex]) end; snmp_get_row(Tab, _RowIndex) -> @@ -2613,7 +2613,7 @@ snmp_get_row(Tab, _RowIndex) -> snmp_get_next_index(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) -> {Next,OrigKey} = dirty_rpc(Tab, mnesia_snmp_hook, get_next_index, [Tab, RowIndex]), case get(mnesia_activity_state) of - {_Mod, Tid, #tidstore{store=Store}} when element(1, Tid) =:= tid -> + {_Mod, Tid, #tidstore{store=Store}} when element(1, Tid) =:= tid -> case OrigKey of undefined -> snmp_order_keys(Store, Tab, RowIndex, []); @@ -2639,7 +2639,7 @@ snmp_get_next_index(Tab, _RowIndex) -> snmp_order_keys(Store,Tab,RowIndex,Def) -> All = ?ets_match(Store, {{Tab,'$1'},'_','$2'}), SnmpType = val({Tab,snmp}), - Keys0 = [mnesia_snmp_hook:key_to_oid(Tab,Key,SnmpType) || + Keys0 = [mnesia_snmp_hook:key_to_oid(Tab,Key,SnmpType) || Key <- ts_keys_1(All, Def)], Keys = lists:sort(Keys0), get_ordered_snmp_key(RowIndex,Keys). @@ -2648,7 +2648,7 @@ get_ordered_snmp_key(Prev, [First|_]) when Prev < First -> {ok, First}; get_ordered_snmp_key(Prev, [_|R]) -> get_ordered_snmp_key(Prev, R); get_ordered_snmp_key(_, []) -> - endOfTable. + endOfTable. %%%%%%%%%% @@ -2657,7 +2657,7 @@ snmp_get_mnesia_key(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(Row {_Mod, Tid, Ts} when element(1, Tid) =:= tid -> Res = dirty_rpc(Tab,mnesia_snmp_hook,get_mnesia_key,[Tab,RowIndex]), snmp_filter_key(Res, RowIndex, Tab, Ts#tidstore.store); - _ -> + _ -> dirty_rpc(Tab, mnesia_snmp_hook, get_mnesia_key, [Tab, RowIndex]) end; snmp_get_mnesia_key(Tab, _RowIndex) -> @@ -2670,7 +2670,7 @@ snmp_oid_to_mnesia_key(RowIndex, Tab) -> {ok, MnesiaKey} -> MnesiaKey; undefined -> unknown end; - MnesiaKey -> + MnesiaKey -> MnesiaKey end. @@ -2690,20 +2690,20 @@ snmp_filter_key(undefined, RowIndex, Tab, Store) -> SnmpType = val({Tab,snmp}), Fix = fun({{_,Key},_,Op}, Res) -> case mnesia_snmp_hook:key_to_oid(Tab,Key,SnmpType) of - RowIndex -> + RowIndex -> case Op of write -> {ok, Key}; _ -> undefined end; - _ -> + _ -> Res end end, lists:foldl(Fix, undefined, Ops); Key -> case ?ets_lookup(Store, {Tab,Key}) of - [] -> + [] -> undefined; Ops -> case lists:last(Ops) of @@ -2716,9 +2716,9 @@ snmp_filter_key(undefined, RowIndex, Tab, Store) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Textfile access -load_textfile(F) -> +load_textfile(F) -> mnesia_text:load_textfile(F). -dump_to_textfile(F) -> +dump_to_textfile(F) -> mnesia_text:dump_to_textfile(F). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2727,7 +2727,7 @@ dump_to_textfile(F) -> table(Tab) -> table(Tab, []). table(Tab,Opts) -> - {[Trav,Lock,NObjects],QlcOptions0} = + {[Trav,Lock,NObjects],QlcOptions0} = qlc_opts(Opts,[{traverse,select},{lock,read},{n_objects,100}]), TF = case Trav of {select,Ms} -> @@ -2740,10 +2740,10 @@ table(Tab,Opts) -> Pre = fun(Arg) -> pre_qlc(Arg, Tab) end, Post = fun() -> post_qlc(Tab) end, Info = fun(Tag) -> qlc_info(Tab, Tag) end, - ParentFun = fun() -> - {mnesia_activity, mnesia:get_activity_id()} + ParentFun = fun() -> + {mnesia_activity, mnesia:get_activity_id()} end, - Lookup = + Lookup = case Trav of {select, _} -> []; _ -> @@ -2757,27 +2757,27 @@ table(Tab,Opts) -> [{lookup_fun, LFun}] end, MFA = fun(Type) -> qlc_format(Type, Tab, NObjects, Lock, Opts) end, - QlcOptions = [{pre_fun, Pre}, {post_fun, Post}, - {info_fun, Info}, {parent_fun, ParentFun}, + QlcOptions = [{pre_fun, Pre}, {post_fun, Post}, + {info_fun, Info}, {parent_fun, ParentFun}, {format_fun, MFA}|Lookup] ++ QlcOptions0, qlc:table(TF, QlcOptions). pre_qlc(Opts, Tab) -> - {_,Tid,_} = + {_,Tid,_} = case get(mnesia_activity_state) of undefined -> case lists:keysearch(parent_value, 1, Opts) of {value, {parent_value,{mnesia_activity,undefined}}} -> abort(no_transaction); {value, {parent_value,{mnesia_activity,Aid}}} -> - {value,{stop_fun,Stop}} = + {value,{stop_fun,Stop}} = lists:keysearch(stop_fun,1,Opts), put_activity_id(Aid,Stop), Aid; _ -> abort(no_transaction) end; - Else -> + Else -> Else end, case element(1,Tid) of @@ -2785,9 +2785,9 @@ pre_qlc(Opts, Tab) -> _ -> case ?catch_val({Tab, setorbag}) of ordered_set -> ok; - _ -> + _ -> dirty_rpc(Tab, mnesia_tm, fixtable, [Tab,true,self()]), - ok + ok end end. @@ -2806,7 +2806,7 @@ post_qlc(Tab) -> qlc_select('$end_of_table') -> []; qlc_select({[], Cont}) -> qlc_select(select(Cont)); -qlc_select({Objects, Cont}) -> +qlc_select({Objects, Cont}) -> Objects ++ fun() -> qlc_select(select(Cont)) end. qlc_opts(Opts, Keys) when is_list(Opts) -> @@ -2826,7 +2826,7 @@ qlc_opts(Opts,[],Acc) -> {lists:reverse(Acc),Opts}. qlc_info(Tab, num_of_objects) -> dirty_rpc(Tab, ?MODULE, raw_table_info, [Tab, size]); -qlc_info(_, keypos) -> 2; +qlc_info(_, keypos) -> 2; qlc_info(_, is_unique_objects) -> true; qlc_info(Tab, is_unique_keys) -> case val({Tab, type}) of @@ -2836,9 +2836,9 @@ qlc_info(Tab, is_unique_keys) -> end; qlc_info(Tab, is_sorted_objects) -> case val({Tab, type}) of - ordered_set -> + ordered_set -> case ?catch_val({Tab, frag_hash}) of - {'EXIT', _} -> + {'EXIT', _} -> ascending; _ -> %% Fragmented tables are not ordered no @@ -2856,11 +2856,11 @@ qlc_format({match_spec, Ms}, Tab, NObjects, Lock, Opts) -> {?MODULE, table, [Tab,[{traverse,{select,Ms}},{n_objects, NObjects}, {lock,Lock}|Opts]]}; qlc_format({lookup, 2, Keys}, Tab, _, Lock, _) -> io_lib:format("lists:flatmap(fun(V) -> " - "~w:read(~w, V, ~w) end, ~w)", + "~w:read(~w, V, ~w) end, ~w)", [?MODULE, Tab, Lock, Keys]); qlc_format({lookup, Index,Keys}, Tab, _, _, _) -> io_lib:format("lists:flatmap(fun(V) -> " - "~w:index_read(~w, V, ~w) end, ~w)", + "~w:index_read(~w, V, ~w) end, ~w)", [?MODULE, Tab, Index, Keys]). @@ -2874,7 +2874,7 @@ do_fixtable(Tab, Store) -> ok; _ -> case ?ets_match_object(Store, {fixtable, {Tab, '_'}}) of - [] -> + [] -> Node = dirty_rpc(Tab, mnesia_tm, fixtable, [Tab,true,self()]), ?ets_insert(Store, {fixtable, {Tab, Node}}); _ -> @@ -2886,10 +2886,10 @@ do_fixtable(Tab, Store) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Mnemosyne exclusive -get_activity_id() -> +get_activity_id() -> get(mnesia_activity_state). -put_activity_id(Activity) -> +put_activity_id(Activity) -> mnesia_tm:put_activity_id(Activity). -put_activity_id(Activity,Fun) -> +put_activity_id(Activity,Fun) -> mnesia_tm:put_activity_id(Activity,Fun). diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl index 2375b72d59..2855792646 100644 --- a/lib/mnesia/src/mnesia.hrl +++ b/lib/mnesia/src/mnesia.hrl @@ -70,6 +70,7 @@ attributes = [key, val], % [Atom] user_properties = [], % [Record] frag_properties = [], % [{Key, Val] + storage_properties = [], % [{Key, Val] cookie = ?unique_cookie, % Term version = {{2, 0}, []}}). % {{Integer, Integer}, [Node]} diff --git a/lib/mnesia/src/mnesia_backup.erl b/lib/mnesia/src/mnesia_backup.erl index f372ca0be5..736f2ed9bf 100644 --- a/lib/mnesia/src/mnesia_backup.erl +++ b/lib/mnesia/src/mnesia_backup.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -56,14 +56,14 @@ -export([ %% Write access - open_write/1, - write/2, - commit_write/1, + open_write/1, + write/2, + commit_write/1, abort_write/1, %% Read access - open_read/1, - read/1, + open_read/1, + read/1, close_read/1 ]). diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 14414537b9..fd87be1759 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -62,7 +62,7 @@ fallback_tmp, skip_tables = [], keep_tables = [], - default_op = keep_tables + default_op = keep_tables }). -type fallback_args() :: #fallback_args{}. @@ -134,7 +134,7 @@ abort_restore(R, What, Args, Reason) -> [Mod, What, Args, Reason]), catch apply(Mod, close_read, [Opaque]), throw({error, Reason}). - + fallback_to_schema() -> Fname = fallback_bup(), fallback_to_schema(Fname). @@ -146,14 +146,14 @@ fallback_to_schema(Fname) -> {error, Reason}; Schema -> case catch lookup_schema(schema, Schema) of - {error, _} -> + {error, _} -> {error, "No schema in fallback"}; List -> {ok, fallback, List} end end. -%% Opens Opaque reads schema and then close +%% Opens Opaque reads schema and then close read_schema(Mod, Opaque) -> R = #restore{bup_module = Mod, bup_data = Opaque}, case catch read_schema_section(R) of @@ -163,7 +163,7 @@ read_schema(Mod, Opaque) -> catch safe_apply(R2, close_read, [R2#restore.bup_data]), Schema end. - + %% Open backup media and extract schema %% rewind backup media and leave it open %% Returns {R, {Header, Schema}} @@ -227,7 +227,7 @@ refresh_cookie(Schema, NewCookie) -> Cs2 = Cs#cstruct{cookie = NewCookie}, Item = {schema, schema, mnesia_schema:cs2list(Cs2)}, lists:keyreplace(schema, 2, Schema, Item); - + false -> Reason = "No schema found. Cannot be used as backup.", throw({error, {Reason, Schema}}) @@ -273,7 +273,7 @@ convert_0_1([{schema, db_nodes, DbNodes} | Schema], Acc, Cs) -> convert_0_1([{schema, version, Version} | Schema], Acc, Cs) -> convert_0_1(Schema, Acc, Cs#cstruct{version = Version}); convert_0_1([{schema, Tab, Def} | Schema], Acc, Cs) -> - Head = + Head = case lists:keysearch(index, 1, Def) of {value, {index, PosList}} -> %% Remove the snmp "index" @@ -334,7 +334,7 @@ create_schema(Ns, ok) -> case mnesia_lib:ensure_loaded(?APPLICATION) of ok -> case mnesia_monitor:get_env(schema_location) of - ram -> + ram -> {error, {has_no_disc, node()}}; _ -> case mnesia_schema:opt_create_dir(true, mnesia_lib:dir()) of @@ -358,7 +358,7 @@ create_schema(Ns, ok) -> {error, Reason} end end - end; + end; {error, Reason} -> {error, Reason} end; @@ -434,7 +434,7 @@ check_fallback_args([Arg | Tail], FA) -> check_fallback_args([], FA) -> {ok, FA}. -check_fallback_arg_type(Arg, FA) -> +check_fallback_arg_type(Arg, FA) -> case Arg of {scope, global} -> FA#fallback_args{scope = global}; @@ -462,10 +462,10 @@ atom_list([H | T]) when is_atom(H) -> atom_list(T); atom_list([]) -> ok. - + do_install_fallback(FA) -> Pid = spawn_link(?MODULE, install_fallback_master, [self(), FA]), - Res = + Res = receive {'EXIT', Pid, Reason} -> % if appl has trapped exit {error, {'EXIT', Reason}}; @@ -506,7 +506,7 @@ restore_recs(Recs, Header, Schema, {start, FA}) -> Pids = [spawn_link(N, ?MODULE, fallback_receiver, Args) || N <- Ns], send_fallback(Pids, {start, Header, Schema2}), Res = restore_recs(Recs, Header, Schema2, Pids), - global:del_lock({{mnesia_table_lock, schema}, self()}, Ns), + global:del_lock({{mnesia_table_lock, schema}, self()}, Ns), Res end; @@ -578,7 +578,7 @@ fallback_tmp_name() -> "FALLBACK.TMP". -spec fallback_receiver(pid(), fallback_args()) -> no_return(). fallback_receiver(Master, FA) -> process_flag(trap_exit, true), - + case catch register(mnesia_fallback, self()) of {'EXIT', _} -> Reason = {already_exists, node()}, @@ -610,7 +610,7 @@ local_fallback_error(Master, Reason) -> Master ! {self(), {error, Reason}}, unlink(Master), exit(Reason). - + check_fallback_dir(Master, FA) -> case mnesia:system_info(schema_location) of ram -> @@ -659,7 +659,7 @@ fallback_receiver_loop(Master, R, FA, State) -> R2 = safe_apply(R, write, [R#restore.bup_data, Recs]), Master ! {self(), ok}, fallback_receiver_loop(Master, R2, FA, records); - + {Master, swap} when State =/= schema -> ?eval_debug_fun({?MODULE, fallback_receiver_loop, pre_swap}, []), safe_apply(R, commit_write, [R#restore.bup_data]), @@ -834,7 +834,7 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) -> ok = dets:delete(schema, {schema, Tab}), create_dat_files(Tail, LocalTabs); Storage =:= disc_only_copies -> - Args = [{file, TmpFile}, {keypos, 2}, + Args = [{file, TmpFile}, {keypos, 2}, {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)}], Open = fun(T, LT) when T =:= LT#local_tab.name -> case mnesia_lib:dets_sync_open(T, Args) of @@ -861,9 +861,9 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) -> Swap = fun(T, LT) when T =:= LT#local_tab.name -> Expunge(), case LT#local_tab.opened of - true -> + true -> Close(T,LT); - false -> + false -> Open(T,LT), Close(T,LT) end, @@ -887,8 +887,8 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) -> create_dat_files(Tail, LocalTabs); Storage =:= ram_copies; Storage =:= disc_copies -> Open = fun(T, LT) when T =:= LT#local_tab.name -> - mnesia_log:open_log({?MODULE, T}, - mnesia_log:dcl_log_header(), + mnesia_log:open_log({?MODULE, T}, + mnesia_log:dcl_log_header(), TmpFile, false, false, @@ -917,7 +917,7 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) -> true -> Log = mnesia_log:open_log(fallback_tab, mnesia_log:dcd_log_header(), - DcdFile, + DcdFile, false), mnesia_log:close_log(Log), case LT#local_tab.opened of @@ -926,7 +926,7 @@ create_dat_files([{schema, Tab, TabDef} | Tail], LocalTabs) -> false -> Open(T,LT), Close(T,LT) - end, + end, case file:rename(TmpFile, DclFile) of ok -> ok; @@ -959,7 +959,7 @@ create_dat_files([], _LocalTabs) -> ok. uninstall_fallback() -> - uninstall_fallback([{scope, global}]). + uninstall_fallback([{scope, global}]). uninstall_fallback(Args) -> case check_fallback_args(Args, #fallback_args{}) of @@ -969,7 +969,7 @@ uninstall_fallback(Args) -> {error, Reason} end. -do_uninstall_fallback(FA) -> +do_uninstall_fallback(FA) -> %% Ensure that we access the intended Mnesia %% directory. This function may not be called %% during startup since it will cause the @@ -1040,11 +1040,11 @@ do_uninstall(_ClientPid, [], GoodPids, BadNodes, BadRes) -> local_uninstall_fallback(Master, FA) -> %% Don't trap exit - + register(mnesia_fallback, self()), % May exit FA2 = check_fallback_dir(Master, FA), % May exit Master ! {self(), started}, - + receive {Master, do_uninstall} -> ?eval_debug_fun({?MODULE, uninstall_fallback2, pre_delete}, []), @@ -1052,7 +1052,7 @@ local_uninstall_fallback(Master, FA) -> Tmp = FA2#fallback_args.fallback_tmp, Bup = FA2#fallback_args.fallback_bup, file:delete(Tmp), - Res = + Res = case fallback_exists(Bup) of true -> file:delete(Bup); false -> ok @@ -1079,7 +1079,7 @@ rec_uninstall(ClientPid, [], Res) -> ClientPid ! {self(), Res}, unlink(ClientPid), exit(normal). - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Backup traversal @@ -1130,7 +1130,7 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) -> if TargetMod =/= read_only -> case catch do_apply(TargetMod, open_write, [Target], Target) of - {error, Error} -> + {error, Error} -> unlink(ClientPid), ClientPid ! {iter_done, self(), {error, Error}}, exit(Error); @@ -1140,15 +1140,15 @@ do_traverse_backup(ClientPid, Source, SourceMod, Target, TargetMod, Fun, Acc) -> ignore end, A = {start, Fun, Acc, TargetMod, Iter}, - Res = + Res = case iterate(SourceMod, fun trav_apply/4, Source, A) of {ok, {iter, _, Acc2, _, Iter2}} when TargetMod =/= read_only -> case catch do_apply(TargetMod, commit_write, [Iter2], Iter2) of - {error, Reason} -> + {error, Reason} -> {error, Reason}; - _ -> + _ -> {ok, Acc2} - end; + end; {ok, {iter, _, Acc2, _, _}} -> {ok, Acc2}; {error, Reason} when TargetMod =/= read_only-> diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 6a561394d5..d488a33d67 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -107,14 +107,14 @@ -include("mnesia.hrl"). --define(SERVER_NAME, ?MODULE). +-define(SERVER_NAME, ?MODULE). -record(state, {supervisor, schema_is_merged = false, early_msgs = [], - loader_pid = [], %% Was Pid is now [{Pid,Work}|..] + loader_pid = [], %% Was Pid is now [{Pid,Work}|..] loader_queue, %% Was list is now gb_tree - sender_pid = [], %% Was a pid or undef is now [{Pid,Work}|..] + sender_pid = [], %% Was a pid or undef is now [{Pid,Work}|..] sender_queue = [], late_loader_queue, %% Was list is now gb_tree dumper_pid, %% Dumper or schema commit pid @@ -124,12 +124,12 @@ is_stopping = false }). %% Backwards Comp. Sender_pid is now a list of senders.. -get_senders(#state{sender_pid = Pids}) when is_list(Pids) -> Pids. +get_senders(#state{sender_pid = Pids}) when is_list(Pids) -> Pids. %% Backwards Comp. loader_pid is now a list of loaders.. -get_loaders(#state{loader_pid = Pids}) when is_list(Pids) -> Pids. +get_loaders(#state{loader_pid = Pids}) when is_list(Pids) -> Pids. max_loaders() -> case ?catch_val(no_table_loaders) of - {'EXIT', _} -> + {'EXIT', _} -> mnesia_lib:set(no_table_loaders,1), 1; Val -> Val @@ -153,7 +153,7 @@ max_loaders() -> remote_storage }). --record(disc_load, {table, +-record(disc_load, {table, reason, opt_reply_to }). @@ -184,7 +184,7 @@ max_loaders() -> val(Var) -> case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); + {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); Value -> Value end. @@ -199,7 +199,7 @@ sync_dump_log(InitBy) -> async_dump_log(InitBy) -> ?SERVER_NAME ! {async_dump_log, InitBy}. - + %% Wait for tables to be active %% If needed, we will wait for Mnesia to start %% If Mnesia stops, we will wait for Mnesia to restart @@ -227,7 +227,7 @@ do_wait_for_tables(Tabs, Timeout) -> exit(Pid, timeout), reply_wait(Tabs) end. - + reply_wait(Tabs) -> case catch mnesia_lib:active_tables() of {'EXIT', _} -> @@ -270,7 +270,7 @@ rec_tabs([Tab | Tabs], AllTabs, From, Init) -> %% This will trigger an exit signal %% to mnesia_init exit(wait_for_tables_timeout); - + {'EXIT', Init, _} -> %% Oops, mnesia_init stopped, exit(mnesia_stopped) @@ -279,11 +279,8 @@ rec_tabs([], _, _, Init) -> unlink(Init), ok. -%% New function that does exactly what get_cstructs() used to do. -%% When this function is called, we know that the calling node knows -%% how to convert cstructs on the receiving end (should they differ). get_remote_cstructs() -> - call(get_cstructs). + get_cstructs(). %% Sigh not forward compatible always check version %% Old function kept for backwards compatibility; converts cstructs before sending. get_cstructs() -> @@ -319,7 +316,7 @@ get_network_copy(Tab, Cs) -> % We can't let the controller queue this one % because that may cause a deadlock between schema_operations % and initial tableloadings which both takes schema locks. -% But we have to get copier_done msgs when the other side +% But we have to get copier_done msgs when the other side % goes down. call({add_other, self()}), Reason = {dumper,add_table_copy}, @@ -341,14 +338,14 @@ get_network_copy(Tab, Cs) -> ignore end, Res#loader_done.reply; - #loader_done{} -> + #loader_done{} -> Res#loader_done.reply; Else -> {not_loaded, Else} end. %% This functions is invoked from the dumper -%% +%% %% There are two cases here: %% startup -> %% no need for sync, since mnesia_controller not started yet @@ -380,11 +377,11 @@ force_load_table(Tab) when is_atom(Tab), Tab /= schema -> end; force_load_table(Tab) -> {error, {bad_type, Tab}}. - + do_force_load_table(Tab) -> Loaded = ?catch_val({Tab, load_reason}), case Loaded of - unknown -> + unknown -> set({Tab, load_by_force}, true), mnesia_late_loader:async_late_disc_load(node(), [Tab], forced_by_user), wait_for_tables([Tab], infinity); @@ -394,7 +391,7 @@ do_force_load_table(Tab) -> wait_for_tables([Tab], infinity); _ -> ok - end. + end. master_nodes_updated(schema, _Masters) -> ignore; master_nodes_updated(Tab, Masters) -> @@ -438,15 +435,15 @@ connect_nodes(Ns) -> connect_nodes(Ns, fun default_merge/1). connect_nodes(Ns, UserFun) -> - case mnesia:system_info(is_running) of + case mnesia:system_info(is_running) of no -> {error, {node_not_running, node()}}; - yes -> + yes -> Pid = spawn_link(?MODULE,connect_nodes2,[self(),Ns, UserFun]), - receive - {?MODULE, Pid, Res, New} -> + receive + {?MODULE, Pid, Res, New} -> case Res of - ok -> + ok -> mnesia_lib:add_list(extra_db_nodes, New), {ok, New}; {aborted, {throw, Str}} when is_list(Str) -> @@ -454,8 +451,8 @@ connect_nodes(Ns, UserFun) -> {error, {merge_schema_failed, lists:flatten(Str)}}; Else -> {error, Else} - end; - {'EXIT', Pid, Reason} -> + end; + {'EXIT', Pid, Reason} -> {error, Reason} end end. @@ -466,16 +463,16 @@ connect_nodes2(Father, Ns, UserFun) -> {NewC, OldC} = mnesia_recover:connect_nodes(Ns), Connected = NewC ++OldC, New1 = mnesia_lib:intersect(Ns, Connected), - New = New1 -- Current, + New = New1 -- Current, process_flag(trap_exit, true), Res = try_merge_schema(New, [], UserFun), Msg = {schema_is_merged, [], late_merge, []}, multicall([node()|Ns], Msg), - After = val({current, db_nodes}), + After = val({current, db_nodes}), Father ! {?MODULE, self(), Res, mnesia_lib:intersect(Ns,After)}, unlink(Father), ok. - + %% Merge the local schema with the schema on other nodes. %% But first we must let all processes that want to force %% load tables wait until the schema merge is done. @@ -483,7 +480,7 @@ connect_nodes2(Father, Ns, UserFun) -> merge_schema() -> AllNodes = mnesia_lib:all_nodes(), case try_merge_schema(AllNodes, [node()], fun default_merge/1) of - ok -> + ok -> schema_is_merged(); {aborted, {throw, Str}} when is_list(Str) -> fatal("Failed to merge schema: ~s~n", [Str]); @@ -535,7 +532,7 @@ im_running(OldFriends, NewFriends) -> schema_is_merged() -> MsgTag = schema_is_merged, SafeLoads = initial_safe_loads(), - + %% At this point we do not know anything about %% which tables that the other nodes already %% has loaded and therefore we let the normal @@ -545,7 +542,7 @@ schema_is_merged() -> %% that all nodes tells each other directly %% when they have loaded a table and are %% willing to share it. - + try_schedule_late_disc_load(SafeLoads, initial, MsgTag). @@ -589,7 +586,7 @@ remote_call(Node, Func, Args) -> Else -> Else end. - + multicall(Nodes, Msg) -> {Good, Bad} = gen_server:multi_call(Nodes, ?MODULE, Msg, infinity), PatchedGood = [Reply || {_Node, Reply} <- Good], @@ -621,9 +618,9 @@ init([Parent]) -> Msg = {async_dump_log, time_threshold}, {ok, Ref} = timer:send_interval(Interval, Msg), mnesia_dumper:start_regulator(), - + Empty = gb_trees:empty(), - {ok, #state{supervisor = Parent, dump_log_timer_ref = Ref, + {ok, #state{supervisor = Parent, dump_log_timer_ref = Ref, loader_queue = Empty, late_loader_queue = Empty}}. @@ -656,17 +653,17 @@ handle_call(block_controller, From, State) -> handle_call({update,Fun}, From, State) -> Res = (catch Fun()), - reply(From, Res), + reply(From, Res), noreply(State); handle_call(get_cstructs, From, State) -> Tabs = val({schema, tables}), Cstructs = [val({T, cstruct}) || T <- Tabs], Running = val({current, db_nodes}), - reply(From, {cstructs, Cstructs, Running}), + reply(From, {cstructs, Cstructs, Running}), noreply(State); -handle_call({schema_is_merged, [], late_merge, []}, From, +handle_call({schema_is_merged, [], late_merge, []}, From, State = #state{schema_is_merged = Merged}) -> case Merged of {false, Node} when Node == node(From) -> @@ -697,8 +694,8 @@ handle_call(disc_load_intents,From,State = #state{loader_queue=LQ,late_loader_qu handle_call({update_where_to_write, [add, Tab, AddNode], _From}, _Dummy, State) -> Current = val({current, db_nodes}), - Res = - case lists:member(AddNode, Current) and + Res = + case lists:member(AddNode, Current) and (State#state.schema_is_merged == true) of true -> mnesia_lib:add_lsort({Tab, where_to_write}, AddNode), @@ -732,7 +729,7 @@ handle_call({add_active_replica, [Tab, ToNode, RemoteS, AccessMode], From}, noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]}) end; -handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) -> +handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) -> KnownNode = lists:member(node(From), val({current, db_nodes})), Merged = State#state.schema_is_merged, if @@ -752,16 +749,16 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) -> end; handle_call({net_load, Tab, Cs}, From, State) -> - State2 = + State2 = case State#state.schema_is_merged of - true -> + true -> Worker = #net_load{table = Tab, opt_reply_to = From, reason = {dumper,add_table_copy}, cstruct = Cs }, add_worker(Worker, State); - false -> + false -> reply(From, {not_loaded, schema_not_merged}), State end, @@ -804,16 +801,16 @@ handle_call({add_other, Who}, _From, State = #state{others=Others0}) -> handle_call({del_other, Who}, _From, State = #state{others=Others0}) -> Others = lists:delete(Who, Others0), {reply, ok, State#state{others=Others}}; - + handle_call(Msg, _From, State) -> error("~p got unexpected call: ~p~n", [?SERVER_NAME, Msg]), noreply(State). -late_disc_load(TabsR, Reason, RemoteLoaders, From, +late_disc_load(TabsR, Reason, RemoteLoaders, From, State = #state{loader_queue = LQ, late_loader_queue = LLQ}) -> verbose("Intend to load tables: ~p~n", [TabsR]), ?eval_debug_fun({?MODULE, late_disc_load}, - [{tabs, TabsR}, + [{tabs, TabsR}, {reason, Reason}, {loaders, RemoteLoaders}]), @@ -822,14 +819,14 @@ late_disc_load(TabsR, Reason, RemoteLoaders, From, %% Remove deleted tabs and queued/loaded LocalTabs = gb_sets:from_ordset(lists:sort(mnesia_lib:val({schema,local_tables}))), - Filter = fun(TabInfo0, Acc) -> - TabInfo = {Tab,_} = - case TabInfo0 of + Filter = fun(TabInfo0, Acc) -> + TabInfo = {Tab,_} = + case TabInfo0 of {_,_} -> TabInfo0; TabN -> {TabN,Reason} end, case gb_sets:is_member(Tab, LocalTabs) of - true -> + true -> case ?catch_val({Tab, where_to_read}) == node() of true -> Acc; false -> @@ -841,12 +838,12 @@ late_disc_load(TabsR, Reason, RemoteLoaders, From, false -> Acc end end, - + Tabs = lists:foldl(Filter, [], TabsR), - + Nodes = val({current, db_nodes}), LateQueue = late_loaders(Tabs, RemoteLoaders, Nodes, LLQ), - State#state{late_loader_queue = LateQueue}. + State#state{late_loader_queue = LateQueue}. late_loaders([{Tab, Reason} | Tabs], RemoteLoaders, Nodes, LLQ) -> case gb_trees:is_defined(Tab, LLQ) of @@ -859,7 +856,7 @@ late_loaders([{Tab, Reason} | Tabs], RemoteLoaders, Nodes, LLQ) -> LateLoad = #late_load{table=Tab,loaders=LoadNodes,reason=Reason}, late_loaders(Tabs, RemoteLoaders, Nodes, gb_trees:insert(Tab,LateLoad,LLQ)); true -> - late_loaders(Tabs, RemoteLoaders, Nodes, LLQ) + late_loaders(Tabs, RemoteLoaders, Nodes, LLQ) end; late_loaders([], _RemoteLoaders, _Nodes, LLQ) -> LLQ. @@ -899,7 +896,7 @@ late_load_filter([RL | RemoteLoaders], Tab, Nodes, Acc) -> end; late_load_filter([], _Tab, _Nodes, Acc) -> Acc. - + %%---------------------------------------------------------------------- %% Func: handle_cast/2 %% Returns: {noreply, State} | @@ -911,7 +908,7 @@ handle_cast({release_schema_commit_lock, _Owner}, State) -> if State#state.is_stopping == true -> {stop, shutdown, State}; - true -> + true -> case State#state.dumper_queue of [#schema_commit_lock{}|Rest] -> [_Worker | Rest] = State#state.dumper_queue, @@ -932,7 +929,7 @@ handle_cast(unblock_controller, State) -> [_Worker | Rest] = State#state.dumper_queue, State2 = State#state{dumper_pid = undefined, dumper_queue = Rest}, - State3 = opt_start_worker(State2), + State3 = opt_start_worker(State2), noreply(State3) end; @@ -948,31 +945,31 @@ handle_cast({mnesia_down, Node}, State) -> %% Fix if we are late_merging against the node that went down case State#state.schema_is_merged of - {false, Node} -> + {false, Node} -> spawn(?MODULE, call, [{schema_is_merged, [], late_merge, []}]); _ -> ignore end, - + %% Fix internal stuff LateQ = remove_loaders(Alltabs, Node, State#state.late_loader_queue), - + case get_senders(State) ++ get_loaders(State) of [] -> ignore; - Senders -> + Senders -> lists:foreach(fun({Pid,_}) -> Pid ! {copier_done, Node} end, Senders) end, - lists:foreach(fun(Pid) -> Pid ! {copier_done,Node} end, + lists:foreach(fun(Pid) -> Pid ! {copier_done,Node} end, State#state.others), - + Remove = fun(ST) -> node(ST#send_table.receiver_pid) /= Node end, NewSenders = lists:filter(Remove, State#state.sender_queue), Early = remove_early_messages(State#state.early_msgs, Node), - noreply(State#state{sender_queue = NewSenders, - early_msgs = Early, + noreply(State#state{sender_queue = NewSenders, + early_msgs = Early, late_loader_queue = LateQ }); @@ -981,8 +978,8 @@ handle_cast({merging_schema, Node}, State) -> false -> %% This comes from dynamic connect_nodes which are made %% after mnesia:start() and the schema_merge. - ImANewKidInTheBlock = - (val({schema, storage_type}) == ram_copies) + ImANewKidInTheBlock = + (val({schema, storage_type}) == ram_copies) andalso (mnesia_lib:val({schema, local_tables}) == [schema]), case ImANewKidInTheBlock of true -> %% I'm newly started ram_node.. @@ -1000,7 +997,7 @@ handle_cast(Msg, State) when State#state.schema_is_merged /= true -> noreply(State#state{early_msgs = [{cast, Msg} | Msgs]}); %% This must be done after schema_is_merged otherwise adopt_orphan -%% might trigger a table load from wrong nodes as a result of that we don't +%% might trigger a table load from wrong nodes as a result of that we don't %% know which tables we can load safly first. handle_cast({im_running, Node, NewFriends}, State) -> LocalTabs = mnesia_lib:local_active_tables() -- [schema], @@ -1027,7 +1024,7 @@ handle_cast({sync_tabs, Tabs, From}, State) -> handle_cast({i_have_tab, Tab, Node}, State) -> case lists:member(Node, val({current, db_nodes})) of - true -> + true -> State2 = node_has_tabs([Tab], Node, State), noreply(State2); false -> @@ -1043,10 +1040,10 @@ handle_cast({force_load_updated, Tab}, State) -> State2 = node_has_tabs([Tab], SomeNode, State), noreply(State2) end; - + handle_cast({master_nodes_updated, Tab, Masters}, State) -> Active = val({Tab, active_replicas}), - Valid = + Valid = case val({Tab, load_by_force}) of true -> Active; @@ -1066,10 +1063,10 @@ handle_cast({master_nodes_updated, Tab, Masters}, State) -> State2 = node_has_tabs([Tab], SomeNode, State), noreply(State2) end; - + handle_cast({adopt_orphans, Node, Tabs}, State) -> State2 = node_has_tabs(Tabs, Node, State), - + case ?catch_val({node_up,Node}) of true -> ignore; _ -> @@ -1101,7 +1098,7 @@ handle_cast(Msg, State) -> error("~p got unexpected cast: ~p~n", [?SERVER_NAME, Msg]), noreply(State). -handle_sync_tabs([Tab | Tabs], From) -> +handle_sync_tabs([Tab | Tabs], From) -> case val({Tab, where_to_read}) of nowhere -> case get({sync_tab, Tab}) of @@ -1145,7 +1142,7 @@ handle_info(#dumper_done{worker_pid=Pid, worker_res=Res}, State) -> {stop, fatal, State} end; -handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) -> +handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) -> LateQueue0 = State0#state.late_loader_queue, State1 = State0#state{loader_pid = lists:keydelete(WPid,1,get_loaders(State0))}, @@ -1153,7 +1150,7 @@ handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) -> case Done#loader_done.is_loaded of true -> %% Optional table announcement - if + if Done#loader_done.needs_announce == true, Done#loader_done.needs_reply == true -> i_have_tab(Tab), @@ -1187,7 +1184,7 @@ handle_info(Done = #loader_done{worker_pid=WPid, table_name=Tab}, State0) -> State1#state{late_loader_queue=gb_trees:delete_any(Tab, LateQueue0)}; false -> %% Either the node went down or table was not - %% loaded remotly yet + %% loaded remotly yet case Done#loader_done.needs_reply of true -> reply(Done#loader_done.reply_to, @@ -1210,7 +1207,7 @@ handle_info(#sender_done{worker_pid=Pid, worker_res=Res}, State) -> Senders = get_senders(State), {value, {Pid,_Worker}} = lists:keysearch(Pid, 1, Senders), if - Res == ok -> + Res == ok -> State2 = State#state{sender_pid = lists:keydelete(Pid, 1, Senders)}, State3 = opt_start_worker(State2), noreply(State3); @@ -1252,7 +1249,7 @@ handle_info(Msg = {'EXIT', Pid, R}, State) when R /= wait_for_tables_timeout -> {stop, fatal, State}; false -> case lists:keymember(Pid, 1, get_loaders(State)) of - true -> + true -> fatal("Loader crashed: ~p~n state: ~p~n", [R, State]), {stop, fatal, State}; false -> @@ -1338,7 +1335,7 @@ code_change(_OldVsn, State0, _Extra) -> State1 = case State0#state.loader_pid of Pids when is_list(Pids) -> State0; undefined -> State0#state{loader_pid = [],loader_queue=gb_trees:empty()}; - Pid when is_pid(Pid) -> + Pid when is_pid(Pid) -> [Loader|Rest] = State0#state.loader_queue, LQ0 = [{element(2,Rec),Rec} || Rec <- Rest], LQ1 = lists:sort(LQ0), @@ -1346,7 +1343,7 @@ code_change(_OldVsn, State0, _Extra) -> State0#state{loader_pid=[{Pid,Loader}], loader_queue=LQ} end, %% LateLoaderQueue - State = if is_list(State1#state.late_loader_queue) -> + State = if is_list(State1#state.late_loader_queue) -> LLQ0 = State1#state.late_loader_queue, LLQ1 = lists:sort([{element(2,Rec),Rec} || Rec <- LLQ0]), LLQ = gb_trees:from_orddict(LLQ1), @@ -1355,7 +1352,7 @@ code_change(_OldVsn, State0, _Extra) -> State1 end, {ok, State}. - + %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- @@ -1365,20 +1362,20 @@ maybe_log_mnesia_down(N) -> %% so if we are not running (i.e haven't decided which tables %% to load locally), don't log mnesia_down yet. case mnesia_lib:is_running() of - yes -> + yes -> verbose("Logging mnesia_down ~w~n", [N]), mnesia_recover:log_mnesia_down(N), ok; - _ -> + _ -> Filter = fun(Tab) -> inactive_copy_holders(Tab, N) end, HalfLoadedTabs = lists:any(Filter, val({schema, local_tables}) -- [schema]), - if + if HalfLoadedTabs == true -> verbose("Logging mnesia_down ~w~n", [N]), mnesia_recover:log_mnesia_down(N), - ok; + ok; true -> %% Unfortunately we have not loaded some common %% tables yet, so we cannot rely on the nodedown @@ -1407,7 +1404,7 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) -> BeingCreated = (?catch_val({Tab, create_table}) == true), Read = val({Tab, where_to_read}), case lists:member(Node, DiscCopyHolders) of - _ when BeingCreated == true -> + _ when BeingCreated == true -> orphan_tables(Tabs, Node, Ns, Local, Remote); _ when Read == node() -> %% Allready loaded orphan_tables(Tabs, Node, Ns, Local, Remote); @@ -1445,13 +1442,13 @@ orphan_tables([], _, _, LocalOrphans, RemoteMasters) -> {LocalOrphans, RemoteMasters}. node_has_tabs([Tab | Tabs], Node, State) when Node /= node() -> - State2 = + State2 = case catch update_whereabouts(Tab, Node, State) of State1 = #state{} -> State1; {'EXIT', R} -> %% Tab was just deleted? case ?catch_val({Tab, cstruct}) of {'EXIT', _} -> State; % yes - _ -> erlang:error(R) + _ -> erlang:error(R) end end, node_has_tabs(Tabs, Node, State2); @@ -1477,14 +1474,14 @@ update_whereabouts(Tab, Node, State) -> true -> lists:member(Node, Masters) end, - + dbg_out("Table ~w is loaded on ~w. s=~w, r=~w, lc=~w, f=~w, m=~w~n", [Tab, Node, Storage, Read, LocalC, ByForce, GoGetIt]), if LocalC == true -> %% Local contents, don't care about other node State; - BeingCreated == true -> + BeingCreated == true -> %% The table is currently being created %% It will be handled elsewhere State; @@ -1501,8 +1498,8 @@ update_whereabouts(Tab, Node, State) -> State end; Storage == unknown -> - %% No own copy, continue to read remotely - add_active_replica(Tab, Node), + %% No own copy, continue to read remotely + add_active_replica(Tab, Node), NodeST = mnesia_lib:storage_type_at_node(Node, Tab), ReadST = mnesia_lib:storage_type_at_node(Read, Tab), if %% Avoid reading from disc_only_copies @@ -1542,16 +1539,16 @@ initial_safe_loads() -> Tabs = val({schema, local_tables}) -- [schema], LastC = fun(T) -> last_consistent_replica(T, Downs) end, lists:zf(LastC, Tabs); - + disc_copies -> Downs = mnesia_recover:get_mnesia_downs(), dbg_out("mnesia_downs = ~p~n", [Downs]), - + Tabs = val({schema, local_tables}) -- [schema], LastC = fun(T) -> last_consistent_replica(T, Downs) end, lists:zf(LastC, Tabs) end. - + last_consistent_replica(Tab, Downs) -> Cs = val({Tab, cstruct}), Storage = mnesia_lib:cs_to_storage_type(node(), Cs), @@ -1628,7 +1625,7 @@ remove_early_messages([], _Node) -> []; remove_early_messages([{call, {add_active_replica, [_, Node, _, _], _}, _}|R], Node) -> remove_early_messages(R, Node); %% Does a reply before queuing -remove_early_messages([{call, {block_table, _, From}, ReplyTo}|R], Node) +remove_early_messages([{call, {block_table, _, From}, ReplyTo}|R], Node) when node(From) == Node -> reply(ReplyTo, ok), %% Remove gen:server waits.. remove_early_messages(R, Node); @@ -1682,9 +1679,9 @@ is_tab_blocked(W2C) when is_list(W2C) -> is_tab_blocked({blocked, W2C}) when is_list(W2C) -> {true, W2C}. -mark_blocked_tab(true, Value) -> +mark_blocked_tab(true, Value) -> {blocked, Value}; -mark_blocked_tab(false, Value) -> +mark_blocked_tab(false, Value) -> Value. %% @@ -1717,7 +1714,7 @@ del_active_replica(Tab, Node) -> update_where_to_wlock(Tab). change_table_access_mode(Cs) -> - W = fun() -> + W = fun() -> Tab = Cs#cstruct.name, lists:foreach(fun(N) -> add_active_replica(Tab, N, Cs) end, val({Tab, active_replicas})) @@ -1746,7 +1743,7 @@ update_where_to_wlock(Tab) -> unannounce_add_table_copy(Tab, To) -> catch del_active_replica(Tab, To), case catch val({Tab , where_to_read}) of - To -> + To -> mnesia_lib:set_remote_where_to_read(Tab); _ -> ignore @@ -1759,7 +1756,7 @@ user_sync_tab(Tab) -> _ -> ignore end, - + case erase({sync_tab, Tab}) of undefined -> ok; @@ -1778,11 +1775,11 @@ i_have_tab(Tab) -> sync_and_block_table_whereabouts(Tab, ToNode, RemoteS, AccessMode) when Tab /= schema -> Current = val({current, db_nodes}), - Ns = + Ns = case lists:member(ToNode, Current) of true -> Current -- [ToNode]; false -> Current - end, + end, remote_call(ToNode, block_table, [Tab]), [remote_call(Node, add_active_replica, [Tab, ToNode, RemoteS, AccessMode]) || Node <- [ToNode | Ns]], @@ -1827,7 +1824,7 @@ get_workers(Timeout) -> {timeout, Timeout} end end. - + info() -> Tabs = mnesia_lib:local_active_tables(), io:format( "---> Active tables <--- ~n", []), @@ -1836,12 +1833,12 @@ info() -> info([Tab | Tail]) -> case val({Tab, storage_type}) of disc_only_copies -> - info_format(Tab, - dets:info(Tab, size), + info_format(Tab, + dets:info(Tab, size), dets:info(Tab, file_size), "bytes on disc"); _ -> - info_format(Tab, + info_format(Tab, ?ets_info(Tab, size), ?ets_info(Tab, memory), "words of mem") @@ -1881,7 +1878,7 @@ handle_early_msg({cast, Msg}, State) -> handle_cast(Msg, State); handle_early_msg({info, Msg}, State) -> handle_info(Msg, State). - + noreply(State) -> {noreply, State}. @@ -1929,7 +1926,7 @@ add_worker(Worker = #send_table{}, State) -> add_worker(Worker = #disc_load{}, State) -> opt_start_worker(add_loader(Worker#disc_load.table,Worker,State)); % Block controller should be used for upgrading mnesia. -add_worker(Worker = #block_controller{}, State) -> +add_worker(Worker = #block_controller{}, State) -> Queue = State#state.dumper_queue, Queue2 = [Worker | Queue], State2 = State#state{dumper_queue = Queue2}, @@ -1938,13 +1935,13 @@ add_worker(Worker = #block_controller{}, State) -> add_loader(Tab,Worker,State = #state{loader_queue=LQ0}) -> case gb_trees:is_defined(Tab, LQ0) of true -> State; - false -> + false -> LQ=gb_trees:insert(Tab, Worker, LQ0), State#state{loader_queue=LQ} end. %% Optionally start a worker -%% +%% %% Dumpers and loaders may run simultaneously %% but neither of them may run during schema commit. %% Loaders may not start if a schema commit is enqueued. @@ -1958,7 +1955,7 @@ opt_start_worker(State) -> %% Great, a worker in queue and neither %% a schema transaction is being %% committed and nor a dumper is running - + %% Start worker but keep him in the queue if is_record(Worker, schema_commit_lock) -> @@ -1966,7 +1963,7 @@ opt_start_worker(State) -> reply(ReplyTo, granted), {Owner, _Tag} = ReplyTo, opt_start_loader(State#state{dumper_pid = Owner}); - + is_record(Worker, dump_log) -> Pid = spawn_link(?MODULE, dump_and_reply, [self(), Worker]), State2 = State#state{dumper_pid = Pid}, @@ -1976,7 +1973,7 @@ opt_start_worker(State) -> %% or sender State3 = opt_start_sender(State2), opt_start_loader(State3); - + is_record(Worker, block_controller) -> case {get_senders(State), get_loaders(State)} of {[], []} -> @@ -1989,7 +1986,7 @@ opt_start_worker(State) -> end end; _ -> - %% Bad luck, try with a loader or sender instead + %% Bad luck, try with a loader or sender instead State2 = opt_start_sender(State), opt_start_loader(State2) end. @@ -1997,8 +1994,8 @@ opt_start_worker(State) -> opt_start_sender(State) -> case State#state.sender_queue of []-> State; %% No need - SenderQ -> - {NewS,Kept} = opt_start_sender2(SenderQ, get_senders(State), + SenderQ -> + {NewS,Kept} = opt_start_sender2(SenderQ, get_senders(State), [], get_loaders(State)), State#state{sender_pid = NewS, sender_queue = Kept} end. @@ -2007,11 +2004,11 @@ opt_start_sender2([], Pids,Kept, _) -> {Pids,Kept}; opt_start_sender2([Sender|R], Pids, Kept, LoaderQ) -> Tab = Sender#send_table.table, Active = val({Tab, active_replicas}), - IgotIt = lists:member(node(), Active), - IsLoading = lists:any(fun({_Pid,Loader}) -> + IgotIt = lists:member(node(), Active), + IsLoading = lists:any(fun({_Pid,Loader}) -> Tab == element(#net_load.table, Loader) end, LoaderQ), - if + if IgotIt, IsLoading -> %% I'm currently finishing loading the table let him wait opt_start_sender2(R,Pids, [Sender|Kept], LoaderQ); @@ -2029,11 +2026,11 @@ opt_start_loader(State = #state{loader_queue = LoaderQ}) -> Current = get_loaders(State), Max = max_loaders(), case gb_trees:is_empty(LoaderQ) of - true -> + true -> State; - _ when length(Current) >= Max -> + _ when length(Current) >= Max -> State; - false -> + false -> SchemaQueue = State#state.dumper_queue, case lists:keymember(schema_commit_lock, 1, SchemaQueue) of false -> @@ -2064,7 +2061,7 @@ already_loading(#disc_load{table=Tab},Loaders) -> already_loading2(Tab, [{_,#net_load{table=Tab}}|_]) -> true; already_loading2(Tab, [{_,#disc_load{table=Tab}}|_]) -> true; -already_loading2(Tab, [_|Rest]) -> already_loading2(Tab,Rest); +already_loading2(Tab, [_|Rest]) -> already_loading2(Tab,Rest); already_loading2(_,[]) -> false. start_remote_sender(Node, Tab, Receiver, Storage) -> @@ -2093,8 +2090,8 @@ send_and_reply(ReplyTo, Worker) -> load_and_reply(ReplyTo, Worker) -> Load = load_table_fun(Worker), - SendAndReply = - fun() -> + SendAndReply = + fun() -> process_flag(trap_exit, true), Done = Load(), ReplyTo ! Done#loader_done{worker_pid = self()}, @@ -2161,7 +2158,7 @@ load_table_fun(#disc_load{table=Tab, reason=Reason, opt_reply_to=ReplyTo}) -> ReadNode == nowhere -> %% Already loaded on other node, lets get it Cs = val({Tab, cstruct}), - fun() -> + fun() -> case mnesia_loader:net_load_table(Tab, Reason, Active, Cs) of {loaded, ok} -> Done#loader_done{needs_sync = true}; @@ -2204,10 +2201,10 @@ filter_active(Tab) -> Active = val({Tab, active_replicas}), Masters = mnesia_recover:get_master_nodes(Tab), Ns = do_filter_active(ByForce, Active, Masters), - %% Reorder the so that we load from fastest first + %% Reorder the so that we load from fastest first LS = ?catch_val({Tab, storage_type}), DOC = val({Tab, disc_only_copies}), - {Good,Worse} = + {Good,Worse} = case LS of disc_only_copies -> G = mnesia_lib:intersect(Ns, DOC), @@ -2218,7 +2215,7 @@ filter_active(Tab) -> end, %% Pick a random node of the fastest Len = length(Good), - if + if Len > 0 -> R = erlang:phash(node(), Len+1), random(R-1,Good,Worse); @@ -2237,5 +2234,5 @@ do_filter_active(false, Active, []) -> Active; do_filter_active(false, Active, Masters) -> mnesia_lib:intersect(Active, Masters). - + diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl index f8d7664156..e2a0aa3bda 100644 --- a/lib/mnesia/src/mnesia_dumper.erl +++ b/lib/mnesia/src/mnesia_dumper.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -43,7 +43,7 @@ %% Internal stuff -export([regulator_init/1]). - + -include("mnesia.hrl"). -include_lib("kernel/include/file.hrl"). @@ -70,14 +70,14 @@ incr_log_writes() -> adjust_log_writes(DoCast) -> Token = {mnesia_adjust_log_writes, self()}, - case global:set_lock(Token, [node()], 1) of + case global:set_lock(Token, [node()], 1) of false -> ignore; %% Somebody else is sending a dump request - true -> - case DoCast of + true -> + case DoCast of false -> ignore; - true -> + true -> mnesia_controller:async_dump_log(write_threshold) end, Max = mnesia_monitor:get_env(dump_log_write_threshold), @@ -93,16 +93,16 @@ adjust_log_writes(DoCast) -> opt_dump_log(InitBy) -> Reg = case whereis(?REGULATOR_NAME) of undefined -> - nopid; + nopid; Pid when is_pid(Pid) -> - Pid + Pid end, perform_dump(InitBy, Reg). %% Scan for decisions perform_dump(InitBy, Regulator) when InitBy == scan_decisions -> ?eval_debug_fun({?MODULE, perform_dump}, [InitBy]), - + dbg_out("Transaction log dump initiated by ~w~n", [InitBy]), scan_decisions(mnesia_log:previous_log_file(), InitBy, Regulator), scan_decisions(mnesia_log:latest_log_file(), InitBy, Regulator); @@ -112,8 +112,8 @@ perform_dump(InitBy, Regulator) -> ?eval_debug_fun({?MODULE, perform_dump}, [InitBy]), LogState = mnesia_log:prepare_log_dump(InitBy), dbg_out("Transaction log dump initiated by ~w: ~w~n", - [InitBy, LogState]), - adjust_log_writes(false), + [InitBy, LogState]), + adjust_log_writes(false), case LogState of already_dumped -> mnesia_recover:allow_garb(), @@ -142,7 +142,7 @@ perform_dump(InitBy, Regulator) -> mnesia_lib:important(Desc, Reason), %% Ignore rest of the log mnesia_log:confirm_log_dump(Diff); - false -> + false -> fatal(Desc, Reason) end end; @@ -189,9 +189,9 @@ do_perform_dump(Cont, InPlace, InitBy, Regulator, OldVersion) -> insert_recs([Rec | Recs], InPlace, InitBy, Regulator, LogV) -> regulate(Regulator), case insert_rec(Rec, InPlace, InitBy, LogV) of - LogH when is_record(LogH, log_header) -> + LogH when is_record(LogH, log_header) -> insert_recs(Recs, InPlace, InitBy, Regulator, LogH#log_header.log_version); - _ -> + _ -> insert_recs(Recs, InPlace, InitBy, Regulator, LogV) end; @@ -199,7 +199,7 @@ insert_recs([], _InPlace, _InitBy, _Regulator, Version) -> Version. insert_rec(Rec, _InPlace, scan_decisions, _LogV) -> - if + if is_record(Rec, commit) -> ignore; is_record(Rec, log_header) -> @@ -227,7 +227,7 @@ insert_rec(H, _InPlace, _InitBy, _LogV) when is_record(H, log_header) -> H#log_header.log_kind /= trans_log -> exit({"Bad kind of transaction log", H}); H#log_header.log_version == CurrentVersion -> - ok; + ok; H#log_header.log_version == "4.2" -> ok; H#log_header.log_version == "4.1" -> @@ -247,8 +247,8 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) -> [] -> ignore; SchemaOps -> - case val({schema, storage_type}) of - ram_copies -> + case val({schema, storage_type}) of + ram_copies -> insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy, LogV); Storage -> true = open_files(schema, Storage, InPlace, InitBy), @@ -264,13 +264,13 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) -> _ -> ignore end. - + update(_Tid, [], _DumperMode) -> dumped; update(Tid, SchemaOps, DumperMode) -> UseDir = mnesia_monitor:use_dir(), - Res = perform_update(Tid, SchemaOps, DumperMode, UseDir), + Res = perform_update(Tid, SchemaOps, DumperMode, UseDir), mnesia_controller:release_schema_commit_lock(), Res. @@ -279,23 +279,23 @@ perform_update(_Tid, _SchemaOps, mandatory, true) -> %% dumper perform needed updates InitBy = schema_update, - ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]), + ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]), opt_dump_log(InitBy); perform_update(Tid, SchemaOps, _DumperMode, _UseDir) -> %% No need for a full transaction log dump. %% Ignore the log file and perform only perform %% the corresponding updates. - InitBy = fast_schema_update, + InitBy = fast_schema_update, InPlace = mnesia_monitor:get_env(dump_log_update_in_place), ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]), - case catch insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy, + case catch insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy, mnesia_log:version()) of {'EXIT', Reason} -> Error = {error, {"Schema update error", Reason}}, close_files(InPlace, Error, InitBy), fatal("Schema update error ~p ~p", [Reason, SchemaOps]); - _ -> + _ -> ?eval_debug_fun({?MODULE, post_dump}, [InitBy]), close_files(InPlace, ok, InitBy), ok @@ -318,7 +318,7 @@ insert_ops(Tid, Storage, [Op | Ops], InPlace, InitBy, Ver) when Ver < "4.3" -> disc_insert(_Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) -> case open_files(Tab, Storage, InPlace, InitBy) of true -> - case Storage of + case Storage of disc_copies when Tab /= schema -> mnesia_log:append({?MODULE,Tab}, {{Tab, Key}, Val, Op}), ok; @@ -331,7 +331,7 @@ disc_insert(_Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) -> %% To fix update_counter so that it behaves better. %% i.e. if nothing have changed in tab except update_counter -%% trust that the value in the dets file is correct. +%% trust that the value in the dets file is correct. %% Otherwise we will get a double increment. %% This is perfect but update_counter is a dirty op. @@ -353,12 +353,12 @@ dets_insert(Op,Tab,Key,Val) -> _ when Incr < 0 -> Zero = {RecName, Key, 0}, ok = dets:insert(Tab, Zero); - _ -> + _ -> Init = {RecName, Key, Incr}, ok = dets:insert(Tab, Init) end; false -> ok - end; + end; delete_object -> dets_updated(Tab,Key), ok = dets:delete_object(Tab, Val); @@ -366,17 +366,17 @@ dets_insert(Op,Tab,Key,Val) -> dets_cleared(Tab), ok = dets:delete_all_objects(Tab) end. - -dets_updated(Tab,Key) -> + +dets_updated(Tab,Key) -> case get(mnesia_dumper_dets) of - undefined -> + undefined -> Empty = gb_trees:empty(), Tree = gb_trees:insert(Tab, gb_sets:singleton(Key), Empty), put(mnesia_dumper_dets, Tree); Tree -> case gb_trees:lookup(Tab,Tree) of {value, cleared} -> ignore; - {value, Set} -> + {value, Set} -> T = gb_trees:update(Tab, gb_sets:add(Key, Set), Tree), put(mnesia_dumper_dets, T); none -> @@ -398,14 +398,14 @@ dets_incr_counter(Tab,Key) -> dets_cleared(Tab) -> case get(mnesia_dumper_dets) of - undefined -> + undefined -> Empty = gb_trees:empty(), Tree = gb_trees:insert(Tab, cleared, Empty), put(mnesia_dumper_dets, Tree); Tree -> case gb_trees:lookup(Tab,Tree) of {value, cleared} -> ignore; - _ -> + _ -> T = gb_trees:enter(Tab, cleared, Tree), put(mnesia_dumper_dets, T) end @@ -417,7 +417,7 @@ insert(Tid, Storage, Tab, Key, [Val | Tail], Op, InPlace, InitBy) -> insert(_Tid, _Storage, _Tab, _Key, [], _Op, _InPlace, _InitBy) -> ok; - + insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) -> Item = {{Tab, Key}, Val, Op}, case InitBy of @@ -447,18 +447,18 @@ insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) -> disc_delete_table(Tab, Storage) -> case mnesia_monitor:use_dir() of true -> - if - Storage == disc_only_copies; Tab == schema -> + if + Storage == disc_only_copies; Tab == schema -> mnesia_monitor:unsafe_close_dets(Tab), Dat = mnesia_lib:tab2dat(Tab), - file:delete(Dat); - true -> + file:delete(Dat); + true -> DclFile = mnesia_lib:tab2dcl(Tab), case get({?MODULE,Tab}) of {opened_dumper, dcl} -> del_opened_tab(Tab), mnesia_log:unsafe_close_log(Tab); - _ -> + _ -> ok end, file:delete(DclFile), @@ -490,7 +490,7 @@ insert_op(Tid, Storage, {{Tab, Key}, Val, Op}, InPlace, InitBy) -> insert_op(_Tid, schema_ops, _OP, _InPlace, Initby) when Initby /= startup, Initby /= fast_schema_update, - Initby /= schema_update -> + Initby /= schema_update -> ignore; insert_op(Tid, _, {op, rec, Storage, Item}, InPlace, InitBy) -> @@ -507,7 +507,7 @@ insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, _ -> ignore end, - if + if N == node() -> Dmp = mnesia_lib:tab2dmp(Tab), Dat = mnesia_lib:tab2dat(Tab), @@ -531,8 +531,8 @@ insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, true = open_files(Tab, disc_only_copies, InPlace, InitBy), %% ram_delete_table must be done before init_indecies, %% it uses info which is reset in init_indecies, - %% it doesn't matter, because init_indecies don't use - %% the ram replica of the table when creating the disc + %% it doesn't matter, because init_indecies don't use + %% the ram replica of the table when creating the disc %% index; Could be improved :) mnesia_schema:ram_delete_table(Tab, FromS), PosList = Cs#cstruct.index, @@ -540,17 +540,17 @@ insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, {disc_only_copies, ram_copies} -> mnesia_monitor:unsafe_close_dets(Tab), disc_delete_indecies(Tab, Cs, disc_only_copies), - case InitBy of - startup -> + case InitBy of + startup -> ignore; - _ -> + _ -> mnesia_controller:get_disc_copy(Tab) end, disc_delete_table(Tab, disc_only_copies); {disc_copies, disc_only_copies} -> ok = ensure_rename(Dmp, Dat), true = open_files(Tab, disc_only_copies, InPlace, InitBy), - mnesia_schema:ram_delete_table(Tab, FromS), + mnesia_schema:ram_delete_table(Tab, FromS), PosList = Cs#cstruct.index, mnesia_index:init_indecies(Tab, disc_only_copies, PosList), file:delete(Dcl), @@ -558,8 +558,8 @@ insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, {disc_only_copies, disc_copies} -> mnesia_monitor:unsafe_close_dets(Tab), disc_delete_indecies(Tab, Cs, disc_only_copies), - case InitBy of - startup -> + case InitBy of + startup -> ignore; _ -> mnesia_log:ets2dcd(Tab), @@ -576,7 +576,7 @@ insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, insert_op(Tid, _, {op, transform, _Fun, TabDef}, InPlace, InitBy) -> Cs = mnesia_schema:list2cs(TabDef), case mnesia_lib:cs_to_storage_type(node(), Cs) of - disc_copies -> + disc_copies -> open_dcl(Cs#cstruct.name); _ -> ignore @@ -604,28 +604,34 @@ insert_op(Tid, _, {op, restore_recreate, TabDef}, InPlace, InitBy) -> mnesia_checkpoint:tm_del_copy(Tab, node()) end end, + StorageProps = Cs#cstruct.storage_properties, + %% And create new ones.. if (InitBy == startup) or (Storage == unknown) -> ignore; Storage == ram_copies -> - Args = [{keypos, 2}, public, named_table, Type], + EtsProps = proplists:get_value(ets, StorageProps, []), + Args = [{keypos, 2}, public, named_table, Type | EtsProps], mnesia_monitor:mktab(Tab, Args); Storage == disc_copies -> - Args = [{keypos, 2}, public, named_table, Type], + EtsProps = proplists:get_value(ets, StorageProps, []), + Args = [{keypos, 2}, public, named_table, Type | EtsProps], mnesia_monitor:mktab(Tab, Args), - File = mnesia_lib:tab2dcd(Tab), - FArg = [{file, File}, {name, {mnesia,create}}, + File = mnesia_lib:tab2dcd(Tab), + FArg = [{file, File}, {name, {mnesia,create}}, {repair, false}, {mode, read_write}], {ok, Log} = mnesia_monitor:open_log(FArg), mnesia_monitor:unsafe_close_log(Log); Storage == disc_only_copies -> File = mnesia_lib:tab2dat(Tab), file:delete(File), + DetsProps = proplists:get_value(dets, StorageProps, []), Args = [{file, mnesia_lib:tab2dat(Tab)}, {type, mnesia_lib:disk_type(Tab, Type)}, {keypos, 2}, - {repair, mnesia_monitor:get_env(auto_repair)}], + {repair, mnesia_monitor:get_env(auto_repair)} + | DetsProps ], mnesia_monitor:open_dets(Tab, Args) end, insert_op(Tid, ignore, {op, create_table, TabDef}, InPlace, InitBy); @@ -635,6 +641,7 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) -> insert_cstruct(Tid, Cs, false, InPlace, InitBy), Tab = Cs#cstruct.name, Storage = mnesia_lib:cs_to_storage_type(node(), Cs), + StorageProps = Cs#cstruct.storage_properties, case InitBy of startup -> case Storage of @@ -644,22 +651,25 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) -> ignore; disc_copies -> Dcd = mnesia_lib:tab2dcd(Tab), - case mnesia_lib:exists(Dcd) of + case mnesia_lib:exists(Dcd) of true -> ignore; false -> - mnesia_log:open_log(temp, + mnesia_log:open_log(temp, mnesia_log:dcd_log_header(), - Dcd, - false, + Dcd, + false, false, read_write), mnesia_log:unsafe_close_log(temp) end; _ -> + DetsProps = proplists:get_value(dets, StorageProps, []), + Args = [{file, mnesia_lib:tab2dat(Tab)}, {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)}, {keypos, 2}, - {repair, mnesia_monitor:get_env(auto_repair)}], + {repair, mnesia_monitor:get_env(auto_repair)} + | DetsProps ], case mnesia_monitor:open_dets(Tab, Args) of {ok, _} -> mnesia_monitor:unsafe_close_dets(Tab); @@ -671,7 +681,7 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) -> Copies = mnesia_lib:copy_holders(Cs), Active = mnesia_lib:intersect(Copies, val({current, db_nodes})), [mnesia_controller:add_active_replica(Tab, N, Cs) || N <- Active], - + case Storage of unknown -> mnesia_lib:unset({Tab, create_table}), @@ -695,8 +705,8 @@ insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) -> %% Indecies are still created by loader disc_delete_indecies(Tab, Cs, Storage) %% disc_delete_table(Tab, Storage) - end, - + end, + %% Update whereabouts and create table mnesia_controller:create_table(Tab), mnesia_lib:unset({Tab, create_table}) @@ -754,7 +764,7 @@ insert_op(Tid, _, {op, clear_table, TabDef}, InPlace, InitBy) -> true -> ignore end, - %% Need to catch this, it crashes on ram_copies if + %% Need to catch this, it crashes on ram_copies if %% the op comes before table is loaded at startup. catch insert(Tid, Storage, Tab, '_', Oid, clear_table, InPlace, InitBy) end; @@ -766,16 +776,16 @@ insert_op(Tid, _, {op, merge_schema, TabDef}, InPlace, InitBy) -> %% If we bootstrap an empty (diskless) mnesia from another node %% we might have changed the storage_type of schema. %% I think this is a good place to do it. - Update = fun(NS = {Node,Storage}) -> + Update = fun(NS = {Node,Storage}) -> case mnesia_lib:cs_to_storage_type(Node, Cs) of Storage -> NS; - disc_copies when Node == node() -> - Dir = mnesia_lib:dir(), + disc_copies when Node == node() -> + Dir = mnesia_lib:dir(), ok = mnesia_schema:opt_create_dir(true, Dir), mnesia_schema:purge_dir(Dir, []), mnesia_log:purge_all_logs(), - mnesia_lib:set(use_dir, true), + mnesia_lib:set(use_dir, true), mnesia_log:init(), Ns = val({current, db_nodes}), F = fun(U) -> mnesia_recover:log_mnesia_up(U) end, @@ -783,11 +793,11 @@ insert_op(Tid, _, {op, merge_schema, TabDef}, InPlace, InitBy) -> raw_named_dump_table(schema, dat), temp_set_master_nodes(), {Node,disc_copies}; - CSstorage -> + CSstorage -> {Node,CSstorage} end end, - + W2C0 = val({schema, where_to_commit}), W2C = case W2C0 of {blocked, List} -> @@ -854,9 +864,9 @@ insert_op(Tid, _, {op, del_snmp, TabDef}, InPlace, InitBy) -> InitBy /= startup, Storage /= unknown -> case ?catch_val({Tab, {index, snmp}}) of - {'EXIT', _} -> + {'EXIT', _} -> ignore; - Stab -> + Stab -> mnesia_snmp_hook:delete_table(Tab, Stab), mnesia_lib:unset({Tab, {index, snmp}}) end; @@ -874,7 +884,7 @@ insert_op(Tid, _, {op, add_index, Pos, TabDef}, InPlace, InitBy) -> true = open_files(Tab, Storage, InPlace, InitBy), mnesia_index:init_indecies(Tab, Storage, [Pos]); startup -> - ignore; + ignore; _ -> case val({Tab,where_to_read}) of nowhere -> ignore; @@ -890,7 +900,7 @@ insert_op(Tid, _, {op, del_index, Pos, TabDef}, InPlace, InitBy) -> case InitBy of startup when Storage == disc_only_copies -> mnesia_index:del_index_table(Tab, Storage, Pos); - startup -> + startup -> ignore; _ -> mnesia_index:del_index_table(Tab, Storage, Pos) @@ -939,16 +949,19 @@ open_files(Tab, Storage, UpdateInPlace, InitBy) {'EXIT', _} -> false; Type -> - case Storage of + case Storage of disc_copies when Tab /= schema -> Bool = open_disc_copies(Tab, InitBy), Bool; _ -> + Props = val({Tab, storage_properties}), + DetsProps = proplists:get_value(dets, Props, []), Fname = prepare_open(Tab, UpdateInPlace), Args = [{file, Fname}, {keypos, 2}, {repair, mnesia_monitor:get_env(auto_repair)}, - {type, mnesia_lib:disk_type(Tab, Type)}], + {type, mnesia_lib:disk_type(Tab, Type)} + | DetsProps], {ok, _} = mnesia_monitor:open_dets(Tab, Args), put({?MODULE, Tab}, {opened_dumper, dat}), true @@ -964,7 +977,7 @@ open_files(_Tab, _Storage, _UpdateInPlace, _InitBy) -> open_disc_copies(Tab, InitBy) -> DclF = mnesia_lib:tab2dcl(Tab), - DumpEts = + DumpEts = case file:read_file_info(DclF) of {error, enoent} -> false; @@ -975,7 +988,7 @@ open_disc_copies(Tab, InitBy) -> mnesia_lib:dbg_out("File ~p info_error ~p ~n", [DcdF, Reason]), true; - {ok, DcdInfo} -> + {ok, DcdInfo} -> Mul = case ?catch_val(dc_dump_limit) of {'EXIT', _} -> ?DumpToEtsMultiplier; Val -> Val @@ -983,12 +996,12 @@ open_disc_copies(Tab, InitBy) -> DcdInfo#file_info.size =< (DclInfo#file_info.size * Mul) end end, - if - DumpEts == false; InitBy == startup -> - mnesia_log:open_log({?MODULE,Tab}, - mnesia_log:dcl_log_header(), - DclF, - mnesia_lib:exists(DclF), + if + DumpEts == false; InitBy == startup -> + mnesia_log:open_log({?MODULE,Tab}, + mnesia_log:dcl_log_header(), + DclF, + mnesia_lib:exists(DclF), mnesia_monitor:get_env(auto_repair), read_write), put({?MODULE, Tab}, {opened_dumper, dcl}), @@ -997,9 +1010,9 @@ open_disc_copies(Tab, InitBy) -> mnesia_log:ets2dcd(Tab), put({?MODULE, Tab}, already_dumped), false - end. + end. -%% Always opens the dcl file for writing overriding already_dumped +%% Always opens the dcl file for writing overriding already_dumped %% mechanismen, used for schema transactions. open_dcl(Tab) -> case get({?MODULE, Tab}) of @@ -1007,10 +1020,10 @@ open_dcl(Tab) -> true; _ -> %% undefined or already_dumped DclF = mnesia_lib:tab2dcl(Tab), - mnesia_log:open_log({?MODULE,Tab}, - mnesia_log:dcl_log_header(), - DclF, - mnesia_lib:exists(DclF), + mnesia_log:open_log({?MODULE,Tab}, + mnesia_log:dcl_log_header(), + DclF, + mnesia_lib:exists(DclF), mnesia_monitor:get_env(auto_repair), read_write), put({?MODULE, Tab}, {opened_dumper, dcl}), @@ -1047,7 +1060,7 @@ close_files(InPlace, Outcome, InitBy, [{{?MODULE, Tab}, {opened_dumper, Type}} | case val({Tab, storage_type}) of disc_only_copies when InitBy /= startup -> ignore; - disc_copies when Tab /= schema -> + disc_copies when Tab /= schema -> mnesia_log:close_log({?MODULE,Tab}); Storage -> do_close(InPlace, Outcome, Tab, Type, Storage) @@ -1082,7 +1095,7 @@ do_close(InPlace, Outcome, Tab, dat, Storage) -> true -> file:delete(mnesia_lib:tab2tmp(Tab)) end. - + ensure_rename(From, To) -> case mnesia_lib:exists(From) of @@ -1096,7 +1109,7 @@ ensure_rename(From, To) -> {error, {rename_failed, From, To}} end end. - + insert_cstruct(Tid, Cs, KeepWhereabouts, InPlace, InitBy) -> Val = mnesia_schema:insert_cstruct(Tid, Cs, KeepWhereabouts), {schema, Tab, _} = Val, @@ -1114,15 +1127,15 @@ delete_cstruct(Tid, Cs, InPlace, InitBy) -> temp_set_master_nodes() -> Tabs = val({schema, local_tables}), - Masters = [{Tab, (val({Tab, disc_copies}) ++ - val({Tab, ram_copies}) ++ - val({Tab, disc_only_copies})) -- [node()]} + Masters = [{Tab, (val({Tab, disc_copies}) ++ + val({Tab, ram_copies}) ++ + val({Tab, disc_only_copies})) -- [node()]} || Tab <- Tabs], %% UseDir = false since we don't want to remember these %% masternodes and we are running (really soon anyway) since we want this %% to be known during table loading. mnesia_recover:log_master_nodes(Masters, false, yes), - ok. + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Raw dump of table. Dumper must have unique access to the ets table. @@ -1152,7 +1165,7 @@ raw_named_dump_table(Tab, Ftype) -> {ok, TabRef} -> Storage = ram_copies, mnesia_lib:db_fixtable(Storage, Tab, true), - + case catch raw_dump_table(TabRef, Tab) of {'EXIT', Reason} -> mnesia_lib:db_fixtable(Storage, Tab, false), @@ -1179,11 +1192,11 @@ raw_dump_table(DetsRef, EtsRef) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Load regulator -%% -%% This is a poor mans substitute for a fair scheduler algorithm -%% in the Erlang emulator. The mnesia_dumper process performs many -%% costly BIF invokations and must pay for this. But since the -%% Emulator does not handle this properly we must compensate for +%% +%% This is a poor mans substitute for a fair scheduler algorithm +%% in the Erlang emulator. The mnesia_dumper process performs many +%% costly BIF invokations and must pay for this. But since the +%% Emulator does not handle this properly we must compensate for %% this with some form of load regulation of ourselves in order to %% not steal all computation power in the Erlang Emulator ans make %% other processes starve. Hopefully this is a temporary solution. @@ -1230,6 +1243,6 @@ regulate(RegulatorPid) -> val(Var) -> case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); - Value -> Value + {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); + Value -> Value end. diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl index 5a060a28ff..8085155fd5 100644 --- a/lib/mnesia/src/mnesia_event.erl +++ b/lib/mnesia/src/mnesia_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/src/mnesia_frag_hash.erl b/lib/mnesia/src/mnesia_frag_hash.erl index 610ba2535c..3dfdb87f30 100644 --- a/lib/mnesia/src/mnesia_frag_hash.erl +++ b/lib/mnesia/src/mnesia_frag_hash.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -101,21 +101,19 @@ del_frag(OldState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) -> - P = SplitN, - A = erlang:phash(Key, power2(L)), +key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash(Key, power2(L + 1)), if - A < P -> - erlang:phash(Key, power2(L + 1)); + A > N -> + A - power2(L); true -> A end; -key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) -> - P = SplitN, - A = erlang:phash2(Key, power2(L)) + 1, +key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash2(Key, power2(L + 1)) + 1, if - A < P -> - erlang:phash2(Key, power2(L + 1)) + 1; + A > N -> + A - power2(L); true -> A end; diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index c4b22814a8..e443b54016 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -61,9 +61,11 @@ do_get_disc_copy2(Tab, _Reason, Storage, _Type) when Storage == unknown -> do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> %% NOW we create the actual table Repair = mnesia_monitor:get_env(auto_repair), - Args = [{keypos, 2}, public, named_table, Type], + StorageProps = val({Tab, storage_properties}), + EtsOpts = proplists:get_value(ets, StorageProps, []), + Args = [{keypos, 2}, public, named_table, Type | EtsOpts], case Reason of - {dumper, _} -> %% Resources allready allocated + {dumper, _} -> %% Resources already allocated ignore; _ -> mnesia_monitor:mktab(Tab, Args), @@ -82,7 +84,9 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> {loaded, ok}; do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies -> - Args = [{keypos, 2}, public, named_table, Type], + StorageProps = val({Tab, storage_properties}), + EtsOpts = proplists:get_value(ets, StorageProps, []), + Args = [{keypos, 2}, public, named_table, Type | EtsOpts], case Reason of {dumper, _} -> %% Resources allready allocated ignore; @@ -115,10 +119,14 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies -> {loaded, ok}; do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -> + StorageProps = val({Tab, storage_properties}), + DetsOpts = proplists:get_value(dets, StorageProps, []), + Args = [{file, mnesia_lib:tab2dat(Tab)}, {type, mnesia_lib:disk_type(Tab, Type)}, {keypos, 2}, - {repair, mnesia_monitor:get_env(auto_repair)}], + {repair, mnesia_monitor:get_env(auto_repair)} + | DetsOpts], case Reason of {dumper, _} -> mnesia_index:init_index(Tab, Storage), @@ -349,17 +357,21 @@ do_init_table(Tab,Storage,Cs,SenderPid, end. create_table(Tab, TabSize, Storage, Cs) -> + StorageProps = val({Tab, storage_properties}), if Storage == disc_only_copies -> mnesia_lib:lock_table(Tab), Tmp = mnesia_lib:tab2tmp(Tab), Size = lists:max([TabSize, 256]), + DetsOpts = lists:keydelete(estimated_no_objects, 1, + proplists:get_value(dets, StorageProps, [])), Args = [{file, Tmp}, {keypos, 2}, %% {ram_file, true}, {estimated_no_objects, Size}, {repair, mnesia_monitor:get_env(auto_repair)}, - {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)}], + {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)} + | DetsOpts], file:delete(Tmp), case mnesia_lib:dets_sync_open(Tab, Args) of {ok, _} -> @@ -370,7 +382,8 @@ create_table(Tab, TabSize, Storage, Cs) -> Else end; (Storage == ram_copies) or (Storage == disc_copies) -> - Args = [{keypos, 2}, public, named_table, Cs#cstruct.type], + EtsOpts = proplists:get_value(ets, StorageProps, []), + Args = [{keypos, 2}, public, named_table, Cs#cstruct.type | EtsOpts], case mnesia_monitor:unsafe_mktab(Tab, Args) of Tab -> {Storage, Tab}; @@ -516,10 +529,13 @@ handle_last({disc_only_copies, Tab}, Type, nobin) -> Dat = mnesia_lib:tab2dat(Tab), case file:rename(Tmp, Dat) of ok -> + StorageProps = val({Tab, storage_properties}), + DetsOpts = proplists:get_value(dets, StorageProps, []), + Args = [{file, mnesia_lib:tab2dat(Tab)}, {type, mnesia_lib:disk_type(Tab, Type)}, {keypos, 2}, - {repair, mnesia_monitor:get_env(auto_repair)}], + {repair, mnesia_monitor:get_env(auto_repair)} | DetsOpts], mnesia_monitor:open_dets(Tab, Args), ok; {error, Reason} -> diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 0492d794f3..a22c95d454 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -66,14 +66,14 @@ -record(queue, {oid, tid, op, pid, lucky}). -%% mnesia_held_locks: contain {Oid, Op, Tid} entries (bag) +%% mnesia_held_locks: contain {Oid, MaxLock, [{Op, Tid}]} entries -define(match_oid_held_locks(Oid), {Oid, '_', '_'}). -%% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag) +%% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag) -define(match_oid_tid_locks(Tid), {Tid, '_', '_'}). %% mnesia_sticky_locks: contain {Oid, Node} entries and {Tab, Node} entries (set) -define(match_oid_sticky_locks(Oid),{Oid, '_'}). %% mnesia_lock_queue: contain {queue, Oid, Tid, Op, ReplyTo, WaitForTid} entries (bag) --define(match_oid_lock_queue(Oid), #queue{oid=Oid, tid='_', op = '_', pid = '_', lucky = '_'}). +-define(match_oid_lock_queue(Oid), #queue{oid=Oid, tid='_', op = '_', pid = '_', lucky = '_'}). %% mnesia_lock_counter: {{write, Tab}, Number} && %% {{read, Tab}, Number} entries (set) @@ -83,11 +83,11 @@ start() -> init(Parent) -> register(?MODULE, self()), process_flag(trap_exit, true), - ?ets_new_table(mnesia_held_locks, [bag, private, named_table]), + ?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]), ?ets_new_table(mnesia_tid_locks, [bag, private, named_table]), ?ets_new_table(mnesia_sticky_locks, [set, private, named_table]), ?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]), - + proc_lib:init_ack(Parent, {ok, self()}), case ?catch_val(pid_sort_order) of r9b_plain -> put(pid_sort_order, r9b_plain); @@ -98,8 +98,8 @@ init(Parent) -> val(Var) -> case ?catch_val(Var) of - {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_); - _VaLuE_ -> _VaLuE_ + {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_); + _VaLuE_ -> _VaLuE_ end. reply(From, R) -> @@ -111,10 +111,10 @@ l_request(Node, X, Store) -> l_req_rec(Node, Store) -> ?ets_insert(Store, {nodes, Node}), - receive - {?MODULE, Node, Reply} -> + receive + {?MODULE, Node, Reply} -> Reply; - {mnesia_down, Node} -> + {mnesia_down, Node} -> {not_granted, {node_not_running, Node}} end. @@ -128,10 +128,10 @@ send_release_tid(Nodes, Tid) -> rpc:abcast(Nodes, ?MODULE, {self(), {sync_release_tid, Tid}}). receive_release_tid_acc([Node | Nodes], Tid) -> - receive - {?MODULE, Node, {tid_released, Tid}} -> + receive + {?MODULE, Node, {tid_released, Tid}} -> receive_release_tid_acc(Nodes, Tid); - {mnesia_down, Node} -> + {mnesia_down, Node} -> receive_release_tid_acc(Nodes, Tid) end; receive_release_tid_acc([], _Tid) -> @@ -152,27 +152,27 @@ loop(State) -> %% Really do a read, but get hold of a write lock %% used by mnesia:wread(Oid). - + {From, {read_write, Tid, Oid}} -> try_sticky_lock(Tid, read_write, From, Oid), loop(State); - + %% Tid has somehow terminated, clear up everything %% and pass locks on to queued processes. %% This is the purpose of the mnesia_tid_locks table - + {release_tid, Tid} -> do_release_tid(Tid), loop(State); - + %% stick lock, first tries this to the where_to_read Node {From, {test_set_sticky, Tid, {Tab, _} = Oid, Lock}} -> case ?ets_lookup(mnesia_sticky_locks, Tab) of - [] -> + [] -> reply(From, not_stuck), loop(State); [{_,Node}] when Node == node() -> - %% Lock is stuck here, see now if we can just set + %% Lock is stuck here, see now if we can just set %% a regular write lock try_lock(Tid, Lock, From, Oid), loop(State); @@ -188,7 +188,7 @@ loop(State) -> ?ets_insert(mnesia_sticky_locks, {Tab, N}), loop(State); - %% The caller which sends this message, must have first + %% The caller which sends this message, must have first %% aquired a write lock on the entire table {unstick, Tab} -> ?ets_delete(mnesia_sticky_locks, Tab), @@ -205,14 +205,14 @@ loop(State) -> [{_,N}] -> Req = {From, {ix_read, Tid, Tab, IxKey, Pos}}, From ! {?MODULE, node(), {switch, N, Req}}, - loop(State) + loop(State) end; {From, {sync_release_tid, Tid}} -> do_release_tid(Tid), reply(From, {tid_released, Tid}), loop(State); - + {release_remote_non_pending, Node, Pending} -> release_remote_non_pending(Node, Pending), mnesia_monitor:mnesia_down(?MODULE, Node), @@ -229,16 +229,23 @@ loop(State) -> {get_table, From, LockTable} -> From ! {LockTable, ?ets_match_object(LockTable, '_')}, loop(State); - + Msg -> error("~p got unexpected message: ~p~n", [?MODULE, Msg]), loop(State) end. -set_lock(Tid, Oid, Op) -> - ?dbg("Granted ~p ~p ~p~n", [Tid,Oid,Op]), - ?ets_insert(mnesia_held_locks, {Oid, Op, Tid}), - ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}). +set_lock(Tid, Oid, Op, []) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}), + ?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]}); +set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}), + ?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]}); +set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}), + ?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]}); +set_lock(Tid, Oid, Op, undefined) -> + set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)). %%%%%%%%%%%%%%%%%%%%%%%%%%% %% Acquire locks @@ -261,32 +268,32 @@ try_lock(Tid, Op, Pid, Oid) -> try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) -> case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(Pid, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(Pid, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output - ?ets_insert(mnesia_lock_queue, - #queue{oid = Oid, tid = Tid, op = Op, + ?ets_insert(mnesia_lock_queue, + #queue{oid = Oid, tid = Tid, op = Op, pid = Pid, lucky = Lucky}), ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}}) end. -grant_lock(Tid, read, Lock, Oid = {Tab, Key}) +grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default) when Key /= ?ALL, Tab /= ?GLOBAL -> case node(Tid#tid.pid) == node() of true -> - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, lookup_in_client}; false -> try Val = mnesia_lib:db_get(Tab, Key), %% lookup as well - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Val} catch _:_Reason -> %% Table has been deleted from this node, @@ -296,87 +303,71 @@ grant_lock(Tid, read, Lock, Oid = {Tab, Key}) {not_granted, C} end end; -grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}) -> +grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}, Default) -> try Res = ix_read_res(Tab, IxKey,Pos), - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Res, [?ALL]} catch _:_ -> {not_granted, {no_exists, Tab, {index, [Pos]}}} end; -grant_lock(Tid, read, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, read, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), {granted, ok}; -grant_lock(Tid, write, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, write, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), granted. %% 1) Impose an ordering on all transactions favour old (low tid) transactions %% newer (higher tid) transactions may never wait on older ones, %% 2) When releasing the tids from the queue always begin with youngest (high tid) %% because of 1) it will avoid the deadlocks. -%% 3) TabLocks is the problem :-) They should not starve and not deadlock +%% 3) TabLocks is the problem :-) They should not starve and not deadlock %% handle tablocks in queue as they had locks on unlocked records. -can_lock(Tid, read, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - %% The key is bound, no need for the other BIF - Oid = {Tab, Key}, - ObjLocks = ?ets_match_object(mnesia_held_locks, {Oid, write, '_'}), - TabLocks = ?ets_match_object(mnesia_held_locks, {{Tab, ?ALL}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, read); +can_lock(Tid, read, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> + ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), + TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), + {check_lock(Tid, Oid, + filter_write(ObjLocks), + filter_write(TabLocks), + yes, AlreadyQ, read), + ObjLocks}; can_lock(Tid, read, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, {{Tab, '_'}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read); + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read), undefined}; -can_lock(Tid, write, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - Oid = {Tab, Key}, +can_lock(Tid, write, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write); + {check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write), ObjLocks}; can_lock(Tid, write, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, ?match_oid_held_locks({Tab, '_'})), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write). + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write), undefined}. + +filter_write([{_, read, _}]) -> []; +filter_write(Res) -> Res. %% Check held locks for conflicting locks -check_lock(Tid, Oid, [Lock | Locks], TabLocks, X, AlreadyQ, Type) -> - case element(3, Lock) of - Tid -> - check_lock(Tid, Oid, Locks, TabLocks, X, AlreadyQ, Type); - WaitForTid -> - Queue = allowed_to_be_queued(WaitForTid,Tid), - if Queue == true -> - check_lock(Tid, Oid, Locks, TabLocks, {queue, WaitForTid}, AlreadyQ, Type); - Tid#tid.pid == WaitForTid#tid.pid -> - dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", - [Oid, Lock, Tid, WaitForTid]), - %% Test.. - {Tab, _Key} = Oid, - HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) - orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), - if - HaveQ -> - {no, WaitForTid}; - true -> - check_lock(Tid,Oid,Locks,TabLocks,{queue,WaitForTid},AlreadyQ,Type) - end; - %%{no, WaitForTid}; Safe solution - true -> - {no, WaitForTid} - end +check_lock(Tid, Oid, [{_, _, Lock} | Locks], TabLocks, _X, AlreadyQ, Type) -> + case can_queue(Lock, Tid, Oid, _X) of + {no, _} = Res -> + Res; + Res -> + check_lock(Tid, Oid, Locks, TabLocks, Res, AlreadyQ, Type) end; check_lock(_, _, [], [], X, {queue, bad_luck}, _) -> X; %% The queue should be correct already no need to check it again check_lock(_, _, [], [], X = {queue, _Tid}, _AlreadyQ, _) -> - X; + X; -check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> - {Tab, Key} = Oid, +check_lock(Tid, Oid = {Tab, Key}, [], [], X, AlreadyQ, Type) -> if Type == write -> check_queue(Tid, Tab, X, AlreadyQ); @@ -387,7 +378,7 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> %% If there is a queue on that object, read_lock shouldn't be granted ObjLocks = ets:lookup(mnesia_lock_queue, Oid), case max(ObjLocks) of - empty -> + empty -> check_queue(Tid, Tab, X, AlreadyQ); ObjL -> case allowed_to_be_queued(ObjL,Tid) of @@ -403,16 +394,36 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> check_lock(Tid, Oid, [], TabLocks, X, AlreadyQ, Type) -> check_lock(Tid, Oid, TabLocks, [], X, AlreadyQ, Type). +can_queue([{_Op, Tid}|Locks], Tid, Oid, Res) -> + can_queue(Locks, Tid, Oid, Res); +can_queue([{Op, WaitForTid}|Locks], Tid, Oid = {Tab, _}, _) -> + case allowed_to_be_queued(WaitForTid,Tid) of + true when Tid#tid.pid == WaitForTid#tid.pid -> + dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", + [Oid, Op, Tid, WaitForTid]), + HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) + orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), + case HaveQ of + true -> {no, WaitForTid}; + false -> can_queue(Locks, Tid, Oid, {queue, WaitForTid}) + end; + true -> + can_queue(Locks, Tid, Oid, {queue, WaitForTid}); + false -> + {no, WaitForTid} + end; +can_queue([], _, _, Res) -> Res. + %% True if WaitForTid > Tid -> % Important order allowed_to_be_queued(WaitForTid, Tid) -> case get(pid_sort_order) of undefined -> WaitForTid > Tid; - r9b_plain -> + r9b_plain -> cmp_tid(true, WaitForTid, Tid) =:= 1; - standard -> + standard -> cmp_tid(false, WaitForTid, Tid) =:= 1 - end. - + end. + %% Check queue for conflicting locks %% Assume that all queued locks belongs to other tid's @@ -421,25 +432,25 @@ check_queue(Tid, Tab, X, AlreadyQ) -> Greatest = max(TabLocks), case Greatest of empty -> X; - Tid -> X; - WaitForTid -> + Tid -> X; + WaitForTid -> case allowed_to_be_queued(WaitForTid,Tid) of true -> {queue, WaitForTid}; - false when AlreadyQ =:= {no, bad_luck} -> + false when AlreadyQ =:= {no, bad_luck} -> {no, WaitForTid} end end. sort_queue(QL) -> case get(pid_sort_order) of - undefined -> + undefined -> lists:reverse(lists:keysort(#queue.tid, QL)); - r9b_plain -> - lists:sort(fun(#queue{tid=X},#queue{tid=Y}) -> + r9b_plain -> + lists:sort(fun(#queue{tid=X},#queue{tid=Y}) -> cmp_tid(true, X, Y) == 1 end, QL); - standard -> + standard -> lists:sort(fun(#queue{tid=X},#queue{tid=Y}) -> cmp_tid(false, X, Y) == 1 end, QL) @@ -456,22 +467,22 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) -> Op = {ix_read,IxKey, Pos}, Lock = read, case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, Op, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, Op, Lock, Oid, Default), reply(From, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = Op, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(From, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output - ?ets_insert(mnesia_lock_queue, - #queue{oid = Oid, tid = Tid, op = Op, + ?ets_insert(mnesia_lock_queue, + #queue{oid = Oid, tid = Tid, op = Op, pid = From, lucky = Lucky}), ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}}) end. - + %%%%%%%%%%%%%%%%%%%%%%%%%%% %% Release of locks @@ -520,30 +531,40 @@ release_locks([]) -> release_lock({Tid, Oid, {queued, _}}) -> ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = '_', pid = '_', lucky = '_'}); -release_lock({Tid, Oid, Op}) -> - if - Op == write -> - ?ets_delete(mnesia_held_locks, Oid); - Op == read -> - ets:delete_object(mnesia_held_locks, {Oid, Op, Tid}) +release_lock({_Tid, Oid, write}) -> + ?ets_delete(mnesia_held_locks, Oid); +release_lock({Tid, Oid, read}) -> + case ?ets_lookup(mnesia_held_locks, Oid) of + [{Oid, Prev, Locks0}] -> + case remove_tid(Locks0, Tid, []) of + [] -> ?ets_delete(mnesia_held_locks, Oid); + Locks -> ?ets_insert(mnesia_held_locks, {Oid, Prev, Locks}) + end; + [] -> ok end. +remove_tid([{_Op, Tid}|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, Acc); +remove_tid([Keep|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, [Keep|Acc]); +remove_tid([], _, Acc) -> Acc. + rearrange_queue([{_Tid, {Tab, Key}, _} | Locks]) -> if - Key /= ?ALL-> - Queue = - ets:lookup(mnesia_lock_queue, {Tab, ?ALL}) ++ + Key /= ?ALL-> + Queue = + ets:lookup(mnesia_lock_queue, {Tab, ?ALL}) ++ ets:lookup(mnesia_lock_queue, {Tab, Key}), - case Queue of - [] -> + case Queue of + [] -> ok; _ -> Sorted = sort_queue(Queue), try_waiters_obj(Sorted) - end; - true -> + end; + true -> Pat = ?match_oid_lock_queue({Tab, '_'}), - Queue = ?ets_match_object(mnesia_lock_queue, Pat), + Queue = ?ets_match_object(mnesia_lock_queue, Pat), Sorted = sort_queue(Queue), try_waiters_tab(Sorted) end, @@ -556,7 +577,7 @@ try_waiters_obj([W | Waiters]) -> case try_waiter(W) of queued -> no; - _ -> + _ -> try_waiters_obj(Waiters) end; try_waiters_obj([]) -> @@ -573,10 +594,10 @@ try_waiters_tab([W | Waiters]) -> end; Oid -> case try_waiter(W) of - queued -> + queued -> Rest = key_delete_all(Oid, #queue.oid, Waiters), try_waiters_tab(Rest); - _ -> + _ -> try_waiters_tab(Waiters) end end; @@ -592,22 +613,22 @@ try_waiter({queue, Oid, Tid, Op, ReplyTo, _}) -> try_waiter(Oid, Op, SimpleOp, Lock, ReplyTo, Tid) -> case can_lock(Tid, Lock, Oid, {queue, bad_luck}) of - yes -> + {yes, Default} -> %% Delete from queue: Nice place for trace output - ?ets_match_delete(mnesia_lock_queue, + ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = Op, pid = ReplyTo, lucky = '_'}), - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(ReplyTo,Reply), locked; - {queue, _Why} -> + {{queue, _Why}, _} -> ?dbg("Keep ~p ~p ~p ~p~n", [Tid, Oid, Lock, _Why]), - queued; % Keep waiter in queue - {no, Lucky} -> + queued; % Keep waiter in queue + {{no, Lucky}, _} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, verbose("** WARNING ** Restarted transaction, possible deadlock in lock queue ~w: cyclic = ~w~n", [Tid, C]), - ?ets_match_delete(mnesia_lock_queue, + ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = Op, pid = ReplyTo, lucky = '_'}), Reply = {not_granted, C}, @@ -645,7 +666,7 @@ mnesia_down(N, Pending) -> Pid ! {release_remote_non_pending, N, Pending} end. -%% Aquire a write lock, but do a read, used by +%% Aquire a write lock, but do a read, used by %% mnesia:wread/1 rwlock(Tid, Store, Oid) -> @@ -657,9 +678,10 @@ rwlock(Tid, Store, Oid) -> Lock = write, case need_lock(Store, Tab, Key, Lock) of yes -> - {Ns, Majority} = w_nodes(Tab), + {Ns0, Majority} = w_nodes(Tab), + Ns = [Node|lists:delete(Node,Ns0)], check_majority(Majority, Tab, Ns), - Res = get_rwlocks_on_nodes(Ns, rwlock, Node, Store, Tid, Oid), + Res = get_rwlocks_on_nodes(Ns, make_ref(), Store, Tid, Oid), ?ets_insert(Store, {{locks, Tab, Key}, Lock}), Res; no -> @@ -718,7 +740,7 @@ sticky_rwlock(Tid, Store, Oid) -> sticky_lock(Tid, Store, Oid, read_write). sticky_lock(Tid, Store, {Tab, Key} = Oid, Lock) -> - N = val({Tab, where_to_read}), + N = val({Tab, where_to_read}), if node() == N -> case need_lock(Store, Tab, Key, write) of @@ -805,9 +827,9 @@ sticky_wlock_table(Tid, Store, Tab) -> %% aquire a wlock on Oid %% We store a {Tabname, write, Tid} in all locktables %% on all nodes containing a copy of Tabname -%% We also store an item {{locks, Tab, Key}, write} in the +%% We also store an item {{locks, Tab, Key}, write} in the %% local store when we have aquired the lock. -%% +%% wlock(Tid, Store, Oid) -> wlock(Tid, Store, Oid, _CheckMajority = true). @@ -845,10 +867,10 @@ wlock_no_exist(Tid, Store, Tab, Ns) -> need_lock(Store, Tab, Key, LockPattern) -> TabL = ?ets_match_object(Store, {{locks, Tab, ?ALL}, LockPattern}), - if + if TabL == [] -> KeyL = ?ets_match_object(Store, {{locks, Tab, Key}, LockPattern}), - if + if KeyL == [] -> yes; true -> @@ -865,7 +887,7 @@ del_debug() -> erase(mnesia_wlock_nodes). %% We first send lock request to the local node if it is part of the lockers -%% then the first sorted node then to the rest of the lockmanagers on all +%% then the first sorted node then to the rest of the lockmanagers on all %% nodes holding a copy of the table get_wlocks_on_nodes([Node | Tail], Orig, Store, Request, Oid) -> @@ -875,51 +897,31 @@ get_wlocks_on_nodes([Node | Tail], Orig, Store, Request, Oid) -> case node() of Node -> %% Local done try one more get_wlocks_on_nodes(Tail, Orig, Store, Request, Oid); - _ -> %% The first succeded cont with the rest + _ -> %% The first succeded cont with the rest get_wlocks_on_nodes(Tail, Store, Request), receive_wlocks(Tail, Orig, Store, Oid) end; -get_wlocks_on_nodes([], Orig, _Store, _Request, _Oid) -> +get_wlocks_on_nodes([], Orig, _Store, _Request, _Oid) -> Orig. get_wlocks_on_nodes([Node | Tail], Store, Request) -> {?MODULE, Node} ! Request, ?ets_insert(Store,{nodes, Node}), get_wlocks_on_nodes(Tail, Store, Request); -get_wlocks_on_nodes([], _, _) -> +get_wlocks_on_nodes([], _, _) -> ok. -get_rwlocks_on_nodes([ReadNode|Tail], _Res, ReadNode, Store, Tid, Oid) -> +get_rwlocks_on_nodes([ReadNode|Tail], Ref, Store, Tid, Oid) -> Op = {self(), {read_write, Tid, Oid}}, {?MODULE, ReadNode} ! Op, ?ets_insert(Store, {nodes, ReadNode}), - Res = receive_wlocks([ReadNode], undefined, Store, Oid), - case node() of - ReadNode -> - get_rwlocks_on_nodes(Tail, Res, ReadNode, Store, Tid, Oid); - _ -> - get_wlocks_on_nodes(Tail, Store, {self(), {write, Tid, Oid}}), - receive_wlocks(Tail, Res, Store, Oid) + case receive_wlocks([ReadNode], Ref, Store, Oid) of + Ref -> + get_rwlocks_on_nodes(Tail, Ref, Store, Tid, Oid); + Res -> + get_wlocks_on_nodes(Tail, Res, Store, {self(), {write, Tid, Oid}}, Oid) end; -get_rwlocks_on_nodes([Node | Tail], Res, ReadNode, Store, Tid, Oid) -> - Op = {self(), {write, Tid, Oid}}, - {?MODULE, Node} ! Op, - ?ets_insert(Store, {nodes, Node}), - receive_wlocks([Node], undefined, Store, Oid), - if node() == Node -> - get_rwlocks_on_nodes(Tail, Res, ReadNode, Store, Tid, Oid); - Res == rwlock -> %% Hmm - Rest = lists:delete(ReadNode, Tail), - Op2 = {self(), {read_write, Tid, Oid}}, - {?MODULE, ReadNode} ! Op2, - ?ets_insert(Store, {nodes, ReadNode}), - get_wlocks_on_nodes(Rest, Store, {self(), {write, Tid, Oid}}), - receive_wlocks([ReadNode|Rest], undefined, Store, Oid); - true -> - get_wlocks_on_nodes(Tail, Store, {self(), {write, Tid, Oid}}), - receive_wlocks(Tail, Res, Store, Oid) - end; -get_rwlocks_on_nodes([],Res,_,_,_,_) -> +get_rwlocks_on_nodes([],Res,_,_,_) -> Res. receive_wlocks([], Res, _Store, _Oid) -> @@ -944,8 +946,8 @@ receive_wlocks(Nodes = [This|Ns], Res, Store, Oid) -> Tail = lists:delete(Node,Nodes), Nonstuck = lists:delete(Sticky,Tail), [?ets_insert(Store, {nodes, NSNode}) || NSNode <- Nonstuck], - case lists:member(Sticky,Tail) of - true -> + case lists:member(Sticky,Tail) of + true -> sticky_flush(Nonstuck,Store), receive_wlocks([Sticky], Res, Store, Oid); false -> @@ -957,7 +959,7 @@ receive_wlocks(Nodes = [This|Ns], Res, Store, Oid) -> flush_remaining(Ns, This, Reason1) end. -sticky_flush([], _) -> +sticky_flush([], _) -> del_debug(), ok; sticky_flush(Ns=[Node | Tail], Store) -> @@ -991,7 +993,7 @@ opt_lookup_in_client(lookup_in_client, Oid, Lock) -> %% Table has been deleted from this node, %% restart the transaction. #cyclic{op = read, lock = Lock, oid = Oid, lucky = nowhere}; - Val -> + Val -> Val end; opt_lookup_in_client(Val, _Oid, _Lock) -> @@ -1000,8 +1002,8 @@ opt_lookup_in_client(Val, _Oid, _Lock) -> return_granted_or_nodes({_, ?ALL} , Nodes) -> Nodes; return_granted_or_nodes({?GLOBAL, _}, Nodes) -> Nodes; return_granted_or_nodes(_ , _Nodes) -> granted. - -%% We store a {Tab, read, From} item in the + +%% We store a {Tab, read, From} item in the %% locks table on the node where we actually do pick up the object %% and we also store an item {lock, Oid, read} in our local store %% so that we can release any locks we hold when we commit. @@ -1059,9 +1061,9 @@ rlock_get_reply(Node, Store, Oid, {granted, V}) -> ?ets_insert(Store, {{locks, Tab, Key}, read}), ?ets_insert(Store, {nodes, Node}), case opt_lookup_in_client(V, Oid, read) of - C = #cyclic{} -> + C = #cyclic{} -> mnesia:abort(C); - Val -> + Val -> Val end; rlock_get_reply(Node, Store, Oid, granted) -> @@ -1079,7 +1081,7 @@ rlock_get_reply(Node, Store, Tab, {granted, V, RealKeys}) -> rlock_get_reply(_Node, _Store, _Oid, {not_granted, Reason}) -> exit({aborted, Reason}); -rlock_get_reply(_Node, Store, Oid, {switch, N2, Req}) -> +rlock_get_reply(_Node, Store, Oid, {switch, N2, Req}) -> ?ets_insert(Store, {nodes, N2}), {?MODULE, N2} ! Req, rlock_get_reply(N2, Store, Oid, l_req_rec(N2, Store)). @@ -1095,7 +1097,7 @@ ixrlock(Tid, Store, Tab, IxKey, Pos) -> %%% Old code %% R = l_request(Node, {ix_read, Tid, Tab, IxKey, Pos}, Store), %% rlock_get_reply(Node, Store, Tab, R) - + case need_lock(Store, Tab, ?ALL, read) of no when Node =:= node() -> ix_read_res(Tab,IxKey,Pos); @@ -1135,11 +1137,23 @@ rec_requests([], _Oid, _Store) -> get_held_locks() -> ?MODULE ! {get_table, self(), mnesia_held_locks}, - receive {mnesia_held_locks, Locks} -> Locks end. + Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end, + rewrite_locks(Locks, []). + +rewrite_locks([{Oid, _, Ls}|Locks], Acc0) -> + Acc = rewrite_locks(Ls, Oid, Acc0), + rewrite_locks(Locks, Acc); +rewrite_locks([], Acc) -> + lists:reverse(Acc). + +rewrite_locks([{Op, Tid}|Ls], Oid, Acc) -> + rewrite_locks(Ls, Oid, [{Oid, Op, Tid}|Acc]); +rewrite_locks([], _, Acc) -> + Acc. get_lock_queue() -> ?MODULE ! {get_table, self(), mnesia_lock_queue}, - Q = receive {mnesia_lock_queue, Locks} -> Locks end, + Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end, [{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q]. do_stop() -> diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl index 94153473cb..18303869ed 100644 --- a/lib/mnesia/src/mnesia_log.erl +++ b/lib/mnesia/src/mnesia_log.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -180,8 +180,8 @@ view/1, write_trans_log_header/0 ]). - - + + -compile({no_auto_import,[error/2]}). -include("mnesia.hrl"). @@ -210,7 +210,7 @@ decision_tab_version() -> "1.0". dcl_version() -> "1.0". dcd_version() -> "1.0". - + append(Log, Bin) when is_binary(Bin) -> disk_log:balog(Log, Bin); append(Log, Term) -> @@ -218,9 +218,9 @@ append(Log, Term) -> %% Synced append sappend(Log, Bin) when is_binary(Bin) -> - ok = disk_log:blog(Log, Bin); + ok = disk_log:blog(Log, Bin); sappend(Log, Term) -> - ok = disk_log:log(Log, Term). + ok = disk_log:log(Log, Term). %% Write commit records to the latest_log log(C) when C#commit.disc_copies == [], @@ -283,7 +283,7 @@ previous_log_file() -> dir("PREVIOUS.LOG"). decision_log_file() -> dir(decision_log_name()). decision_tab_file() -> dir(decision_tab_name()). - + previous_decision_log_file() -> dir("PDECISION.LOG"). latest_log_name() -> "LATEST.LOG". @@ -297,10 +297,10 @@ init() -> true -> Prev = previous_log_file(), verify_no_exists(Prev), - + Latest = latest_log_file(), verify_no_exists(Latest), - + Header = trans_log_header(), open_log(latest_log, Header, Latest); false -> @@ -346,20 +346,20 @@ open_log(Name, Header, Fname, Exists, Repair, Mode) -> write_header(Log, Header), Log; {repaired, Log, _Recover, BadBytes} -> - mnesia_lib:important("Data may be missing, log ~p repaired: Lost ~p bytes~n", + mnesia_lib:important("Data may be missing, log ~p repaired: Lost ~p bytes~n", [Fname, BadBytes]), Log; {error, Reason} when Repair == true -> file:delete(Fname), - mnesia_lib:important("Data may be missing, Corrupt logfile deleted: ~p, ~p ~n", + mnesia_lib:important("Data may be missing, Corrupt logfile deleted: ~p, ~p ~n", [Fname, Reason]), - %% Create a new + %% Create a new open_log(Name, Header, Fname, false, false, read_write); {error, Reason} -> fatal("Cannot open log file ~p: ~p~n", [Fname, Reason]) end. -write_header(Log, Header) -> +write_header(Log, Header) -> append(Log, Header). write_trans_log_header() -> @@ -376,12 +376,12 @@ stop() -> close_log(Log) -> %% io:format("mnesia_log:close_log ~p~n", [Log]), %% io:format("mnesia_log:close_log ~p~n", [Log]), - case disk_log:sync(Log) of + case disk_log:sync(Log) of ok -> ok; - {error, {read_only_mode, Log}} -> + {error, {read_only_mode, Log}} -> ok; - {error, Reason} -> - mnesia_lib:important("Failed syncing ~p to_disk reason ~p ~n", + {error, Reason} -> + mnesia_lib:important("Failed syncing ~p to_disk reason ~p ~n", [Log, Reason]) end, mnesia_monitor:close_log(Log). @@ -392,7 +392,7 @@ unsafe_close_log(Log) -> purge_some_logs() -> - mnesia_monitor:unsafe_close_log(latest_log), + mnesia_monitor:unsafe_close_log(latest_log), file:delete(latest_log_file()), file:delete(decision_tab_file()). @@ -466,10 +466,10 @@ chunk_log(Log, Cont) -> [Log, Reason]); {C2, Chunk, _BadBytes} -> %% Read_only case, should we warn about the bad log file? - %% BUGBUG Should we crash if Repair == false ?? + %% BUGBUG Should we crash if Repair == false ?? %% We got to check this !! mnesia_lib:important("~p repaired, lost ~p bad bytes~n", [Log, _BadBytes]), - {C2, Chunk}; + {C2, Chunk}; Other -> Other end. @@ -492,7 +492,7 @@ open_decision_log() -> Latest = decision_log_file(), open_log(decision_log, decision_log_header(), Latest), start. - + prepare_decision_log_dump() -> Prev = previous_decision_log_file(), prepare_decision_log_dump(exists(Prev), Prev). @@ -586,11 +586,11 @@ view_file(C, Log) -> eof; {C2, Terms, _BadBytes} -> dbg_out("Lost ~p bytes in ~p ~n", [_BadBytes, Log]), - lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, + lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, Terms), view_file(C2, Log); {C2, Terms} -> - lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, + lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, Terms), view_file(C2, Log) end. @@ -655,7 +655,7 @@ check_backup_args([Arg | Tail], B) -> check_backup_args([], B) -> {ok, B}. -check_backup_arg_type(Arg, B) -> +check_backup_arg_type(Arg, B) -> case Arg of {scope, global} -> B#backup_args{scope = global}; @@ -714,7 +714,7 @@ select_tables(AllTabs, B) -> safe_write(B, []) -> B; -safe_write(B, Recs) -> +safe_write(B, Recs) -> safe_apply(B, write, [B#backup_args.opaque, Recs]). backup_schema(B, Tabs) -> @@ -754,7 +754,7 @@ abort_write(B, What, Args, Reason) -> [Mod, abort_write, [Opaque], Other]), throw({error, Reason}) end. - + backup_tab(Tab, B) -> Name = B#backup_args.name, case mnesia_checkpoint:most_local_node(Name, Tab) of @@ -768,7 +768,7 @@ backup_tab(Tab, B) -> {error, Reason} -> abort_write(B, {?MODULE, backup_tab}, [Tab, B], {error, Reason}) end. - + tab_copier(Pid, B, Tab) when is_record(B, backup_args) -> %% Intentional crash at exit Name = B#backup_args.name, @@ -829,7 +829,7 @@ handle_last(Pid, _Acc) -> exit(normal). iterate(B, Name, Tab, Pid, Source, Age, Pass, Acc) -> - Fun = + Fun = if Pid == self() -> RecName = val({Tab, record_name}), @@ -874,7 +874,7 @@ tab_receiver(Pid, B, Tab, RecName, Slot) -> Recs2 = rec_filter(B, Tab, RecName, Recs), B2 = safe_write(B, Recs2), tab_receiver(Pid, B2, Tab, RecName, Next); - + {Pid, {last, {ok,_}}} -> B; @@ -885,7 +885,7 @@ tab_receiver(Pid, B, Tab, RecName, Slot) -> Reason = {error, {"Tab copier crashed", {'EXIT', R}}}, abort_write(B, {?MODULE, remote_tab_sender}, [self(), B, Tab], Reason); Msg -> - R = {error, {"Tab receiver got unexpected msg", Msg}}, + R = {error, {"Tab receiver got unexpected msg", Msg}}, abort_write(B, {?MODULE, remote_tab_sender}, [self(), B, Tab], R) end. @@ -910,9 +910,9 @@ ets2dcd(Tab, Ftype) -> case Ftype of dcd -> mnesia_lib:tab2dcd(Tab); dmp -> mnesia_lib:tab2dmp(Tab) - end, + end, TmpF = mnesia_lib:tab2tmp(Tab), - file:delete(TmpF), + file:delete(TmpF), Log = open_log({Tab, ets2dcd}, dcd_log_header(), TmpF, false), mnesia_lib:db_fixtable(ram_copies, Tab, true), ok = ets2dcd(mnesia_lib:db_init_chunk(ram_copies, Tab, 1000), Tab, Log), @@ -926,8 +926,8 @@ ets2dcd(Tab, Ftype) -> ets2dcd('$end_of_table', _Tab, _Log) -> ok; -ets2dcd({Recs, Cont}, Tab, Log) -> - ok = disk_log:alog_terms(Log, Recs), +ets2dcd({Recs, Cont}, Tab, Log) -> + ok = disk_log:log_terms(Log, Recs), ets2dcd(mnesia_lib:db_chunk(ram_copies, Cont), Tab, Log). dcd2ets(Tab) -> @@ -937,12 +937,12 @@ dcd2ets(Tab, Rep) -> Dcd = mnesia_lib:tab2dcd(Tab), case mnesia_lib:exists(Dcd) of true -> - Log = open_log({Tab, dcd2ets}, dcd_log_header(), Dcd, + Log = open_log({Tab, dcd2ets}, dcd_log_header(), Dcd, true, Rep, read_only), Data = chunk_log(Log, start), ok = insert_dcdchunk(Data, Log, Tab), close_log(Log), - load_dcl(Tab, Rep); + load_dcl(Tab, Rep); false -> %% Handle old dets files, and conversion from disc_only to disc. Fname = mnesia_lib:tab2dat(Tab), Type = val({Tab, setorbag}), @@ -956,13 +956,13 @@ dcd2ets(Tab, Rep) -> end end. -insert_dcdchunk({Cont, [LogH | Rest]}, Log, Tab) - when is_record(LogH, log_header), - LogH#log_header.log_kind == dcd_log, - LogH#log_header.log_version >= "1.0" -> - insert_dcdchunk({Cont, Rest}, Log, Tab); +insert_dcdchunk({Cont, [LogH | Rest]}, Log, Tab) + when is_record(LogH, log_header), + LogH#log_header.log_kind == dcd_log, + LogH#log_header.log_version >= "1.0" -> + insert_dcdchunk({Cont, Rest}, Log, Tab); -insert_dcdchunk({Cont, Recs}, Log, Tab) -> +insert_dcdchunk({Cont, Recs}, Log, Tab) -> true = ets:insert(Tab, Recs), insert_dcdchunk(chunk_log(Log, Cont), Log, Tab); insert_dcdchunk(eof, _Log, _Tab) -> @@ -971,13 +971,13 @@ insert_dcdchunk(eof, _Log, _Tab) -> load_dcl(Tab, Rep) -> FName = mnesia_lib:tab2dcl(Tab), case mnesia_lib:exists(FName) of - true -> + true -> Name = {load_dcl,Tab}, - open_log(Name, - dcl_log_header(), - FName, + open_log(Name, + dcl_log_header(), + FName, true, - Rep, + Rep, read_only), FirstChunk = chunk_log(Name, start), N = insert_logchunk(FirstChunk, Name, 0), @@ -1015,10 +1015,10 @@ add_recs([{{Tab, Key}, Val, update_counter} | Rest], N) -> true = ets:insert(Tab, Zero) end, add_recs(Rest, N+1); -add_recs([LogH|Rest], N) - when is_record(LogH, log_header), - LogH#log_header.log_kind == dcl_log, - LogH#log_header.log_version >= "1.0" -> +add_recs([LogH|Rest], N) + when is_record(LogH, log_header), + LogH#log_header.log_kind == dcl_log, + LogH#log_header.log_version >= "1.0" -> add_recs(Rest, N); add_recs([{{Tab, _Key}, _Val, clear_table} | Rest], N) -> Size = ets:info(Tab, size), diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index 8cb2e92c08..c08bbc879f 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -80,9 +80,9 @@ going_down = [], tm_started = false, early_connects = [], connecting, mq = []}). --define(current_protocol_version, {8,0}). +-define(current_protocol_version, {8,1}). --define(previous_protocol_version, {7,6}). +-define(previous_protocol_version, {8,0}). start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, @@ -188,7 +188,7 @@ protocol_version() -> %% A sorted list of acceptable protocols the %% preferred protocols are first in the list acceptable_protocol_versions() -> - [protocol_version(), ?previous_protocol_version]. + [protocol_version(), ?previous_protocol_version, {7,6}]. needs_protocol_conversion(Node) -> case {?catch_val({protocol, Node}), protocol_version()} of @@ -417,6 +417,8 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State) case hd(Protocols) of ?previous_protocol_version -> accept_protocol(Mon, MyVersion, ?previous_protocol_version, From, State); + {7,6} -> + accept_protocol(Mon, MyVersion, {7,6}, From, State); _ -> verbose("Connection with ~p rejected. " "version = ~p, protocols = ~p, " diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 179e15197e..6e43052fb0 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -188,6 +188,7 @@ do_set_schema(Tab, Cs) -> [set({Tab, user_property, element(1, P)}, P) || P <- Cs#cstruct.user_properties], set({Tab, frag_properties}, Cs#cstruct.frag_properties), mnesia_frag:set_frag_hash(Tab, Cs#cstruct.frag_properties), + set({Tab, storage_properties}, Cs#cstruct.storage_properties), set({Tab, attributes}, Cs#cstruct.attributes), Arity = length(Cs#cstruct.attributes) + 1, set({Tab, arity}, Arity), @@ -644,6 +645,14 @@ cs2list(Cs) when is_record(Cs, cstruct) -> rec2list(Tags, Tags, 2, Cs); cs2list(CreateList) when is_list(CreateList) -> CreateList; +%% 4.6 +cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 19 -> + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,majority,index,snmp,local_content, + record_name,attributes, + user_properties,frag_properties,storage_properties, + cookie,version], + rec2list(Tags, Tags, 2, Cs); %% 4.4.19 cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> Tags = [name,type,ram_copies,disc_copies,disc_only_copies, @@ -674,8 +683,17 @@ cs2list(ver4_4_19, Cs) -> load_order,access_mode,majority,index,snmp,local_content, record_name,attributes,user_properties,frag_properties, cookie,version], + rec2list(Tags, Orig, 2, Cs); +cs2list(ver4_6, Cs) -> + Orig = record_info(fields, cstruct), + Tags = [name,type,ram_copies,disc_copies,disc_only_copies, + load_order,access_mode,majority,index,snmp,local_content, + record_name,attributes, + user_properties,frag_properties,storage_properties, + cookie,version], rec2list(Tags, Orig, 2, Cs). + rec2list([Tag | Tags], [Tag | Orig], Pos, Rec) -> Val = element(Pos, Rec), [{Tag, Val} | rec2list(Tags, Orig, Pos + 1, Rec)]; @@ -728,6 +746,29 @@ list2cs(List) when is_list(List) -> Frag = pick(Name, frag_properties, List, []), verify({alt, [nil, list]}, mnesia_lib:etype(Frag), {badarg, Name, {frag_properties, Frag}}), + + BEProps = pick(Name, storage_properties, List, []), + verify({alt, [nil, list]}, mnesia_lib:etype(Ix), + {badarg, Name, {storage_properties, BEProps}}), + CheckProp = fun(Opt, Opts) when is_atom(Opt) -> + lists:member(Opt, Opts) + andalso mnesia:abort({badarg, Name, Opt}); + (Tuple, Opts) when is_tuple(Tuple) -> + lists:member(element(1,Tuple), Opts) + andalso mnesia:abort({badarg, Name, Tuple}); + (What,_) -> + mnesia:abort({badarg, Name, What}) + end, + BadEtsOpts = [set, ordered_set, bag, duplicate_bag, + public, private, protected, + keypos, named_table], + EtsOpts = proplists:get_value(ets, BEProps, []), + is_list(EtsOpts) orelse mnesia:abort({badarg, Name, {ets, EtsOpts}}), + [CheckProp(Prop, BadEtsOpts) || Prop <- EtsOpts], + BadDetsOpts = [type, keypos, repair, access, file], + DetsOpts = proplists:get_value(dets, BEProps, []), + is_list(DetsOpts) orelse mnesia:abort({badarg, Name, {dets, DetsOpts}}), + [CheckProp(Prop, BadDetsOpts) || Prop <- DetsOpts], #cstruct{name = Name, ram_copies = Rc, disc_copies = Dc, @@ -743,6 +784,7 @@ list2cs(List) when is_list(List) -> attributes = Attrs, user_properties = lists:sort(UserProps), frag_properties = lists:sort(Frag), + storage_properties = lists:sort(BEProps), cookie = Cookie, version = Version}. @@ -1881,18 +1923,18 @@ prepare_op(Tid, {op, create_table, TabDef}, _WaitFor) -> mnesia:abort(UseDirReason); ram_copies -> mnesia_lib:set({Tab, create_table},true), - create_ram_table(Tab, Cs#cstruct.type), + create_ram_table(Tab, Cs), insert_cstruct(Tid, Cs, false), {true, optional}; disc_copies -> mnesia_lib:set({Tab, create_table},true), - create_ram_table(Tab, Cs#cstruct.type), + create_ram_table(Tab, Cs), create_disc_table(Tab), insert_cstruct(Tid, Cs, false), {true, optional}; disc_only_copies -> mnesia_lib:set({Tab, create_table},true), - create_disc_only_table(Tab,Cs#cstruct.type), + create_disc_only_table(Tab,Cs), insert_cstruct(Tid, Cs, false), {true, optional}; unknown -> %% No replica on this node @@ -2044,7 +2086,7 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor) mnesia_dumper:raw_named_dump_table(Tab, dmp); FromS == disc_only_copies -> Type = Cs#cstruct.type, - create_ram_table(Tab, Type), + create_ram_table(Tab, Cs), Datname = mnesia_lib:tab2dat(Tab), Repair = mnesia_monitor:get_env(auto_repair), case mnesia_lib:dets_to_ets(Tab, Tab, Datname, Type, Repair, no) of @@ -2132,8 +2174,9 @@ prepare_op(_Tid, {op, merge_schema, TabDef}, _WaitFor) -> prepare_op(_Tid, _Op, _WaitFor) -> {true, optional}. -create_ram_table(Tab, Type) -> - Args = [{keypos, 2}, public, named_table, Type], +create_ram_table(Tab, #cstruct{type=Type, storage_properties=Props}) -> + EtsOpts = proplists:get_value(ets, Props, []), + Args = [{keypos, 2}, public, named_table, Type | EtsOpts], case mnesia_monitor:unsafe_mktab(Tab, Args) of Tab -> ok; @@ -2141,6 +2184,7 @@ create_ram_table(Tab, Type) -> Err = "Failed to create ets table", mnesia:abort({system_limit, Tab, {Err,Reason}}) end. + create_disc_table(Tab) -> File = mnesia_lib:tab2dcd(Tab), file:delete(File), @@ -2154,13 +2198,15 @@ create_disc_table(Tab) -> Err = "Failed to create disc table", mnesia:abort({system_limit, Tab, {Err,Reason}}) end. -create_disc_only_table(Tab,Type) -> +create_disc_only_table(Tab, #cstruct{type=Type, storage_properties=Props}) -> File = mnesia_lib:tab2dat(Tab), file:delete(File), + DetsOpts = proplists:get_value(dets, Props, []), Args = [{file, mnesia_lib:tab2dat(Tab)}, {type, mnesia_lib:disk_type(Tab, Type)}, {keypos, 2}, - {repair, mnesia_monitor:get_env(auto_repair)}], + {repair, mnesia_monitor:get_env(auto_repair)} + | DetsOpts], case mnesia_monitor:unsafe_open_dets(Tab, Args) of {ok, _} -> ok; @@ -2688,17 +2734,17 @@ restore_schema([{schema, Tab, List} | Schema], R) -> R2 = R#r{tables = [{Tab, undefined, Snmp, RecName} | R#r.tables]}, restore_schema(Schema, R2); recreate_tables -> - case ?catch_val({Tab, cstruct}) of - {'EXIT', _} -> - TidTs = {_Mod, Tid, Ts} = get(mnesia_activity_state), - RunningNodes = val({current, db_nodes}), - Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)), - RunningNodes), - mnesia_locker:wlock_no_exist(Tid, Ts#tidstore.store, Tab, Nodes), - TidTs; - _ -> - TidTs = get_tid_ts_and_lock(Tab, write) - end, + TidTs = case ?catch_val({Tab, cstruct}) of + {'EXIT', _} -> + TTs = {_Mod, Tid, Ts} = get(mnesia_activity_state), + RunningNodes = val({current, db_nodes}), + Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)), + RunningNodes), + mnesia_locker:wlock_no_exist(Tid, Ts#tidstore.store, Tab, Nodes), + TTs; + _ -> + get_tid_ts_and_lock(Tab, write) + end, NC = {cookie, ?unique_cookie}, List2 = lists:keyreplace(cookie, 1, List, NC), Where = where_to_commit(Tab, List2), @@ -2839,15 +2885,15 @@ do_merge_schema(LockTabs0) -> end. fetch_cstructs(Node) -> - case mnesia_monitor:needs_protocol_conversion(Node) of - true -> + case need_old_cstructs([Node]) of + false -> + rpc:call(Node, mnesia_controller, get_remote_cstructs, []); + _Ver -> case rpc:call(Node, mnesia_controller, get_cstructs, []) of {cstructs, Cs0, RR} -> {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RR}; Err -> Err - end; - false -> - rpc:call(Node, mnesia_controller, get_remote_cstructs, []) + end end. need_old_cstructs() -> @@ -2868,7 +2914,9 @@ need_old_cstructs(Nodes) -> Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 17 -> ver4_4_18; % Without majority Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 18 -> - ver4_4_19 % With majority + ver4_4_19; % With majority + Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 19 -> + ver4_6 % With storage_properties end end. diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index f62f7cb7c8..0af7f55c06 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -36,7 +36,7 @@ prepare_checkpoint/2, prepare_checkpoint/1, % Internal prepare_snmp/3, - do_snmp/2, + do_snmp/2, put_activity_id/1, put_activity_id/2, block_tab/1, @@ -68,7 +68,7 @@ majority = [] }). --record(participant, {tid, pid, commit, disc_nodes = [], +-record(participant, {tid, pid, commit, disc_nodes = [], ram_nodes = [], protocol = sym_trans}). start() -> @@ -77,12 +77,12 @@ start() -> init(Parent) -> register(?MODULE, self()), process_flag(trap_exit, true), - + %% Initialize the schema IgnoreFallback = mnesia_monitor:get_env(ignore_fallback_at_startup), mnesia_bup:tm_fallback_start(IgnoreFallback), mnesia_schema:init(IgnoreFallback), - + %% Handshake and initialize transaction recovery mnesia_recover:init(), Early = mnesia_monitor:init(), @@ -101,11 +101,11 @@ init(Parent) -> false -> ignore end, - + mnesia_schema:purge_tmp_files(), mnesia_recover:start_garb(), - - ?eval_debug_fun({?MODULE, init}, [{nodes, AllOthers}]), + + ?eval_debug_fun({?MODULE, init}, [{nodes, AllOthers}]), case val(debug) of Debug when Debug /= debug, Debug /= trace -> @@ -118,8 +118,8 @@ init(Parent) -> val(Var) -> case ?catch_val(Var) of - {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_); - _VaLuE_ -> _VaLuE_ + {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_); + _VaLuE_ -> _VaLuE_ end. reply({From,Ref}, R) -> @@ -136,7 +136,7 @@ req(R) -> undefined -> {error, {node_not_running, node()}}; Pid -> - Ref = make_ref(), + Ref = make_ref(), Pid ! {{self(), Ref}, R}, rec(Pid, Ref) end. @@ -161,7 +161,7 @@ rec(Pid, Ref) -> Reply; {'EXIT', Pid, _} -> {error, {node_not_running, node()}} - end. + end. tmlink({From, Ref}) when is_reference(Ref) -> link(From); @@ -209,7 +209,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= State2 = State#state{dirty_queue = [Item | State#state.dirty_queue]}, doit_loop(State2) end; - + {From, {sync_dirty, Tid, Commit, Tab}} -> case lists:member(Tab, State#state.blocked_tabs) of false -> @@ -220,7 +220,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= State2 = State#state{dirty_queue = [Item | State#state.dirty_queue]}, doit_loop(State2) end; - + {From, start_outer} -> %% Create and associate ets_tab with Tid case catch ?ets_new_table(mnesia_trans_store, [bag, public]) of {'EXIT', Reason} -> %% system limit @@ -236,16 +236,16 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= S2 = State#state{coordinators = A2}, reply(From, {new_tid, Tid, Etab}, S2) end; - + {From, {ask_commit, Protocol, Tid, Commit, DiscNs, RamNs}} -> - ?eval_debug_fun({?MODULE, doit_ask_commit}, + ?eval_debug_fun({?MODULE, doit_ask_commit}, [{tid, Tid}, {prot, Protocol}]), mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), - Pid = + Pid = case Protocol of asym_trans when node(Tid#tid.pid) /= node() -> Args = [tmpid(From), Tid, Commit, DiscNs, RamNs], - spawn_link(?MODULE, commit_participant, Args); + spawn_link(?MODULE, commit_participant, Args); _ when node(Tid#tid.pid) /= node() -> %% *_sym_trans reply(From, {vote_yes, Tid}), nopid @@ -258,7 +258,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= protocol = Protocol}, State2 = State#state{participants = gb_trees:insert(Tid,P,Participants)}, doit_loop(State2); - + {Tid, do_commit} -> case gb_trees:lookup(Tid, Participants) of none -> @@ -272,14 +272,14 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= Member = lists:member(node(), P#participant.disc_nodes), if Member == false -> ignore; - P#participant.protocol == sym_trans -> + P#participant.protocol == sym_trans -> mnesia_log:log(Commit); - P#participant.protocol == sync_sym_trans -> + P#participant.protocol == sync_sym_trans -> mnesia_log:slog(Commit) end, mnesia_recover:note_decision(Tid, committed), do_commit(Tid, Commit), - if + if P#participant.protocol == sync_sym_trans -> Tid#tid.pid ! {?MODULE, node(), {committed, Tid}}; true -> @@ -296,13 +296,13 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= doit_loop(State) end end; - + {Tid, simple_commit} -> mnesia_recover:note_decision(Tid, committed), mnesia_locker:release_tid(Tid), transaction_terminated(Tid), doit_loop(State); - + {Tid, {do_abort, Reason}} -> ?eval_debug_fun({?MODULE, do_abort, pre}, [{tid, Tid}]), case gb_trees:lookup(Tid, Participants) of @@ -317,7 +317,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= Commit = P#participant.commit, mnesia_recover:note_decision(Tid, aborted), do_abort(Tid, Commit), - if + if P#participant.protocol == sync_sym_trans -> Tid#tid.pid ! {?MODULE, node(), {aborted, Tid}}; true -> @@ -335,7 +335,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= doit_loop(State) end end; - + {From, {add_store, Tid}} -> %% new store for nested transaction case catch ?ets_new_table(mnesia_trans_store, [bag, public]) of {'EXIT', Reason} -> %% system limit @@ -355,14 +355,14 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= {'EXIT', Pid, Reason} -> handle_exit(Pid, Reason, State); - + {From, {restart, Tid, Store}} -> A2 = restore_stores(Coordinators, Tid, Store), clear_fixtable([Store]), ?ets_match_delete(Store, '_'), ?ets_insert(Store, {nodes, node()}), reply(From, {restarted, Tid}, State#state{coordinators = A2}); - + {delete_transaction, Tid} -> %% used to clear transactions which are committed %% in coordinator or participant processes @@ -377,7 +377,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= clear_fixtable(Etabs), erase_ets_tabs(Etabs), transaction_terminated(Tid), - doit_loop(State#state{coordinators = + doit_loop(State#state{coordinators = gb_trees:delete(Tid,Coordinators)}) end; true -> @@ -385,20 +385,20 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= State2 = State#state{participants=gb_trees:delete(Tid,Participants)}, doit_loop(State2) end; - + {sync_trans_serial, Tid} -> %% Do the Lamport thing here mnesia_recover:sync_trans_tid_serial(Tid), doit_loop(State); - + {From, info} -> - reply(From, {info, gb_trees:values(Participants), + reply(From, {info, gb_trees:values(Participants), gb_trees:to_list(Coordinators)}, State); - + {mnesia_down, N} -> verbose("Got mnesia_down from ~p, reconfiguring...~n", [N]), reconfigure_coordinators(N, gb_trees:to_list(Coordinators)), - + Tids = gb_trees:keys(Participants), reconfigure_participants(N, gb_trees:values(Participants)), NewState = clear_fixtable(N, State), @@ -408,34 +408,34 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= {From, {unblock_me, Tab}} -> case lists:member(Tab, State#state.blocked_tabs) of false -> - verbose("Wrong dirty Op blocked on ~p ~p ~p", + verbose("Wrong dirty Op blocked on ~p ~p ~p", [node(), Tab, From]), reply(From, unblocked), doit_loop(State); true -> - Item = {Tab, unblock_me, From}, + Item = {Tab, unblock_me, From}, State2 = State#state{dirty_queue = [Item | State#state.dirty_queue]}, doit_loop(State2) - end; - + end; + {From, {block_tab, Tab}} -> State2 = State#state{blocked_tabs = [Tab | State#state.blocked_tabs]}, reply(From, ok, State2); - + {From, {unblock_tab, Tab}} -> BlockedTabs2 = State#state.blocked_tabs -- [Tab], case lists:member(Tab, BlockedTabs2) of false -> mnesia_controller:unblock_table(Tab), Queue = process_dirty_queue(Tab, State#state.dirty_queue), - State2 = State#state{blocked_tabs = BlockedTabs2, + State2 = State#state{blocked_tabs = BlockedTabs2, dirty_queue = Queue}, reply(From, ok, State2); true -> State2 = State#state{blocked_tabs = BlockedTabs2}, reply(From, ok, State2) end; - + {From, {prepare_checkpoint, Cp}} -> Res = mnesia_checkpoint:tm_prepare(Cp), case Res of @@ -448,18 +448,18 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= reply(From, Res, State); {From, {fixtable, [Tab,Lock,Requester]}} -> case ?catch_val({Tab, storage_type}) of - {'EXIT', _} -> + {'EXIT', _} -> reply(From, error, State); Storage -> mnesia_lib:db_fixtable(Storage,Tab,Lock), NewState = manage_fixtable(Tab,Lock,Requester,State), reply(From, node(), NewState) end; - + {system, From, Msg} -> dbg_out("~p got {system, ~p, ~p}~n", [?MODULE, From, Msg]), sys:handle_system_msg(Msg, From, Sup, ?MODULE, [], State); - + Msg -> verbose("** ERROR ** ~p got unexpected message: ~p~n", [?MODULE, Msg]), doit_loop(State) @@ -508,7 +508,7 @@ prepare_pending_coordinators([{Tid, [Store | _Etabs]} | Coords], IgnoreNew) -> ignore end, prepare_pending_coordinators(Coords, IgnoreNew); - {'EXIT', _} -> + {'EXIT', _} -> prepare_pending_coordinators(Coords, IgnoreNew) end; prepare_pending_coordinators([], _IgnoreNew) -> @@ -538,7 +538,7 @@ handle_exit(Pid, _Reason, State) when Pid == State#state.supervisor -> handle_exit(Pid, Reason, State) -> %% Check if it is a coordinator - case pid_search_delete(Pid, gb_trees:to_list(State#state.coordinators)) of + case pid_search_delete(Pid, gb_trees:to_list(State#state.coordinators)) of {none, _} -> %% Check if it is a participant Ps = gb_trees:values(State#state.participants), @@ -552,9 +552,9 @@ handle_exit(Pid, Reason, State) -> NewPs = gb_trees:delete(P#participant.tid,State#state.participants), doit_loop(State#state{participants = NewPs}) end; - + {{Tid, Etabs}, RestC} -> - %% A local coordinator has died and + %% A local coordinator has died and %% we must determine the outcome of the %% transaction and tell mnesia_tm on the %% other nodes about it and then recover @@ -578,7 +578,7 @@ recover_coordinator(Tid, Etabs) -> %% Tell the participants about the outcome Protocol = Prep#prep.protocol, Outcome = tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes), - + %% Recover locally CR = Prep#prep.records, {DiscNs, RamNs} = commit_nodes(CR, [], []), @@ -589,7 +589,7 @@ recover_coordinator(Tid, Etabs) -> recover_coordinator(Tid, Protocol, Outcome, Local, DiscNs, RamNs), ?eval_debug_fun({?MODULE, recover_coordinator, post}, [{tid, Tid}, {outcome, Outcome}, {prot, Protocol}]); - false -> %% When killed before store havn't been copied to + false -> %% When killed before store havn't been copied to ok %% to the new nested trans store. end end, @@ -610,12 +610,12 @@ recover_coordinator(Tid, sync_sym_trans, aborted, _Local, _, _) -> recover_coordinator(Tid, asym_trans, committed, Local, DiscNs, RamNs) -> D = #decision{tid = Tid, outcome = committed, - disc_nodes = DiscNs, ram_nodes = RamNs}, + disc_nodes = DiscNs, ram_nodes = RamNs}, mnesia_recover:log_decision(D), do_commit(Tid, Local); recover_coordinator(Tid, asym_trans, aborted, Local, DiscNs, RamNs) -> D = #decision{tid = Tid, outcome = aborted, - disc_nodes = DiscNs, ram_nodes = RamNs}, + disc_nodes = DiscNs, ram_nodes = RamNs}, mnesia_recover:log_decision(D), do_abort(Tid, Local). @@ -631,7 +631,7 @@ add_coord_store(Coords, Tid, Etab) -> del_coord_store(Coords, Tid, Current, Obsolete) -> Stores = gb_trees:get(Tid, Coords), - Rest = + Rest = case Stores of [Obsolete, Current | Tail] -> Tail; [Current, Obsolete | Tail] -> Tail @@ -642,14 +642,14 @@ del_coord_store(Coords, Tid, Current, Obsolete) -> erase_ets_tabs([H | T]) -> ?ets_delete_table(H), erase_ets_tabs(T); -erase_ets_tabs([]) -> +erase_ets_tabs([]) -> ok. %% Clear one transactions all fixtables clear_fixtable([Store|_]) -> Fixed = get_elements(fixtable, Store), lists:foreach(fun({Tab,Node}) -> - rpc:cast(Node, ?MODULE, fixtable, [Tab,false,self()]) + rpc:cast(Node, ?MODULE, fixtable, [Tab,false,self()]) end, Fixed). %% Clear all fixtable Node have done @@ -661,7 +661,7 @@ clear_fixtable(Node, State=#state{fixed_tabs = FT0}) -> lists:foreach( fun(Tab) -> case ?catch_val({Tab, storage_type}) of - {'EXIT', _} -> + {'EXIT', _} -> ignore; Storage -> mnesia_lib:db_fixtable(Storage,Tab,false) @@ -680,9 +680,9 @@ manage_fixtable(Tab,true,Requester,State=#state{fixed_tabs = FT0}) -> end; manage_fixtable(Tab,false,Requester,State = #state{fixed_tabs = FT0}) -> Node = node(Requester), - case mnesia_lib:key_search_delete(Node, 1, FT0) of + case mnesia_lib:key_search_delete(Node, 1, FT0) of {none,_FT} -> State; % Hmm? Safeguard - {{Node, Tabs0},FT} -> + {{Node, Tabs0},FT} -> case lists:delete(Tab, Tabs0) of [] -> State#state{fixed_tabs=FT}; Tabs -> State#state{fixed_tabs=[{Node,Tabs}|FT]} @@ -691,7 +691,7 @@ manage_fixtable(Tab,false,Requester,State = #state{fixed_tabs = FT0}) -> %% Deletes a pid from a list of participants %% or from a gb_trees of coordinators -%% {none, All} or {Tr, Rest} +%% {none, All} or {Tr, Rest} pid_search_delete(Pid, Trs) -> pid_search_delete(Pid, Trs, none, []). pid_search_delete(Pid, [Tr = {Tid, _Ts} | Trs], _Val, Ack) when Tid#tid.pid == Pid -> @@ -701,7 +701,7 @@ pid_search_delete(Pid, [Tr | Trs], Val, Ack) -> pid_search_delete(_Pid, [], Val, Ack) -> {Val, gb_trees:from_orddict(lists:reverse(Ack))}. - + transaction_terminated(Tid) -> mnesia_checkpoint:tm_exit_pending(Tid), Pid = Tid#tid.pid, @@ -713,14 +713,14 @@ transaction_terminated(Tid) -> end. %% If there are an surrounding transaction, we inherit it's context -non_transaction(OldState={_,_,Trans}, Fun, Args, ActivityKind, Mod) +non_transaction(OldState={_,_,Trans}, Fun, Args, ActivityKind, Mod) when Trans /= non_transaction -> - Kind = case ActivityKind of + Kind = case ActivityKind of sync_dirty -> sync; _ -> async end, case transaction(OldState, Fun, Args, infinity, Mod, Kind) of - {atomic, Res} -> + {atomic, Res} -> Res; {aborted,Res} -> exit(Res) @@ -766,7 +766,7 @@ transaction(OldTidTs, Fun, Args, Retries, Mod, Type) -> execute_outer(Mod, Fun, Args, Factor, Retries, Type) -> case req(start_outer) of - {error, Reason} -> + {error, Reason} -> {aborted, Reason}; {new_tid, Tid, Store} -> Ts = #tidstore{store = Store}, @@ -792,7 +792,7 @@ execute_inner(Mod, Tid, OldMod, Ts, Fun, Args, Factor, Retries, Type) -> copy_ets(From, To) -> do_copy_ets(?ets_first(From), From, To). -do_copy_ets('$end_of_table', _,_) -> +do_copy_ets('$end_of_table', _,_) -> ok; do_copy_ets(K, From, To) -> Objs = ?ets_lookup(From, K), @@ -813,7 +813,7 @@ execute_transaction(Fun, Args, Factor, Retries, Type) -> mnesia_lib:incr_counter(trans_commits), erase(mnesia_activity_state), %% no need to clear locks, already done by commit ... - %% Flush any un processed mnesia_down messages we might have + %% Flush any un processed mnesia_down messages we might have flush_downs(), catch unlink(whereis(?MODULE)), {atomic, Value}; @@ -846,7 +846,7 @@ check_exit(Fun, Args, Factor, Retries, Reason, Type) -> maybe_restart(Fun, Args, Factor, Retries, Type, {node_not_running, N}); {aborted, {bad_commit, N}} -> maybe_restart(Fun, Args, Factor, Retries, Type, {bad_commit, N}); - _ -> + _ -> return_abort(Fun, Args, Reason) end. @@ -888,11 +888,11 @@ restart(Mod, Tid, Ts, Fun, Args, Factor0, Retries0, Type, Why) -> SleepTime = mnesia_lib:random_time(Factor, Tid#tid.counter), dbg_out("Restarting transaction ~w: in ~wms ~w~n", [Tid, SleepTime, Why]), timer:sleep(SleepTime), - execute_outer(Mod, Fun, Args, Factor, Retries, Type); + execute_outer(Mod, Fun, Args, Factor, Retries, Type); _ -> SleepTime = mnesia_lib:random_time(Factor0, Tid#tid.counter), dbg_out("Restarting transaction ~w: in ~wms ~w~n", [Tid, SleepTime, Why]), - + if Factor0 /= 10 -> ignore; @@ -911,7 +911,7 @@ restart(Mod, Tid, Ts, Fun, Args, Factor0, Retries0, Type, Why) -> mnesia_locker:receive_release_tid_acc(Nodes, Tid), case get_restarted(Tid) of {restarted, Tid} -> - execute_transaction(Fun, Args, Factor0 + 1, + execute_transaction(Fun, Args, Factor0 + 1, Retries, Type); {error, Reason} -> mnesia:abort(Reason) @@ -934,7 +934,7 @@ decr(_X) -> 0. return_abort(Fun, Args, Reason) -> {_Mod, Tid, Ts} = get(mnesia_activity_state), - dbg_out("Transaction ~p calling ~p with ~p failed: ~n ~p~n", + dbg_out("Transaction ~p calling ~p with ~p failed: ~n ~p~n", [Tid, Fun, Args, Reason]), OldStore = Ts#tidstore.store, Nodes = get_elements(nodes, OldStore), @@ -945,7 +945,7 @@ return_abort(Fun, Args, Reason) -> Level == 1 -> mnesia_locker:async_release_tid(Nodes, Tid), ?MODULE ! {delete_transaction, Tid}, - erase(mnesia_activity_state), + erase(mnesia_activity_state), flush_downs(), catch unlink(whereis(?MODULE)), {aborted, mnesia_lib:fix_error(Reason)}; @@ -958,14 +958,14 @@ return_abort(Fun, Args, Reason) -> level = Level - 1}, NewTidTs = {OldMod, Tid, Ts2}, put(mnesia_activity_state, NewTidTs), - case Reason of + case Reason of #cyclic{} -> exit({aborted, Reason}); - {node_not_running, _N} -> + {node_not_running, _N} -> exit({aborted, Reason}); - {bad_commit, _N}-> + {bad_commit, _N}-> exit({aborted, Reason}); - _ -> + _ -> {aborted, mnesia_lib:fix_error(Reason)} end end. @@ -982,10 +982,10 @@ put_activity_id(MTT) -> put_activity_id(MTT, undefined). put_activity_id(undefined,_) -> erase_activity_id(); -put_activity_id({Mod, Tid = #tid{}, Ts = #tidstore{}},Fun) -> +put_activity_id({Mod, Tid = #tid{}, Ts = #tidstore{}},Fun) -> flush_downs(), Store = Ts#tidstore.store, - if + if is_function(Fun) -> ?ets_insert(Store, {friends, {stop,Fun}}); true -> @@ -1000,14 +1000,14 @@ erase_activity_id() -> flush_downs(), erase(mnesia_activity_state). -get_elements(Type,Store) -> +get_elements(Type,Store) -> case catch ?ets_lookup(Store, Type) of [] -> []; [{_,Val}] -> [Val]; {'EXIT', _} -> []; Vals -> [Val|| {_,Val} <- Vals] end. - + opt_propagate_store(_Current, _Obsolete, false) -> ok; opt_propagate_store(Current, Obsolete, true) -> @@ -1030,8 +1030,8 @@ intercept_best_friend([],_) -> ok; intercept_best_friend([{stop,Fun} | R],Ignore) -> catch Fun(), intercept_best_friend(R,Ignore); -intercept_best_friend([Pid | R],false) -> - Pid ! {activity_ended, undefined, self()}, +intercept_best_friend([Pid | R],false) -> + Pid ! {activity_ended, undefined, self()}, wait_for_best_friend(Pid, 0), intercept_best_friend(R,true); intercept_best_friend([_|R],true) -> @@ -1047,18 +1047,18 @@ wait_for_best_friend(Pid, Timeout) -> false -> ok end end. - + my_process_is_alive(Pid) -> case catch erlang:is_process_alive(Pid) of % New BIF in R5 - true -> + true -> true; - false -> + false -> false; - {'EXIT', _} -> % Pre R5 backward compatibility + {'EXIT', _} -> % Pre R5 backward compatibility case process_info(Pid, message_queue_len) of undefined -> false; _ -> true - end + end end. dirty(Protocol, Item) -> @@ -1070,12 +1070,12 @@ dirty(Protocol, Item) -> async_dirty -> %% Send commit records to the other involved nodes, %% but do only wait for one node to complete. - %% Preferrably, the local node if possible. - + %% Preferrably, the local node if possible. + ReadNode = val({Tab, where_to_read}), {WaitFor, FirstRes} = async_send_dirty(Tid, CR, Tab, ReadNode), rec_dirty(WaitFor, FirstRes); - + sync_dirty -> %% Send commit records to the other involved nodes, %% and wait for all nodes to complete @@ -1097,7 +1097,7 @@ t_commit(Type) -> if Ts#tidstore.level == 1 -> intercept_friends(Tid, Ts), - %% N is number of updates + %% N is number of updates case arrange(Tid, Store, Type) of {N, Prep} when N > 0 -> multi_commit(Prep#prep.protocol, @@ -1135,8 +1135,8 @@ arrange(Tid, Store, Type) -> Recs = prep_recs(Nodes, []), Key = ?ets_first(Store), N = 0, - Prep = - case Type of + Prep = + case Type of async -> #prep{protocol = sym_trans, records = Recs}; sync -> #prep{protocol = sync_sym_trans, records = Recs} end, @@ -1146,7 +1146,7 @@ arrange(Tid, Store, Type) -> case Reason of {aborted, R} -> mnesia:abort(R); - _ -> + _ -> mnesia:abort(Reason) end; {New, Prepared} -> @@ -1155,7 +1155,7 @@ arrange(Tid, Store, Type) -> reverse([]) -> []; -reverse([H=#commit{ram_copies=Ram, disc_copies=DC, +reverse([H=#commit{ram_copies=Ram, disc_copies=DC, disc_only_copies=DOC,snmp = Snmp} |R]) -> [ @@ -1164,7 +1164,7 @@ reverse([H=#commit{ram_copies=Ram, disc_copies=DC, disc_copies = lists:reverse(DC), disc_only_copies = lists:reverse(DOC), snmp = lists:reverse(Snmp) - } + } | reverse(R)]. prep_recs([N | Nodes], Recs) -> @@ -1191,7 +1191,7 @@ do_arrange(Tid, Store, RestoreKey, Prep, N) when RestoreKey == restore_op -> (BupRec, CommitRecs, RecName, Where, Snmp) -> Tab = element(1, BupRec), Key = element(2, BupRec), - Item = + Item = if Tab == RecName -> [{{Tab, Key}, BupRec, write}]; @@ -1200,7 +1200,7 @@ do_arrange(Tid, Store, RestoreKey, Prep, N) when RestoreKey == restore_op -> [{{Tab, Key}, BupRec2, write}] end, do_prepare_items(Tid, Tab, Key, Where, Snmp, Item, CommitRecs) - end, + end, Recs2 = mnesia_schema:arrange_restore(R, Fun, Prep#prep.records), P2 = Prep#prep{protocol = asym_trans, records = Recs2}, do_arrange(Tid, Store, ?ets_next(Store, RestoreKey), P2, N + 1); @@ -1222,20 +1222,20 @@ prepare_items(Tid, Tab, Key, Items, Prep) when Prep#prep.prev_tab == Tab -> Recs = Prep#prep.records, Recs2 = do_prepare_items(Tid, Tab, Key, Types, Snmp, Items, Recs), Prep#prep{records = Recs2}; - + prepare_items(Tid, Tab, Key, Items, Prep) -> Types = val({Tab, where_to_commit}), case Types of [] -> mnesia:abort({no_exists, Tab}); - {blocked, _} -> + {blocked, _} -> unblocked = req({unblock_me, Tab}), prepare_items(Tid, Tab, Key, Items, Prep); _ -> Majority = needs_majority(Tab, Prep), Snmp = val({Tab, snmp}), - Recs2 = do_prepare_items(Tid, Tab, Key, Types, + Recs2 = do_prepare_items(Tid, Tab, Key, Types, Snmp, Items, Prep#prep.records), - Prep2 = Prep#prep{records = Recs2, prev_tab = Tab, + Prep2 = Prep#prep{records = Recs2, prev_tab = Tab, majority = Majority, prev_types = Types, prev_snmp = Snmp}, check_prep(Prep2, Types) @@ -1273,7 +1273,7 @@ have_majority([{Tab, AllNodes} | Rest], Nodes) -> end. prepare_snmp(Tab, Key, Items) -> - case val({Tab, snmp}) of + case val({Tab, snmp}) of [] -> []; Ustruct when Key /= '_' -> @@ -1286,10 +1286,10 @@ prepare_snmp(Tab, Key, Items) -> [{clear_table, Tab}] end. -prepare_snmp(_Tid, _Tab, _Key, _Types, [], _Items, Recs) -> +prepare_snmp(_Tid, _Tab, _Key, _Types, [], _Items, Recs) -> Recs; -prepare_snmp(Tid, Tab, Key, Types, Us, Items, Recs) -> +prepare_snmp(Tid, Tab, Key, Types, Us, Items, Recs) -> if Key /= '_' -> {_Oid, _Val, Op} = hd(Items), SnmpOid = mnesia_snmp_hook:key_to_oid(Tab, Key, Us), % May exit @@ -1334,7 +1334,7 @@ prepare_node(Node, Storage, [Item | Items], Rec, Kind) when Kind == snmp -> Rec2 = Rec#commit{snmp = [Item | Rec#commit.snmp]}, prepare_node(Node, Storage, Items, Rec2, Kind); prepare_node(Node, Storage, [Item | Items], Rec, Kind) when Kind /= schema -> - Rec2 = + Rec2 = case Storage of ram_copies -> Rec#commit{ram_copies = [Item | Rec#commit.ram_copies]}; @@ -1345,7 +1345,7 @@ prepare_node(Node, Storage, [Item | Items], Rec, Kind) when Kind /= schema -> [Item | Rec#commit.disc_only_copies]} end, prepare_node(Node, Storage, Items, Rec2, Kind); -prepare_node(_Node, _Storage, Items, Rec, Kind) +prepare_node(_Node, _Storage, Items, Rec, Kind) when Kind == schema, Rec#commit.schema_ops == [] -> Rec#commit{schema_ops = Items}; prepare_node(_Node, _Storage, [], Rec, _Kind) -> @@ -1354,7 +1354,7 @@ prepare_node(_Node, _Storage, [], Rec, _Kind) -> %% multi_commit((Protocol, Tid, CommitRecords, Store) %% Local work is always performed in users process multi_commit(read_only, _Maj = [], Tid, CR, _Store) -> - %% This featherweight commit protocol is used when no + %% This featherweight commit protocol is used when no %% updates has been performed in the transaction. {DiscNs, RamNs} = commit_nodes(CR, [], []), @@ -1381,11 +1381,11 @@ multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> %% perform the updates. %% %% The outcome is kept 3 minutes in the transient decision table. - %% + %% %% Recovery: %% If somebody dies before the coordinator has %% broadcasted do_commit, the transaction is aborted. - %% + %% %% If a participant dies, the table load algorithm %% ensures that the contents of the involved tables %% are picked from another node. @@ -1394,15 +1394,15 @@ multi_commit(sym_trans, _Maj = [], Tid, CR, Store) -> %% the outcome with all the others. If all are uncertain %% about the outcome, the transaction is aborted. If %% somebody knows the outcome the others will follow. - + {DiscNs, RamNs} = commit_nodes(CR, [], []), Pending = mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), ?ets_insert(Store, Pending), {WaitFor, Local} = ask_commit(sym_trans, Tid, CR, DiscNs, RamNs), - {Outcome, []} = rec_all(WaitFor, Tid, do_commit, []), - ?eval_debug_fun({?MODULE, multi_commit_sym}, - [{tid, Tid}, {outcome, Outcome}]), + {Outcome, []} = rec_all(WaitFor, Tid, do_commit, []), + ?eval_debug_fun({?MODULE, multi_commit_sym}, + [{tid, Tid}, {outcome, Outcome}]), rpc:abcast(DiscNs -- [node()], ?MODULE, {Tid, Outcome}), rpc:abcast(RamNs -- [node()], ?MODULE, {Tid, Outcome}), case Outcome of @@ -1422,15 +1422,15 @@ multi_commit(sync_sym_trans, _Maj = [], Tid, CR, Store) -> %% This protocol is the same as sym_trans except that it %% uses syncronized calls to disk_log and syncronized commits %% when several nodes are involved. - + {DiscNs, RamNs} = commit_nodes(CR, [], []), Pending = mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), ?ets_insert(Store, Pending), {WaitFor, Local} = ask_commit(sync_sym_trans, Tid, CR, DiscNs, RamNs), - {Outcome, []} = rec_all(WaitFor, Tid, do_commit, []), - ?eval_debug_fun({?MODULE, multi_commit_sym_sync}, - [{tid, Tid}, {outcome, Outcome}]), + {Outcome, []} = rec_all(WaitFor, Tid, do_commit, []), + ?eval_debug_fun({?MODULE, multi_commit_sym_sync}, + [{tid, Tid}, {outcome, Outcome}]), [?ets_insert(Store, {waiting_for_commit_ack, Node}) || Node <- WaitFor], rpc:abcast(DiscNs -- [node()], ?MODULE, {Tid, Outcome}), rpc:abcast(RamNs -- [node()], ?MODULE, {Tid, Outcome}), @@ -1451,7 +1451,7 @@ multi_commit(sync_sym_trans, _Maj = [], Tid, CR, Store) -> Outcome; multi_commit(asym_trans, Majority, Tid, CR, Store) -> - %% This more expensive commit protocol is used when + %% This more expensive commit protocol is used when %% table definitions are changed (schema transactions). %% It is also used when the involved tables are %% replicated asymetrically. If the storage type differs @@ -1462,14 +1462,14 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> %% commit record and votes yes or no depending of the %% outcome of the prepare. The preparation is also performed %% by the coordinator. - %% + %% %% 2a Somebody has died or voted no %% Tell all yes voters to do_abort %% 2b Everybody has voted yes %% Put a unclear marker in the log. %% Tell the others to pre_commit. I.e. that they should %% put a unclear marker in the log and reply - %% acc_pre_commit when they are done. + %% acc_pre_commit when they are done. %% %% 3a Somebody died %% Tell the remaining participants to do_abort @@ -1492,7 +1492,7 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> %% If we have no unclear marker in the log we may %% safely abort, since we know that nobody may have %% decided to commit yet. - %% + %% %% If we have a committed marker in the log we may %% safely commit since we know that everybody else %% also will come to this conclusion. @@ -1506,7 +1506,7 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> %% up. When all involved nodes are up and uncertain, %% we decide to commit (first put a committed marker %% in the log, then do the updates). - + D = #decision{tid = Tid, outcome = presume_abort}, {D2, CR2} = commit_decision(D, CR, [], []), DiscNs = D2#decision.disc_nodes, @@ -1518,10 +1518,10 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> Pending = mnesia_checkpoint:tm_enter_pending(Tid, DiscNs, RamNs), ?ets_insert(Store, Pending), {WaitFor, Local} = ask_commit(asym_trans, Tid, CR2, DiscNs, RamNs), - SchemaPrep = (catch mnesia_schema:prepare_commit(Tid, Local, {coord, WaitFor})), - {Votes, Pids} = rec_all(WaitFor, Tid, do_commit, []), - - ?eval_debug_fun({?MODULE, multi_commit_asym_got_votes}, + SchemaPrep = (catch mnesia_schema:prepare_commit(Tid, Local, {coord, WaitFor})), + {Votes, Pids} = rec_all(WaitFor, Tid, do_commit, []), + + ?eval_debug_fun({?MODULE, multi_commit_asym_got_votes}, [{tid, Tid}, {votes, Votes}]), case Votes of do_commit -> @@ -1530,20 +1530,20 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> mnesia_log:log(C), % C is not a binary ?eval_debug_fun({?MODULE, multi_commit_asym_log_commit_rec}, [{tid, Tid}]), - + D3 = C#commit.decision, - D4 = D3#decision{outcome = unclear}, - mnesia_recover:log_decision(D4), + D4 = D3#decision{outcome = unclear}, + mnesia_recover:log_decision(D4), ?eval_debug_fun({?MODULE, multi_commit_asym_log_commit_dec}, [{tid, Tid}]), tell_participants(Pids, {Tid, pre_commit}), %% Now we are uncertain and we do not know %% if all participants have logged that %% they are uncertain or not - rec_acc_pre_commit(Pids, Tid, Store, {C,Local}, + rec_acc_pre_commit(Pids, Tid, Store, {C,Local}, do_commit, DumperMode, [], []); {'EXIT', Reason} -> - %% The others have logged the commit + %% The others have logged the commit %% record but they are not uncertain mnesia_recover:note_decision(Tid, aborted), ?eval_debug_fun({?MODULE, multi_commit_asym_prepare_exit}, @@ -1564,7 +1564,7 @@ multi_commit(asym_trans, Majority, Tid, CR, Store) -> end. %% Returns do_commit or {do_abort, Reason} -rec_acc_pre_commit([Pid | Tail], Tid, Store, Commit, Res, DumperMode, +rec_acc_pre_commit([Pid | Tail], Tid, Store, Commit, Res, DumperMode, GoodPids, SchemaAckPids) -> receive {?MODULE, _, {acc_pre_commit, Tid, Pid, true}} -> @@ -1598,7 +1598,7 @@ rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, Sc %% everybody are uncertain. prepare_sync_schema_commit(Store, SchemaAckPids), tell_participants(GoodPids, {Tid, committed}), - D2 = D#decision{outcome = committed}, + D2 = D#decision{outcome = committed}, mnesia_recover:log_decision(D2), ?eval_debug_fun({?MODULE, rec_acc_pre_commit_log_commit}, [{tid, Tid}]), @@ -1611,10 +1611,10 @@ rec_acc_pre_commit([], Tid, Store, {Commit,OrigC}, Res, DumperMode, GoodPids, Sc sync_schema_commit(Tid, Store, SchemaAckPids), mnesia_locker:release_tid(Tid), ?MODULE ! {delete_transaction, Tid}; - + {do_abort, Reason} -> tell_participants(GoodPids, {Tid, {do_abort, Reason}}), - D2 = D#decision{outcome = aborted}, + D2 = D#decision{outcome = aborted}, mnesia_recover:log_decision(D2), ?eval_debug_fun({?MODULE, rec_acc_pre_commit_log_abort}, [{tid, Tid}]), @@ -1702,7 +1702,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> end, ?eval_debug_fun({?MODULE, commit_participant, do_commit}, [{tid, Tid}]); - + {Tid, {do_abort, _Reason}} -> mnesia_recover:log_decision(D#decision{outcome = aborted}), ?eval_debug_fun({?MODULE, commit_participant, log_abort}, @@ -1710,7 +1710,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> mnesia_schema:undo_prepare_commit(Tid, C0), ?eval_debug_fun({?MODULE, commit_participant, undo_prepare}, [{tid, Tid}]); - + {'EXIT', _, _} -> mnesia_recover:log_decision(D#decision{outcome = aborted}), ?eval_debug_fun({?MODULE, commit_participant, exit_log_abort}, @@ -1718,7 +1718,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> mnesia_schema:undo_prepare_commit(Tid, C0), ?eval_debug_fun({?MODULE, commit_participant, exit_undo_prepare}, [{tid, Tid}]); - + Msg -> verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n", [Tid, Msg]) @@ -1739,7 +1739,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n", [Tid, Msg]) end; - + {'EXIT', Reason} -> ?eval_debug_fun({?MODULE, commit_participant, vote_no}, [{tid, Tid}]), @@ -1750,7 +1750,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> ?MODULE ! {delete_transaction, Tid}, unlink(whereis(?MODULE)), exit(normal). - + do_abort(Tid, Bin) when is_binary(Bin) -> %% Possible optimization: %% If we want we could pass arround a flag @@ -1761,7 +1761,7 @@ do_abort(Tid, Bin) when is_binary(Bin) -> %% mnesia_schema:undo_prepare_commit/1. do_abort(Tid, binary_to_term(Bin)); do_abort(Tid, Commit) -> - mnesia_schema:undo_prepare_commit(Tid, Commit), + mnesia_schema:undo_prepare_commit(Tid, Commit), Commit. do_dirty(Tid, Commit) when Commit#commit.schema_ops == [] -> @@ -1799,7 +1799,7 @@ do_update(Tid, Storage, [Op | Ops], OldRes) -> verbose("do_update in ~w failed: ~p -> {'EXIT', ~p}~n", [Tid, Op, Reason]), - do_update(Tid, Storage, Ops, OldRes); + do_update(Tid, Storage, Ops, OldRes); NewRes -> do_update(Tid, Storage, Ops, NewRes) end; @@ -1807,7 +1807,7 @@ do_update(_Tid, _Storage, [], Res) -> Res. do_update_op(Tid, Storage, {{Tab, K}, Obj, write}) -> - commit_write(?catch_val({Tab, commit_work}), Tid, + commit_write(?catch_val({Tab, commit_work}), Tid, Tab, K, Obj, undefined), mnesia_lib:db_put(Storage, Tab, Obj); @@ -1816,7 +1816,7 @@ do_update_op(Tid, Storage, {{Tab, K}, Val, delete}) -> mnesia_lib:db_erase(Storage, Tab, K); do_update_op(Tid, Storage, {{Tab, K}, {RecName, Incr}, update_counter}) -> - {NewObj, OldObjs} = + {NewObj, OldObjs} = case catch mnesia_lib:db_update_counter(Storage, Tab, K, Incr) of NewVal when is_integer(NewVal), NewVal >= 0 -> {{RecName, K, NewVal}, [{RecName, K, NewVal - Incr}]}; @@ -1824,17 +1824,17 @@ do_update_op(Tid, Storage, {{Tab, K}, {RecName, Incr}, update_counter}) -> New = {RecName, K, Incr}, mnesia_lib:db_put(Storage, Tab, New), {New, []}; - _ -> + _ -> Zero = {RecName, K, 0}, mnesia_lib:db_put(Storage, Tab, Zero), {Zero, []} end, - commit_update(?catch_val({Tab, commit_work}), Tid, Tab, + commit_update(?catch_val({Tab, commit_work}), Tid, Tab, K, NewObj, OldObjs), element(3, NewObj); do_update_op(Tid, Storage, {{Tab, Key}, Obj, delete_object}) -> - commit_del_object(?catch_val({Tab, commit_work}), + commit_del_object(?catch_val({Tab, commit_work}), Tid, Tab, Key, Obj, undefined), mnesia_lib:db_match_erase(Storage, Tab, Obj); @@ -1846,11 +1846,11 @@ commit_write([], _, _, _, _, _) -> ok; commit_write([{checkpoints, CpList}|R], Tid, Tab, K, Obj, Old) -> mnesia_checkpoint:tm_retain(Tid, Tab, K, write, CpList), commit_write(R, Tid, Tab, K, Obj, Old); -commit_write([H|R], Tid, Tab, K, Obj, Old) +commit_write([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == subscribers -> mnesia_subscr:report_table_event(H, Tab, Tid, Obj, write, Old), commit_write(R, Tid, Tab, K, Obj, Old); -commit_write([H|R], Tid, Tab, K, Obj, Old) +commit_write([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == index -> mnesia_index:add_index(H, Tab, K, Obj, Old), commit_write(R, Tid, Tab, K, Obj, Old). @@ -1859,11 +1859,11 @@ commit_update([], _, _, _, _, _) -> ok; commit_update([{checkpoints, CpList}|R], Tid, Tab, K, Obj, _) -> Old = mnesia_checkpoint:tm_retain(Tid, Tab, K, write, CpList), commit_update(R, Tid, Tab, K, Obj, Old); -commit_update([H|R], Tid, Tab, K, Obj, Old) +commit_update([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == subscribers -> mnesia_subscr:report_table_event(H, Tab, Tid, Obj, write, Old), commit_update(R, Tid, Tab, K, Obj, Old); -commit_update([H|R], Tid, Tab, K, Obj, Old) +commit_update([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == index -> mnesia_index:add_index(H, Tab, K, Obj, Old), commit_update(R, Tid, Tab, K, Obj, Old). @@ -1872,11 +1872,11 @@ commit_delete([], _, _, _, _, _) -> ok; commit_delete([{checkpoints, CpList}|R], Tid, Tab, K, Obj, _) -> Old = mnesia_checkpoint:tm_retain(Tid, Tab, K, delete, CpList), commit_delete(R, Tid, Tab, K, Obj, Old); -commit_delete([H|R], Tid, Tab, K, Obj, Old) +commit_delete([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == subscribers -> mnesia_subscr:report_table_event(H, Tab, Tid, Obj, delete, Old), commit_delete(R, Tid, Tab, K, Obj, Old); -commit_delete([H|R], Tid, Tab, K, Obj, Old) +commit_delete([H|R], Tid, Tab, K, Obj, Old) when element(1, H) == index -> mnesia_index:delete_index(H, Tab, K), commit_delete(R, Tid, Tab, K, Obj, Old). @@ -1885,12 +1885,12 @@ commit_del_object([], _, _, _, _, _) -> ok; commit_del_object([{checkpoints, CpList}|R], Tid, Tab, K, Obj, _) -> Old = mnesia_checkpoint:tm_retain(Tid, Tab, K, delete_object, CpList), commit_del_object(R, Tid, Tab, K, Obj, Old); -commit_del_object([H|R], Tid, Tab, K, Obj, Old) - when element(1, H) == subscribers -> +commit_del_object([H|R], Tid, Tab, K, Obj, Old) + when element(1, H) == subscribers -> mnesia_subscr:report_table_event(H, Tab, Tid, Obj, delete_object, Old), commit_del_object(R, Tid, Tab, K, Obj, Old); -commit_del_object([H|R], Tid, Tab, K, Obj, Old) - when element(1, H) == index -> +commit_del_object([H|R], Tid, Tab, K, Obj, Old) + when element(1, H) == index -> mnesia_index:del_object_index(H, Tab, K, Obj, Old), commit_del_object(R, Tid, Tab, K, Obj, Old). @@ -1898,11 +1898,11 @@ commit_clear([], _, _, _, _) -> ok; commit_clear([{checkpoints, CpList}|R], Tid, Tab, K, Obj) -> mnesia_checkpoint:tm_retain(Tid, Tab, K, clear_table, CpList), commit_clear(R, Tid, Tab, K, Obj); -commit_clear([H|R], Tid, Tab, K, Obj) +commit_clear([H|R], Tid, Tab, K, Obj) when element(1, H) == subscribers -> mnesia_subscr:report_table_event(H, Tab, Tid, Obj, clear_table, undefined), commit_clear(R, Tid, Tab, K, Obj); -commit_clear([H|R], Tid, Tab, K, Obj) +commit_clear([H|R], Tid, Tab, K, Obj) when element(1, H) == index -> mnesia_index:clear_index(H, Tab, K, Obj), commit_clear(R, Tid, Tab, K, Obj). @@ -1913,7 +1913,7 @@ do_snmp(Tid, [Head | Tail]) -> {'EXIT', Reason} -> %% This should only happen when we recently have %% deleted our local replica or recently deattached - %% the snmp table + %% the snmp table verbose("do_snmp in ~w failed: ~p -> {'EXIT', ~p}~n", [Tid, Head, Reason]); @@ -1922,7 +1922,7 @@ do_snmp(Tid, [Head | Tail]) -> end, do_snmp(Tid, Tail). -commit_nodes([C | Tail], AccD, AccR) +commit_nodes([C | Tail], AccD, AccR) when C#commit.disc_copies == [], C#commit.disc_only_copies == [], C#commit.schema_ops == [] -> @@ -1934,7 +1934,7 @@ commit_nodes([], AccD, AccR) -> commit_decision(D, [C | Tail], AccD, AccR) -> N = C#commit.node, - {D2, Tail2} = + {D2, Tail2} = case C#commit.schema_ops of [] when C#commit.disc_copies == [], C#commit.disc_only_copies == [] -> @@ -1954,8 +1954,8 @@ commit_decision(D, [], AccD, AccR) -> {D#decision{disc_nodes = AccD, ram_nodes = AccR}, []}. ram_only_ops(N, [{op, change_table_copy_type, N, _FromS, _ToS, Cs} | _Ops ]) -> - case lists:member({name, schema}, Cs) of - true -> + case lists:member({name, schema}, Cs) of + true -> %% We always use disk if change type of the schema false; false -> @@ -2025,12 +2025,12 @@ get_dirty_reply(Node, Res) -> Reply; {mnesia_down, Node} -> case get(mnesia_activity_state) of - {_, Tid, _Ts} when element(1,Tid) == tid -> + {_, Tid, _Ts} when element(1,Tid) == tid -> %% Hmm dirty called inside a transaction, to avoid %% hanging transaction we need to restart the transaction mnesia:abort({node_not_running, Node}); _ -> - %% It's ok to ignore mnesia_down's since we will make + %% It's ok to ignore mnesia_down's since we will make %% the replicas consistent again when Node is started Res end @@ -2068,10 +2068,10 @@ ask_commit(_Protocol, _Tid, [], _DiscNs, _RamNs, WaitFor, Local) -> %% to be safe we let erts do the translation (many times maybe and thus %% slower but it works. % opt_term_to_binary(asym_trans, Head, Nodes) -> -% opt_term_to_binary(Nodes, Head); +% opt_term_to_binary(Nodes, Head); opt_term_to_binary(_Protocol, Head, _Nodes) -> Head. - + rec_all([Node | Tail], Tid, Res, Pids) -> receive {?MODULE, Node, {vote_yes, Tid}} -> @@ -2085,7 +2085,7 @@ rec_all([Node | Tail], Tid, Res, Pids) -> {?MODULE, Node, {aborted, Tid}} -> rec_all(Tail, Tid, Res, Pids); - {mnesia_down, Node} -> + {mnesia_down, Node} -> %% Make sure that mnesia_tm knows it has died %% it may have been restarted Abort = {do_abort, {bad_commit, Node}}, @@ -2095,7 +2095,7 @@ rec_all([Node | Tail], Tid, Res, Pids) -> rec_all([], _Tid, Res, Pids) -> {Res, Pids}. -get_transactions() -> +get_transactions() -> {info, Participant, Coordinator} = req(info), lists:map(fun({Tid, _Tabs}) -> Status = tr_status(Tid,Participant), @@ -2125,7 +2125,7 @@ get_info(Timeout) -> display_info(Stream, {timeout, T}) -> io:format(Stream, "---> No info about coordinator and participant transactions, " "timeout ~p <--- ~n", [T]); - + display_info(Stream, {info, Part, Coord}) -> io:format(Stream, "---> Participant transactions <--- ~n", []), lists:foreach(fun(P) -> pr_participant(Stream, P) end, Part), @@ -2134,7 +2134,7 @@ display_info(Stream, {info, Part, Coord}) -> pr_participant(Stream, P) -> Commit0 = P#participant.commit, - Commit = + Commit = if is_binary(Commit0) -> binary_to_term(Commit0); true -> Commit0 @@ -2161,11 +2161,11 @@ search_pr_coordinator(S, [{Tid, _Ts}|Tail]) -> io:format( "Tid is coordinator, owner == \n", []), display_pid_info(Tid#tid.pid), search_pr_coordinator(S, Tail); - _ -> + _ -> search_pr_coordinator(S, Tail) end. -search_pr_participant(_S, []) -> +search_pr_participant(_S, []) -> false; search_pr_participant(S, [ P | Tail]) -> Tid = P#participant.tid, @@ -2176,15 +2176,15 @@ search_pr_participant(S, [ P | Tail]) -> Pid = Tid#tid.pid, display_pid_info(Pid), io:format( "Tid wants to write objects \n",[]), - Commit = + Commit = if is_binary(Commit0) -> binary_to_term(Commit0); true -> Commit0 end, - + io:format("~p~n", [Commit]), search_pr_participant(S,Tail); %% !!!!! - true -> + true -> search_pr_participant(S, Tail) end. @@ -2200,7 +2200,7 @@ display_pid_info(Pid) -> Other -> Other end, - Reds = fetch(reductions, Info), + Reds = fetch(reductions, Info), LM = length(fetch(messages, Info)), pformat(io_lib:format("~p", [Pid]), io_lib:format("~p", [Call]), @@ -2254,7 +2254,7 @@ send_to_pids([_ | Pids], Msg) -> send_to_pids(Pids, Msg); send_to_pids([], _Msg) -> ok. - + reconfigure_participants(N, [P | Tail]) -> case lists:member(N, P#participant.disc_nodes) or lists:member(N, P#participant.ram_nodes) of @@ -2262,25 +2262,25 @@ reconfigure_participants(N, [P | Tail]) -> %% Ignore, since we are not a participant %% in the transaction. reconfigure_participants(N, Tail); - + true -> %% We are on a participant node, lets %% check if the dead one was a %% participant or a coordinator. Tid = P#participant.tid, - if + if node(Tid#tid.pid) /= N -> %% Another participant node died. Ignore. reconfigure_participants(N, Tail); true -> - %% The coordinator node has died and + %% The coordinator node has died and %% we must determine the outcome of the %% transaction and tell mnesia_tm on all %% nodes (including the local node) about it verbose("Coordinator ~p in transaction ~p died~n", [Tid#tid.pid, Tid]), - + Nodes = P#participant.disc_nodes ++ P#participant.ram_nodes, AliveNodes = Nodes -- [N], @@ -2332,8 +2332,8 @@ system_terminate(_Reason, _Parent, _Debug, State) -> system_code_change(State=#state{coordinators=Cs0,participants=Ps0},_Module,_OldVsn,downgrade) -> case is_tuple(Cs0) of - true -> - Cs = gb_trees:to_list(Cs0), + true -> + Cs = gb_trees:to_list(Cs0), Ps = gb_trees:values(Ps0), {ok, State#state{coordinators=Cs,participants=Ps}}; false -> @@ -2342,7 +2342,7 @@ system_code_change(State=#state{coordinators=Cs0,participants=Ps0},_Module,_OldV system_code_change(State=#state{coordinators=Cs0,participants=Ps0},_Module,_OldVsn,_Extra) -> case is_list(Cs0) of - true -> + true -> Cs = gb_trees:from_orddict(lists:sort(Cs0)), Ps1 = [{P#participant.tid,P}|| P <- Ps0], Ps = gb_trees:from_orddict(lists:sort(Ps1)), diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl index cf878fc820..06c4d16d71 100644 --- a/lib/mnesia/test/mnesia_atomicity_test.erl +++ b/lib/mnesia/test/mnesia_atomicity_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,13 +31,13 @@ end_per_testcase(Func, Conf) -> mnesia_test_lib:end_per_testcase(Func, Conf). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -all() -> +all() -> [explicit_abort_in_middle_of_trans, runtime_error_in_middle_of_trans, kill_self_in_middle_of_trans, throw_in_middle_of_trans, {group, mnesia_down_in_middle_of_trans}]. -groups() -> +groups() -> [{mnesia_down_in_middle_of_trans, [], [mnesia_down_during_infinite_trans, {group, lock_waiter}, {group, restart_check}]}, @@ -297,7 +297,7 @@ mnesia_down_during_infinite_trans(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write({Tab, 1, test_ok}) end)), mnesia_test_lib:start_sync_transactions([A2, A1]), - + %% Obtain a write lock and wait forever RecA = {Tab, 1, test_not_ok}, A1 ! fun() -> mnesia:write(RecA) end, @@ -471,12 +471,12 @@ lock_waiter_w_wt(Config) when is_list(Config) -> start_lock_waiter(BlockOpA, BlockOpB, Config) -> [N1, N2] = Nodes = ?acquire_nodes(2, Config), - + TabName = mk_tab_name(lock_waiter_), ?match({atomic, ok}, mnesia:create_table(TabName, [{ram_copies, [N1, N2]}])), - - %% initialize the table with object {1, c} - when there + + %% initialize the table with object {1, c} - when there %% is a read transaction, the read will find that value ?match({atomic, ok}, mnesia:sync_transaction(fun() -> mnesia:write({TabName, 1, c}) end)), rpc:call(N2, ?MODULE, sync_tid_release, []), @@ -484,7 +484,7 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> Tester = self(), Fun_A =fun() -> NewCounter = incr_restart_counter(), - if + if NewCounter == 1 -> Tester ! go_ahead_test, receive go_ahead -> ok end; @@ -493,13 +493,13 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> lock_waiter_fun(BlockOpA, TabName, a), NewCounter end, - + %% it's not possible to just spawn the transaction, because %% the result shall be evaluated A = spawn_link(N1, ?MODULE, perform_restarted_transaction, [Fun_A]), - + ?match(ok, receive go_ahead_test -> ok after 10000 -> timeout end), - + mnesia_test_lib:sync_trans_tid_serial([N1, N2]), Fun_B = fun() -> @@ -507,21 +507,21 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> A ! go_ahead, wait(infinity) end, - + B = spawn_link(N2, mnesia, transaction, [Fun_B, 100]), - + io:format("waiting for A (~p on ~p) to be in the queue ~n", [A, [N1, N2]]), wait_for_a(A, [N1, N2]), - - io:format("Queus ~p~n", + + io:format("Queus ~p~n", [[{N,rpc:call(N, mnesia, system_info, [lock_queue])} || N <- Nodes]]), - + KillNode = node(B), io:format("A was in the queue, time to kill Mnesia on B's node (~p on ~p)~n", [B, KillNode]), - + mnesia_test_lib:kill_mnesia([KillNode]), % kill mnesia of fun B - + %% Read Ops does not need to be restarted ExpectedCounter = if @@ -535,20 +535,22 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) -> BlockOpA == rt, BlockOpB /= sw -> 1; true -> 2 end, - ?match_multi_receive([{'EXIT', A, {atomic, ExpectedCounter}}, - {'EXIT', B, killed}]), - + receive {'EXIT', B, _} -> ok + after 3000 -> ?error("Timeout~n", []) end, + receive {'EXIT', A, Exp1} -> ?match({atomic, ExpectedCounter}, Exp1) + after 3000 -> ?error("Timeout~n", []) end, + %% the expected result depends on the transaction of %% fun A - when that doesn't change the object in the %% table (e.g. it is a read) then the predefined %% value {Tabname, 1, c} is expected to be the result here - ExpectedResult = + ExpectedResult = case BlockOpA of w -> {TabName, 1, a}; sw ->{TabName, 1, a}; _all_other -> {TabName, 1, c} end, - + ?match({atomic, [ExpectedResult]}, mnesia:transaction(fun() -> mnesia:read({TabName, 1}) end, 100)), ?verify_mnesia([N1], [N2]). @@ -567,7 +569,7 @@ lock_waiter_fun(Op, TabName, Val) -> srw -> mnesia:read(TabName, 1, sticky_write); sw -> mnesia:s_write({TabName, 1, Val}) end. - + wait_for_a(Pid, Nodes) -> wait_for_a(Pid, Nodes, 5). @@ -589,12 +591,12 @@ check_q(Pid, [_ | Tail], N, Count) -> check_q(Pid, [], N, Count) -> timer:sleep(500), wait_for_a(Pid, N, Count - 1). - + perform_restarted_transaction (Fun_Trans) -> %% the result of the transaction shall be: %% - undefined (if the transaction was never executed) %% - Times ( number of times that the transaction has been executed) - + Result = mnesia:transaction(Fun_Trans, 100), exit(Result). @@ -666,10 +668,10 @@ restart_sw_two(Config) when is_list(Config) -> start_restart_check(RestartOp, ReplicaNeed, Config) -> [N1, N2, N3] = Nodes = ?acquire_nodes(3, Config), - + {TabName, _TabNodes} = create_restart_table(ReplicaNeed, Nodes), - - %% initialize the table with object {1, c} - when there + + %% initialize the table with object {1, c} - when there %% is a read transaction, the read will find that value ?match({atomic, ok}, mnesia:sync_transaction(fun() -> mnesia:write({TabName, 1, c}) end)), @@ -681,9 +683,9 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> NewCounter = incr_restart_counter(), case NewCounter of 1 -> - mnesia:write({TabName, 1, d}), + mnesia:write({TabName, 1, d}), %% send a message to the test proc - Coord ! {self(),fun_a_is_blocked}, + Coord ! {self(),fun_a_is_blocked}, receive go_ahead -> ok end; _ -> %% the fun will NOT be blocked here @@ -691,19 +693,19 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> end, NewCounter end, - + A = spawn_link(N1, ?MODULE, perform_restarted_transaction, [Fun_A]), - ?match_receive({A,fun_a_is_blocked}), - + ?match_receive({A,fun_a_is_blocked}), + %% mnesia shall be killed at that node, where A is reading %% the information from kill_where_to_read(TabName, N1, [N2, N3]), - + %% wait some time to let mnesia go down and spread those news around %% fun A shall be able to finish its job before being restarted - wait(500), + wait(500), A ! go_ahead, - + %% the sticky write doesnt work on remote nodes !!! ExpectedMsg = case RestartOp of @@ -717,19 +719,19 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> {'EXIT',A,{atomic, 2}} end end, - - ?match_receive(ExpectedMsg), - + + ?match_receive(ExpectedMsg), + %% now mnesia has to be started again on the node KillNode %% because the next test suite will need it ?match([], mnesia_test_lib:start_mnesia(Nodes, [TabName])), - - + + %% the expected result depends on the transaction of %% fun A - when that doesnt change the object in the %% table (e.g. it is a read) then the predefined %% value {Tabname, 1, c} is expected to be the result here - + ExpectedResult = case ReplicaNeed of one -> @@ -746,7 +748,7 @@ start_restart_check(RestartOp, ReplicaNeed, Config) -> ?verify_mnesia(Nodes, []). create_restart_table(ReplicaNeed, [_N1, N2, N3]) -> - TabNodes = + TabNodes = case ReplicaNeed of one -> [N2]; two -> [N2, N3] @@ -754,7 +756,7 @@ create_restart_table(ReplicaNeed, [_N1, N2, N3]) -> TabName = mk_tab_name(restart_check_), ?match({atomic, ok}, mnesia:create_table(TabName, [{ram_copies, TabNodes}])), {TabName, TabNodes}. - + restart_fun_A(Op, TabName) -> case Op of rt -> mnesia:read_lock_table(TabName); @@ -774,8 +776,8 @@ kill_where_to_read(TabName, N1, Nodes) -> ?error("Fault while killing Mnesia: ~p~n", [Read]), mnesia_test_lib:kill_mnesia(Nodes) end. - -sync_tid_release() -> + +sync_tid_release() -> sys:get_status(whereis(mnesia_tm)), sys:get_status(whereis(mnesia_locker)), ok. diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 17d6c6c212..64b61288ef 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -37,7 +37,8 @@ end_per_testcase(Func, Conf) -> all() -> [system_info, table_info, error_description, db_node_lifecycle, evil_delete_db_node, start_and_stop, - checkpoint, table_lifecycle, add_copy_conflict, + checkpoint, table_lifecycle, storage_options, + add_copy_conflict, add_copy_when_going_down, replica_management, schema_availability, local_content, {group, table_access_modifications}, replica_location, @@ -244,7 +245,7 @@ db_node_lifecycle(Config) when is_list(Config) -> ?match([], mnesia_test_lib:start_mnesia(AllNodes)), ?match([SNs, SNs, SNs], - lists:map({lists, sort}, + lists:map(fun lists:sort/1, element(1, rpc:multicall(AllNodes, mnesia, table_info, [schema, disc_copies])))), @@ -259,7 +260,7 @@ db_node_lifecycle(Config) when is_list(Config) -> mnesia:change_table_copy_type(schema, Node2, disc_copies)), ?match([SNs, SNs, SNs], - lists:map({lists, sort}, + lists:map(fun lists:sort/1, element(1, rpc:multicall(AllNodes, mnesia, table_info, [schema, disc_copies])))), @@ -462,7 +463,7 @@ table_lifecycle(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:create_table([{name, already_exists}, {ram_copies, [Node1]}])), ?match({aborted, Reason23 } when element(1, Reason23) ==already_exists, - mnesia:create_table([{name, already_exists}, + mnesia:create_table([{name, already_exists}, {ram_copies, [Node1]}])), ?match({aborted, Reason21 } when element(1, Reason21) == bad_type, mnesia:create_table([{name, bad_node}, {ram_copies, ["foo"]}])), @@ -520,12 +521,57 @@ table_lifecycle(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:create_table([{name, create_with_index}, {index, [3]}, {ram_copies, [Node1]}])), - ets:new(ets_table, [named_table]), + ets:new(ets_table, [named_table]), ?match({aborted, _}, mnesia:create_table(ets_table, [{ram_copies, Nodes}])), + ?match({aborted, _}, mnesia:create_table(ets_table, [{ram_copies, [Node1]}])), + ets:delete(ets_table), + ?match({atomic, ok}, mnesia:create_table(ets_table, [{ram_copies, [Node1]}])), + ?match(Node1, rpc:call(Node1, mnesia_lib, val, [{ets_table,where_to_read}])), + ?match(Node1, rpc:call(Node2, mnesia_lib, val, [{ets_table,where_to_read}])), + ?match({atomic, ok}, mnesia:change_table_copy_type(ets_table, Node1, disc_only_copies)), + ?match(Node1, rpc:call(Node2, mnesia_lib, val, [{ets_table,where_to_read}])), + + ?verify_mnesia(Nodes, []). + + +storage_options(suite) -> []; +storage_options(Config) when is_list(Config) -> + [N1,N2,N3] = Nodes = ?acquire_nodes(3, Config), + + ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,foobar}]}])), + ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,[foobar]}]}])), + ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,[duplicate_bag]}]}])), + ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{dets,[{type,bag}]}]}])), + + ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [N1]}, + {disc_only_copies, [N2]}, + {storage_properties, + [{ets,[compressed]}, + {dets, [{auto_save, 5000}]} ]}])), + ?match(true, ets:info(a, compressed)), + ?match(5000, rpc:call(N2, dets, info, [a, auto_save])), + ?match(ok, mnesia:dirty_write({a,1,1})), + ?match([{a,1,1}], mnesia:dirty_read({a,1})), + mnesia:dump_log(), + W2C1 = [{N2, disc_only_copies}, {N1, ram_copies}], + ?match(W2C1, lists:sort(rpc:call(N2, mnesia_lib, val, [{a, where_to_commit}]))), + ?match(W2C1, lists:sort(rpc:call(N3, mnesia_lib, val, [{a, where_to_commit}]))), + ?match({atomic,ok}, mnesia:change_table_copy_type(a, N1, disc_only_copies)), + W2C2 = [{N2, disc_only_copies}, {N1, disc_only_copies}], + ?match(W2C2, lists:sort(rpc:call(N2, mnesia_lib, val, [{a, where_to_commit}]))), + ?match(W2C2, lists:sort(rpc:call(N3, mnesia_lib, val, [{a, where_to_commit}]))), + ?match(undefined, ets:info(a, compressed)), + ?match(5000, dets:info(a, auto_save)), + ?match({atomic,ok}, mnesia:change_table_copy_type(a, N1, disc_copies)), + ?match(true, ets:info(a, compressed)), ?verify_mnesia(Nodes, []). + + + + add_copy_conflict(suite) -> []; add_copy_conflict(doc) -> ["Verify that OTP-5065 doesn't happen again, whitebox testing"]; diff --git a/lib/mnesia/test/mnesia_frag_hash_test.erl b/lib/mnesia/test/mnesia_frag_hash_test.erl new file mode 100644 index 0000000000..095d25e74f --- /dev/null +++ b/lib/mnesia/test/mnesia_frag_hash_test.erl @@ -0,0 +1,94 @@ +-module(mnesia_frag_hash_test). + +-export([test/0]). + +-define(NUM_FRAGS, 20). +-define(NUM_KEYS, 10000). + +-record(hash_state, + {n_fragments, + next_n_to_split, + n_doubles, + function}). + +% OLD mnesia_frag_hash:key_to_frag_number/2. +old_key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) -> + P = SplitN, + A = erlang:phash(Key, power2(L)), + if + A < P -> + erlang:phash(Key, power2(L + 1)); + true -> + A + end; +old_key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) -> + P = SplitN, + A = erlang:phash2(Key, power2(L)) + 1, + if + A < P -> + erlang:phash2(Key, power2(L + 1)) + 1; + true -> + A + end; +old_key_to_frag_number(OldState, Key) -> + State = convert_old_state(OldState), + old_key_to_frag_number(State, Key). + + +% NEW mnesia_frag_hash:key_to_frag_number/2. +new_key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash(Key, power2(L + 1)), + if + A > N -> + A - power2(L); + true -> + A + end; +new_key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) -> + A = erlang:phash2(Key, power2(L + 1)) + 1, + if + A > N -> + A - power2(L); + true -> + A + end; +new_key_to_frag_number(OldState, Key) -> + State = convert_old_state(OldState), + new_key_to_frag_number(State, Key). + + +% Helpers for key_to_frag_number functions. + +power2(Y) -> + 1 bsl Y. % trunc(math:pow(2, Y)). + +convert_old_state({hash_state, N, P, L}) -> + #hash_state{n_fragments = N, + next_n_to_split = P, + n_doubles = L, + function = phash}. + + +test() -> + test2(mnesia_frag_hash:init_state(undefined, undefined)), % phash2 + test2({hash_state, 1, 1, 0}). % phash + +test2(I) -> + test_keys(I), + lists:foldl( + fun(_, S) -> test_frag(S) end, + I, lists:seq(1, ?NUM_FRAGS)), + ok. + +test_frag(State) -> + {State2,_,_} = mnesia_frag_hash:add_frag(State), + test_keys(State2), + State2. + +test_keys(State) -> + [test_key(State, Key) || Key <- lists:seq(1, ?NUM_KEYS)]. + +test_key(State, Key) -> + Old = old_key_to_frag_number(State, Key), + New = new_key_to_frag_number(State, Key), + Old = New. diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl index 3a2d44aa95..06d53d3912 100644 --- a/lib/mnesia/test/mnesia_install_test.erl +++ b/lib/mnesia/test/mnesia_install_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index 9da45975d5..ba5bf84e24 100644 --- a/lib/mnesia/test/mnesia_test_lib.erl +++ b/lib/mnesia/test/mnesia_test_lib.erl @@ -99,7 +99,7 @@ slave_start_link/0, slave_start_link/1, slave_sup/0, - + start_mnesia/1, start_mnesia/2, start_appls/2, @@ -131,7 +131,7 @@ struct/1, init_per_testcase/2, end_per_testcase/2, - kill_tc/2 + kill_tc/2 ]). -include("mnesia_test_lib.hrl"). @@ -187,7 +187,7 @@ verbose(Format, Args, File, Line) -> ok end end. - + -record('REASON', {file, line, desc}). error(Format, Args, File, Line) -> @@ -196,9 +196,9 @@ error(Format, Args, File, Line) -> line = Line, desc = Args}, case global:whereis_name(mnesia_test_case_sup) of - undefined -> + undefined -> ignore; - Pid -> + Pid -> Pid ! Fail %% global:send(mnesia_test_case_sup, Fail), end, @@ -217,7 +217,7 @@ storage_type(Default, Config) -> default_config() -> [{nodes, default_nodes()}]. -default_nodes() -> +default_nodes() -> mk_nodes(3, []). mk_nodes(0, Nodes) -> @@ -231,7 +231,7 @@ mk_nodes(N, Nodes) when N > 0 -> mk_node(N, Name, Host) -> list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). - + slave_start_link() -> slave_start_link(node()). @@ -247,11 +247,11 @@ slave_start_link(Host, Name) -> slave_start_link(Host, Name, Retries) -> Debug = atom_to_list(mnesia:system_info(debug)), - Args = "-mnesia debug " ++ Debug ++ + Args = "-mnesia debug " ++ Debug ++ + " -pa " ++ + filename:dirname(code:which(?MODULE)) ++ " -pa " ++ - filename:dirname(code:which(?MODULE)) ++ - " -pa " ++ - filename:dirname(code:which(mnesia)), + filename:dirname(code:which(mnesia)), case starter(Host, Name, Args) of {ok, NewNode} -> ?match(pong, net_adm:ping(NewNode)), @@ -264,8 +264,8 @@ slave_start_link(Host, Name, Retries) -> {ok, NewNode}; {error, Reason} when Retries == 0-> {error, Reason}; - {error, Reason} -> - io:format("Could not start slavenode ~p ~p retrying~n", + {error, Reason} -> + io:format("Could not start slavenode ~p ~p retrying~n", [{Host, Name, Args}, Reason]), timer:sleep(500), slave_start_link(Host, Name, Retries - 1) @@ -284,7 +284,7 @@ starter(Host, Name, Args) -> slave_sup() -> process_flag(trap_exit, true), receive - {'EXIT', _, _} -> + {'EXIT', _, _} -> case os:type() of vxworks -> erlang:halt(); @@ -292,7 +292,7 @@ slave_sup() -> ignore end end. - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Index the test case structure @@ -305,7 +305,7 @@ doc(TestCases) when is_list(TestCases) -> io:format(Fd, "<TITLE>Test specification for ~p</TITLE>.~n", [TestCases]), io:format(Fd, "<H1>Test specification for ~p</H1>~n", [TestCases]), io:format(Fd, "Test cases which not are implemented yet are written in <B>bold face</B>.~n~n", []), - + io:format(Fd, "<BR><BR>~n", []), io:format(Fd, "~n<DL>~n", []), do_doc(Fd, TestCases, []), @@ -349,7 +349,7 @@ do_doc(Fd, Module, TestCase, List) -> print_doc(Fd, Mod, Fun, Head) -> case catch (apply(Mod, Fun, [doc])) of - {'EXIT', _} -> + {'EXIT', _} -> io:format(Fd, "<DT>~s</DT>~n", [Head]); Doc when is_list(Doc) -> io:format(Fd, "<DT><U>~s</U><BR><DD>~n", [Head]), @@ -428,10 +428,10 @@ test_driver({Module, TestCase}, Config) -> _ -> log("Eval test case: ~w~n", [{Module, TestCase}]), try timer:tc(?MODULE, eval_test_case, [Module, TestCase, Config]) of - {T, Res} -> + {T, Res} -> log("Tested ~w in ~w sec~n", [TestCase, T div Sec]), {T div Sec, Res} - catch error:function_clause -> + catch error:function_clause -> log("<WARNING> Test case ~w NYI~n", [{Module, TestCase}]), {0, {skip, {Module, TestCase}, "NYI"}} end @@ -472,13 +472,13 @@ get_suite(Module, TestCase, Config) -> %% Returns a list (possibly empty) or the atom 'NYI' get_suite(Mod, {group, Suite}) -> - try + try Groups = Mod:groups(), {_, _, TCList} = lists:keyfind(Suite, 1, Groups), TCList catch _:Reason -> - io:format("Not implemented ~p ~p (~p ~p)~n", + io:format("Not implemented ~p ~p (~p ~p)~n", [Mod,Suite,Reason, erlang:get_stacktrace()]), 'NYI' end; @@ -487,7 +487,7 @@ get_suite(Mod, all) -> {'EXIT', _} -> 'NYI'; List when is_list(List) -> List end; -get_suite(_Mod, _Fun) -> +get_suite(_Mod, _Fun) -> []. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -511,7 +511,7 @@ wait_for_evaluator(Pid, Mod, Fun, Config) -> receive {'EXIT', Pid, {test_case_ok, _PidRes}} -> Errors = flush(), - Res = + Res = case Errors of [] -> ok; Errors -> failed @@ -531,7 +531,7 @@ wait_for_evaluator(Pid, Mod, Fun, Config) -> test_case_evaluator(Mod, Fun, [Config]) -> NewConfig = Mod:init_per_testcase(Fun, Config), - try + try R = apply(Mod, Fun, [NewConfig]), Mod:end_per_testcase(Fun, NewConfig), exit({test_case_ok, R}) @@ -588,7 +588,7 @@ mapl(_Fun, []) -> diskless(Config) -> case lists:keysearch(diskless, 1, Config) of - {value, {diskless, true}} -> + {value, {diskless, true}} -> true; _Else -> false @@ -634,7 +634,7 @@ sync_trans_tid_serial(Nodes) -> select_nodes(N, Config, File, Line) -> prepare_test_case([], N, Config, File, Line). - + prepare_test_case(Actions, N, Config, File, Line) -> NodeList1 = lookup_config(nodes, Config), NodeList2 = lookup_config(nodenames, Config), %% For testserver @@ -666,10 +666,10 @@ do_prepare([delete_schema | Actions], Selected, All, Config, File, Line) -> true -> skip; false -> - Del = fun(Node) -> + Del = fun(Node) -> case mnesia:delete_schema([Node]) of ok -> ok; - {error, {"All nodes not running",_}} -> + {error, {"All nodes not running",_}} -> ok; Else -> ?log("Delete schema error ~p ~n", [Else]) @@ -680,7 +680,7 @@ do_prepare([delete_schema | Actions], Selected, All, Config, File, Line) -> do_prepare(Actions, Selected, All, Config, File, Line); do_prepare([create_schema | Actions], Selected, All, Config, File, Line) -> case diskless(Config) of - true -> + true -> skip; _Else -> case mnesia:create_schema(Selected) of @@ -705,12 +705,12 @@ set_kill_timer(Config) -> case init:get_argument(mnesia_test_timeout) of {ok, _ } -> ok; _ -> - Time0 = + Time0 = case lookup_config(tc_timeout, Config) of [] -> timer:minutes(5); ConfigTime when is_integer(ConfigTime) -> ConfigTime end, - Mul = try + Mul = try test_server:timetrap_scale_factor() catch _:_ -> 1 end, (catch test_server:timetrap(Mul*Time0 + 1000)), @@ -718,7 +718,7 @@ set_kill_timer(Config) -> end. kill_tc(Pid, Time) -> - receive + receive after Time -> case process_info(Pid) of undefined -> ok; @@ -739,10 +739,10 @@ kill_tc(Pid, Time) -> exit(Pid, kill) end end. - + append_unique([], List) -> List; -append_unique([H|R], List) -> +append_unique([H|R], List) -> case lists:member(H, List) of true -> append_unique(R, List); false -> [H | append_unique(R, List)] @@ -751,13 +751,13 @@ append_unique([H|R], List) -> pick_nodes(all, Nodes, File, Line) -> pick_nodes(length(Nodes), Nodes, File, Line); pick_nodes(N, [H | T], File, Line) when N > 0 -> - [H | pick_nodes(N - 1, T, File, Line)]; + [H | pick_nodes(N - 1, T, File, Line)]; pick_nodes(0, _Nodes, _File, _Line) -> []; pick_nodes(N, [], File, Line) -> ?skip("Test case (~p(~p)) ignored: ~p nodes missing~n", [File, Line, N]). - + init_nodes([Node | Nodes], File, Line) -> case net_adm:ping(Node) of pong -> @@ -777,7 +777,7 @@ init_nodes([Node | Nodes], File, Line) -> init_nodes([], _File, _Line) -> []. -%% Returns [Name, Host] +%% Returns [Name, Host] node_to_name_and_host(Node) -> string:tokens(atom_to_list(Node), [$@]). @@ -793,7 +793,7 @@ lookup_config(Key,Config) -> start_appls(Appls, Nodes) -> start_appls(Appls, Nodes, [], [schema]). - + start_appls(Appls, Nodes, Config) -> start_appls(Appls, Nodes, Config, [schema]). @@ -815,9 +815,9 @@ start_appls([], _Nodes, _Config, _Tabs) -> remote_start(mnesia, Config, Nodes) -> case diskless(Config) of - true -> - application_controller:set_env(mnesia, - extra_db_nodes, + true -> + application_controller:set_env(mnesia, + extra_db_nodes, Nodes -- [node()]), application_controller:set_env(mnesia, schema_location, @@ -830,7 +830,7 @@ remote_start(mnesia, Config, Nodes) -> end, {node(), mnesia:start()}; remote_start(Appl, _Config, _Nodes) -> - Res = + Res = case application:start(Appl) of {error, {already_started, Appl}} -> ok; @@ -842,13 +842,13 @@ remote_start(Appl, _Config, _Nodes) -> %% Start Mnesia on all given nodes and wait for specified %% tables to be accessible on each node. The atom all means %% that we should wait for all tables to be loaded -%% +%% %% Returns a list of error tuples {BadNode, mnesia, Reason} start_mnesia(Nodes) -> start_appls([mnesia], Nodes). start_mnesia(Nodes, Tabs) when is_list(Nodes) -> start_appls([mnesia], Nodes, [], Tabs). - + %% Wait for the tables to be accessible from all nodes in the list %% and that all nodes are aware of that the other nodes also ... sync_tables(Nodes, Tabs) -> @@ -924,26 +924,26 @@ verify_nodes([Tab| Tabs], N) -> mnesia:table_info(Tab, ram_copies), Local = mnesia:table_info(Tab, local_content), case Copies -- Nodes of - [] -> + [] -> verify_nodes(Tabs, 0); _Else when Local == true, Nodes /= [] -> verify_nodes(Tabs, 0); Else -> - N2 = + N2 = if - N > 20 -> - log("<>WARNING<> ~w Waiting for table: ~p on ~p ~n", + N > 20 -> + log("<>WARNING<> ~w Waiting for table: ~p on ~p ~n", [node(), Tab, Else]), 0; true -> N+1 - end, + end, timer:sleep(500), verify_nodes([Tab| Tabs], N2) end. %% Nicely stop Mnesia on all given nodes -%% +%% %% Returns a list of error tuples {BadNode, Reason} stop_mnesia(Nodes) when is_list(Nodes) -> stop_appls([mnesia], Nodes). @@ -1047,7 +1047,7 @@ verify_replica_location(Tab, DiscOnly0, Ram0, Disc0, AliveNodes0) -> Read = ignore_dead(DiscOnly ++ Ram ++ Disc, AliveNodes), This = node(), - timer:sleep(100), + timer:sleep(100), S1 = ?match(AliveNodes, lists:sort(mnesia:system_info(running_db_nodes))), S2 = ?match(DiscOnly, lists:sort(mnesia:table_info(Tab, disc_only_copies))), @@ -1080,7 +1080,7 @@ do_remote_activate_debug_fun(From, I, F, C, File, Line) -> timer:sleep(infinity). % Dies whenever the test process dies !! -sort(L) when is_list(L) -> +sort(L) when is_list(L) -> lists:sort(L); sort({atomic, L}) when is_list(L) -> {atomic, lists:sort(L)}; diff --git a/lib/mnesia/test/mnesia_test_lib.hrl b/lib/mnesia/test/mnesia_test_lib.hrl index fc377dbd2c..281634c239 100644 --- a/lib/mnesia/test/mnesia_test_lib.hrl +++ b/lib/mnesia/test/mnesia_test_lib.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -112,7 +112,7 @@ -define(remote_deactivate_debug_fun(N, I), rpc:call(N, mnesia_lib, deactivate_debug_fun, [I, ?FILE, ?LINE])). --define(is_debug_compiled, +-define(is_debug_compiled, case mnesia_lib:is_debug_compiled() of false -> ?skip("Mnesia is not debug compiled, test case ignored.~n", []); @@ -120,7 +120,7 @@ ok end). --define(needs_disc(Config), +-define(needs_disc(Config), case mnesia_test_lib:diskless(Config) of false -> ok; @@ -128,5 +128,5 @@ ?skip("Must have disc, test case ignored.~n", []) end). --define(verify_mnesia(Ups, Downs), +-define(verify_mnesia(Ups, Downs), mnesia_test_lib:verify_mnesia(Ups, Downs, ?FILE, ?LINE)). diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl index ca3f0fbf49..c040d0ca3f 100644 --- a/lib/mnesia/test/mnesia_trans_access_test.erl +++ b/lib/mnesia/test/mnesia_trans_access_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% +%% %% Copyright Ericsson AB 1996-2011. All Rights Reserved. -%% +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -31,22 +31,22 @@ end_per_testcase(Func, Conf) -> -define(receive_messages(Msgs), mnesia_recovery_test:receive_messages(Msgs, ?FILE, ?LINE)). -% First Some debug logging +% First Some debug logging -define(dgb, true). -ifdef(dgb). -define(dl(X, Y), ?verbose("**TRACING: " ++ X ++ "**~n", Y)). --else. +-else. -define(dl(X, Y), ok). -endif. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -all() -> +all() -> [write, read, wread, delete, delete_object, match_object, select, select14, all_keys, transaction, {group, nested_activities}, {group, index_tabs}, {group, index_lifecycle}]. -groups() -> +groups() -> [{nested_activities, [], [basic_nested, {group, nested_transactions}, mix_of_nested_activities]}, @@ -80,128 +80,133 @@ end_per_group(_GroupName, Config) -> write(suite) -> []; write(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = write, - Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:write([]) end)), - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:write({Tab, 2}) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:write({foo, 2}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:write({Tab, 1, 2})), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = write, + Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:write([]) end)), + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:write({Tab, 2}) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:write({foo, 2}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:write({Tab, 1, 2})), ?verify_mnesia(Nodes, []). %% Read records read(suite) -> []; read(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = read, - Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - OneRec = {Tab, 1, 2}, - TwoRec = {Tab, 1, 3}, - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:read([]) end)), - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:read({Tab}) end)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = read, + Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + OneRec = {Tab, 1, 2}, + TwoRec = {Tab, 1, 3}, + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:read([]) end)), + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:read({Tab}) end)), ?match({aborted, {bad_type, _}} - , mnesia:transaction(fun() -> mnesia:read(OneRec) end)), - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, [OneRec]}, - mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), - ?match({atomic, [OneRec, TwoRec]}, - mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:read({Tab, 1})), + , mnesia:transaction(fun() -> mnesia:read(OneRec) end)), + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, [OneRec]}, + mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), + ?match({atomic, [OneRec, TwoRec]}, + mnesia:transaction(fun() -> mnesia:read({Tab, 1}) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:read({Tab, 1})), ?verify_mnesia(Nodes, []). %% Read records and set write lock wread(suite) -> []; wread(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = wread, - Schema = [{name, Tab}, {type, set}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - OneRec = {Tab, 1, 2}, - TwoRec = {Tab, 1, 3}, - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:wread([]) end)), - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:wread({Tab}) end)), + [_N1,N2] = Nodes = ?acquire_nodes(2, Config), + Tab = wread, + Schema = [{name, Tab}, {type, set}, {attributes, [k, v]}, {ram_copies, Nodes}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + OneRec = {Tab, 1, 2}, + TwoRec = {Tab, 1, 3}, + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:wread([]) end)), + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:wread({Tab}) end)), ?match({aborted, {bad_type, _}} - , mnesia:transaction(fun() -> mnesia:wread(OneRec) end)), - - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - - ?match({atomic, [OneRec]}, - mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), - ?match({atomic, [TwoRec]}, - mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:wread({Tab, 1})), + , mnesia:transaction(fun() -> mnesia:wread(OneRec) end)), + + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + + ?match({atomic, [OneRec]}, + mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), + ?match({atomic, [TwoRec]}, + mnesia:transaction(fun() -> mnesia:wread({Tab, 1}) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:wread({Tab, 1})), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Tab, {Tab, 42, a}, sticky_write) end)), + ?match({atomic, [{Tab,42, a}]}, + rpc:call(N2, mnesia, transaction, [fun() -> mnesia:wread({Tab, 42}) end])), ?verify_mnesia(Nodes, []). %% Delete record delete(suite) -> []; delete(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = delete, - Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:delete([]) end)), - ?match({aborted, {bad_type, _}}, - mnesia:transaction(fun() -> mnesia:delete({Tab}) end)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = delete, + Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:delete([]) end)), + ?match({aborted, {bad_type, _}}, + mnesia:transaction(fun() -> mnesia:delete({Tab}) end)), ?match({aborted, {bad_type, _}} - , mnesia:transaction(fun() -> mnesia:delete({Tab, 1, 2}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:delete({Tab, 1})), + , mnesia:transaction(fun() -> mnesia:delete({Tab, 1, 2}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 1, 2}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:delete({Tab, 1}) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:delete({Tab, 1})), ?verify_mnesia(Nodes, []). %% Delete matching record delete_object(suite) -> []; delete_object(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = delete_object, - Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = delete_object, + Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), - OneRec = {Tab, 1, 2}, + OneRec = {Tab, 1, 2}, ?match({aborted, {bad_type, _}}, mnesia:transaction(fun() -> mnesia:delete_object([]) end)), ?match({aborted, {bad_type, _}}, @@ -215,17 +220,17 @@ delete_object(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(OneRec) end)), ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, ok}, + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(OneRec) end)), - + ?match({'EXIT', {aborted, no_transaction}}, mnesia:delete_object(OneRec)), - ?match({aborted, {bad_type, Tab, _}}, + ?match({aborted, {bad_type, Tab, _}}, mnesia:transaction(fun() -> mnesia:delete_object({Tab, {['_']}, 21}) end)), - ?match({aborted, {bad_type, Tab, _}}, + ?match({aborted, {bad_type, Tab, _}}, mnesia:transaction(fun() -> mnesia:delete_object({Tab, {['$5']}, 21}) end)), ?verify_mnesia(Nodes, []). @@ -234,108 +239,108 @@ delete_object(Config) when is_list(Config) -> match_object(suite) -> []; match_object(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = match, - Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - OneRec = {Tab, 1, 2}, - OnePat = {Tab, '$1', 2}, - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:match_object(OnePat) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, [OneRec]}, - mnesia:transaction(fun() -> mnesia:match_object(OnePat) end)), - - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:match_object({foo, '$1', 2}) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:match_object({[], '$1', 2}) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:match_object(OnePat)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = match, + Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + OneRec = {Tab, 1, 2}, + OnePat = {Tab, '$1', 2}, + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:match_object(OnePat) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, [OneRec]}, + mnesia:transaction(fun() -> mnesia:match_object(OnePat) end)), + + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:match_object({foo, '$1', 2}) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:match_object({[], '$1', 2}) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:match_object(OnePat)), ?verify_mnesia(Nodes, []). %% select select(suite) -> []; select(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = match, - Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = match, + Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), - OneRec = {Tab, 1, 2}, - TwoRec = {Tab, 2, 3}, + OneRec = {Tab, 1, 2}, + TwoRec = {Tab, 2, 3}, OnePat = [{{Tab, '$1', 2}, [], ['$_']}], - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:select(Tab, OnePat) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), - ?match({atomic, [OneRec]}, - mnesia:transaction(fun() -> mnesia:select(Tab, OnePat) end)), - - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:select(Tab, {match, '$1', 2}) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:select(Tab, [{'_', [], '$1'}]) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:select(Tab, OnePat)), + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:select(Tab, OnePat) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), + ?match({atomic, [OneRec]}, + mnesia:transaction(fun() -> mnesia:select(Tab, OnePat) end)), + + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:select(Tab, {match, '$1', 2}) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:select(Tab, [{'_', [], '$1'}]) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:select(Tab, OnePat)), ?verify_mnesia(Nodes, []). %% more select select14(suite) -> []; select14(Config) when is_list(Config) -> - [Node1,Node2] = Nodes = ?acquire_nodes(2, Config), - Tab1 = select14_ets, - Tab2 = select14_dets, - Tab3 = select14_remote, - Tab4 = select14_remote_dets, - Schemas = [[{name, Tab1}, {attributes, [k, v]}, {ram_copies, [Node1]}], - [{name, Tab2}, {attributes, [k, v]}, {disc_only_copies, [Node1]}], + [Node1,Node2] = Nodes = ?acquire_nodes(2, Config), + Tab1 = select14_ets, + Tab2 = select14_dets, + Tab3 = select14_remote, + Tab4 = select14_remote_dets, + Schemas = [[{name, Tab1}, {attributes, [k, v]}, {ram_copies, [Node1]}], + [{name, Tab2}, {attributes, [k, v]}, {disc_only_copies, [Node1]}], [{name, Tab3}, {attributes, [k, v]}, {ram_copies, [Node2]}], - [{name, Tab4}, {attributes, [k, v]}, {disc_only_copies, [Node2]}]], + [{name, Tab4}, {attributes, [k, v]}, {disc_only_copies, [Node2]}]], [?match({atomic, ok}, mnesia:create_table(Schema)) || Schema <- Schemas], %% Some Helpers Trans = fun(Fun) -> mnesia:transaction(Fun) end, LoopHelp = fun('$end_of_table',_) -> []; - ({Recs,Cont},Fun) -> + ({Recs,Cont},Fun) -> Sel = mnesia:select(Cont), Recs ++ Fun(Sel, Fun) end, - Loop = fun(Table,Pattern) -> + Loop = fun(Table,Pattern) -> Sel = mnesia:select(Table, Pattern, 1, read), Res = LoopHelp(Sel,LoopHelp), case mnesia:table_info(Table, type) of ordered_set -> Res; _ -> lists:sort(Res) - end + end end, - Test = + Test = fun(Tab) -> - OneRec = {Tab, 1, 2}, - TwoRec = {Tab, 2, 3}, + OneRec = {Tab, 1, 2}, + TwoRec = {Tab, 2, 3}, OnePat = [{{Tab, '$1', 2}, [], ['$_']}], All = [OneRec,TwoRec], AllPat = [{'_', [], ['$_']}], - ?match({atomic, []}, Trans(fun() -> Loop(Tab, OnePat) end)), - ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), - ?match({atomic, [OneRec]}, Trans(fun() -> Loop(Tab, OnePat) end)), - ?match({atomic, All}, Trans(fun() -> Loop(Tab, AllPat) end)), - + ?match({atomic, []}, Trans(fun() -> Loop(Tab, OnePat) end)), + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(TwoRec) end)), + ?match({atomic, [OneRec]}, Trans(fun() -> Loop(Tab, OnePat) end)), + ?match({atomic, All}, Trans(fun() -> Loop(Tab, AllPat) end)), + {atomic,{_, Cont}} = Trans(fun() -> mnesia:select(Tab, OnePat, 1, read) end), ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(Cont) end)), - - ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, {match, '$1', 2},1,read) end)), - ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, [{'_', [], '$1'}],1,read) end)), - ?match({aborted, _}, Trans(fun() -> mnesia:select(sune) end)), - ?match({'EXIT', {aborted, no_transaction}}, mnesia:select(Tab, OnePat,1,read)), - ?match({aborted, {badarg,sune}}, + + ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, {match, '$1', 2},1,read) end)), + ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, [{'_', [], '$1'}],1,read) end)), + ?match({aborted, _}, Trans(fun() -> mnesia:select(sune) end)), + ?match({'EXIT', {aborted, no_transaction}}, mnesia:select(Tab, OnePat,1,read)), + ?match({aborted, {badarg,sune}}, Trans(fun() -> mnesia:select(sune) end)) end, Test(Tab1), @@ -349,28 +354,28 @@ select14(Config) when is_list(Config) -> all_keys(suite) ->[]; all_keys(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = all_keys, - Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - - Write = fun() -> mnesia:write({Tab, 14, 4}) end, - AllKeys = fun() -> mnesia:all_keys(Tab) end, - - ?match({atomic, []}, mnesia:transaction(AllKeys)), - - ?match({atomic, ok}, mnesia:transaction(Write)), - ?match({atomic, [14]}, mnesia:transaction(AllKeys)), - - ?match({atomic, ok}, mnesia:transaction(Write)), - ?match({atomic, [14]}, mnesia:transaction(AllKeys)), - - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:all_keys(foo) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:all_keys([]) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:all_keys(Tab)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = all_keys, + Schema = [{name, Tab}, {type, bag}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + + Write = fun() -> mnesia:write({Tab, 14, 4}) end, + AllKeys = fun() -> mnesia:all_keys(Tab) end, + + ?match({atomic, []}, mnesia:transaction(AllKeys)), + + ?match({atomic, ok}, mnesia:transaction(Write)), + ?match({atomic, [14]}, mnesia:transaction(AllKeys)), + + ?match({atomic, ok}, mnesia:transaction(Write)), + ?match({atomic, [14]}, mnesia:transaction(AllKeys)), + + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:all_keys(foo) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:all_keys([]) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:all_keys(Tab)), ?verify_mnesia(Nodes, []). @@ -436,49 +441,49 @@ transaction(Config) when is_list(Config) -> basic_nested(doc) -> ["Test the basic functionality of nested transactions"]; basic_nested(suite) -> []; basic_nested(Config) when is_list(Config) -> - Nodes = ?acquire_nodes(3, Config), - Args = [{ram_copies, Nodes}, - {attributes, record_info(fields, ntab)}], - ?match({atomic, ok}, mnesia:create_table(ntab, Args)), - do_nested(top), + Nodes = ?acquire_nodes(3, Config), + Args = [{ram_copies, Nodes}, + {attributes, record_info(fields, ntab)}], + ?match({atomic, ok}, mnesia:create_table(ntab, Args)), + do_nested(top), case mnesia_test_lib:diskless(Config) of false -> lists:foreach(fun(N) -> - ?match({atomic, ok}, + ?match({atomic, ok}, mnesia:change_table_copy_type(ntab, N, disc_only_copies)) - end, Nodes), + end, Nodes), do_nested(top); - true -> + true -> skip end, ?verify_mnesia(Nodes, []). do_nested(How) -> F1 = fun() -> - mnesia:write(#ntab{a= 1}), + mnesia:write(#ntab{a= 1}), mnesia:write(#ntab{a= 2}) - end, + end, F2 = fun() -> mnesia:read({ntab, 1}) - end, - ?match({atomic, ok}, mnesia:transaction(F1)), - ?match({atomic, _}, mnesia:transaction(F2)), + end, + ?match({atomic, ok}, mnesia:transaction(F1)), + ?match({atomic, _}, mnesia:transaction(F2)), - ?match({atomic, {aborted, _}}, - mnesia:transaction(fun() -> n_f1(), + ?match({atomic, {aborted, _}}, + mnesia:transaction(fun() -> n_f1(), mnesia:transaction(fun() -> n_f2() end) - end)), + end)), - ?match({atomic, {aborted, _}}, - mnesia:transaction(fun() -> n_f1(), + ?match({atomic, {aborted, _}}, + mnesia:transaction(fun() -> n_f1(), mnesia:transaction(fun() -> n_f3() end) - end)), - ?match({atomic, {atomic, [#ntab{a = 5}]}}, - mnesia:transaction(fun() -> mnesia:write(#ntab{a = 5}), + end)), + ?match({atomic, {atomic, [#ntab{a = 5}]}}, + mnesia:transaction(fun() -> mnesia:write(#ntab{a = 5}), mnesia:transaction(fun() -> n_f4() end) - end)), - Cyclic = fun() -> mnesia:abort({cyclic,a,a,a,a,a}) end, %% Ugly - NodeNotR = fun() -> mnesia:abort({node_not_running, testNode}) end, + end)), + Cyclic = fun() -> mnesia:abort({cyclic,a,a,a,a,a}) end, %% Ugly + NodeNotR = fun() -> mnesia:abort({node_not_running, testNode}) end, TestAbort = fun(Fun) -> case get(restart_counter) of @@ -490,46 +495,46 @@ do_nested(How) -> ok end end, - - ?match({atomic,{atomic,ok}}, + + ?match({atomic,{atomic,ok}}, mnesia:transaction(fun()->mnesia:transaction(TestAbort, [Cyclic])end)), - - ?match({atomic,{atomic,ok}}, + + ?match({atomic,{atomic,ok}}, mnesia:transaction(fun()->mnesia:transaction(TestAbort, [NodeNotR])end)), - + %% Now try the restart thingie case How of - top -> - Pids = [spawn(?MODULE, do_nested, [{spawned, self()}]), - spawn(?MODULE, do_nested, [{spawned, self()}]), - spawn(?MODULE, do_nested, [{spawned, self()}]), - spawn(?MODULE, do_nested, [{spawned, self()}])], - ?match({info, _, _}, mnesia_tm:get_info(2000)), + top -> + Pids = [spawn(?MODULE, do_nested, [{spawned, self()}]), + spawn(?MODULE, do_nested, [{spawned, self()}]), + spawn(?MODULE, do_nested, [{spawned, self()}]), + spawn(?MODULE, do_nested, [{spawned, self()}])], + ?match({info, _, _}, mnesia_tm:get_info(2000)), lists:foreach(fun(P) -> receive {P, ok} -> ok end - end, Pids), + end, Pids), ?match([], [Tab || Tab <- ets:all(), mnesia_trans_store == ets:info(Tab, name)]); - + {spawned, Pid} -> - ?match({info, _, _}, mnesia_tm:get_info(2000)), + ?match({info, _, _}, mnesia_tm:get_info(2000)), Pid ! {self(), ok}, exit(normal) end. n_f1() -> - mnesia:read({ntab, 1}), + mnesia:read({ntab, 1}), mnesia:write(#ntab{a = 3}). n_f2() -> - mnesia:write(#ntab{a = 4}), + mnesia:write(#ntab{a = 4}), erlang:error(exit_here). n_f3() -> - mnesia:write(#ntab{a = 4}), + mnesia:write(#ntab{a = 4}), throw(funky). n_f4() -> @@ -555,24 +560,24 @@ nested_trans_both_dies(Config) when is_list(Config) -> nested_transactions(Config, abort, abort). nested_transactions(Config, Child, Father) -> - [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), + [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), Tab = nested_trans, - Def = + Def = case mnesia_test_lib:diskless(Config) of true -> [{name, Tab}, {ram_copies, Nodes}]; false -> - [{name, Tab}, {ram_copies, [Node1]}, + [{name, Tab}, {ram_copies, [Node1]}, {disc_copies, [Node2]}, {disc_only_copies, [Node3]}] end, ?match({atomic, ok}, mnesia:create_table(Def)), ?match(ok, mnesia:dirty_write({Tab, father, not_updated})), - ?match(ok, mnesia:dirty_write({Tab, child, not_updated})), + ?match(ok, mnesia:dirty_write({Tab, child, not_updated})), ChildOk = fun() -> mnesia:write({Tab, child, updated}) end, - ChildAbort = fun() -> + ChildAbort = fun() -> mnesia:write({Tab, child, updated}), erlang:error(exit_here) end, @@ -616,7 +621,7 @@ nested_transactions(Config, Child, Father) -> ?verify_mnesia(Nodes, []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -mix_of_nested_activities(doc) -> +mix_of_nested_activities(doc) -> ["Verify that dirty operations in a transaction are handled like ", "normal transactions"]; mix_of_nested_activities(suite) -> []; @@ -624,27 +629,27 @@ mix_of_nested_activities(Config) when is_list(Config) -> [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), Tab = tab, - Def = + Def = case mnesia_test_lib:diskless(Config) of true -> [{ram_copies, Nodes}]; - false -> - [{ram_copies, [Node1]}, - {disc_copies, [Node2]}, + false -> + [{ram_copies, [Node1]}, + {disc_copies, [Node2]}, {disc_only_copies, [Node3]}] end, ?match({atomic, ok}, mnesia:create_table(Tab, [{type,bag}|Def])), - Activities = [transaction, sync_transaction, + Activities = [transaction, sync_transaction, ets, async_dirty, sync_dirty], %% Make a test for all 3000 combinations - Tests = [[A,B,C,D,E] || + Tests = [[A,B,C,D,E] || A <- Activities, B <- Activities, C <- Activities, D <- Activities, E <- Activities], - Foreach = - fun(Test,No) -> + Foreach = + fun(Test,No) -> Result = lists:reverse(Test), ?match({No,Result},{No,catch apply_op({Tab,No},Test)}), No+1 @@ -661,9 +666,9 @@ apply_op(Oid = {Tab,Key},[Type|Next]) -> apply_op(Oid,Next) end)). -check_res(transaction, {atomic,Res}) -> +check_res(transaction, {atomic,Res}) -> Res; -check_res(sync_transaction, {atomic,Res}) -> +check_res(sync_transaction, {atomic,Res}) -> Res; check_res(async_dirty, Res) when is_list(Res) -> Res; @@ -673,11 +678,11 @@ check_res(ets, Res) when is_list(Res) -> Res; check_res(Type,Res) -> ?match(bug,{Type,Res}). - + read_op(Oid) -> case lists:reverse(mnesia:read(Oid)) of [] -> []; - [{_,_,Ops}|_] -> + [{_,_,Ops}|_] -> Ops end. @@ -686,24 +691,24 @@ read_op(Oid) -> index_match_object(suite) -> []; index_match_object(Config) when is_list(Config) -> - [Node1, Node2] = Nodes = ?acquire_nodes(2, Config), - Tab = index_match_object, - Schema = [{name, Tab}, {attributes, [k, v, e]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - ValPos = 3, - BadValPos = ValPos + 2, - ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), - - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:index_match_object({Tab, '$1', 2}, ValPos) end)), - OneRec = {Tab, {1, 1}, 2, {1, 1}}, - OnePat = {Tab, '$1', 2, '_'}, + [Node1, Node2] = Nodes = ?acquire_nodes(2, Config), + Tab = index_match_object, + Schema = [{name, Tab}, {attributes, [k, v, e]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + ValPos = 3, + BadValPos = ValPos + 2, + ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), + + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:index_match_object({Tab, '$1', 2}, ValPos) end)), + OneRec = {Tab, {1, 1}, 2, {1, 1}}, + OnePat = {Tab, '$1', 2, '_'}, BadPat = {Tab, '$1', '$2', '_'}, %% See ref guide - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - Imatch = fun(Patt, Pos) -> + Imatch = fun(Patt, Pos) -> mnesia:transaction(fun() -> lists:sort(mnesia:index_match_object(Patt, Pos)) end) end, ?match({atomic, [OneRec]}, Imatch(OnePat, ValPos)), @@ -711,13 +716,13 @@ index_match_object(Config) when is_list(Config) -> ?match({aborted, _}, Imatch({foo, '$1', 2, '_'}, ValPos)), ?match({aborted, _}, Imatch({[], '$1', 2, '_'}, ValPos)), ?match({aborted, _}, Imatch(BadPat, ValPos)), - ?match({'EXIT', {aborted, no_transaction}}, mnesia:index_match_object(OnePat, ValPos)), + ?match({'EXIT', {aborted, no_transaction}}, mnesia:index_match_object(OnePat, ValPos)), Another = {Tab, {3,1}, 2, {4,4}}, - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Another) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, {4, 4}, 3, {4, 4}}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Another) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, {4, 4}, 3, {4, 4}}) end)), ?match({atomic, [OneRec]}, Imatch({Tab, {1,1}, 2, {1,1}}, ValPos)), ?match({atomic, [OneRec]}, Imatch({Tab, {1,1}, 2, '$1'}, ValPos)), @@ -727,110 +732,110 @@ index_match_object(Config) when is_list(Config) -> ?match({atomic, [OneRec]}, Imatch({Tab, {'$2', '$1'}, 2, {'_', '$1'}}, ValPos)), ?match({atomic, [OneRec, Another]}, Imatch({Tab, '_', 2, '_'}, ValPos)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 4, 5, {7, 4}}) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write({Tab, 7, 5, {7, 5}}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 4, 5, {7, 4}}) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write({Tab, 7, 5, {7, 5}}) end)), ?match({atomic, [{Tab, 4, 5, {7, 4}}]}, Imatch({Tab, '$1', 5, {'_', '$1'}}, ValPos)), ?match({atomic, [OneRec]}, rpc:call(Node2, mnesia, transaction, - [fun() -> - lists:sort(mnesia:index_match_object({Tab, {1,1}, 2, + [fun() -> + lists:sort(mnesia:index_match_object({Tab, {1,1}, 2, {1,1}}, ValPos)) - end])), + end])), ?verify_mnesia(Nodes, []). %% Read records by using an index index_read(suite) -> []; index_read(Config) when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = index_read, - Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - ValPos = 3, - BadValPos = ValPos + 1, - ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), - - OneRec = {Tab, 1, 2}, - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(OneRec) end)), - ?match({atomic, [OneRec]}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, BadValPos) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:index_read(foo, 2, ValPos) end)), - ?match({aborted, _}, - mnesia:transaction(fun() -> mnesia:index_read([], 2, ValPos) end)), - - ?match({'EXIT', {aborted, no_transaction}}, mnesia:index_read(Tab, 2, ValPos)), + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = index_read, + Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + ValPos = 3, + BadValPos = ValPos + 1, + ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), + + OneRec = {Tab, 1, 2}, + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(OneRec) end)), + ?match({atomic, [OneRec]}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, BadValPos) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:index_read(foo, 2, ValPos) end)), + ?match({aborted, _}, + mnesia:transaction(fun() -> mnesia:index_read([], 2, ValPos) end)), + + ?match({'EXIT', {aborted, no_transaction}}, mnesia:index_read(Tab, 2, ValPos)), ?verify_mnesia(Nodes, []). index_update_set(suite) -> []; index_update_set(Config)when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = index_test, - Schema = [{name, Tab}, {attributes, [k, v1, v2, v3]}, {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - ValPos = v1, + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = index_test, + Schema = [{name, Tab}, {attributes, [k, v1, v2, v3]}, {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + ValPos = v1, ValPos2 = v3, - ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), - + ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), + Pat1 = {Tab, '$1', 2, '$2', '$3'}, - Pat2 = {Tab, '$1', '$2', '$3', '$4'}, - - Rec1 = {Tab, 1, 2, 3, 4}, + Pat2 = {Tab, '$1', '$2', '$3', '$4'}, + + Rec1 = {Tab, 1, 2, 3, 4}, Rec2 = {Tab, 2, 2, 13, 14}, - Rec3 = {Tab, 1, 12, 13, 14}, - Rec4 = {Tab, 4, 2, 13, 14}, - - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec1) end)), - ?match({atomic, [Rec1]}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec2) end)), - {atomic, R1} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), + Rec3 = {Tab, 1, 12, 13, 14}, + Rec4 = {Tab, 4, 2, 13, 14}, + + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec1) end)), + ?match({atomic, [Rec1]}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec2) end)), + {atomic, R1} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2], lists:sort(R1)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec3) end)), - {atomic, R2} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec3) end)), + {atomic, R2} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec2], lists:sort(R2)), - ?match({atomic, [Rec2]}, - mnesia:transaction(fun() -> mnesia:index_match_object(Pat1, ValPos) end)), - - {atomic, R3} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), + ?match({atomic, [Rec2]}, + mnesia:transaction(fun() -> mnesia:index_match_object(Pat1, ValPos) end)), + + {atomic, R3} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), ?match([Rec3, Rec2], lists:sort(R3)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec4) end)), - {atomic, R4} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec4) end)), + {atomic, R4} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec2, Rec4], lists:sort(R4)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:delete({Tab, 4}) end)), - ?match({atomic, [Rec2]}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:delete({Tab, 4}) end)), + ?match({atomic, [Rec2]}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({atomic, ok}, mnesia:del_table_index(Tab, ValPos)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec4) end)), ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos2)), - - {atomic, R5} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), + + {atomic, R5} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), ?match([Rec3, Rec2, Rec4], lists:sort(R5)), - + {atomic, R6} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec2, Rec4], lists:sort(R6)), - + ?match({atomic, []}, mnesia:transaction(fun() -> mnesia:index_read(Tab, 4, ValPos2) end)), {atomic, R7} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 14, ValPos2) end), @@ -857,62 +862,62 @@ index_update_set(Config)when is_list(Config) -> ?match([Rec1], lists:sort(R11)), ?match({atomic, [Rec1]},mnesia:transaction(fun() -> mnesia:index_read(Tab, 4, ValPos2) end)), ?match({atomic, []},mnesia:transaction(fun() -> mnesia:index_read(Tab, 14, ValPos2) end)), - + ?verify_mnesia(Nodes, []). index_update_bag(suite) -> []; index_update_bag(Config)when is_list(Config) -> - [Node1] = Nodes = ?acquire_nodes(1, Config), - Tab = index_test, + [Node1] = Nodes = ?acquire_nodes(1, Config), + Tab = index_test, Schema = [{name, Tab}, {type, bag}, - {attributes, [k, v1, v2, v3]}, - {ram_copies, [Node1]}], - ?match({atomic, ok}, mnesia:create_table(Schema)), - ValPos = v1, + {attributes, [k, v1, v2, v3]}, + {ram_copies, [Node1]}], + ?match({atomic, ok}, mnesia:create_table(Schema)), + ValPos = v1, ValPos2 = v3, - ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), + ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), Pat1 = {Tab, '$1', 2, '$2', '$3'}, - Pat2 = {Tab, '$1', '$2', '$3', '$4'}, + Pat2 = {Tab, '$1', '$2', '$3', '$4'}, - Rec1 = {Tab, 1, 2, 3, 4}, - Rec2 = {Tab, 2, 2, 13, 14}, - Rec3 = {Tab, 1, 12, 13, 14}, - Rec4 = {Tab, 4, 2, 13, 4}, + Rec1 = {Tab, 1, 2, 3, 4}, + Rec2 = {Tab, 2, 2, 13, 14}, + Rec3 = {Tab, 1, 12, 13, 14}, + Rec4 = {Tab, 4, 2, 13, 4}, Rec5 = {Tab, 1, 2, 234, 14}, %% Simple Index - ?match({atomic, []}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec1) end)), - ?match({atomic, [Rec1]}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec2) end)), + ?match({atomic, []}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec1) end)), + ?match({atomic, [Rec1]}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec2) end)), {atomic, R1} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2], lists:sort(R1)), - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec3) end)), + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec3) end)), {atomic, R2} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2], lists:sort(R2)), {atomic, R3} = mnesia:transaction(fun() -> mnesia:index_match_object(Pat1, ValPos) end), ?match([Rec1, Rec2], lists:sort(R3)), - + {atomic, R4} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), ?match([Rec1, Rec3, Rec2], lists:sort(R4)), - - ?match({atomic, ok}, - mnesia:transaction(fun() -> mnesia:write(Rec4) end)), - {atomic, R5} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), + + ?match({atomic, ok}, + mnesia:transaction(fun() -> mnesia:write(Rec4) end)), + {atomic, R5} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2, Rec4], lists:sort(R5)), - ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete({Tab, 4}) end)), + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete({Tab, 4}) end)), {atomic, R6} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2], lists:sort(R6)), @@ -922,20 +927,20 @@ index_update_bag(Config)when is_list(Config) -> ITab = mnesia_lib:val({index_test,{index, IPos}}), io:format("~n Index ~p @ ~p => ~p ~n~n",[IPos,ITab, ets:tab2list(ITab)]), ?match([{2,1},{2,2},{12,1}], ets:tab2list(ITab)), - + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec5) end)), {atomic, R60} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1,Rec5,Rec2], lists:sort(R60)), ?match([{2,1},{2,2},{12,1}], ets:tab2list(ITab)), - + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec3) end)), {atomic, R61} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1,Rec5,Rec2], lists:sort(R61)), {atomic, R62} = mnesia:transaction(fun() -> mnesia:index_read(Tab,12, ValPos) end), ?match([], lists:sort(R62)), ?match([{2,1},{2,2}], ets:tab2list(ITab)), - + %% reset for rest of testcase ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec3) end)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec5) end)), @@ -943,19 +948,19 @@ index_update_bag(Config)when is_list(Config) -> ?match([Rec1, Rec2], lists:sort(R6)), %% OTP-6587 - ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec1) end)), - ?match({atomic, [Rec2]}, - mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), + ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:delete_object(Rec1) end)), + ?match({atomic, [Rec2]}, + mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end)), {atomic, R7} = mnesia:transaction(fun() -> mnesia:match_object(Pat2) end), ?match([Rec3, Rec2], lists:sort(R7)), - + %% Two indexies ?match({atomic, ok}, mnesia:del_table_index(Tab, ValPos)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec1) end)), ?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec4) end)), ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos2)), - + {atomic, R8} = mnesia:transaction(fun() -> mnesia:index_read(Tab, 2, ValPos) end), ?match([Rec1, Rec2, Rec4], lists:sort(R8)), @@ -1001,12 +1006,12 @@ index_update_bag(Config)when is_list(Config) -> index_write(suite) -> []; index_write(doc) -> ["See ticket OTP-8072"]; index_write(Config)when is_list(Config) -> - Nodes = ?acquire_nodes(1, Config), + Nodes = ?acquire_nodes(1, Config), mnesia:create_table(a, [{index, [val]}]), mnesia:create_table(counter, []), CreateIfNonExist = - fun(Index) -> + fun(Index) -> case mnesia:index_read(a, Index, 3) of [] -> Id = mnesia:dirty_update_counter(counter, id, 1), @@ -1017,7 +1022,7 @@ index_write(Config)when is_list(Config) -> Found end end, - + Trans = fun(A) -> mnesia:transaction(CreateIfNonExist, [A]) %% This works better most of the time @@ -1030,9 +1035,9 @@ index_write(Config)when is_list(Config) -> Res = lists:map(Trans, lists:seq(1,10)), Self ! {self(), Res} end, - + Pids = [spawn(Update) || _ <- lists:seq(1,5)], - + Gather = fun(Pid, Acc) -> receive {Pid, Res} -> [Res|Acc] end end, Results = lists:foldl(Gather, [], Pids), Expected = hd(Results), @@ -1075,7 +1080,7 @@ add_table_index(Config, Storage) -> mnesia:add_table_index(Tab, 1)), ?match({aborted, Reason44 } when element(1, Reason44) == bad_type, mnesia:add_table_index(Tab, 0)), - ?match({aborted, Reason45 } when element(1, Reason45) == bad_type, + ?match({aborted, Reason45 } when element(1, Reason45) == bad_type, mnesia:add_table_index(Tab, -1)), ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), ?match({aborted, Reason46 } when element(1, Reason46) == already_exists, @@ -1083,10 +1088,10 @@ add_table_index(Config, Storage) -> NestedFun = fun() -> ?match({aborted, nested_transaction}, - mnesia:add_table_index(Tab, ValPos)), + mnesia:add_table_index(Tab, ValPos)), ok end, - ?match({atomic, ok}, mnesia:transaction(NestedFun)), + ?match({atomic, ok}, mnesia:transaction(NestedFun)), ?verify_mnesia(Nodes, []). create_live_table_index_ram(suite) -> []; @@ -1110,7 +1115,7 @@ create_live_table_index(Config, Storage) -> mnesia:dirty_write({Tab, 1, 2}), Fun = fun() -> - ?match(ok, mnesia:write({Tab, 2, 2})), + ?match(ok, mnesia:write({Tab, 2, 2})), ok end, ?match({atomic, ok}, mnesia:transaction(Fun)), @@ -1133,17 +1138,17 @@ create_live_table_index(Config, Storage) -> end, ?match([{atomic,ok}|_], [Create(N) || N <- lists:seq(1,50)]), - + ?match([], mnesia_test_lib:stop_mnesia([N2,N3])), ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes,[N1]}]])), ?match(ok, rpc:call(N3, mnesia, start, [[{extra_db_nodes,[N1]}]])), - + ?match({atomic, ok}, mnesia:add_table_index(Tab, ValPos)), - + ?match({atomic, [{Tab, 1, 2},{Tab, 2, 2}]}, mnesia:transaction(IRead)), - ?match({atomic, [{Tab, 1, 2},{Tab, 2, 2}]}, + ?match({atomic, [{Tab, 1, 2},{Tab, 2, 2}]}, rpc:call(N2, mnesia, transaction, [IRead])), - + ?verify_mnesia(Nodes, []). %% Drop table index @@ -1210,49 +1215,49 @@ idx_schema_changes(Config, Storage) -> ram_copies -> {disc_copies, disc_only_copies} end, - + Write = fun(N) -> mnesia:write({Tab, N, N+50}) - end, - + end, + [mnesia:sync_transaction(Write, [N]) || N <- lists:seq(1, 10)], ?match([{Tab, 1, 51}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 51, Idx])), ?match([{Tab, 1, 51}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 51, Idx])), ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, N1, Storage1)), - + ?match({atomic, ok}, rpc:call(N1, mnesia, sync_transaction, [Write, [17]])), ?match({atomic, ok}, rpc:call(N2, mnesia, sync_transaction, [Write, [18]])), - + ?match([{Tab, 17, 67}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 67, Idx])), ?match([{Tab, 18, 68}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 68, Idx])), - + ?match({atomic, ok}, mnesia:del_table_copy(Tab, N1)), ?match({atomic, ok}, rpc:call(N1, mnesia, sync_transaction, [Write, [11]])), ?match({atomic, ok}, rpc:call(N2, mnesia, sync_transaction, [Write, [12]])), - + ?match([{Tab, 11, 61}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 61, Idx])), ?match([{Tab, 12, 62}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 62, Idx])), ?match({atomic, ok}, mnesia:move_table_copy(Tab, N2, N1)), ?match({atomic, ok}, rpc:call(N1, mnesia, sync_transaction, [Write, [19]])), ?match({atomic, ok}, rpc:call(N2, mnesia, sync_transaction, [Write, [20]])), - + ?match([{Tab, 19, 69}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 69, Idx])), - ?match([{Tab, 20, 70}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 70, Idx])), - + ?match([{Tab, 20, 70}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 70, Idx])), + ?match({atomic, ok}, mnesia:add_table_copy(Tab, N2, Storage)), ?match({atomic, ok}, rpc:call(N1, mnesia, sync_transaction, [Write, [13]])), ?match({atomic, ok}, rpc:call(N2, mnesia, sync_transaction, [Write, [14]])), - + ?match([{Tab, 13, 63}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 63, Idx])), ?match([{Tab, 14, 64}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 64, Idx])), - + ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, N2, Storage2)), - + ?match({atomic, ok}, rpc:call(N1, mnesia, sync_transaction, [Write, [15]])), ?match({atomic, ok}, rpc:call(N2, mnesia, sync_transaction, [Write, [16]])), - + ?match([{Tab, 15, 65}], rpc:call(N2, mnesia, dirty_index_read, [Tab, 65, Idx])), ?match([{Tab, 16, 66}], rpc:call(N1, mnesia, dirty_index_read, [Tab, 66, Idx])), diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index ebf79dd2ae..080548acac 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.5.1 +MNESIA_VSN = 4.6 |