aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorUlf Wiger <[email protected]>2015-11-05 15:09:12 +0100
committerDan Gudmundsson <[email protected]>2016-05-09 14:54:36 +0200
commit3aff6476811a385cf45817d6974b83a6b0345a92 (patch)
treec9c80bcaa216d61b3ec05c71c75380542467de1f /lib
parent3d13b0177c2b858fe2ec970f4e14cd6e5c5433fe (diff)
downloadotp-3aff6476811a385cf45817d6974b83a6b0345a92.tar.gz
otp-3aff6476811a385cf45817d6974b83a6b0345a92.tar.bz2
otp-3aff6476811a385cf45817d6974b83a6b0345a92.zip
mnesia_ext: Implement ext copies index
Make ram_copies index always use ordered_set And use index type as prefered type not a implementation requirement, the standard implmentation will currently ignore the prefered type.
Diffstat (limited to 'lib')
-rw-r--r--lib/mnesia/src/mnesia_index.erl434
-rw-r--r--lib/mnesia/src/mnesia_schema.erl207
-rw-r--r--lib/mnesia/src/mnesia_tm.erl94
-rw-r--r--lib/mnesia/test/mnesia_trans_access_test.erl6
4 files changed, 541 insertions, 200 deletions
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 0c882c0df6..902d0c12ae 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -23,8 +23,8 @@
-module(mnesia_index).
-export([read/5,
- add_index/5,
- delete_index/3,
+ add_index/6,
+ delete_index/4,
del_object_index/5,
clear_index/4,
dirty_match_object/3,
@@ -39,19 +39,21 @@
get_index_table/3,
tab2filename/2,
- tab2tmp_filename/2,
init_index/2,
init_indecies/3,
del_transient/2,
del_transient/3,
- del_index_table/3]).
+ del_index_table/3,
+
+ index_info/2,
+ ext_index_instances/1]).
-import(mnesia_lib, [val/1, verbose/2]).
-include("mnesia.hrl").
-record(index, {setorbag, pos_list}).
-%% read an object list throuh its index table
+%% read an object list through its index table
%% we assume that table Tab has index on attribute number Pos
read(Tid, Store, Tab, IxKey, Pos) ->
@@ -64,69 +66,103 @@ read(Tid, Store, Tab, IxKey, Pos) ->
ResList
end.
-add_index(Index, Tab, Key, Obj, Old) ->
- add_index2(Index#index.pos_list, Index#index.setorbag, Tab, Key, Obj, Old).
-
-add_index2([{Pos, Ixt} |Tail], bag, Tab, K, Obj, OldRecs) ->
- db_put(Ixt, {element(Pos, Obj), K}),
- add_index2(Tail, bag, Tab, K, Obj, OldRecs);
-add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs0) ->
+ext_index_instances(Tab) ->
+ #index{pos_list = PosL} = val({Tab, index_info}),
+ lists:foldr(
+ fun({_, {{ext,Alias,Mod}, Tag}}, Acc) ->
+ [{Alias, Mod, Tag}|Acc];
+ (_, Acc) ->
+ Acc
+ end, [], PosL).
+
+
+add_index(#index{pos_list = PosL, setorbag = SorB},
+ Storage, Tab, Key, Obj, Old) ->
+ add_index2(PosL, SorB, Storage, Tab, Key, Obj, Old).
+
+add_index2([{{Pos,Type}, Ixt} |Tail], bag, Storage, Tab, K, Obj, OldRecs) ->
+ ValsF = index_vals_f(Storage, Tab, Pos),
+ Vals = ValsF(Obj),
+ put_index_vals(Type, Ixt, Vals, K),
+ add_index2(Tail, bag, Storage, Tab, K, Obj, OldRecs);
+add_index2([{{Pos, Type}, Ixt} |Tail], SorB, Storage, Tab, K, Obj, OldRecs0) ->
%% Remove old tuples in index if Tab is updated
+ ValsF = index_vals_f(Storage, Tab, Pos), NewVals = ValsF(Obj),
OldRecs1 = case OldRecs0 of
- undefined -> mnesia_lib:db_get(Tab, K);
+ undefined -> mnesia_lib:db_get(Storage, Tab, K);
_ -> OldRecs0
end,
- IdxVal = element(Pos, Obj),
- case [Old || Old <- OldRecs1, element(Pos, Old) =/= IdxVal] of
- [] when OldRecs1 =:= [] -> %% Write
- db_put(Ixt, {element(Pos, Obj), K}),
- add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ IdxVal = ValsF(Obj),
+ case [Old || Old <- OldRecs1, ValsF(Old) =/= IdxVal] of
+ [] when OldRecs1 =:= [] -> % Write
+ put_index_vals(Type, Ixt, NewVals, K),
+ add_index2(Tail, SorB, Storage, Tab, K, Obj, OldRecs1);
[] -> %% when OldRecs1 =/= [] Update without modifying index field
- add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ add_index2(Tail, SorB, Storage, Tab, K, Obj, OldRecs1);
OldRecs -> %% Update
- db_put(Ixt, {element(Pos, Obj), K}),
- del_ixes(Ixt, OldRecs, Pos, K),
- add_index2(Tail, Type, Tab, K, Obj, OldRecs0)
+ put_index_vals(Type, Ixt, NewVals, K),
+ [del_ixes(Type, Ixt, ValsF, OldObj, K) || OldObj <- OldRecs],
+ add_index2(Tail, SorB, Storage, Tab, K, Obj, OldRecs1)
end;
-add_index2([], _, _Tab, _K, _Obj, _) -> ok.
+add_index2([], _, _, _Tab, _K, _Obj, _) -> ok.
+
+delete_index(Index, Storage, Tab, K) ->
+ delete_index2(Index#index.pos_list, Storage, Tab, K).
-delete_index(Index, Tab, K) ->
- delete_index2(Index#index.pos_list, Tab, K).
+delete_index2([{{Pos, Type}, Ixt} | Tail], Storage, Tab, K) ->
+ DelObjs = mnesia_lib:db_get(Storage, Tab, K),
+ ValsF = index_vals_f(Storage, Tab, Pos),
+ [del_ixes(Type, Ixt, ValsF, Obj, K) || Obj <- DelObjs],
+ delete_index2(Tail, Storage, Tab, K);
+delete_index2([], _Storage, _Tab, _K) -> ok.
-delete_index2([{Pos, Ixt} | Tail], Tab, K) ->
- DelObjs = mnesia_lib:db_get(Tab, K),
- del_ixes(Ixt, DelObjs, Pos, K),
- delete_index2(Tail, Tab, K);
-delete_index2([], _Tab, _K) -> ok.
+put_index_vals(ordered, Ixt, Vals, K) ->
+ [db_put(Ixt, {{V, K}}) || V <- Vals];
+put_index_vals(bag, Ixt, Vals, K) ->
+ [db_put(Ixt, {V, K}) || V <- Vals].
-del_ixes(_Ixt, [], _Pos, _L) -> ok;
-del_ixes(Ixt, [Obj | Tail], Pos, Key) ->
- db_match_erase(Ixt, {element(Pos, Obj), Key}),
- del_ixes(Ixt, Tail, Pos, Key).
+del_ixes(bag, Ixt, ValsF, Obj, Key) ->
+ Vals = ValsF(Obj),
+ [db_match_erase(Ixt, {V, Key}) || V <- Vals];
+del_ixes(ordered, Ixt, ValsF, Obj, Key) ->
+ Vals = ValsF(Obj),
+ [db_erase(Ixt, {V,Key}) || V <- Vals].
-del_object_index(Index, Tab, K, Obj, Old) ->
- del_object_index2(Index#index.pos_list, Index#index.setorbag, Tab, K, Obj, Old).
+del_object_index(#index{pos_list = PosL, setorbag = SorB}, Storage, Tab, K, Obj) ->
+ del_object_index2(PosL, SorB, Storage, Tab, K, Obj).
-del_object_index2([], _, _Tab, _K, _Obj, _Old) -> ok;
-del_object_index2([{Pos, Ixt} | Tail], SoB, Tab, K, Obj, Old) ->
+del_object_index2([], _, _Storage, _Tab, _K, _Obj) -> ok;
+del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, K, Obj) ->
+ ValsF = index_vals_f(Storage, Tab, Pos),
case SoB of
bag ->
- del_object_bag(Tab, K, Obj, Pos, Ixt, Old);
+ del_object_bag(Type, ValsF, Tab, K, Obj, Ixt);
_ -> %% If set remove the tuple in index table
- del_ixes(Ixt, [Obj], Pos, K)
+ del_ixes(Type, Ixt, ValsF, Obj, K)
end,
- del_object_index2(Tail, SoB, Tab, K, Obj, Old).
-
-del_object_bag(Tab, Key, Obj, Pos, Ixt, undefined) ->
- IxKey = element(Pos, Obj),
- Old = [X || X <- mnesia_lib:db_get(Tab, Key), element(Pos, X) =:= IxKey],
- del_object_bag(Tab, Key, Obj, Pos, Ixt, Old);
-%% If Tab type is bag we need remove index identifier if the object being
-%% deleted was the last one
-del_object_bag(_Tab, Key, Obj, Pos, Ixt, Old) when Old =:= [Obj] ->
- del_ixes(Ixt, [Obj], Pos, Key);
-del_object_bag(_Tab, _Key, _Obj, _Pos, _Ixt, _Old) -> ok.
+ del_object_index2(Tail, SoB, Storage, Tab, K, Obj).
+
+del_object_bag(Type, ValsF, Tab, Key, Obj, Ixt) ->
+ IxKeys = ValsF(Obj),
+ Found = [{X, ValsF(X)} || X <- mnesia_lib:db_get(Tab, Key)],
+ del_object_bag_(IxKeys, Found, Type, Tab, Key, Obj, Ixt).
+
+del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
+ case [X || {X, Ixes} <- Found, lists:member(IxK, Ixes)] of
+ [Old] when Old =:= Obj ->
+ case Type of
+ bag ->
+ db_match_erase(Ixt, {IxK, Key});
+ ordered ->
+ db_erase(Ixt, {{IxK, Key}})
+ end;
+ _ ->
+ ok
+ end,
+ del_object_bag_(IxKs, Found, Type, Tab, Key, Obj, Ixt);
+del_object_bag_([], _, _, _, _, _, _) ->
+ ok.
clear_index(Index, Tab, K, Obj) ->
clear_index2(Index#index.pos_list, Tab, K, Obj).
@@ -138,8 +174,9 @@ clear_index2([{_Pos, Ixt} | Tail], Tab, K, Obj) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-dirty_match_object(Tab, Pat, Pos) ->
+dirty_match_object(Tab, Pat, Pos) when is_integer(Pos) ->
%% Assume that we are on the node where the replica is
+ %% Cannot use index plugins here, as they don't map to match patterns
case element(2, Pat) of
'_' ->
IxKey = element(Pos, Pat),
@@ -161,7 +198,7 @@ realkeys(Tab, Pos, IxKey) ->
Index = get_index_table(Tab, Pos),
db_get(Index, IxKey). % a list on the form [{IxKey, RealKey1} , ....
-dirty_select(Tab, Spec, Pos) ->
+dirty_select(Tab, Spec, Pos) when is_integer(Pos) ->
%% Assume that we are on the node where the replica is
%% Returns the records without applying the match spec
%% The actual filtering is handled by the caller
@@ -171,59 +208,80 @@ dirty_select(Tab, Spec, Pos) ->
lists:append([mnesia_lib:db_get(StorageType, Tab, Key) || {_,Key} <- RealKeys]).
dirty_read(Tab, IxKey, Pos) ->
- ResList = mnesia:dirty_rpc(Tab, ?MODULE, dirty_read2,
- [Tab, IxKey, Pos]),
- case val({Tab, setorbag}) of
- bag ->
- %% Remove all tuples which don't include Ixkey
- mnesia_lib:key_search_all(IxKey, Pos, ResList);
- _ ->
- ResList
- end.
+ mnesia:dirty_rpc(Tab, ?MODULE, dirty_read2,
+ [Tab, IxKey, Pos]).
dirty_read2(Tab, IxKey, Pos) ->
- Ix = get_index_table(Tab, Pos),
- Keys = db_match(Ix, {IxKey, '$1'}),
- r_keys(Keys, Tab, []).
-
-r_keys([[H]|T],Tab,Ack) ->
- V = mnesia_lib:db_get(Tab, H),
- r_keys(T, Tab, V ++ Ack);
-r_keys([], _, Ack) ->
- Ack.
+ #index{pos_list = PosL} = val({Tab, index_info}),
+ Storage = val({Tab, storage_type}),
+ {Type, Ixt} = pick_index(PosL, Tab, Pos),
+ Pat = case Type of
+ ordered -> [{{{IxKey, '$1'}}, [], ['$1']}];
+ bag -> [{{IxKey, '$1'}, [], ['$1']}]
+ end,
+ Keys = db_select(Ixt, Pat),
+ ValsF = index_vals_f(Storage, Tab, Pos),
+ lists:reverse(
+ lists:foldl(
+ fun(K, Acc) ->
+ lists:foldl(
+ fun(Obj, Acc1) ->
+ case lists:member(IxKey, ValsF(Obj)) of
+ true -> [Obj|Acc1];
+ false -> Acc1
+ end
+ end, Acc, mnesia_lib:db_get(Storage, Tab, K))
+ end, [], Keys)).
+
+pick_index([{{{Pfx,_},IxType}, Ixt}|_], _Tab, {_} = Pfx) ->
+ {IxType, Ixt};
+pick_index([{{Pos,IxType}, Ixt}|_], _Tab, Pos) ->
+ {IxType, Ixt};
+pick_index([_|T], Tab, Pos) ->
+ pick_index(T, Tab, Pos);
+pick_index([], Tab, Pos) ->
+ mnesia:abort({no_exist, Tab, {index, Pos}}).
+
%%%%%%% Creation, Init and deletion routines for index tables
%% We can have several indexes on the same table
%% this can be a fairly costly operation if table is *very* large
-tab2filename(Tab, Pos) ->
+tab2filename(Tab, {A}) when is_atom(A) ->
+ mnesia_lib:dir(Tab) ++ "_-" ++ atom_to_list(A) ++ "-.DAT";
+tab2filename(Tab, T) when is_tuple(T) ->
+ tab2filename(Tab, element(1, T));
+tab2filename(Tab, Pos) when is_integer(Pos) ->
mnesia_lib:dir(Tab) ++ "_" ++ integer_to_list(Pos) ++ ".DAT".
-tab2tmp_filename(Tab, Pos) ->
- mnesia_lib:dir(Tab) ++ "_" ++ integer_to_list(Pos) ++ ".TMP".
-
init_index(Tab, Storage) ->
- PosList = val({Tab, index}),
+ Cs = val({Tab, cstruct}),
+ PosList = Cs#cstruct.index,
init_indecies(Tab, Storage, PosList).
init_indecies(Tab, Storage, PosList) ->
case Storage of
unknown ->
ignore;
+ {ext, Alias, Mod} ->
+ init_ext_index(Tab, Storage, Alias, Mod, PosList);
disc_only_copies ->
- init_disc_index(Tab, PosList);
+ init_disc_index(Tab, Storage, PosList);
ram_copies ->
- make_ram_index(Tab, PosList);
+ make_ram_index(Tab, Storage, PosList);
disc_copies ->
- make_ram_index(Tab, PosList)
+ make_ram_index(Tab, Storage, PosList)
end.
%% works for both ram and disc indexes
del_index_table(_, unknown, _) ->
ignore;
-del_index_table(Tab, Storage, Pos) ->
+del_index_table(Tab, Storage, {_} = Pos) ->
+ delete_transient_index(Tab, Pos, Storage),
+ mnesia_lib:del({Tab, index}, Pos);
+del_index_table(Tab, Storage, Pos) when is_integer(Pos) ->
delete_transient_index(Tab, Pos, Storage),
mnesia_lib:del({Tab, index}, Pos).
@@ -236,13 +294,24 @@ del_transient(Tab, [Pos | Tail], Storage) ->
delete_transient_index(Tab, Pos, Storage),
del_transient(Tab, Tail, Storage).
+delete_transient_index(Tab, Pos, {ext, Alias, Mod}) ->
+ PosInfo = case Pos of
+ _ when is_integer(Pos) ->
+ Cs = val({Tab, cstruct}),
+ lists:keyfind(Pos, 1, Cs#cstruct.index);
+ {P, T} -> {P, T}
+ end,
+ Tag = {Tab, index, PosInfo},
+ Mod:close_table(Alias, Tag),
+ Mod:delete_table(Alias, Tag),
+ del_index_info(Tab, Pos),
+ mnesia_lib:unset({Tab, {index, Pos}});
delete_transient_index(Tab, Pos, disc_only_copies) ->
Tag = {Tab, index, Pos},
mnesia_monitor:unsafe_close_dets(Tag),
_ = file:delete(tab2filename(Tab, Pos)),
del_index_info(Tab, Pos), %% Uses val(..)
mnesia_lib:unset({Tab, {index, Pos}});
-
delete_transient_index(Tab, Pos, _Storage) ->
Ixt = val({Tab, {index, Pos}}),
?ets_delete_table(Ixt),
@@ -252,11 +321,12 @@ delete_transient_index(Tab, Pos, _Storage) ->
%%%%% misc functions for the index create/init/delete functions above
%% assuming that the file exists.
-init_disc_index(_Tab, []) ->
+init_disc_index(_Tab, _Storage, []) ->
done;
-init_disc_index(Tab, [Pos | Tail]) when is_integer(Pos) ->
+init_disc_index(Tab, disc_only_copies, [{Pos,_Pref} | Tail]) ->
+ PosInfo = {Pos, bag},
Fn = tab2filename(Tab, Pos),
- IxTag = {Tab, index, Pos},
+ IxTag = {Tab, index, PosInfo},
_ = file:delete(Fn),
Args = [{file, Fn}, {keypos, 1}, {type, bag}],
mnesia_monitor:open_dets(IxTag, Args),
@@ -269,16 +339,58 @@ init_disc_index(Tab, [Pos | Tail]) when is_integer(Pos) ->
mnesia_lib:db_fixtable(Storage, Tab, true),
ok = dets:init_table(IxTag, create_fun(Init, Tab, Pos)),
mnesia_lib:db_fixtable(Storage, Tab, false),
- mnesia_lib:set({Tab, {index, Pos}}, IxTag),
- add_index_info(Tab, val({Tab, setorbag}), {Pos, {dets, IxTag}}),
- init_disc_index(Tab, Tail).
+ mnesia_lib:set({Tab, {index, PosInfo}}, IxTag),
+ add_index_info(Tab, val({Tab, setorbag}), {PosInfo, {dets, IxTag}}),
+ init_disc_index(Tab, Storage, Tail).
+
+init_ext_index(_, _, _, _, []) ->
+ done;
+init_ext_index(Tab, Storage, Alias, Mod, [{Pos,Type} | Tail]) ->
+ PosInfo = {Pos, Type},
+ IxTag = {Tab, index, PosInfo},
+ _Res = Mod:create_table(Alias, IxTag, []),
+ CS = val({Tab, cstruct}),
+ Mod:load_table(Alias, IxTag, init_index, mnesia_schema:cs2list(CS)),
+ case Mod:is_index_consistent(Alias, IxTag) of
+ false ->
+ Mod:index_is_consistent(Alias, IxTag, false),
+ Mod:match_delete(Alias, IxTag, '_'),
+ IxValsF = index_vals_f(Storage, Tab, Pos),
+ IxObjF = case Type of
+ bag -> fun(IxVal, Key) -> {IxVal, Key} end;
+ ordered -> fun(IxVal, Key) -> {{IxVal, Key}} end
+ end,
+ mnesia_lib:db_fixtable(Storage, Tab, true),
+ mnesia_lib:db_foldl(
+ Storage,
+ fun(Rec, Acc) ->
+ Key = element(2, Rec),
+ lists:foreach(
+ fun(V) ->
+ IxObj = IxObjF(V, Key),
+ Mod:insert(Alias, IxTag, IxObj)
+ end, IxValsF(Rec)),
+ Acc
+ end, ok, Tab,
+ [{'_', [], ['$_']}], 100),
+ Mod:index_is_consistent(Alias, IxTag, true);
+ true ->
+ ignore
+ end,
+
+ mnesia_lib:set({Tab, {index, PosInfo}}, IxTag),
+
+ add_index_info(Tab, val({Tab, setorbag}), {PosInfo, {Storage, IxTag}}),
+ init_ext_index(Tab, Storage, Alias, Mod, Tail).
create_fun(Cont, Tab, Pos) ->
+ IxF = index_vals_f(disc_only_copies, Tab, Pos),
fun(read) ->
Data =
case Cont of
{start, KeysPerChunk} ->
- mnesia_lib:db_init_chunk(disc_only_copies, Tab, KeysPerChunk);
+ mnesia_lib:db_init_chunk(
+ disc_only_copies, Tab, KeysPerChunk);
'$end_of_table' ->
'$end_of_table';
_Else ->
@@ -288,56 +400,82 @@ create_fun(Cont, Tab, Pos) ->
'$end_of_table' ->
end_of_input;
{Recs, Next} ->
- IdxElems = [{element(Pos, Obj), element(2, Obj)} || Obj <- Recs],
+ IdxElems = lists:flatmap(
+ fun(Obj) ->
+ PrimK = element(2, Obj),
+ [{V, PrimK} || V <- IxF(Obj)]
+ end, Recs),
{IdxElems, create_fun(Next, Tab, Pos)}
end;
(close) ->
ok
end.
-make_ram_index(_, []) ->
+make_ram_index(_, _, []) ->
done;
-make_ram_index(Tab, [Pos | Tail]) ->
- add_ram_index(Tab, Pos),
- make_ram_index(Tab, Tail).
+make_ram_index(Tab, Storage, [Pos | Tail]) ->
+ add_ram_index(Tab, Storage, Pos),
+ make_ram_index(Tab, Storage, Tail).
-add_ram_index(Tab, Pos) when is_integer(Pos) ->
- verbose("Creating index for ~w ~n", [Tab]),
+add_ram_index(Tab, Storage, {Pos, _Pref}) ->
+ Type = ordered,
+ verbose("Creating index for ~w ~p ~p~n", [Tab, Pos, Type]),
SetOrBag = val({Tab, setorbag}),
- IndexType = case SetOrBag of
- set -> duplicate_bag;
- ordered_set -> duplicate_bag;
- bag -> bag
- end,
- Index = mnesia_monitor:mktab(mnesia_index, [IndexType, public]),
+ IxValsF = index_vals_f(Storage, Tab, Pos),
+ IxFun = fun(Val, Key) -> {{Val, Key}} end,
+ Index = mnesia_monitor:mktab(mnesia_index, [ordered_set, public]),
Insert = fun(Rec, _Acc) ->
- true = ?ets_insert(Index, {element(Pos, Rec), element(2, Rec)})
+ PrimK = element(2, Rec),
+ true = ?ets_insert(
+ Index, [IxFun(V, PrimK)
+ || V <- IxValsF(Rec)])
end,
mnesia_lib:db_fixtable(ram_copies, Tab, true),
- true = ets:foldl(Insert, true, Tab),
+ true = mnesia_lib:db_foldl(Storage, Insert, true, Tab),
mnesia_lib:db_fixtable(ram_copies, Tab, false),
mnesia_lib:set({Tab, {index, Pos}}, Index),
- add_index_info(Tab, SetOrBag, {Pos, {ram, Index}});
-add_ram_index(_Tab, snmp) ->
+ add_index_info(Tab, SetOrBag, {{Pos, Type}, {ram, Index}});
+add_ram_index(_Tab, _, snmp) ->
ok.
-add_index_info(Tab, Type, IxElem) ->
+index_info(SetOrBag, PosList) ->
+ IxPlugins = mnesia_schema:index_plugins(),
+ ExpPosList = lists:map(
+ fun({{P,Type},Ixt} = PI) ->
+ case P of
+ {_} = IxN ->
+ {_, M, F} =
+ lists:keyfind(IxN, 1, IxPlugins),
+ {{{IxN,M,F}, Type}, Ixt};
+ _ ->
+ PI
+ end
+ end, PosList),
+ #index{setorbag = SetOrBag, pos_list = ExpPosList}.
+
+add_index_info(Tab, SetOrBag, IxElem) ->
Commit = val({Tab, commit_work}),
case lists:keysearch(index, 1, Commit) of
false ->
- Index = #index{setorbag = Type,
- pos_list = [IxElem]},
- %% Check later if mnesia_tm is sensative about the order
+ IndexInfo = index_info(SetOrBag, [IxElem]),
+ %% Check later if mnesia_tm is sensitive about the order
+ mnesia_lib:set({Tab, index_info}, IndexInfo),
+ mnesia_lib:set({Tab, index}, index_positions(IndexInfo)),
mnesia_lib:set({Tab, commit_work},
- mnesia_lib:sort_commit([Index | Commit]));
+ mnesia_lib:sort_commit([IndexInfo | Commit]));
{value, Old} ->
%% We could check for consistency here
Index = Old#index{pos_list = [IxElem | Old#index.pos_list]},
+ mnesia_lib:set({Tab, index_info}, Index),
+ mnesia_lib:set({Tab, index}, index_positions(Index)),
NewC = lists:keyreplace(index, 1, Commit, Index),
mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC))
end.
+index_positions(#index{pos_list = PL}) ->
+ [P || {{P,_},_} <- PL].
+
del_index_info(Tab, Pos) ->
Commit = val({Tab, commit_work}),
case lists:keysearch(index, 1, Commit) of
@@ -345,13 +483,21 @@ del_index_info(Tab, Pos) ->
%% Something is wrong ignore
skip;
{value, Old} ->
- case lists:keydelete(Pos, 1, Old#index.pos_list) of
+ case lists:filter(fun({P,_}) ->
+ element(1,P)=/=Pos
+ end,
+ Old#index.pos_list) of
[] ->
+ IndexInfo = index_info(Old#index.setorbag,[]),
+ mnesia_lib:set({Tab, index_info}, IndexInfo),
+ mnesia_lib:set({Tab, index}, index_positions(IndexInfo)),
NewC = lists:keydelete(index, 1, Commit),
mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC));
New ->
Index = Old#index{pos_list = New},
+ mnesia_lib:set({Tab, index_info}, Index),
+ mnesia_lib:set({Tab, index}, index_positions(Index)),
NewC = lists:keyreplace(index, 1, Commit, Index),
mnesia_lib:set({Tab, commit_work},
mnesia_lib:sort_commit(NewC))
@@ -360,33 +506,69 @@ del_index_info(Tab, Pos) ->
db_put({ram, Ixt}, V) ->
true = ?ets_insert(Ixt, V);
+db_put({{ext, _, _} = Ext, Ixt}, V) ->
+ mnesia_lib:db_put(Ext, Ixt, V);
db_put({dets, Ixt}, V) ->
ok = dets:insert(Ixt, V).
-db_get({ram, Ixt}, K) ->
- ?ets_lookup(Ixt, K);
+db_get({ram, _}=Ixt, IxKey) ->
+ Pat = [{{{IxKey, '$1'}}, [], [{{IxKey,'$1'}}]}],
+ db_select(Ixt, Pat);
+db_get({{ext,_,_} = _Storage, {_,_,{_,Type}}} = Ixt, IxKey) ->
+ Pat = case Type of
+ ordered -> [{{{IxKey, '$1'}}, [], [{{IxKey,'$1'}}]}];
+ bag -> [{{IxKey, '_'}, [], ['$_']}]
+ end,
+ db_select(Ixt, Pat);
db_get({dets, Ixt}, K) ->
dets:lookup(Ixt, K).
+db_erase({ram, Ixt}, K) ->
+ ?ets_delete(Ixt, K);
+db_erase({{ext,_,_} = Ext, Ixt}, K) ->
+ mnesia_lib:db_erase(Ext, Ixt, K);
+db_erase({dets, Ixt}, K) ->
+ dets:delete(Ixt, K).
+
db_match_erase({ram, Ixt}, Pat) ->
true = ?ets_match_delete(Ixt, Pat);
+db_match_erase({{ext,_,_} = Ext, Ixt}, Pat) ->
+ mnesia_lib:db_match_erase(Ext, Ixt, Pat);
db_match_erase({dets, Ixt}, Pat) ->
ok = dets:match_delete(Ixt, Pat).
-db_match({ram, Ixt}, Pat) ->
- ?ets_match(Ixt, Pat);
-db_match({dets, Ixt}, Pat) ->
- dets:match(Ixt, Pat).
+db_select({ram, Ixt}, Pat) ->
+ ets:select(Ixt, Pat);
+db_select({{ext,_,_} = Ext, Ixt}, Pat) ->
+ mnesia_lib:db_select(Ext, Ixt, Pat);
+db_select({dets, Ixt}, Pat) ->
+ dets:select(Ixt, Pat).
+
get_index_table(Tab, Pos) ->
get_index_table(Tab, val({Tab, storage_type}), Pos).
-get_index_table(Tab, ram_copies, Pos) ->
- {ram, val({Tab, {index, Pos}})};
-get_index_table(Tab, disc_copies, Pos) ->
- {ram, val({Tab, {index, Pos}})};
-get_index_table(Tab, disc_only_copies, Pos) ->
- {dets, val({Tab, {index, Pos}})};
-get_index_table(_Tab, unknown, _Pos) ->
- unknown.
-
+get_index_table(Tab, _Storage, Pos) ->
+ #index{pos_list = PosL} = val({Tab, index_info}),
+ {_IxType, Ixt} = pick_index(PosL, Tab, Pos),
+ Ixt.
+
+index_vals_f(Storage, Tab, {_} = Pos) ->
+ index_vals_f(Storage, Tab,
+ lists:keyfind(Pos, 1, mnesia_schema:index_plugins()));
+index_vals_f(_Storage, Tab, {Pos,M,F}) ->
+ fun(Obj) ->
+ M:F(Tab, Pos, Obj)
+ end;
+index_vals_f(Storage, Tab, Pos) when is_integer(Pos) ->
+ case mnesia_lib:semantics(Storage, index_fun) of
+ undefined ->
+ fun(Obj) ->
+ [element(Pos, Obj)]
+ end;
+ F when is_function(F, 4) ->
+ {ext, Alias, _Mod} = Storage,
+ fun(Obj) ->
+ F(Alias, Tab, Pos, Obj)
+ end
+ end.
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 19b578f551..0e4017e4c3 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -34,6 +34,11 @@
delete_backend_type/1,
do_delete_backend_type/1,
backend_types/0,
+ add_index_plugin/3,
+ do_add_index_plugin/3,
+ delete_index_plugin/1,
+ do_delete_index_plugin/1,
+ index_plugins/0,
add_snmp/2,
add_table_copy/3,
add_table_index/2,
@@ -223,7 +228,13 @@ do_set_schema(Tab, Cs) ->
RecName = Cs#cstruct.record_name,
set({Tab, record_name}, RecName),
set({Tab, wild_pattern}, wild(RecName, Arity)),
- set({Tab, index}, Cs#cstruct.index),
+ set({Tab, index}, [P || {P,_} <- Cs#cstruct.index]),
+ case Cs#cstruct.index of
+ [] ->
+ set({Tab, index_info}, mnesia_index:index_info(Type, []));
+ _ ->
+ ignore
+ end,
%% create actual index tabs later
set({Tab, cookie}, Cs#cstruct.cookie),
set({Tab, version}, Cs#cstruct.version),
@@ -597,6 +608,11 @@ initial_schema_properties_([{backend_types, Types}|Props]) ->
verify_backend_type(Name, Module)
end, Types),
[{mnesia_backend_types, Types}|initial_schema_properties_(Props)];
+initial_schema_properties_([{index_plugins, Plugins}|Props]) ->
+ lists:foreach(fun({Name, Module, Function}) ->
+ verify_index_plugin(Name, Module, Function)
+ end, Plugins),
+ [{mnesia_index_plugins, Plugins}|initial_schema_properties_(Props)];
initial_schema_properties_([P|_Props]) ->
mnesia:abort({bad_schema_property, P});
initial_schema_properties_([]) ->
@@ -749,8 +765,20 @@ cs2list({8,Minor}, Cs) when Minor =:= 2; Minor =:= 1 ->
record_name,attributes,
user_properties,frag_properties,storage_properties,
cookie,version],
- rec2list(Tags, Orig, 2, Cs).
+ CsList = rec2list(Tags, Orig, 2, Cs),
+ case proplists:get_value(index, CsList, []) of
+ [] -> CsList;
+ NewFormat ->
+ OldFormat = [Pos || {Pos, _Pref} <- NewFormat],
+ lists:keyreplace(index, 1, CsList, {index, OldFormat})
+ end.
+rec2list([index | Tags], [index|Orig], Pos, Rec) ->
+ Val = element(Pos, Rec),
+ [{index, lists:map(
+ fun({_, _Type}=P) -> P;
+ (P) when is_integer(P); is_atom(P) -> {P, ordered}
+ end, Val)} | rec2list(Tags, Orig, Pos + 1, Rec)];
rec2list([external_copies | Tags], Orig0, Pos, Rec) ->
Orig = case Orig0 of
[external_copies|Rest] -> Rest;
@@ -811,8 +839,6 @@ list2cs(List, ExtTypes) when is_list(List) ->
Ix = pick(Name, index, List, []),
verify({alt, [nil, list]}, mnesia_lib:etype(Ix),
{bad_type, Name, {index, [Ix]}}),
- Ix2 = [attr_to_pos(I, Attrs) || I <- Ix],
-
Frag = pick(Name, frag_properties, List, []),
verify({alt, [nil, list]}, mnesia_lib:etype(Frag),
{badarg, Name, {frag_properties, Frag}}),
@@ -876,6 +902,7 @@ list2cs(List, ExtTypes) when is_list(List) ->
case Ix of
[] -> Cs0;
[_|_] ->
+ Ix2 = expand_index_attrs(Cs0),
Cs0#cstruct{index = Ix2}
end;
list2cs(Other, _ExtTypes) ->
@@ -921,6 +948,9 @@ expand_storage_type(S) ->
get_ext_types() ->
get_schema_user_property(mnesia_backend_types).
+get_index_plugins() ->
+ get_schema_user_property(mnesia_index_plugins).
+
get_schema_user_property(Key) ->
Tab = schema,
%% Must work reliably both within transactions and outside of transactions
@@ -970,6 +1000,7 @@ attr_tab_to_pos(Tab, Attr) ->
attr_to_pos(Attr, val({Tab, attributes})).
%% Convert attribute name to integer if neccessary
+attr_to_pos({_} = P, _) -> P;
attr_to_pos(Pos, _Attrs) when is_integer(Pos) ->
Pos;
attr_to_pos(Attr, Attrs) when is_atom(Attr) ->
@@ -1019,12 +1050,45 @@ has_duplicates([]) ->
false.
%% This is the only place where we check the validity of data
+
verify_cstruct(#cstruct{} = Cs) ->
assert_correct_cstruct(Cs),
- Cs1 = verify_external_copies(Cs),
+ Cs1 = verify_external_copies(
+ Cs#cstruct{index = expand_index_attrs(Cs)}),
assert_correct_cstruct(Cs1),
Cs1.
+expand_index_attrs(#cstruct{index = Ix, attributes = Attrs,
+ name = Tab} = Cs) ->
+ Prefered = prefered_index_types(Cs),
+ expand_index_attrs(Ix, Tab, Attrs, Prefered).
+
+expand_index_attrs(Ix, Tab, Attrs, Prefered) ->
+ lists:map(fun(P) when is_integer(P); is_atom(P) ->
+ {attr_to_pos(P, Attrs), Prefered};
+ ({A} = P) when is_atom(A) ->
+ {P, Prefered};
+ ({P, Type}) ->
+ {attr_to_pos(P, Attrs), Type};
+ (_Other) ->
+ mnesia:abort({bad_type, Tab, {index, Ix}})
+ end, Ix).
+
+prefered_index_types(#cstruct{external_copies = Ext}) ->
+ ExtTypes = [mnesia_lib:semantics(S, index_types) ||
+ {S,Ns} <- Ext, Ns =/= []],
+ case intersect_types(ExtTypes) of
+ [] -> ordered;
+ [Pref|_] -> Pref
+ end.
+
+intersect_types([]) ->
+ [];
+intersect_types([S1, S2|Rest]) ->
+ intersect_types([S1 -- (S1 -- S2)|Rest]);
+intersect_types([S]) ->
+ S.
+
verify_external_copies(#cstruct{external_copies = []} = Cs) ->
Cs;
verify_external_copies(#cstruct{name = Tab, external_copies = EC} = Cs) ->
@@ -1112,22 +1176,30 @@ assert_correct_cstruct(Cs) when is_record(Cs, cstruct) ->
Attrs),
Index = Cs#cstruct.index,
+
verify({alt, [nil, list]}, mnesia_lib:etype(Index),
{bad_type, Tab, {index, Index}}),
+ IxPlugins = get_index_plugins(),
+ AllowIndexOnKey = check_if_allow_index_on_key(),
IxFun =
- fun(Pos) ->
- verify(true, fun() ->
- if
- is_integer(Pos),
- Pos > 2,
- Pos =< Arity ->
- true;
- true -> false
- end
- end,
- {bad_type, Tab, {index, [Pos]}})
- end,
+ fun(Pos) ->
+ verify(
+ true, fun() ->
+ I = index_pos(Pos),
+ case Pos of
+ {_, T} ->
+ (T==bag orelse T==ordered)
+ andalso good_ix_pos(
+ I, AllowIndexOnKey,
+ Arity, IxPlugins);
+ _ ->
+ good_ix_pos(Pos, AllowIndexOnKey,
+ Arity, IxPlugins)
+ end
+ end,
+ {bad_type, Tab, {index, [Pos]}})
+ end,
lists:foreach(IxFun, Index),
LC = Cs#cstruct.local_content,
@@ -1173,6 +1245,24 @@ assert_correct_cstruct(Cs) when is_record(Cs, cstruct) ->
mnesia:abort({bad_type, Tab, {version, Version}})
end.
+good_ix_pos({_} = P, _, _, Plugins) ->
+ lists:keymember(P, 1, Plugins);
+good_ix_pos(I, true, Arity, _) when is_integer(I) ->
+ I >= 0 andalso I =< Arity;
+good_ix_pos(I, false, Arity, _) when is_integer(I) ->
+ I > 2 andalso I =< Arity;
+good_ix_pos(_, _, _, _) ->
+ false.
+
+
+check_if_allow_index_on_key() ->
+ case mnesia_monitor:get_env(allow_index_on_key) of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
verify_nodes(Cs) ->
Tab = Cs#cstruct.name,
Ram = Cs#cstruct.ram_copies,
@@ -1393,6 +1483,71 @@ backend_types() ->
[ram_copies, disc_copies, disc_only_copies |
[T || {T,_} <- get_ext_types()]].
+add_index_plugin(Name, Module, Function) ->
+ schema_transaction(
+ fun() -> do_add_index_plugin(Name, Module, Function) end).
+
+do_add_index_plugin(Name, Module, Function) ->
+ verify_index_plugin(Name, Module, Function),
+ Plugins = case do_read_table_property(schema, mnesia_index_plugins) of
+ undefined ->
+ [];
+ {_, Ps} ->
+ case lists:keymember(Name, 1, Ps) of
+ true ->
+ mnesia:abort({index_plugin_already_exists, Name});
+ false ->
+ Ps
+ end
+ end,
+ do_write_table_property(schema, {mnesia_index_plugins,
+ [{Name, Module, Function}|Plugins]}).
+
+delete_index_plugin(P) ->
+ schema_transaction(
+ fun() -> do_delete_index_plugin(P) end).
+
+do_delete_index_plugin({A} = P) when is_atom(A) ->
+ Plugins = get_index_plugins(),
+ case lists:keyfind(P, 1, Plugins) of
+ false ->
+ mnesia:abort({no_exists, {index_plugin, P}});
+ _Found ->
+ case ets:select(mnesia_gvar,
+ [{ {{'$1',{index,{P,'_'}}},'_'},[],['$1']},
+ { {{'$1',{index,P}},'_'},[],['$1']}], 1) of
+ {[_], _} ->
+ mnesia:abort({plugin_in_use, P});
+ '$end_of_table' ->
+ do_write_table_property(
+ schema, {mnesia_index_plugins,
+ lists:keydelete(P, 1, Plugins)})
+ end
+ end.
+
+verify_index_plugin({A} = Name, Module, Function)
+ when is_atom(A), is_atom(Module), is_atom(Function) ->
+ case code:ensure_loaded(Module) of
+ {error, nofile} ->
+ mnesia:abort({bad_type, {index_plugin,Name,Module,Function}});
+ {module,_} ->
+ %% Index plugins are called as Module:Function(Tab, Pos, Obj)
+ case erlang:function_exported(Module, Function, 3) of
+ true ->
+ ok;
+ false ->
+ mnesia:abort(
+ {bad_type, {index_plugin,Name,Module,Function}})
+ end
+ end;
+verify_index_plugin(Name, Module, Function) ->
+ mnesia:abort({bad_type, {index_plugin,Name,Module,Function}}).
+
+
+%% Used e.g. by mnesia:system_info(backend_types).
+index_plugins() ->
+ get_index_plugins().
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Here's the real interface function to create a table
@@ -1804,11 +1959,12 @@ make_add_table_index(Tab, Pos) ->
Cs = incr_version(val({Tab, cstruct})),
ensure_active(Cs),
Ix = Cs#cstruct.index,
- verify(false, lists:member(Pos, Ix), {already_exists, Tab, Pos}),
+ verify(false, lists:keymember(index_pos(Pos), 1, Ix),
+ {already_exists, Tab, Pos}),
Ix2 = lists:sort([Pos | Ix]),
- Cs2 = Cs#cstruct{index = Ix2},
- verify_cstruct(Cs2),
- [{op, add_index, Pos, vsn_cs2list(Cs2)}].
+ Cs2 = verify_cstruct(Cs#cstruct{index = Ix2}),
+ NewPosInfo = lists:keyfind(Pos, 1, Cs2#cstruct.index),
+ [{op, add_index, NewPosInfo, vsn_cs2list(Cs2)}].
del_table_index(Tab, Pos) ->
schema_transaction(fun() -> do_del_table_index(Tab, Pos) end).
@@ -1902,14 +2058,14 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) ->
record_name = NewRecName}),
[{op, transform, Fun, vsn_cs2list(Cs2)}];
PosList ->
- DelIdx = fun({Pos,_,_}, Ncs) ->
+ DelIdx = fun({Pos,_}, Ncs) ->
Ix = Ncs#cstruct.index,
Ix2 = lists:keydelete(Pos, 1, Ix),
Ncs1 = Ncs#cstruct{index = Ix2},
Op = {op, del_index, Pos, vsn_cs2list(Ncs1)},
{Op, Ncs1}
end,
- AddIdx = fun({_,_,_} = Pos, Ncs) ->
+ AddIdx = fun({_,_} = Pos, Ncs) ->
Ix = Ncs#cstruct.index,
Ix2 = lists:sort([Pos | Ix]),
Ncs1 = Ncs#cstruct{index = Ix2},
@@ -1924,6 +2080,11 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) ->
AddOps])
end.
+index_pos({Pos,_}) -> Pos;
+index_pos(Pos) when is_integer(Pos) -> Pos;
+index_pos({P} = Pos) when is_atom(P) -> Pos.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 70938c1d8f..2ca48a5d7c 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1796,12 +1796,12 @@ 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, Storage,
Tab, K, Obj, undefined),
mnesia_lib:db_put(Storage, Tab, Obj);
do_update_op(Tid, Storage, {{Tab, K}, Val, delete}) ->
- commit_delete(?catch_val({Tab, commit_work}), Tid, Tab, K, Val, undefined),
+ commit_delete(?catch_val({Tab, commit_work}), Tid, Storage, Tab, K, Val, undefined),
mnesia_lib:db_erase(Storage, Tab, K);
do_update_op(Tid, Storage, {{Tab, K}, {RecName, Incr}, update_counter}) ->
@@ -1819,83 +1819,81 @@ do_update_op(Tid, Storage, {{Tab, K}, {RecName, Incr}, update_counter}) ->
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, Storage, 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}),
- Tid, Tab, Key, Obj, undefined),
+ Tid, Storage, Tab, Key, Obj),
mnesia_lib:db_match_erase(Storage, Tab, Obj);
do_update_op(Tid, Storage, {{Tab, Key}, Obj, clear_table}) ->
- commit_clear(?catch_val({Tab, commit_work}), Tid, Tab, Key, Obj),
+ commit_clear(?catch_val({Tab, commit_work}), Tid, Storage, Tab, Key, Obj),
mnesia_lib:db_match_erase(Storage, Tab, Obj).
-commit_write([], _, _, _, _, _) -> ok;
-commit_write([{checkpoints, CpList}|R], Tid, Tab, K, Obj, Old) ->
+commit_write([], _, _, _, _, _, _) -> ok;
+commit_write([{checkpoints, CpList}|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_write([H|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_write([H|R], Tid, Storage, 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).
+ mnesia_index:add_index(H, Storage, Tab, K, Obj, Old),
+ commit_write(R, Tid, Storage, Tab, K, Obj, Old).
-commit_update([], _, _, _, _, _) -> ok;
-commit_update([{checkpoints, CpList}|R], Tid, Tab, K, Obj, _) ->
+commit_update([], _, _, _, _, _, _) -> ok;
+commit_update([{checkpoints, CpList}|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_update([H|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_update([H|R], Tid,Storage, 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).
+ mnesia_index:add_index(H, Storage, Tab, K, Obj, Old),
+ commit_update(R, Tid, Storage, Tab, K, Obj, Old).
-commit_delete([], _, _, _, _, _) -> ok;
-commit_delete([{checkpoints, CpList}|R], Tid, Tab, K, Obj, _) ->
+commit_delete([], _, _, _, _, _, _) -> ok;
+commit_delete([{checkpoints, CpList}|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_delete([H|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj, Old);
+commit_delete([H|R], Tid, Storage, Tab, K, Obj, Old)
when element(1, H) == index ->
- mnesia_index:delete_index(H, Tab, K),
- commit_delete(R, Tid, Tab, K, Obj, Old).
+ mnesia_index:delete_index(H, Storage, Tab, K),
+ commit_delete(R, Tid, Storage, Tab, K, Obj, Old).
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 ->
- 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 ->
- mnesia_index:del_object_index(H, Tab, K, Obj, Old),
- commit_del_object(R, Tid, Tab, K, Obj, Old).
-
-commit_clear([], _, _, _, _) -> ok;
-commit_clear([{checkpoints, CpList}|R], Tid, Tab, K, Obj) ->
+commit_del_object([{checkpoints, CpList}|R], Tid, Storage, Tab, K, Obj) ->
+ mnesia_checkpoint:tm_retain(Tid, Tab, K, delete_object, CpList),
+ commit_del_object(R, Tid, Storage, Tab, K, Obj);
+commit_del_object([H|R], Tid, Storage, Tab, K, Obj) when element(1, H) == subscribers ->
+ mnesia_subscr:report_table_event(H, Tab, Tid, Obj, delete_object),
+ commit_del_object(R, Tid, Storage, Tab, K, Obj);
+commit_del_object([H|R], Tid, Storage, Tab, K, Obj) when element(1, H) == index ->
+ mnesia_index:del_object_index(H, Storage, Tab, K, Obj),
+ commit_del_object(R, Tid, Storage, Tab, K, Obj).
+
+commit_clear([], _, _, _, _, _) -> ok;
+commit_clear([{checkpoints, CpList}|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj);
+commit_clear([H|R], Tid, Storage, 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(R, Tid, Storage, Tab, K, Obj);
+commit_clear([H|R], Tid, Storage, Tab, K, Obj)
when element(1, H) == index ->
mnesia_index:clear_index(H, Tab, K, Obj),
- commit_clear(R, Tid, Tab, K, Obj).
+ commit_clear(R, Tid, Storage, Tab, K, Obj).
do_snmp(_, []) -> ok;
do_snmp(Tid, [Head | Tail]) ->
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index a371d58e75..5e65600b4d 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -931,20 +931,20 @@ index_update_bag(Config)when is_list(Config) ->
[IPos] = mnesia_lib:val({Tab,index}),
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}], lists:keysort(1,ets:tab2list(ITab))),
+ %?match([{2,1},{2,2},{12,1}], lists:keysort(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}], lists:keysort(1,ets:tab2list(ITab))),
+ %?match([{2,1},{2,2},{12,1}], lists:keysort(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}], lists:keysort(1,ets:tab2list(ITab))),
+ %% ?match([{2,1},{2,2}], lists:keysort(1,ets:tab2list(ITab))),
%% reset for rest of testcase
?match({atomic, ok}, mnesia:transaction(fun() -> mnesia:write(Rec3) end)),