1
%% ``The contents of this file are subject to the Erlang Public License,
2
%% Version 1.1, (the "License"); you may not use this file except in
3
%% compliance with the License. You should have received a copy of the
4
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
7
%% Software distributed under the License is distributed on an "AS IS"
8
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
%% the License for the specific language governing rights and limitations
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
16
%% $Id: mnesia_lib.erl,v 1.3 2009/07/01 15:45:40 kostis Exp $
18
%% This module contains all sorts of various which doesn't fit
19
%% anywhere else. Basically everything is exported.
23
-include("mnesia.hrl").
24
-include_lib("kernel/include/file.hrl").
26
-export([core_file/0]).
82
dirty_rpc_error_tag/1,
106
local_active_tables/0,
115
remote_copy_holders/1,
117
report_system_event/1,
120
schema_cs_to_storage_type/2,
124
set_local_content_whereabouts/1,
125
set_remote_where_to_read/1,
126
set_remote_where_to_read/2,
130
storage_type_at_node/2,
153
activate_debug_fun/5,
154
deactivate_debug_fun/3,
160
search_delete(Obj, List) ->
161
search_delete(Obj, List, [], none).
162
search_delete(Obj, [Obj|Tail], Ack, _Res) ->
163
search_delete(Obj, Tail, Ack, Obj);
164
search_delete(Obj, [H|T], Ack, Res) ->
165
search_delete(Obj, T, [H|Ack], Res);
166
search_delete(_, [], Ack, Res) ->
169
key_search_delete(Key, Pos, TupleList) ->
170
key_search_delete(Key, Pos, TupleList, none, []).
171
key_search_delete(Key, Pos, [H|T], _Obj, Ack) when element(Pos, H) == Key ->
172
key_search_delete(Key, Pos, T, H, Ack);
173
key_search_delete(Key, Pos, [H|T], Obj, Ack) ->
174
key_search_delete(Key, Pos, T, Obj, [H|Ack]);
175
key_search_delete(_, _, [], Obj, Ack) ->
178
key_search_all(Key, Pos, TupleList) ->
179
key_search_all(Key, Pos, TupleList, []).
180
key_search_all(Key, N, [H|T], Ack) when element(N, H) == Key ->
181
key_search_all(Key, N, T, [H|Ack]);
182
key_search_all(Key, N, [_|T], Ack) ->
183
key_search_all(Key, N, T, Ack);
184
key_search_all(_, _, [], Ack) -> Ack.
190
[element(I, H) | elems(I, T)];
194
%% sort_commit see to that checkpoint info is always first in
195
%% commit_work structure the other info don't need to be sorted.
197
sort_commit2(List, []).
199
sort_commit2([{checkpoints, ChkpL}| Rest], Acc) ->
200
[{checkpoints, ChkpL}| Rest] ++ Acc;
201
sort_commit2([H | R], Acc) ->
202
sort_commit2(R, [H | Acc]);
203
sort_commit2([], Acc) -> Acc.
207
0 =< H, H < 256, integer(H) -> is_string(T);
210
is_string([]) -> true.
215
case lists:member(H, L2) of
216
true -> union(L1, L2);
217
false -> [H | union(L1, L2)]
224
[H|T] = lists:sort(List),
227
uniq1(H, [H|R], Ack) ->
229
uniq1(Old, [H|R], Ack) ->
230
uniq1(H, R, [Old|Ack]);
231
uniq1(Old, [], Ack) ->
234
to_list(X) when list(X) -> X;
235
to_list(X) -> atom_to_list(X).
238
Ns = mnesia:system_info(db_nodes) ++
239
mnesia:system_info(extra_db_nodes),
243
running_nodes(all_nodes()).
246
{Replies, _BadNs} = rpc:multicall(Ns, ?MODULE, is_running_remote, []),
247
[N || {GoodState, N} <- Replies, GoodState == true].
249
is_running_remote() ->
250
IsRunning = is_running(),
251
{IsRunning == yes, node()}.
253
is_running(Node) when atom(Node) ->
254
case rpc:call(Node, ?MODULE, is_running, []) of
260
case ?catch_val(mnesia_status) of
263
starting -> starting;
270
io:format(user, F, A).
273
pad_name([Char | Chars], Len, Tail) ->
274
[Char | pad_name(Chars, Len - 1, Tail)];
275
pad_name([], Len, Tail) when Len =< 0 ->
277
pad_name([], Len, Tail) ->
278
[$ | pad_name([], Len - 1, Tail)].
280
%% Some utility functions .....
282
case val({Tab, where_to_read}) of
283
Node when Node == node() -> true;
287
not_active_here(Tab) ->
288
not active_here(Tab).
291
case file:open(Fname, [raw,read]) of
292
{ok, F} ->file:close(F), true;
296
dir() -> mnesia_monitor:get_env(dir).
299
filename:join([dir(), to_list(Fname)]).
301
tab2dat(Tab) -> %% DETS files
302
dir(lists:concat([Tab, ".DAT"])).
305
dir(lists:concat([Tab, ".TMP"])).
307
tab2dmp(Tab) -> %% Dumped ets tables
308
dir(lists:concat([Tab, ".DMP"])).
310
tab2dcd(Tab) -> %% Disc copies data
311
dir(lists:concat([Tab, ".DCD"])).
313
tab2dcl(Tab) -> %% Disc copies log
314
dir(lists:concat([Tab, ".DCL"])).
316
storage_type_at_node(Node, Tab) ->
317
search_key(Node, [{disc_copies, val({Tab, disc_copies})},
318
{ram_copies, val({Tab, ram_copies})},
319
{disc_only_copies, val({Tab, disc_only_copies})}]).
321
cs_to_storage_type(Node, Cs) ->
322
search_key(Node, [{disc_copies, Cs#cstruct.disc_copies},
323
{ram_copies, Cs#cstruct.ram_copies},
324
{disc_only_copies, Cs#cstruct.disc_only_copies}]).
326
schema_cs_to_storage_type(Node, Cs) ->
327
case cs_to_storage_type(Node, Cs) of
328
unknown when Cs#cstruct.name == schema -> ram_copies;
333
search_key(Key, [{Val, List} | Tail]) ->
334
case lists:member(Key, List) of
336
false -> search_key(Key, Tail)
338
search_key(_Key, []) ->
341
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342
%% ops, we've got some global variables here :-)
346
%% {Tab, setorbag}, -> set | bag
347
%% {Tab, storage_type} -> disc_copies |ram_copies | unknown (**)
348
%% {Tab, disc_copies} -> node list (from schema)
349
%% {Tab, ram_copies}, -> node list (from schema)
350
%% {Tab, arity}, -> number
351
%% {Tab, attributes}, -> atom list
352
%% {Tab, wild_pattern}, -> record tuple with '_'s
353
%% {Tab, {index, Pos}} -> ets table
354
%% {Tab, index} -> integer list
355
%% {Tab, cstruct} -> cstruct structure
358
%% The following fields are dynamic according to the
359
%% the current node/table situation
361
%% {Tab, where_to_write} -> node list
362
%% {Tab, where_to_read} -> node | nowhere
364
%% {schema, tables} -> tab list
365
%% {schema, local_tables} -> tab list (**)
367
%% {current, db_nodes} -> node list
369
%% dir -> directory path (**)
370
%% mnesia_status -> status | running | stopping (**)
371
%% (**) == (Different on all nodes)
375
case ?catch_val(Var) of
376
{'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
381
?ets_insert(mnesia_gvar, {Var, Val}).
384
?ets_delete(mnesia_gvar, Var).
386
other_val(Var, Other) ->
388
{_, where_to_read} -> nowhere;
389
{_, where_to_write} -> [];
390
{_, active_replicas} -> [];
395
pr_other(Var, Other) ->
398
no -> {node_not_running, node()};
399
_ -> {no_exists, Var}
401
verbose("~p (~p) val(mnesia_gvar, ~w) -> ~p ~p ~n",
402
[self(), process_info(self(), registered_name),
405
{badarg, [{ets, lookup_element, _}|_]} ->
411
%% Some functions for list valued variables
414
set(Var, [Val | lists:delete(Val, L)]).
416
add_list(Var, List) ->
418
set(Var, union(L, List)).
422
set(Var, lists:delete(Val, L)).
424
%% This function is needed due to the fact
425
%% that the application_controller enters
426
%% a deadlock now and then. ac is implemented
427
%% as a rather naive server.
428
ensure_loaded(Appl) ->
429
case application_controller:get_loaded(Appl) of
433
case application:load(Appl) of
436
{error, {already_loaded, Appl}} ->
439
{error, {application_load_error, Reason}}
443
local_active_tables() ->
444
Tabs = val({schema, local_tables}),
445
lists:zf(fun(Tab) -> active_here(Tab) end, Tabs).
448
Tabs = val({schema, tables}),
450
case val({Tab, where_to_read}) of
457
etype(X) when integer(X) -> integer;
459
etype(X) when list(X) -> list;
460
etype(X) when tuple(X) -> tuple;
461
etype(X) when atom(X) -> atom;
462
etype(_) -> othertype.
464
remote_copy_holders(Cs) ->
465
copy_holders(Cs) -- [node()].
467
copy_holders(Cs) when Cs#cstruct.local_content == false ->
469
copy_holders(Cs) when Cs#cstruct.local_content == true ->
470
case lists:member(node(), cs_to_nodes(Cs)) of
476
set_remote_where_to_read(Tab) ->
477
set_remote_where_to_read(Tab, []).
479
set_remote_where_to_read(Tab, Ignore) ->
480
Active = val({Tab, active_replicas}),
482
case mnesia_recover:get_master_nodes(Tab) of
484
Masters -> mnesia_lib:intersect(Masters, Active)
486
Available = mnesia_lib:intersect(val({current, db_nodes}), Valid -- Ignore),
487
DiscOnlyC = val({Tab, disc_only_copies}),
488
Prefered = Available -- DiscOnlyC,
491
set({Tab, where_to_read}, hd(Prefered));
493
set({Tab, where_to_read}, hd(Available));
495
set({Tab, where_to_read}, nowhere)
499
set_local_content_whereabouts(Tab) ->
500
add({schema, local_tables}, Tab),
501
add({Tab, active_replicas}, node()),
502
set({Tab, where_to_write}, [node()]),
503
set({Tab, where_to_read}, node()).
507
create_counter(Name) ->
508
set_counter(Name, 0).
510
set_counter(Name, Val) ->
511
?ets_insert(mnesia_gvar, {Name, Val}).
513
incr_counter(Name) ->
514
?ets_update_counter(mnesia_gvar, Name, 1).
516
incr_counter(Name, I) ->
517
?ets_update_counter(mnesia_gvar, Name, I).
519
update_counter(Name, Val) ->
520
?ets_update_counter(mnesia_gvar, Name, Val).
522
read_counter(Name) ->
523
?ets_lookup_element(mnesia_gvar, Name, 2).
526
Cs#cstruct.disc_only_copies ++
527
Cs#cstruct.disc_copies ++
528
Cs#cstruct.ram_copies.
531
dist_coredump(all_nodes()).
533
{Replies, _} = rpc:multicall(Ns, ?MODULE, coredump, []),
537
coredump({crashinfo, {"user initiated~n", []}}).
538
coredump(CrashInfo) ->
539
Core = mkcore(CrashInfo),
541
important("Writing Mnesia core to file: ~p...~p~n", [Out, CrashInfo]),
542
file:write_file(Out, Core),
546
Integers = tuple_to_list(date()) ++ tuple_to_list(time()),
547
Fun = fun(I) when I < 10 -> ["_0", I];
550
List = lists:append([Fun(I) || I <- Integers]),
551
filename:absname(lists:concat(["MnesiaCore.", node()] ++ List)).
554
% dbg_out("Making a Mnesia core dump...~p~n", [CrashInfo]),
555
Nodes = [node() |nodes()],
556
TidLocks = (catch ets:tab2list(mnesia_tid_locks)),
559
{time, {date(), time()}},
560
{self, catch process_info(self())},
561
{nodes, catch rpc:multicall(Nodes, ?MODULE, get_node_number, [])},
562
{applications, catch lists:sort(application:loaded_applications())},
563
{flags, catch init:get_arguments()},
564
{code_path, catch code:get_path()},
565
{code_loaded, catch lists:sort(code:all_loaded())},
566
{etsinfo, catch ets_info(ets:all())},
568
{version, catch mnesia:system_info(version)},
569
{schema, catch ets:tab2list(schema)},
570
{gvar, catch ets:tab2list(mnesia_gvar)},
571
{master_nodes, catch mnesia_recover:get_master_node_info()},
573
{processes, catch procs()},
574
{relatives, catch relatives()},
575
{workers, catch workers(mnesia_controller:get_workers(2000))},
576
{locking_procs, catch locking_procs(TidLocks)},
578
{held_locks, catch mnesia:system_info(held_locks)},
579
{tid_locks, TidLocks},
580
{lock_queue, catch mnesia:system_info(lock_queue)},
581
{load_info, catch mnesia_controller:get_info(2000)},
582
{trans_info, catch mnesia_tm:get_info(2000)},
584
{schema_file, catch file:read_file(tab2dat(schema))},
585
{dir_info, catch dir_info()},
586
{logfile, catch {ok, read_log_files()}}
588
term_to_binary(Core).
591
Fun = fun(P) -> {P, (catch lists:zf(fun proc_info/1, process_info(P)))} end,
592
lists:map(Fun, processes()).
594
proc_info({registered_name, Val}) -> {true, Val};
595
proc_info({message_queue_len, Val}) -> {true, Val};
596
proc_info({status, Val}) -> {true, Val};
597
proc_info({current_function, Val}) -> {true, Val};
598
proc_info(_) -> false.
604
[{F, catch file:read_file(F)} || F <- mnesia_log:log_files()].
607
{ok, Cwd} = file:get_cwd(),
609
[{cwd, Cwd, file:read_file_info(Cwd)},
610
{mnesia_dir, Dir, file:read_file_info(Dir)}] ++
611
case file:list_dir(Dir) of
613
[{mnesia_file, F, catch file:read_file_info(dir(F))} || F <- Files];
619
[{table, H, ets:info(H)} | ets_info(T)];
624
case whereis(Name) of
626
Pid -> {true, {Name, Pid, catch process_info(Pid)}}
629
lists:zf(Info, mnesia:ms()).
631
workers({workers, Loader, Sender, Dumper}) ->
632
Info = fun({Name, Pid}) ->
635
Pid -> {true, {Name, Pid, catch process_info(Pid)}}
638
lists:zf(Info, [{loader, Loader}, {sender, Sender}, {dumper, Dumper}]).
640
locking_procs(LockList) when list(LockList) ->
641
Tids = [element(1, Lock) || Lock <- LockList],
645
case node(Pid) == node() of
647
{true, {Pid, catch process_info(Pid)}};
655
Bin = mkcore({crashinfo, {"view only~n", []}}),
658
%% Displays a Mnesia file on the tty. The file may be repaired.
660
case suffix([".DAT", ".RET", ".DMP", ".TMP"], File) of
664
case suffix([".LOG", ".BUP", ".ETS"], File) of
668
case lists:prefix("MnesiaCore.", File) of
672
{error, "Unknown file name"}
680
mnesia_log:view(File);
684
suffix(Suffixes, File) ->
685
Fun = fun(S) -> lists:suffix(S, File) end,
686
lists:any(Fun, Suffixes).
691
Prefix = lists:concat(["MnesiaCore.", node()]),
692
Filter = fun(F) -> lists:prefix(Prefix, F) end,
693
{ok, Cwd} = file:get_cwd(),
694
case file:list_dir(Cwd) of
696
CoreFiles = lists:sort(lists:zf(Filter, Files)),
697
show("Mnesia core files: ~p~n", [CoreFiles]),
698
vcore(lists:last(CoreFiles));
703
vcore(Bin) when binary(Bin) ->
704
Core = binary_to_term(Bin),
705
Fun = fun({Item, Info}) ->
706
show("***** ~p *****~n", [Item]),
707
case catch vcore_elem({Item, Info}) of
709
show("{'EXIT', ~p}~n", [Reason]);
713
lists:foreach(Fun, Core);
716
show("~n***** Mnesia core: ~p *****~n", [File]),
717
case file:read_file(File) of
724
vcore_elem({schema_file, {ok, B}}) ->
725
Fname = "/tmp/schema.DAT",
726
file:write_file(Fname, B),
730
vcore_elem({logfile, {ok, BinList}}) ->
731
Fun = fun({F, Info}) ->
732
show("----- logfile: ~p -----~n", [F]),
735
Fname = "/tmp/mnesia_vcore_elem.TMP",
736
file:write_file(Fname, B),
737
mnesia_log:view(Fname),
743
lists:foreach(Fun, BinList);
745
vcore_elem({crashinfo, {Format, Args}}) ->
747
vcore_elem({gvar, L}) ->
748
show("~p~n", [lists:sort(L)]);
749
vcore_elem({transactions, Info}) ->
750
mnesia_tm:display_info(user, Info);
752
vcore_elem({_Item, Info}) ->
753
show("~p~n", [Info]).
756
set(last_error, X), %% for debugabililty
758
{aborted, Reason} -> Reason;
759
{abort, Reason} -> Reason;
761
{'EXIT', {_Reason, {Mod, _, _}}} when atom(Mod) ->
763
case atom_to_list(Mod) of
764
[$m, $n, $e|_] -> badarg;
773
%% The following is a list of possible mnesia errors and what they
776
error_desc(nested_transaction) -> "Nested transactions are not allowed";
777
error_desc(badarg) -> "Bad or invalid argument, possibly bad type";
778
error_desc(no_transaction) -> "Operation not allowed outside transactions";
779
error_desc(combine_error) -> "Table options were ilegally combined";
780
error_desc(bad_index) -> "Index already exists or was out of bounds";
781
error_desc(already_exists) -> "Some schema option we try to set is already on";
782
error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
783
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
784
error_desc(system_limit) -> "Some system_limit was exhausted";
785
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
786
"node which died while transaction was executing"
787
"*and* object(s) are no longer available elsewhere"
789
error_desc(not_a_db_node) -> "A node which is non existant in "
790
"the schema was mentioned";
791
error_desc(bad_type) -> "Bad type on some provided arguments";
792
error_desc(node_not_running) -> "Node not running";
793
error_desc(truncated_binary_file) -> "Truncated binary in file";
794
error_desc(active) -> "Some delete ops require that "
795
"all active objects are removed";
796
error_desc(illegal) -> "Operation not supported on object";
797
error_desc({'EXIT', Reason}) ->
799
error_desc({error, Reason}) ->
801
error_desc({aborted, Reason}) ->
803
error_desc(Reason) when tuple(Reason), size(Reason) > 0 ->
804
setelement(1, Reason, error_desc(element(1, Reason)));
805
error_desc(Reason) ->
808
dirty_rpc_error_tag(Reason) ->
810
{'EXIT', _} -> badarg;
811
no_variable -> badarg;
815
fatal(Format, Args) ->
816
catch set(mnesia_status, stopping),
817
Core = mkcore({crashinfo, {Format, Args}}),
818
report_fatal(Format, Args, Core),
819
timer:sleep(10000), % Enough to write the core dump to disc?
823
report_fatal(Format, Args) ->
824
report_fatal(Format, Args, nocore).
826
report_fatal(Format, Args, Core) ->
827
report_system_event({mnesia_fatal, Format, Args, Core}),
828
catch exit(whereis(mnesia_monitor), fatal).
830
%% We sleep longer and longer the more we try
831
%% Made some testing and came up with the following constants
832
random_time(Retries, _Counter0) ->
834
% MaxIntv = trunc(UpperLimit * (1-(4/((Retries*Retries)+4)))),
836
Dup = Retries * Retries,
837
MaxIntv = trunc(UpperLimit * (1-(50/((Dup)+50)))),
839
case get(random_seed) of
841
{X, Y, Z} = erlang:now(), %% time()
842
random:seed(X, Y, Z),
843
Time = Dup + random:uniform(MaxIntv),
844
%% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]),
847
Time = Dup + random:uniform(MaxIntv),
848
%% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]),
852
report_system_event(Event0) ->
853
Event = {mnesia_system_event, Event0},
854
report_system_event(catch_notify(Event), Event),
855
case ?catch_val(subscribers) of
856
{'EXIT', _} -> ignore;
857
Pids -> lists:foreach(fun(Pid) -> Pid ! Event end, Pids)
861
catch_notify(Event) ->
862
case whereis(mnesia_event) of
864
{'EXIT', {badarg, {mnesia_event, Event}}};
866
gen_event:notify(Pid, Event)
869
report_system_event({'EXIT', Reason}, Event) ->
870
Mod = mnesia_monitor:get_env(event_module),
871
case mnesia_sup:start_event() of
874
gen_event:call(mnesia_event, Mod, Event, infinity),
877
%% We get an exit signal if server dies
879
{'EXIT', Pid, _Reason} ->
880
{error, {node_not_running, node()}}
882
gen_event:stop(mnesia_event),
887
Msg = "Mnesia(~p): Cannot report event ~p: ~p (~p)~n",
888
error_logger:format(Msg, [node(), Event, Reason, Error])
890
report_system_event(_Res, _Event) ->
893
%% important messages are reported regardless of debug level
894
important(Format, Args) ->
895
save({Format, Args}),
896
report_system_event({mnesia_info, Format, Args}).
898
%% Warning messages are reported regardless of debug level
899
warning(Format, Args) ->
900
save({Format, Args}),
901
report_system_event({mnesia_warning, Format, Args}).
903
%% error messages are reported regardless of debug level
904
error(Format, Args) ->
905
save({Format, Args}),
906
report_system_event({mnesia_error, Format, Args}).
908
%% verbose messages are reported if debug level == debug or verbose
909
verbose(Format, Args) ->
910
case mnesia_monitor:get_env(debug) of
911
none -> save({Format, Args});
912
verbose -> important(Format, Args);
913
debug -> important(Format, Args);
914
trace -> important(Format, Args)
917
%% debug message are display if debug level == 2
918
dbg_out(Format, Args) ->
919
case mnesia_monitor:get_env(debug) of
921
verbose -> save({Format, Args});
922
_ -> report_system_event({mnesia_info, Format, Args})
925
%% Keep the last 10 debug print outs
927
catch save2(DbgInfo).
930
Key = {'$$$_report', current_pos},
932
case ?ets_lookup_element(mnesia_gvar, Key, 2) of
936
set({'$$$_report', current_pos}, P+1),
937
set({'$$$_report', P+1}, {date(), time(), DbgInfo}).
939
copy_file(From, To) ->
940
case file:open(From, [raw, binary, read]) of
942
case file:open(To, [raw, binary, write]) of
944
Res = copy_file_loop(F, T, 8000),
955
copy_file_loop(F, T, ChunkSize) ->
956
case file:read(F, ChunkSize) of
961
copy_file_loop(F, T, ChunkSize);
964
copy_file_loop(F, T, ChunkSize);
973
%% versions of all the lowlevel db funcs that determine whether we
974
%% shall go to disc or ram to do the actual operation.
977
db_get(val({Tab, storage_type}), Tab, Key).
978
db_get(ram_copies, Tab, Key) -> ?ets_lookup(Tab, Key);
979
db_get(disc_copies, Tab, Key) -> ?ets_lookup(Tab, Key);
980
db_get(disc_only_copies, Tab, Key) -> dets:lookup(Tab, Key).
982
db_init_chunk(Tab) ->
983
db_init_chunk(val({Tab, storage_type}), Tab, 1000).
984
db_init_chunk(Tab, N) ->
985
db_init_chunk(val({Tab, storage_type}), Tab, N).
987
db_init_chunk(disc_only_copies, Tab, N) ->
988
dets:select(Tab, [{'_', [], ['$_']}], N);
989
db_init_chunk(_, Tab, N) ->
990
ets:select(Tab, [{'_', [], ['$_']}], N).
992
db_chunk(disc_only_copies, State) ->
994
db_chunk(_, State) ->
998
db_put(val({Tab, storage_type}), Tab, Val).
1000
db_put(ram_copies, Tab, Val) -> ?ets_insert(Tab, Val), ok;
1001
db_put(disc_copies, Tab, Val) -> ?ets_insert(Tab, Val), ok;
1002
db_put(disc_only_copies, Tab, Val) -> dets:insert(Tab, Val).
1004
db_match_object(Tab, Pat) ->
1005
db_match_object(val({Tab, storage_type}), Tab, Pat).
1006
db_match_object(Storage, Tab, Pat) ->
1007
db_fixtable(Storage, Tab, true),
1008
Res = catch_match_object(Storage, Tab, Pat),
1009
db_fixtable(Storage, Tab, false),
1011
{'EXIT', Reason} -> exit(Reason);
1015
catch_match_object(disc_only_copies, Tab, Pat) ->
1016
catch dets:match_object(Tab, Pat);
1017
catch_match_object(_, Tab, Pat) ->
1018
catch ets:match_object(Tab, Pat).
1020
db_select(Tab, Pat) ->
1021
db_select(val({Tab, storage_type}), Tab, Pat).
1023
db_select(Storage, Tab, Pat) ->
1024
db_fixtable(Storage, Tab, true),
1025
Res = catch_select(Storage, Tab, Pat),
1026
db_fixtable(Storage, Tab, false),
1028
{'EXIT', Reason} -> exit(Reason);
1032
catch_select(disc_only_copies, Tab, Pat) ->
1033
dets:select(Tab, Pat);
1034
catch_select(_, Tab, Pat) ->
1035
ets:select(Tab, Pat).
1037
db_fixtable(ets, Tab, Bool) ->
1038
ets:safe_fixtable(Tab, Bool);
1039
db_fixtable(ram_copies, Tab, Bool) ->
1040
ets:safe_fixtable(Tab, Bool);
1041
db_fixtable(disc_copies, Tab, Bool) ->
1042
ets:safe_fixtable(Tab, Bool);
1043
db_fixtable(dets, Tab, Bool) ->
1044
dets:safe_fixtable(Tab, Bool);
1045
db_fixtable(disc_only_copies, Tab, Bool) ->
1046
dets:safe_fixtable(Tab, Bool).
1048
db_erase(Tab, Key) ->
1049
db_erase(val({Tab, storage_type}), Tab, Key).
1050
db_erase(ram_copies, Tab, Key) -> ?ets_delete(Tab, Key), ok;
1051
db_erase(disc_copies, Tab, Key) -> ?ets_delete(Tab, Key), ok;
1052
db_erase(disc_only_copies, Tab, Key) -> dets:delete(Tab, Key).
1054
db_match_erase(Tab, Pat) ->
1055
db_match_erase(val({Tab, storage_type}), Tab, Pat).
1056
db_match_erase(ram_copies, Tab, Pat) -> ?ets_match_delete(Tab, Pat), ok;
1057
db_match_erase(disc_copies, Tab, Pat) -> ?ets_match_delete(Tab, Pat), ok;
1058
db_match_erase(disc_only_copies, Tab, Pat) -> dets:match_delete(Tab, Pat).
1061
db_first(val({Tab, storage_type}), Tab).
1062
db_first(ram_copies, Tab) -> ?ets_first(Tab);
1063
db_first(disc_copies, Tab) -> ?ets_first(Tab);
1064
db_first(disc_only_copies, Tab) -> dets:first(Tab).
1066
db_next_key(Tab, Key) ->
1067
db_next_key(val({Tab, storage_type}), Tab, Key).
1068
db_next_key(ram_copies, Tab, Key) -> ?ets_next(Tab, Key);
1069
db_next_key(disc_copies, Tab, Key) -> ?ets_next(Tab, Key);
1070
db_next_key(disc_only_copies, Tab, Key) -> dets:next(Tab, Key).
1073
db_last(val({Tab, storage_type}), Tab).
1074
db_last(ram_copies, Tab) -> ?ets_last(Tab);
1075
db_last(disc_copies, Tab) -> ?ets_last(Tab);
1076
db_last(disc_only_copies, Tab) -> dets:first(Tab). %% Dets don't have order
1078
db_prev_key(Tab, Key) ->
1079
db_prev_key(val({Tab, storage_type}), Tab, Key).
1080
db_prev_key(ram_copies, Tab, Key) -> ?ets_prev(Tab, Key);
1081
db_prev_key(disc_copies, Tab, Key) -> ?ets_prev(Tab, Key);
1082
db_prev_key(disc_only_copies, Tab, Key) -> dets:next(Tab, Key). %% Dets don't have order
1084
db_slot(Tab, Pos) ->
1085
db_slot(val({Tab, storage_type}), Tab, Pos).
1086
db_slot(ram_copies, Tab, Pos) -> ?ets_slot(Tab, Pos);
1087
db_slot(disc_copies, Tab, Pos) -> ?ets_slot(Tab, Pos);
1088
db_slot(disc_only_copies, Tab, Pos) -> dets:slot(Tab, Pos).
1090
db_update_counter(Tab, C, Val) ->
1091
db_update_counter(val({Tab, storage_type}), Tab, C, Val).
1092
db_update_counter(ram_copies, Tab, C, Val) ->
1093
?ets_update_counter(Tab, C, Val);
1094
db_update_counter(disc_copies, Tab, C, Val) ->
1095
?ets_update_counter(Tab, C, Val);
1096
db_update_counter(disc_only_copies, Tab, C, Val) ->
1097
dets:update_counter(Tab, C, Val).
1099
db_erase_tab(Tab) ->
1100
db_erase_tab(val({Tab, storage_type}), Tab).
1101
db_erase_tab(ram_copies, Tab) -> ?ets_delete_table(Tab);
1102
db_erase_tab(disc_copies, Tab) -> ?ets_delete_table(Tab);
1103
db_erase_tab(disc_only_copies, _Tab) -> ignore.
1105
%% assuming that Tab is a valid ets-table
1106
dets_to_ets(Tabname, Tab, File, Type, Rep, Lock) ->
1107
{Open, Close} = mkfuns(Lock),
1108
case Open(Tabname, [{file, File}, {type, disk_type(Tab, Type)},
1109
{keypos, 2}, {repair, Rep}]) of
1111
Res = dets:to_ets(Tabname, Tab),
1118
trav_ret(Tabname, Tabname) -> loaded;
1119
trav_ret(Other, _Tabname) -> Other.
1122
{fun(Tab, Args) -> dets_sync_open(Tab, Args) end,
1123
fun(Tab) -> dets_sync_close(Tab) end};
1125
{fun(Tab, Args) -> dets:open_file(Tab, Args) end,
1126
fun(Tab) -> dets:close(Tab) end}.
1129
disk_type(Tab, val({Tab, setorbag})).
1131
disk_type(_Tab, ordered_set) ->
1133
disk_type(_, Type) ->
1136
dets_sync_open(Tab, Ref, File) ->
1137
Args = [{file, File},
1139
{repair, mnesia_monitor:get_env(auto_repair)},
1140
{type, disk_type(Tab)}],
1141
dets_sync_open(Ref, Args).
1144
global:set_lock({{mnesia_table_lock, Tab}, self()}, [node()], infinity).
1145
% dbg_out("dets_sync_open: ~p ~p~n", [T, self()]),
1147
unlock_table(Tab) ->
1148
global:del_lock({{mnesia_table_lock, Tab}, self()}, [node()]).
1149
% dbg_out("unlock_table: ~p ~p~n", [T, self()]),
1151
dets_sync_open(Tab, Args) ->
1153
case dets:open_file(Tab, Args) of
1157
dets_sync_close(Tab),
1161
dets_sync_close(Tab) ->
1162
catch dets:close(Tab),
1166
cleanup_tmp_files([Tab | Tabs]) ->
1167
dets_sync_close(Tab),
1168
file:delete(tab2tmp(Tab)),
1169
cleanup_tmp_files(Tabs);
1170
cleanup_tmp_files([]) ->
1173
%% Returns a list of bad tables
1174
swap_tmp_files([Tab | Tabs]) ->
1175
dets_sync_close(Tab),
1178
case file:rename(Tmp, Dat) of
1180
swap_tmp_files(Tabs);
1183
[Tab | swap_tmp_files(Tabs)]
1185
swap_tmp_files([]) ->
1188
readable_indecies(Tab) ->
1191
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192
%% Managing conditional debug functions
1194
%% The main idea with the debug_fun's is to allow test programs
1195
%% to control the internal behaviour of Mnesia. This is needed
1196
%% to make the test programs independent of system load, swapping
1197
%% and other circumstances that may affect the behaviour of Mnesia.
1199
%% First should calls to ?eval_debug_fun be inserted at well
1200
%% defined places in Mnesia's code. E.g. in critical situations
1201
%% of startup, transaction commit, backups etc.
1203
%% Then compile Mnesia with the compiler option 'debug'.
1205
%% In test programs ?activate_debug_fun should be called
1206
%% in order to bind a fun to the debug identifier stated
1207
%% in the call to ?eval_debug_fun.
1209
%% If eval_debug_fun finds that the fun is activated it
1210
%% invokes the fun as NewContext = Fun(PreviousContext, EvalContext)
1211
%% and replaces the PreviousContext with the NewContext.
1212
%% The initial context of a debug_fun is given as argument to
1213
%% activate_debug_fun.
1215
-define(DEBUG_TAB, mnesia_debug).
1216
-record(debug_info, {id, function, context, file, line}).
1218
scratch_debug_fun() ->
1219
dbg_out("scratch_debug_fun(): ~p~n", [?DEBUG_TAB]),
1220
(catch ?ets_delete_table(?DEBUG_TAB)),
1221
?ets_new_table(?DEBUG_TAB, [set, public, named_table, {keypos, 2}]).
1223
activate_debug_fun(FunId, Fun, InitialContext, File, Line) ->
1224
Info = #debug_info{id = FunId,
1226
context = InitialContext,
1230
update_debug_info(Info).
1232
update_debug_info(Info) ->
1233
case catch ?ets_insert(?DEBUG_TAB, Info) of
1235
scratch_debug_fun(),
1236
?ets_insert(?DEBUG_TAB, Info);
1240
dbg_out("update_debug_info(~p)~n", [Info]),
1243
deactivate_debug_fun(FunId, _File, _Line) ->
1244
catch ?ets_delete(?DEBUG_TAB, FunId),
1247
eval_debug_fun(FunId, EvalContext, EvalFile, EvalLine) ->
1248
case catch ?ets_lookup(?DEBUG_TAB, FunId) of
1252
OldContext = Info#debug_info.context,
1253
dbg_out("~s(~p): ~w "
1254
"activated in ~s(~p)~n "
1255
"eval_debug_fun(~w, ~w)~n",
1256
[filename:basename(EvalFile), EvalLine, Info#debug_info.id,
1257
filename:basename(Info#debug_info.file), Info#debug_info.line,
1258
OldContext, EvalContext]),
1259
Fun = Info#debug_info.function,
1260
NewContext = Fun(OldContext, EvalContext),
1262
case catch ?ets_lookup(?DEBUG_TAB, FunId) of
1263
[Info] when NewContext /= OldContext ->
1264
NewInfo = Info#debug_info{context = NewContext},
1265
update_debug_info(NewInfo);
1273
is_debug_compiled() -> true.
1275
is_debug_compiled() -> false.