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.erl,v 1.2 2010/03/04 13:54:19 maria Exp $
18
%% This module exports the public interface of the Mnesia DBMS engine
21
%-behaviour(mnesia_access).
24
%% Start, stop and debugging
25
start/0, start/1, stop/0, % Not for public use
26
set_debug_level/1, lkill/0, kill/0, % Not for public use
27
ms/0, nc/0, nc/1, ni/0, ni/1, % Not for public use
31
abort/1, transaction/1, transaction/2, transaction/3,
32
sync_transaction/1, sync_transaction/2, sync_transaction/3,
33
async_dirty/1, async_dirty/2, sync_dirty/1, sync_dirty/2, ets/1, ets/2,
34
activity/2, activity/3, activity/4, % Not for public use
36
%% Access within an activity - Lock acquisition
41
%% Access within an activity - Updates
42
write/1, s_write/1, write/3, write/5,
43
delete/1, s_delete/1, delete/3, delete/5,
44
delete_object/1, s_delete_object/1, delete_object/3, delete_object/5,
46
%% Access within an activity - Reads
47
read/1, wread/1, read/3, read/5,
48
match_object/1, match_object/3, match_object/5,
49
select/2, select/3, select/5,
50
all_keys/1, all_keys/4,
51
index_match_object/2, index_match_object/4, index_match_object/6,
52
index_read/3, index_read/6,
54
%% Iterators within an activity
55
foldl/3, foldl/4, foldr/3, foldr/4,
57
%% Dirty access regardless of activities - Updates
58
dirty_write/1, dirty_write/2,
59
dirty_delete/1, dirty_delete/2,
60
dirty_delete_object/1, dirty_delete_object/2,
61
dirty_update_counter/2, dirty_update_counter/3,
63
%% Dirty access regardless of activities - Read
64
dirty_read/1, dirty_read/2,
66
dirty_match_object/1, dirty_match_object/2, dirty_all_keys/1,
67
dirty_index_match_object/2, dirty_index_match_object/3,
68
dirty_index_read/3, dirty_slot/2,
69
dirty_first/1, dirty_next/2, dirty_last/1, dirty_prev/2,
72
table_info/2, table_info/4, schema/0, schema/1,
73
error_description/1, info/0, system_info/1,
74
system_info/0, % Not for public use
77
create_schema/1, delete_schema/1,
78
backup/1, backup/2, traverse_backup/4, traverse_backup/6,
79
install_fallback/1, install_fallback/2,
80
uninstall_fallback/0, uninstall_fallback/1,
81
activate_checkpoint/1, deactivate_checkpoint/1,
82
backup_checkpoint/2, backup_checkpoint/3, restore/2,
85
create_table/1, create_table/2, delete_table/1,
86
add_table_copy/3, del_table_copy/2, move_table_copy/3,
87
add_table_index/2, del_table_index/2,
88
transform_table/3, transform_table/4,
89
change_table_copy_type/3,
90
read_table_property/2, write_table_property/2, delete_table_property/2,
95
dump_tables/1, wait_for_tables/2, force_load_table/1,
96
change_table_access_mode/2, change_table_load_order/2,
97
set_master_nodes/1, set_master_nodes/2,
100
dump_log/0, subscribe/1, unsubscribe/1, report_event/1,
103
snmp_open_table/2, snmp_close_table/1,
104
snmp_get_row/2, snmp_get_next_index/2, snmp_get_mnesia_key/2,
107
load_textfile/1, dump_to_textfile/1,
109
%% Mnemosyne exclusive
110
get_activity_id/0, put_activity_id/1, % Not for public use
112
%% Mnesia internal functions
113
dirty_rpc/4, % Not for public use
114
has_var/1, fun_select/7,
117
%% Module internal callback functions
118
remote_dirty_match_object/2, % Not for public use
119
remote_dirty_select/2 % Not for public use
122
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124
-include("mnesia.hrl").
125
-import(mnesia_lib, [verbose/2]).
127
-define(DEFAULT_ACCESS, ?MODULE).
130
-define(PATTERN_TO_OBJECT_MATCH_SPEC(Pat), [{Pat,[],['$_']}]).
131
-define(PATTERN_TO_BINDINGS_MATCH_SPEC(Pat), [{Pat,[],['$$']}]).
133
%% Local function in order to avoid external function call
135
case ?catch_val(Var) of
136
{'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
140
is_dollar_digits(Var) ->
141
case atom_to_list(Var) of
148
is_digits([Dig | Tail]) ->
150
$0 =< Dig, Dig =< $9 ->
158
has_var(X) when atom(X) ->
167
has_var(X) when tuple(X) ->
168
e_has_var(X, size(X));
176
e_has_var(_, 0) -> false;
178
case has_var(element(Pos, X))of
179
false -> e_has_var(X, Pos-1);
183
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
{Time , Res} = timer:tc(application, start, [?APPLICATION, temporary]),
189
Secs = Time div 1000000,
192
verbose("Mnesia started, ~p seconds~n",[ Secs]),
194
{error, {already_started, mnesia}} ->
195
verbose("Mnesia already started, ~p seconds~n",[ Secs]),
198
verbose("Mnesia failed to start, ~p seconds: ~p~n",[ Secs, R]),
202
start(ExtraEnv) when list(ExtraEnv) ->
203
case mnesia_lib:ensure_loaded(?APPLICATION) of
205
patched_start(ExtraEnv);
210
{error, {badarg, ExtraEnv}}.
212
patched_start([{Env, Val} | Tail]) when atom(Env) ->
213
case mnesia_monitor:patch_env(Env, Val) of
219
patched_start([Head | _]) ->
220
{error, {bad_type, Head}};
225
case application:stop(?APPLICATION) of
227
{error, {not_started, ?APPLICATION}} -> stopped;
231
change_config(extra_db_nodes, Ns) when list(Ns) ->
232
mnesia_controller:connect_nodes(Ns);
233
change_config(BadKey, _BadVal) ->
234
{error, {badarg, BadKey}}.
236
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239
set_debug_level(Level) ->
240
mnesia_subscr:set_debug_level(Level).
246
rpc:multicall(mnesia_sup, kill, []).
254
mnesia_checkpoint_sup,
260
mnesia_frag_old_hash,
277
%% Keep these last in the list, so
278
%% mnesia_sup kills these last
287
nc(Mods) when list(Mods)->
288
[Mod || Mod <- Mods, ok /= load(Mod, compile)].
294
ni(Mods) when list(Mods) ->
295
[Mod || Mod <- Mods, ok /= load(Mod, interpret)].
297
load(Mod, How) when atom(Mod) ->
298
case try_load(Mod, How) of
302
mnesia_lib:show( "~n RETRY ~p FROM: ", [Mod]),
307
case try_load(Abs, How) of
311
mnesia_lib:show( " *** ERROR *** ~p~n", [Reason]),
315
try_load(Mod, How) ->
316
mnesia_lib:show( " ~p ", [Mod]),
317
Flags = [{d, debug}],
320
case catch c:nc(Mod, Flags) of
322
Other -> {error, Other}
325
case catch int:ni(Mod, Flags) of
327
Other -> {error, Other}
332
ModString = atom_to_list(Mod),
334
case lists:suffix("test", ModString) of
338
filename:join([code:lib_dir(?APPLICATION), SubDir, ModString]).
340
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
exit({aborted, Reason}).
347
transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, async).
348
transaction(Fun, Retries) when integer(Retries), Retries >= 0 ->
349
transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async);
350
transaction(Fun, Retries) when Retries == infinity ->
351
transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async);
352
transaction(Fun, Args) ->
353
transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, async).
354
transaction(Fun, Args, Retries) ->
355
transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, async).
357
sync_transaction(Fun) ->
358
transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, sync).
359
sync_transaction(Fun, Retries) when integer(Retries), Retries >= 0 ->
360
transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync);
361
sync_transaction(Fun, Retries) when Retries == infinity ->
362
transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync);
363
sync_transaction(Fun, Args) ->
364
transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, sync).
365
sync_transaction(Fun, Args, Retries) ->
366
transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, sync).
369
transaction(State, Fun, Args, Retries, Mod, Kind)
370
when function(Fun), list(Args), Retries == infinity, atom(Mod) ->
371
mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind);
372
transaction(State, Fun, Args, Retries, Mod, Kind)
373
when function(Fun), list(Args), integer(Retries), Retries >= 0, atom(Mod) ->
374
mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind);
375
transaction(_State, Fun, Args, Retries, Mod, _Kind) ->
376
{aborted, {badarg, Fun, Args, Retries, Mod}}.
378
non_transaction(State, Fun, Args, ActivityKind, Mod)
379
when function(Fun), list(Args), atom(Mod) ->
380
mnesia_tm:non_transaction(State, Fun, Args, ActivityKind, Mod);
381
non_transaction(_State, Fun, Args, _ActivityKind, _Mod) ->
382
{aborted, {badarg, Fun, Args}}.
385
async_dirty(Fun, []).
386
async_dirty(Fun, Args) ->
387
non_transaction(get(mnesia_activity_state), Fun, Args, async_dirty, ?DEFAULT_ACCESS).
391
sync_dirty(Fun, Args) ->
392
non_transaction(get(mnesia_activity_state), Fun, Args, sync_dirty, ?DEFAULT_ACCESS).
397
non_transaction(get(mnesia_activity_state), Fun, Args, ets, ?DEFAULT_ACCESS).
399
activity(Kind, Fun) ->
400
activity(Kind, Fun, []).
401
activity(Kind, Fun, Args) when list(Args) ->
402
activity(Kind, Fun, Args, mnesia_monitor:get_env(access_module));
403
activity(Kind, Fun, Mod) ->
404
activity(Kind, Fun, [], Mod).
406
activity(Kind, Fun, Args, Mod) ->
407
State = get(mnesia_activity_state),
409
ets -> non_transaction(State, Fun, Args, Kind, Mod);
410
async_dirty -> non_transaction(State, Fun, Args, Kind, Mod);
411
sync_dirty -> non_transaction(State, Fun, Args, Kind, Mod);
412
transaction -> wrap_trans(State, Fun, Args, infinity, Mod, async);
413
{transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, async);
414
sync_transaction -> wrap_trans(State, Fun, Args, infinity, Mod, sync);
415
{sync_transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, sync);
416
_ -> {aborted, {bad_type, Kind}}
419
wrap_trans(State, Fun, Args, Retries, Mod, Kind) ->
420
case transaction(State, Fun, Args, Retries, Mod, Kind) of
421
{'atomic', GoodRes} -> GoodRes;
422
BadRes -> exit(BadRes)
425
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426
%% Access within an activity - lock acquisition
428
%% Grab a lock on an item in the global lock table
429
%% Item may be any term. Lock may be write or read.
430
%% write lock is set on all the given nodes
431
%% read lock is only set on the first node
432
%% Nodes may either be a list of nodes or one node as an atom
433
%% Mnesia on all Nodes must be connected to each other, but
434
%% it is not neccessary that they are up and running.
436
lock(LockItem, LockKind) ->
437
case get(mnesia_activity_state) of
438
{?DEFAULT_ACCESS, Tid, Ts} ->
439
lock(Tid, Ts, LockItem, LockKind);
441
Mod:lock(Tid, Ts, LockItem, LockKind);
443
abort(no_transaction)
446
lock(Tid, Ts, LockItem, LockKind) ->
447
case element(1, Tid) of
450
{record, Tab, Key} ->
451
lock_record(Tid, Ts, Tab, Key, LockKind);
453
lock_table(Tid, Ts, Tab, LockKind);
454
{global, GlobalKey, Nodes} ->
455
global_lock(Tid, Ts, GlobalKey, LockKind, Nodes);
457
abort({bad_type, LockItem})
463
%% Grab a read lock on a whole table
464
read_lock_table(Tab) ->
465
lock({table, Tab}, read),
468
%% Grab a write lock on a whole table
469
write_lock_table(Tab) ->
470
lock({table, Tab}, write),
473
lock_record(Tid, Ts, Tab, Key, LockKind) when atom(Tab) ->
474
Store = Ts#tidstore.store,
478
mnesia_locker:rlock(Tid, Store, Oid);
480
mnesia_locker:wlock(Tid, Store, Oid);
482
mnesia_locker:sticky_wlock(Tid, Store, Oid);
486
abort({bad_type, Tab, LockKind})
488
lock_record(_Tid, _Ts, Tab, _Key, _LockKind) ->
489
abort({bad_type, Tab}).
491
lock_table(Tid, Ts, Tab, LockKind) when atom(Tab) ->
492
Store = Ts#tidstore.store,
495
mnesia_locker:rlock_table(Tid, Store, Tab);
497
mnesia_locker:wlock_table(Tid, Store, Tab);
499
mnesia_locker:sticky_wlock_table(Tid, Store, Tab);
503
abort({bad_type, Tab, LockKind})
505
lock_table(_Tid, _Ts, Tab, _LockKind) ->
506
abort({bad_type, Tab}).
508
global_lock(Tid, Ts, Item, Kind, Nodes) when list(Nodes) ->
509
case element(1, Tid) of
511
Store = Ts#tidstore.store,
512
GoodNs = good_global_nodes(Nodes),
514
Kind /= read, Kind /= write ->
515
abort({bad_type, Kind});
517
mnesia_locker:global_lock(Tid, Store, Item, Kind, GoodNs)
522
global_lock(_Tid, _Ts, _Item, _Kind, Nodes) ->
523
abort({bad_type, Nodes}).
525
good_global_nodes(Nodes) ->
526
Recover = [node() | val(recover_nodes)],
527
mnesia_lib:intersect(Nodes, Recover).
529
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530
%% Access within an activity - updates
532
write(Val) when tuple(Val), size(Val) > 2 ->
533
Tab = element(1, Val),
534
write(Tab, Val, write);
536
abort({bad_type, Val}).
538
s_write(Val) when tuple(Val), size(Val) > 2 ->
539
Tab = element(1, Val),
540
write(Tab, Val, sticky_write).
542
write(Tab, Val, LockKind) ->
543
case get(mnesia_activity_state) of
544
{?DEFAULT_ACCESS, Tid, Ts} ->
545
write(Tid, Ts, Tab, Val, LockKind);
547
Mod:write(Tid, Ts, Tab, Val, LockKind);
549
abort(no_transaction)
552
write(Tid, Ts, Tab, Val, LockKind)
553
when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
554
case element(1, Tid) of
556
?ets_insert(Tab, Val),
559
Store = Ts#tidstore.store,
560
Oid = {Tab, element(2, Val)},
563
mnesia_locker:wlock(Tid, Store, Oid);
565
mnesia_locker:sticky_wlock(Tid, Store, Oid);
567
abort({bad_type, Tab, LockKind})
569
write_to_store(Tab, Store, Oid, Val);
571
do_dirty_write(Protocol, Tab, Val)
573
write(_Tid, _Ts, Tab, Val, LockKind) ->
574
abort({bad_type, Tab, Val, LockKind}).
576
write_to_store(Tab, Store, Oid, Val) ->
577
case ?catch_val({Tab, record_validation}) of
578
{RecName, Arity, Type}
579
when size(Val) == Arity, RecName == element(1, Val) ->
582
?ets_insert(Store, {Oid, Val, write});
584
?ets_delete(Store, Oid),
585
?ets_insert(Store, {Oid, Val, write})
589
abort({no_exists, Tab});
591
abort({bad_type, Val})
594
delete({Tab, Key}) ->
595
delete(Tab, Key, write);
597
abort({bad_type, Oid}).
599
s_delete({Tab, Key}) ->
600
delete(Tab, Key, sticky_write);
602
abort({bad_type, Oid}).
604
delete(Tab, Key, LockKind) ->
605
case get(mnesia_activity_state) of
606
{?DEFAULT_ACCESS, Tid, Ts} ->
607
delete(Tid, Ts, Tab, Key, LockKind);
609
Mod:delete(Tid, Ts, Tab, Key, LockKind);
611
abort(no_transaction)
614
delete(Tid, Ts, Tab, Key, LockKind)
615
when atom(Tab), Tab /= schema ->
616
case element(1, Tid) of
618
?ets_delete(Tab, Key),
621
Store = Ts#tidstore.store,
625
mnesia_locker:wlock(Tid, Store, Oid);
627
mnesia_locker:sticky_wlock(Tid, Store, Oid);
629
abort({bad_type, Tab, LockKind})
631
?ets_delete(Store, Oid),
632
?ets_insert(Store, {Oid, Oid, delete}),
635
do_dirty_delete(Protocol, Tab, Key)
637
delete(_Tid, _Ts, Tab, _Key, _LockKind) ->
638
abort({bad_type, Tab}).
640
delete_object(Val) when tuple(Val), size(Val) > 2 ->
641
Tab = element(1, Val),
642
delete_object(Tab, Val, write);
643
delete_object(Val) ->
644
abort({bad_type, Val}).
646
s_delete_object(Val) when tuple(Val), size(Val) > 2 ->
647
Tab = element(1, Val),
648
delete_object(Tab, Val, sticky_write);
649
s_delete_object(Val) ->
650
abort({bad_type, Val}).
652
delete_object(Tab, Val, LockKind) ->
653
case get(mnesia_activity_state) of
654
{?DEFAULT_ACCESS, Tid, Ts} ->
655
delete_object(Tid, Ts, Tab, Val, LockKind);
657
Mod:delete_object(Tid, Ts, Tab, Val, LockKind);
659
abort(no_transaction)
662
delete_object(Tid, Ts, Tab, Val, LockKind)
663
when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
664
case element(1, Tid) of
666
?ets_match_delete(Tab, Val),
669
Store = Ts#tidstore.store,
670
Oid = {Tab, element(2, Val)},
673
mnesia_locker:wlock(Tid, Store, Oid);
675
mnesia_locker:sticky_wlock(Tid, Store, Oid);
677
abort({bad_type, Tab, LockKind})
679
case val({Tab, setorbag}) of
681
?ets_match_delete(Store, {Oid, Val, '_'}),
682
?ets_insert(Store, {Oid, Val, delete_object});
684
case ?ets_match_object(Store, {Oid, '_', write}) of
686
?ets_match_delete(Store, {Oid, Val, '_'}),
687
?ets_insert(Store, {Oid, Val, delete_object});
689
?ets_delete(Store, Oid),
690
?ets_insert(Store, {Oid, Oid, delete})
695
do_dirty_delete_object(Protocol, Tab, Val)
697
delete_object(_Tid, _Ts, Tab, _Key, _LockKind) ->
698
abort({bad_type, Tab}).
700
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701
%% Access within an activity - read
704
read(Tab, Key, read);
706
abort({bad_type, Oid}).
709
read(Tab, Key, write);
711
abort({bad_type, Oid}).
713
read(Tab, Key, LockKind) ->
714
case get(mnesia_activity_state) of
715
{?DEFAULT_ACCESS, Tid, Ts} ->
716
read(Tid, Ts, Tab, Key, LockKind);
718
Mod:read(Tid, Ts, Tab, Key, LockKind);
720
abort(no_transaction)
723
read(Tid, Ts, Tab, Key, LockKind)
724
when atom(Tab), Tab /= schema ->
725
case element(1, Tid) of
727
?ets_lookup(Tab, Key);
729
Store = Ts#tidstore.store,
734
mnesia_locker:rlock(Tid, Store, Oid);
736
mnesia_locker:rwlock(Tid, Store, Oid);
738
mnesia_locker:sticky_rwlock(Tid, Store, Oid);
740
abort({bad_type, Tab, LockKind})
742
add_written(?ets_lookup(Store, Oid), Tab, Objs);
746
read(_Tid, _Ts, Tab, _Key, _LockKind) ->
747
abort({bad_type, Tab}).
749
%%%%%%%%%%%%%%%%%%%%%
752
foldl(Fun, Acc, Tab) ->
753
foldl(Fun, Acc, Tab, read).
755
foldl(Fun, Acc, Tab, LockKind) when function(Fun) ->
756
case get(mnesia_activity_state) of
757
{?DEFAULT_ACCESS, Tid, Ts} ->
758
foldl(Tid, Ts, Fun, Acc, Tab, LockKind);
760
Mod:foldl(Tid, Ts, Fun, Acc, Tab, LockKind);
762
abort(no_transaction)
765
foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
766
{Type, Prev} = init_iteration(ActivityId, Opaque, Tab, LockKind),
767
Res = (catch do_foldl(ActivityId, Opaque, Tab, dirty_first(Tab), Fun, Acc, Type, Prev)),
768
close_iteration(Res, Tab).
770
do_foldl(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
771
lists:foldl(fun(Key, Acc) ->
772
lists:foldl(Fun, Acc, read(A, O, Tab, Key, read))
774
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
775
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
776
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, Stored);
777
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
778
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
779
do_foldl(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored);
780
do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
781
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
782
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
783
do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
784
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
785
NewStored = ordsets:del_element(Key, Stored),
786
do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored).
788
foldr(Fun, Acc, Tab) ->
789
foldr(Fun, Acc, Tab, read).
790
foldr(Fun, Acc, Tab, LockKind) when function(Fun) ->
791
case get(mnesia_activity_state) of
792
{?DEFAULT_ACCESS, Tid, Ts} ->
793
foldr(Tid, Ts, Fun, Acc, Tab, LockKind);
795
Mod:foldr(Tid, Ts, Fun, Acc, Tab, LockKind);
797
abort(no_transaction)
800
foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) ->
801
{Type, TempPrev} = init_iteration(ActivityId, Opaque, Tab, LockKind),
804
Type == ordered_set ->
805
lists:reverse(TempPrev);
806
true -> %% Order doesn't matter for set and bag
807
TempPrev %% Keep the order so we can use ordsets:del_element
809
Res = (catch do_foldr(ActivityId, Opaque, Tab, dirty_last(Tab), Fun, Acc, Type, Prev)),
810
close_iteration(Res, Tab).
812
do_foldr(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) ->
813
lists:foldl(fun(Key, Acc) ->
814
lists:foldl(Fun, Acc, read(A, O, Tab, Key, read))
816
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key ->
817
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
818
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, Stored);
819
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key ->
820
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)),
821
do_foldr(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored);
822
do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key ->
823
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
824
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]);
825
do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag
826
NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)),
827
NewStored = ordsets:del_element(Key, Stored),
828
do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, Type, NewStored).
830
init_iteration(ActivityId, Opaque, Tab, LockKind) ->
831
lock(ActivityId, Opaque, {table, Tab}, LockKind),
832
Type = val({Tab, setorbag}),
833
Previous = add_previous(ActivityId, Opaque, Type, Tab),
834
St = val({Tab, storage_type}),
839
mnesia_lib:db_fixtable(St, Tab, true)
843
close_iteration(Res, Tab) ->
844
case val({Tab, storage_type}) of
848
mnesia_lib:db_fixtable(St, Tab, false)
851
{'EXIT', {aborted, What}} ->
859
add_previous(_ActivityId, non_transaction, _Type, _Tab) ->
861
add_previous(_Tid, Ts, _Type, Tab) ->
862
Previous = ?ets_match(Ts#tidstore.store, {{Tab, '$1'}, '_', write}),
863
lists:sort(lists:concat(Previous)).
865
%% This routine fixes up the return value from read/1 so that
866
%% it is correct with respect to what this particular transaction
867
%% has already written, deleted .... etc
869
add_written([], _Tab, Objs) ->
870
Objs; % standard normal fast case
871
add_written(Written, Tab, Objs) ->
872
case val({Tab, setorbag}) of
874
add_written_to_bag(Written, Objs, []);
876
add_written_to_set(Written)
879
add_written_to_set(Ws) ->
880
case lists:last(Ws) of
881
{_, _, delete} -> [];
882
{_, Val, write} -> [Val];
883
{_, _, delete_object} -> []
886
add_written_to_bag([{_, Val, write} | Tail], Objs, Ack) ->
887
add_written_to_bag(Tail, lists:delete(Val, Objs), [Val | Ack]);
888
add_written_to_bag([], Objs, Ack) ->
889
Objs ++ lists:reverse(Ack); %% Oldest write first as in ets
890
add_written_to_bag([{_, _ , delete} | Tail], _Objs, _Ack) ->
891
%% This transaction just deleted all objects
893
add_written_to_bag(Tail, [], []);
894
add_written_to_bag([{_, Val, delete_object} | Tail], Objs, Ack) ->
895
add_written_to_bag(Tail, lists:delete(Val, Objs), lists:delete(Val, Ack)).
897
match_object(Pat) when tuple(Pat), size(Pat) > 2 ->
898
Tab = element(1, Pat),
899
match_object(Tab, Pat, read);
901
abort({bad_type, Pat}).
903
match_object(Tab, Pat, LockKind) ->
904
case get(mnesia_activity_state) of
905
{?DEFAULT_ACCESS, Tid, Ts} ->
906
match_object(Tid, Ts, Tab, Pat, LockKind);
908
Mod:match_object(Tid, Ts, Tab, Pat, LockKind);
910
abort(no_transaction)
913
match_object(Tid, Ts, Tab, Pat, LockKind)
914
when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
915
case element(1, Tid) of
917
mnesia_lib:db_match_object(ram_copies, Tab, Pat);
919
Key = element(2, Pat),
921
false -> lock_record(Tid, Ts, Tab, Key, LockKind);
922
true -> lock_table(Tid, Ts, Tab, LockKind)
924
Objs = dirty_match_object(Tab, Pat),
925
add_written_match(Ts#tidstore.store, Pat, Tab, Objs);
927
dirty_match_object(Tab, Pat)
929
match_object(_Tid, _Ts, Tab, Pat, _LockKind) ->
930
abort({bad_type, Tab, Pat}).
932
add_written_match(S, Pat, Tab, Objs) ->
933
Ops = find_ops(S, Tab, Pat),
934
add_match(Ops, Objs, val({Tab, setorbag})).
936
find_ops(S, Tab, Pat) ->
937
GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']},
938
{{{Tab, '_'}, '_', delete}, [], ['$_']},
939
{{{Tab, '_'}, Pat, delete_object}, [], ['$_']}],
940
ets:select(S, GetWritten).
942
add_match([], Objs, _Type) ->
944
add_match(Written, Objs, ordered_set) ->
945
%% Must use keysort which is stable
946
add_ordered_match(lists:keysort(1,Written), Objs, []);
947
add_match([{Oid, _, delete}|R], Objs, Type) ->
948
add_match(R, deloid(Oid, Objs), Type);
949
add_match([{_Oid, Val, delete_object}|R], Objs, Type) ->
950
add_match(R, lists:delete(Val, Objs), Type);
951
add_match([{_Oid, Val, write}|R], Objs, bag) ->
952
add_match(R, [Val | lists:delete(Val, Objs)], bag);
953
add_match([{Oid, Val, write}|R], Objs, set) ->
954
add_match(R, [Val | deloid(Oid,Objs)],set).
956
%% For ordered_set only !!
957
add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc)
958
when Key > element(2, Obj) ->
959
add_ordered_match(Written, Objs, [Obj|Acc]);
960
add_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_], Acc)
961
when Key < element(2, Obj) ->
962
add_ordered_match(Rest, [Val|Objs],Acc);
963
add_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc)
964
when Key < element(2, Obj) ->
965
add_ordered_match(Rest,Objs,Acc);
966
%% Greater than last object
967
add_ordered_match([{_, Val, write}|Rest], [], Acc) ->
968
add_ordered_match(Rest, [Val], Acc);
969
add_ordered_match([_|Rest], [], Acc) ->
970
add_ordered_match(Rest, [], Acc);
971
%% Keys are equal from here
972
add_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) ->
973
add_ordered_match(Rest, [Val|Objs], Acc);
974
add_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) ->
975
add_ordered_match(Rest, Objs, Acc);
976
add_ordered_match([{_, Val, delete_object}|Rest], [Val|Objs], Acc) ->
977
add_ordered_match(Rest, Objs, Acc);
978
add_ordered_match([{_, _, delete_object}|Rest], Objs, Acc) ->
979
add_ordered_match(Rest, Objs, Acc);
980
add_ordered_match([], Objs, Acc) ->
981
lists:reverse(Acc, Objs).
988
select(Tab, Pat, read).
989
select(Tab, Pat, LockKind)
990
when atom(Tab), Tab /= schema, list(Pat) ->
991
case get(mnesia_activity_state) of
992
{?DEFAULT_ACCESS, Tid, Ts} ->
993
select(Tid, Ts, Tab, Pat, LockKind);
995
Mod:select(Tid, Ts, Tab, Pat, LockKind);
997
abort(no_transaction)
999
select(Tab, Pat, _Lock) ->
1000
abort({badarg, Tab, Pat}).
1002
select(Tid, Ts, Tab, Spec, LockKind) ->
1003
SelectFun = fun(FixedSpec) -> dirty_select(Tab, FixedSpec) end,
1004
fun_select(Tid, Ts, Tab, Spec, LockKind, Tab, SelectFun).
1006
fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, SelectFun) ->
1007
case element(1, Tid) of
1009
mnesia_lib:db_select(ram_copies, Tab, Spec);
1011
Store = Ts#tidstore.store,
1012
Written = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}),
1013
%% Avoid table lock if possible
1015
[{HeadPat,_, _}] when tuple(HeadPat), size(HeadPat) > 2 ->
1016
Key = element(2, HeadPat),
1017
case has_var(Key) of
1018
false -> lock_record(Tid, Ts, Tab, Key, LockKind);
1019
true -> lock_table(Tid, Ts, Tab, LockKind)
1022
lock_table(Tid, Ts, Tab, LockKind)
1026
%% Nothing changed in the table during this transaction,
1027
%% Simple case get results from [d]ets
1030
%% Hard (slow case) records added or deleted earlier
1031
%% in the transaction, have to cope with that.
1032
Type = val({Tab, setorbag}),
1033
FixedSpec = get_record_pattern(Spec),
1034
TabRecs = SelectFun(FixedSpec),
1035
FixedRes = add_match(Written, TabRecs, Type),
1036
CMS = ets:match_spec_compile(Spec),
1039
% ets:match_spec_run(lists:sort(FixedRes), CMS);
1041
% ets:match_spec_run(FixedRes, CMS)
1043
ets:match_spec_run(FixedRes, CMS)
1049
get_record_pattern([]) ->
1051
get_record_pattern([{M,C,_B}|R]) ->
1052
[{M,C,['$_']} | get_record_pattern(R)].
1056
deloid({Tab, Key}, [H | T]) when element(2, H) == Key ->
1057
deloid({Tab, Key}, T);
1058
deloid(Oid, [H | T]) ->
1059
[H | deloid(Oid, T)].
1062
case get(mnesia_activity_state) of
1063
{?DEFAULT_ACCESS, Tid, Ts} ->
1064
all_keys(Tid, Ts, Tab, read);
1066
Mod:all_keys(Tid, Ts, Tab, read);
1068
abort(no_transaction)
1071
all_keys(Tid, Ts, Tab, LockKind)
1072
when atom(Tab), Tab /= schema ->
1073
Pat0 = val({Tab, wild_pattern}),
1074
Pat = setelement(2, Pat0, '$1'),
1075
Keys = select(Tid, Ts, Tab, [{Pat, [], ['$1']}], LockKind),
1076
case val({Tab, setorbag}) of
1078
mnesia_lib:uniq(Keys);
1082
all_keys(_Tid, _Ts, Tab, _LockKind) ->
1083
abort({bad_type, Tab}).
1085
index_match_object(Pat, Attr) when tuple(Pat), size(Pat) > 2 ->
1086
Tab = element(1, Pat),
1087
index_match_object(Tab, Pat, Attr, read);
1088
index_match_object(Pat, _Attr) ->
1089
abort({bad_type, Pat}).
1091
index_match_object(Tab, Pat, Attr, LockKind) ->
1092
case get(mnesia_activity_state) of
1093
{?DEFAULT_ACCESS, Tid, Ts} ->
1094
index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind);
1096
Mod:index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind);
1098
abort(no_transaction)
1101
index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind)
1102
when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
1103
case element(1, Tid) of
1105
dirty_index_match_object(Tab, Pat, Attr); % Should be optimized?
1107
case mnesia_schema:attr_tab_to_pos(Tab, Attr) of
1108
Pos when Pos =< size(Pat) ->
1111
Store = Ts#tidstore.store,
1112
mnesia_locker:rlock_table(Tid, Store, Tab),
1113
Objs = dirty_index_match_object(Tab, Pat, Attr),
1114
add_written_match(Store, Pat, Tab, Objs);
1116
abort({bad_type, Tab, LockKind})
1119
abort({bad_type, Tab, BadPos})
1122
dirty_index_match_object(Tab, Pat, Attr)
1124
index_match_object(_Tid, _Ts, Tab, Pat, _Attr, _LockKind) ->
1125
abort({bad_type, Tab, Pat}).
1127
index_read(Tab, Key, Attr) ->
1128
case get(mnesia_activity_state) of
1129
{?DEFAULT_ACCESS, Tid, Ts} ->
1130
index_read(Tid, Ts, Tab, Key, Attr, read);
1132
Mod:index_read(Tid, Ts, Tab, Key, Attr, read);
1134
abort(no_transaction)
1137
index_read(Tid, Ts, Tab, Key, Attr, LockKind)
1138
when atom(Tab), Tab /= schema ->
1139
case element(1, Tid) of
1141
dirty_index_read(Tab, Key, Attr); % Should be optimized?
1143
Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr),
1146
case has_var(Key) of
1148
Store = Ts#tidstore.store,
1149
Objs = mnesia_index:read(Tid, Store, Tab, Key, Pos),
1150
Pat = setelement(Pos, val({Tab, wild_pattern}), Key),
1151
add_written_match(Store, Pat, Tab, Objs);
1153
abort({bad_type, Tab, Attr, Key})
1156
abort({bad_type, Tab, LockKind})
1159
dirty_index_read(Tab, Key, Attr)
1161
index_read(_Tid, _Ts, Tab, _Key, _Attr, _LockKind) ->
1162
abort({bad_type, Tab}).
1164
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165
%% Dirty access regardless of activities - updates
1167
dirty_write(Val) when tuple(Val), size(Val) > 2 ->
1168
Tab = element(1, Val),
1169
dirty_write(Tab, Val);
1171
abort({bad_type, Val}).
1173
dirty_write(Tab, Val) ->
1174
do_dirty_write(async_dirty, Tab, Val).
1176
do_dirty_write(SyncMode, Tab, Val)
1177
when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
1178
case ?catch_val({Tab, record_validation}) of
1179
{RecName, Arity, _Type}
1180
when size(Val) == Arity, RecName == element(1, Val) ->
1181
Oid = {Tab, element(2, Val)},
1182
mnesia_tm:dirty(SyncMode, {Oid, Val, write});
1184
abort({no_exists, Tab});
1186
abort({bad_type, Val})
1188
do_dirty_write(_SyncMode, Tab, Val) ->
1189
abort({bad_type, Tab, Val}).
1191
dirty_delete({Tab, Key}) ->
1192
dirty_delete(Tab, Key);
1193
dirty_delete(Oid) ->
1194
abort({bad_type, Oid}).
1196
dirty_delete(Tab, Key) ->
1197
do_dirty_delete(async_dirty, Tab, Key).
1199
do_dirty_delete(SyncMode, Tab, Key) when atom(Tab), Tab /= schema ->
1201
mnesia_tm:dirty(SyncMode, {Oid, Oid, delete});
1202
do_dirty_delete(_SyncMode, Tab, _Key) ->
1203
abort({bad_type, Tab}).
1205
dirty_delete_object(Val) when tuple(Val), size(Val) > 2 ->
1206
Tab = element(1, Val),
1207
dirty_delete_object(Tab, Val);
1208
dirty_delete_object(Val) ->
1209
abort({bad_type, Val}).
1211
dirty_delete_object(Tab, Val) ->
1212
do_dirty_delete_object(async_dirty, Tab, Val).
1214
do_dirty_delete_object(SyncMode, Tab, Val)
1215
when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 ->
1216
Oid = {Tab, element(2, Val)},
1217
mnesia_tm:dirty(SyncMode, {Oid, Val, delete_object});
1218
do_dirty_delete_object(_SyncMode, Tab, Val) ->
1219
abort({bad_type, Tab, Val}).
1221
%% A Counter is an Oid being {CounterTab, CounterName}
1223
dirty_update_counter({Tab, Key}, Incr) ->
1224
dirty_update_counter(Tab, Key, Incr);
1225
dirty_update_counter(Counter, _Incr) ->
1226
abort({bad_type, Counter}).
1228
dirty_update_counter(Tab, Key, Incr) ->
1229
do_dirty_update_counter(async_dirty, Tab, Key, Incr).
1231
do_dirty_update_counter(SyncMode, Tab, Key, Incr)
1232
when atom(Tab), Tab /= schema, integer(Incr) ->
1233
case ?catch_val({Tab, record_validation}) of
1234
{RecName, 3, set} ->
1236
mnesia_tm:dirty(SyncMode, {Oid, {RecName, Incr}, update_counter});
1238
abort({combine_error, Tab, update_counter})
1240
do_dirty_update_counter(_SyncMode, Tab, _Key, Incr) ->
1241
abort({bad_type, Tab, Incr}).
1243
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244
%% Dirty access regardless of activities - read
1246
dirty_read({Tab, Key}) ->
1247
dirty_read(Tab, Key);
1249
abort({bad_type, Oid}).
1251
dirty_read(Tab, Key)
1252
when atom(Tab), Tab /= schema ->
1253
%% case catch ?ets_lookup(Tab, Key) of
1255
%% Bad luck, we have to perform a real lookup
1256
dirty_rpc(Tab, mnesia_lib, db_get, [Tab, Key]);
1260
dirty_read(Tab, _Key) ->
1261
abort({bad_type, Tab}).
1263
dirty_match_object(Pat) when tuple(Pat), size(Pat) > 2 ->
1264
Tab = element(1, Pat),
1265
dirty_match_object(Tab, Pat);
1266
dirty_match_object(Pat) ->
1267
abort({bad_type, Pat}).
1269
dirty_match_object(Tab, Pat)
1270
when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
1271
dirty_rpc(Tab, ?MODULE, remote_dirty_match_object, [Tab, Pat]);
1272
dirty_match_object(Tab, Pat) ->
1273
abort({bad_type, Tab, Pat}).
1275
remote_dirty_match_object(Tab, Pat) ->
1276
Key = element(2, Pat),
1277
case has_var(Key) of
1279
mnesia_lib:db_match_object(Tab, Pat);
1281
PosList = val({Tab, index}),
1282
remote_dirty_match_object(Tab, Pat, PosList)
1285
remote_dirty_match_object(Tab, Pat, [Pos | Tail]) when Pos =< size(Pat) ->
1286
IxKey = element(Pos, Pat),
1287
case has_var(IxKey) of
1289
mnesia_index:dirty_match_object(Tab, Pat, Pos);
1291
remote_dirty_match_object(Tab, Pat, Tail)
1293
remote_dirty_match_object(Tab, Pat, []) ->
1294
mnesia_lib:db_match_object(Tab, Pat);
1295
remote_dirty_match_object(Tab, Pat, _PosList) ->
1296
abort({bad_type, Tab, Pat}).
1298
dirty_select(Tab, Spec) when atom(Tab), Tab /= schema, list(Spec) ->
1299
dirty_rpc(Tab, ?MODULE, remote_dirty_select, [Tab, Spec]);
1300
dirty_select(Tab, Spec) ->
1301
abort({bad_type, Tab, Spec}).
1303
remote_dirty_select(Tab, Spec) ->
1305
[{HeadPat, _, _}] when tuple(HeadPat), size(HeadPat) > 2 ->
1306
Key = element(2, HeadPat),
1307
case has_var(Key) of
1309
mnesia_lib:db_select(Tab, Spec);
1311
PosList = val({Tab, index}),
1312
remote_dirty_select(Tab, Spec, PosList)
1315
mnesia_lib:db_select(Tab, Spec)
1318
remote_dirty_select(Tab, [{HeadPat,_, _}] = Spec, [Pos | Tail])
1319
when tuple(HeadPat), size(HeadPat) > 2, Pos =< size(Spec) ->
1320
Key = element(Pos, HeadPat),
1321
case has_var(Key) of
1323
Recs = mnesia_index:dirty_select(Tab, Spec, Pos),
1324
%% Returns the records without applying the match spec
1325
%% The actual filtering is handled by the caller
1326
CMS = ets:match_spec_compile(Spec),
1327
case val({Tab, setorbag}) of
1329
ets:match_spec_run(lists:sort(Recs), CMS);
1331
ets:match_spec_run(Recs, CMS)
1334
remote_dirty_select(Tab, Spec, Tail)
1336
remote_dirty_select(Tab, Spec, _) ->
1337
mnesia_lib:db_select(Tab, Spec).
1339
dirty_all_keys(Tab) when atom(Tab), Tab /= schema ->
1340
case ?catch_val({Tab, wild_pattern}) of
1342
abort({no_exists, Tab});
1344
Pat = setelement(2, Pat0, '$1'),
1345
Keys = dirty_select(Tab, [{Pat, [], ['$1']}]),
1346
case val({Tab, setorbag}) of
1347
bag -> mnesia_lib:uniq(Keys);
1351
dirty_all_keys(Tab) ->
1352
abort({bad_type, Tab}).
1354
dirty_index_match_object(Pat, Attr) when tuple(Pat), size(Pat) > 2 ->
1355
Tab = element(1, Pat),
1356
dirty_index_match_object(Tab, Pat, Attr);
1357
dirty_index_match_object(Pat, _Attr) ->
1358
abort({bad_type, Pat}).
1360
dirty_index_match_object(Tab, Pat, Attr)
1361
when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 ->
1362
case mnesia_schema:attr_tab_to_pos(Tab, Attr) of
1363
Pos when Pos =< size(Pat) ->
1364
case has_var(element(2, Pat)) of
1366
dirty_match_object(Tab, Pat);
1368
Elem = element(Pos, Pat),
1369
case has_var(Elem) of
1371
dirty_rpc(Tab, mnesia_index, dirty_match_object,
1374
abort({bad_type, Tab, Attr, Elem})
1378
abort({bad_type, Tab, BadPos})
1380
dirty_index_match_object(Tab, Pat, _Attr) ->
1381
abort({bad_type, Tab, Pat}).
1383
dirty_index_read(Tab, Key, Attr) when atom(Tab), Tab /= schema ->
1384
Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr),
1385
case has_var(Key) of
1387
mnesia_index:dirty_read(Tab, Key, Pos);
1389
abort({bad_type, Tab, Attr, Key})
1391
dirty_index_read(Tab, _Key, _Attr) ->
1392
abort({bad_type, Tab}).
1394
dirty_slot(Tab, Slot) when atom(Tab), Tab /= schema, integer(Slot) ->
1395
dirty_rpc(Tab, mnesia_lib, db_slot, [Tab, Slot]);
1396
dirty_slot(Tab, Slot) ->
1397
abort({bad_type, Tab, Slot}).
1399
dirty_first(Tab) when atom(Tab), Tab /= schema ->
1400
dirty_rpc(Tab, mnesia_lib, db_first, [Tab]);
1402
abort({bad_type, Tab}).
1404
dirty_last(Tab) when atom(Tab), Tab /= schema ->
1405
dirty_rpc(Tab, mnesia_lib, db_last, [Tab]);
1407
abort({bad_type, Tab}).
1409
dirty_next(Tab, Key) when atom(Tab), Tab /= schema ->
1410
dirty_rpc(Tab, mnesia_lib, db_next_key, [Tab, Key]);
1411
dirty_next(Tab, _Key) ->
1412
abort({bad_type, Tab}).
1414
dirty_prev(Tab, Key) when atom(Tab), Tab /= schema ->
1415
dirty_rpc(Tab, mnesia_lib, db_prev_key, [Tab, Key]);
1416
dirty_prev(Tab, _Key) ->
1417
abort({bad_type, Tab}).
1420
dirty_rpc(Tab, M, F, Args) ->
1421
Node = val({Tab, where_to_read}),
1422
do_dirty_rpc(Tab, Node, M, F, Args).
1424
do_dirty_rpc(_Tab, nowhere, _, _, Args) ->
1425
mnesia:abort({no_exists, Args});
1426
do_dirty_rpc(Tab, Node, M, F, Args) ->
1427
case rpc:call(Node, M, F, Args) of
1428
{badrpc,{'EXIT', {undef, [{ M, F, _} | _]}}}
1429
when M == ?MODULE, F == remote_dirty_select ->
1430
%% Oops, the other node has not been upgraded
1431
%% to 4.0.3 yet. Lets do it the old way.
1432
%% Remove this in next release.
1433
do_dirty_rpc(Tab, Node, mnesia_lib, db_select, Args);
1435
erlang:yield(), %% Do not be too eager
1436
case mnesia_controller:call({check_w2r, Node, Tab}) of % Sync
1437
NewNode when NewNode == Node ->
1438
ErrorTag = mnesia_lib:dirty_rpc_error_tag(Reason),
1439
mnesia:abort({ErrorTag, Args});
1441
case get(mnesia_activity_state) of
1442
{_Mod, Tid, _Ts} when record(Tid, tid) ->
1443
%% In order to perform a consistent
1444
%% retry of a transaction we need
1445
%% to acquire the lock on the NewNode.
1446
%% In this context we do neither know
1447
%% the kind or granularity of the lock.
1448
%% --> Abort the transaction
1449
mnesia:abort({node_not_running, Node});
1451
%% Splendid! A dirty retry is safe
1452
%% 'Node' probably went down now
1453
%% Let mnesia_controller get broken link message first
1454
do_dirty_rpc(Tab, NewNode, M, F, Args)
1461
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464
%% Info about one table
1465
table_info(Tab, Item) ->
1466
case get(mnesia_activity_state) of
1468
any_table_info(Tab, Item);
1469
{?DEFAULT_ACCESS, _Tid, _Ts} ->
1470
any_table_info(Tab, Item);
1472
Mod:table_info(Tid, Ts, Tab, Item);
1474
abort(no_transaction)
1477
table_info(_Tid, _Ts, Tab, Item) ->
1478
any_table_info(Tab, Item).
1481
any_table_info(Tab, Item) when atom(Tab) ->
1484
mnesia_recover:get_master_nodes(Tab);
1486
% case ?catch_val({Tab, commit_work}) of
1487
% [{checkpoints, List} | _] -> List;
1488
% No_chk when list(No_chk) -> [];
1489
% Else -> info_reply(Else, Tab, Item)
1492
raw_table_info(Tab, Item);
1494
raw_table_info(Tab, Item);
1496
case ?catch_val({Tab, setorbag}) of
1498
bad_info_reply(Tab, Item);
1503
case mnesia_schema:get_table_properties(Tab) of
1505
abort({no_exists, Tab, Item});
1507
lists:map(fun({setorbag, Type}) -> {type, Type};
1512
case ?catch_val({Tab, Item}) of
1514
bad_info_reply(Tab, Item);
1519
any_table_info(Tab, _Item) ->
1520
abort({bad_type, Tab}).
1522
raw_table_info(Tab, Item) ->
1523
case ?catch_val({Tab, storage_type}) of
1525
info_reply(catch ?ets_info(Tab, Item), Tab, Item);
1527
info_reply(catch ?ets_info(Tab, Item), Tab, Item);
1529
info_reply(catch dets:info(Tab, Item), Tab, Item);
1531
bad_info_reply(Tab, Item);
1533
bad_info_reply(Tab, Item)
1536
info_reply({'EXIT', _Reason}, Tab, Item) ->
1537
bad_info_reply(Tab, Item);
1538
info_reply({error, _Reason}, Tab, Item) ->
1539
bad_info_reply(Tab, Item);
1540
info_reply(Val, _Tab, _Item) ->
1543
bad_info_reply(_Tab, size) -> 0;
1544
bad_info_reply(_Tab, memory) -> 0;
1545
bad_info_reply(Tab, Item) -> abort({no_exists, Tab, Item}).
1547
%% Raw info about all tables
1549
mnesia_schema:info().
1551
%% Raw info about one tables
1553
mnesia_schema:info(Tab).
1555
error_description(Err) ->
1556
mnesia_lib:error_desc(Err).
1559
case mnesia_lib:is_running() of
1561
TmInfo = mnesia_tm:get_info(10000),
1562
Held = system_info(held_locks),
1563
Queued = system_info(lock_queue),
1565
io:format("---> Processes holding locks <--- ~n", []),
1566
lists:foreach(fun(L) -> io:format("Lock: ~p~n", [L]) end,
1569
io:format( "---> Processes waiting for locks <--- ~n", []),
1570
lists:foreach(fun({Oid, Op, _Pid, Tid, OwnerTid}) ->
1571
io:format("Tid ~p waits for ~p lock "
1572
"on oid ~p owned by ~p ~n",
1573
[Tid, Op, Oid, OwnerTid])
1575
mnesia_tm:display_info(group_leader(), TmInfo),
1577
Pat = {'_', unclear, '_'},
1578
Uncertain = ets:match_object(mnesia_decision, Pat),
1580
io:format( "---> Uncertain transactions <--- ~n", []),
1581
lists:foreach(fun({Tid, _, Nodes}) ->
1582
io:format("Tid ~w waits for decision "
1587
mnesia_controller:info(),
1588
display_system_info(Held, Queued, TmInfo, Uncertain);
1595
io:format("===> System info in version ~p, debug level = ~p <===~n",
1596
[system_info(version), system_info(debug)]),
1598
case system_info(use_dir) of
1603
io:format("~w. Directory ~p is ~sused.~n",
1604
[system_info(schema_location), system_info(directory), Not]),
1605
io:format("use fallback at restart = ~w~n",
1606
[system_info(fallback_activated)]),
1607
Running = system_info(running_db_nodes),
1608
io:format("running db nodes = ~w~n", [Running]),
1609
All = mnesia_lib:all_nodes(),
1610
io:format("stopped db nodes = ~w ~n", [All -- Running]).
1612
display_system_info(Held, Queued, TmInfo, Uncertain) ->
1615
S = fun(Items) -> [system_info(I) || I <- Items] end,
1617
io:format("~w transactions committed, ~w aborted, "
1618
"~w restarted, ~w logged to disc~n",
1619
S([transaction_commits, transaction_failures,
1620
transaction_restarts, transaction_log_writes])),
1624
{timeout, _} -> {infinity, infinity};
1625
{info, P, A} -> {length(A), length(P)}
1627
io:format("~w held locks, ~w in queue; "
1628
"~w local transactions, ~w remote~n",
1629
[length(Held), length(Queued), Active, Pending]),
1631
Ufold = fun({_, _, Ns}, {C, Old}) ->
1632
New = [N || N <- Ns, not lists:member(N, Old)],
1635
{Ucount, Unodes} = lists:foldl(Ufold, {0, []}, Uncertain),
1636
io:format("~w transactions waits for other nodes: ~p~n",
1639
display_tab_info() ->
1640
MasterTabs = mnesia_recover:get_master_node_tables(),
1641
io:format("master node tables = ~p~n", [lists:sort(MasterTabs)]),
1643
Tabs = system_info(tables),
1645
{Unknown, Ram, Disc, DiscOnly} =
1646
lists:foldl(fun storage_count/2, {[], [], [], []}, Tabs),
1648
io:format("remote = ~p~n", [lists:sort(Unknown)]),
1649
io:format("ram_copies = ~p~n", [lists:sort(Ram)]),
1650
io:format("disc_copies = ~p~n", [lists:sort(Disc)]),
1651
io:format("disc_only_copies = ~p~n", [lists:sort(DiscOnly)]),
1653
Rfoldl = fun(T, Acc) ->
1655
case val({T, access_mode}) of
1657
lists:sort([{A, read_only} || A <- val({T, active_replicas})]);
1659
table_info(T, where_to_commit)
1661
case lists:keysearch(Rpat, 1, Acc) of
1662
{value, {_Rpat, Rtabs}} ->
1663
lists:keyreplace(Rpat, 1, Acc, {Rpat, [T | Rtabs]});
1668
Repl = lists:foldl(Rfoldl, [], Tabs),
1669
Rdisp = fun({Rpat, Rtabs}) -> io:format("~p = ~p~n", [Rpat, Rtabs]) end,
1670
lists:foreach(Rdisp, lists:sort(Repl)).
1672
storage_count(T, {U, R, D, DO}) ->
1673
case table_info(T, storage_type) of
1674
unknown -> {[T | U], R, D, DO};
1675
ram_copies -> {U, [T | R], D, DO};
1676
disc_copies -> {U, R, [T | D], DO};
1677
disc_only_copies -> {U, R, D, [T | DO]}
1680
system_info(Item) ->
1681
case catch system_info2(Item) of
1682
{'EXIT',Error} -> abort(Error);
1686
system_info2(all) ->
1687
Items = system_info_items(mnesia_lib:is_running()),
1688
[{I, system_info(I)} || I <- Items];
1690
system_info2(db_nodes) ->
1691
DiscNs = ?catch_val({schema, disc_copies}),
1692
RamNs = ?catch_val({schema, ram_copies}),
1694
list(DiscNs), list(RamNs) ->
1697
case mnesia_schema:read_nodes() of
1698
{ok, Nodes} -> Nodes;
1699
{error,Reason} -> exit(Reason)
1702
system_info2(running_db_nodes) ->
1703
case ?catch_val({current, db_nodes}) of
1705
%% Ensure that we access the intended Mnesia
1706
%% directory. This function may not be called
1707
%% during startup since it will cause the
1708
%% application_controller to get into deadlock
1709
load_mnesia_or_abort(),
1710
mnesia_lib:running_nodes();
1715
system_info2(extra_db_nodes) ->
1716
case ?catch_val(extra_db_nodes) of
1718
%% Ensure that we access the intended Mnesia
1719
%% directory. This function may not be called
1720
%% during startup since it will cause the
1721
%% application_controller to get into deadlock
1722
load_mnesia_or_abort(),
1723
mnesia_monitor:get_env(extra_db_nodes);
1728
system_info2(directory) ->
1729
case ?catch_val(directory) of
1731
%% Ensure that we access the intended Mnesia
1732
%% directory. This function may not be called
1733
%% during startup since it will cause the
1734
%% application_controller to get into deadlock
1735
load_mnesia_or_abort(),
1736
mnesia_monitor:get_env(dir);
1741
system_info2(use_dir) ->
1742
case ?catch_val(use_dir) of
1744
%% Ensure that we access the intended Mnesia
1745
%% directory. This function may not be called
1746
%% during startup since it will cause the
1747
%% application_controller to get into deadlock
1748
load_mnesia_or_abort(),
1749
mnesia_monitor:use_dir();
1754
system_info2(schema_location) ->
1755
case ?catch_val(schema_location) of
1757
%% Ensure that we access the intended Mnesia
1758
%% directory. This function may not be called
1759
%% during startup since it will cause the
1760
%% application_controller to get into deadlock
1761
load_mnesia_or_abort(),
1762
mnesia_monitor:get_env(schema_location);
1767
system_info2(fallback_activated) ->
1768
case ?catch_val(fallback_activated) of
1770
%% Ensure that we access the intended Mnesia
1771
%% directory. This function may not be called
1772
%% during startup since it will cause the
1773
%% application_controller to get into deadlock
1774
load_mnesia_or_abort(),
1775
mnesia_bup:fallback_exists();
1780
system_info2(version) ->
1781
case ?catch_val(version) of
1783
Apps = application:loaded_applications(),
1784
case lists:keysearch(?APPLICATION, 1, Apps) of
1785
{value, {_Name, _Desc, Version}} ->
1788
%% Ensure that it does not match
1789
{mnesia_not_loaded, node(), now()}
1795
system_info2(access_module) -> mnesia_monitor:get_env(access_module);
1796
system_info2(auto_repair) -> mnesia_monitor:get_env(auto_repair);
1797
system_info2(is_running) -> mnesia_lib:is_running();
1798
system_info2(backup_module) -> mnesia_monitor:get_env(backup_module);
1799
system_info2(event_module) -> mnesia_monitor:get_env(event_module);
1800
system_info2(debug) -> mnesia_monitor:get_env(debug);
1801
system_info2(dump_log_load_regulation) -> mnesia_monitor:get_env(dump_log_load_regulation);
1802
system_info2(dump_log_write_threshold) -> mnesia_monitor:get_env(dump_log_write_threshold);
1803
system_info2(dump_log_time_threshold) -> mnesia_monitor:get_env(dump_log_time_threshold);
1804
system_info2(dump_log_update_in_place) ->
1805
mnesia_monitor:get_env(dump_log_update_in_place);
1806
system_info2(dump_log_update_in_place) ->
1807
mnesia_monitor:get_env(dump_log_update_in_place);
1808
system_info2(max_wait_for_decision) -> mnesia_monitor:get_env(max_wait_for_decision);
1809
system_info2(embedded_mnemosyne) -> mnesia_monitor:get_env(embedded_mnemosyne);
1810
system_info2(ignore_fallback_at_startup) -> mnesia_monitor:get_env(ignore_fallback_at_startup);
1811
system_info2(fallback_error_function) -> mnesia_monitor:get_env(fallback_error_function);
1812
system_info2(log_version) -> mnesia_log:version();
1813
system_info2(protocol_version) -> mnesia_monitor:protocol_version();
1814
system_info2(schema_version) -> mnesia_schema:version(); %backward compatibility
1815
system_info2(tables) -> val({schema, tables});
1816
system_info2(local_tables) -> val({schema, local_tables});
1817
system_info2(master_node_tables) -> mnesia_recover:get_master_node_tables();
1818
system_info2(subscribers) -> mnesia_subscr:subscribers();
1819
system_info2(checkpoints) -> mnesia_checkpoint:checkpoints();
1820
system_info2(held_locks) -> mnesia_locker:get_held_locks();
1821
system_info2(lock_queue) -> mnesia_locker:get_lock_queue();
1822
system_info2(transactions) -> mnesia_tm:get_transactions();
1823
system_info2(transaction_failures) -> mnesia_lib:read_counter(trans_failures);
1824
system_info2(transaction_commits) -> mnesia_lib:read_counter(trans_commits);
1825
system_info2(transaction_restarts) -> mnesia_lib:read_counter(trans_restarts);
1826
system_info2(transaction_log_writes) -> mnesia_dumper:get_log_writes();
1828
system_info2(Item) -> exit({badarg, Item}).
1830
system_info_items(yes) ->
1839
dump_log_load_regulation,
1840
dump_log_time_threshold,
1841
dump_log_update_in_place,
1842
dump_log_write_threshold,
1848
ignore_fallback_at_startup,
1849
fallback_error_function,
1855
max_wait_for_decision,
1862
transaction_commits,
1863
transaction_failures,
1864
transaction_log_writes,
1865
transaction_restarts,
1870
system_info_items(no) ->
1877
dump_log_load_regulation,
1878
dump_log_time_threshold,
1879
dump_log_update_in_place,
1880
dump_log_write_threshold,
1883
ignore_fallback_at_startup,
1884
fallback_error_function,
1887
max_wait_for_decision,
1897
IsRunning = mnesia_lib:is_running(),
1900
TmInfo = mnesia_tm:get_info(10000),
1901
Held = system_info(held_locks),
1902
Queued = system_info(lock_queue),
1903
Pat = {'_', unclear, '_'},
1904
Uncertain = ets:match_object(mnesia_decision, Pat),
1905
display_system_info(Held, Queued, TmInfo, Uncertain);
1911
load_mnesia_or_abort() ->
1912
case mnesia_lib:ensure_loaded(?APPLICATION) of
1919
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922
create_schema(Ns) ->
1923
mnesia_bup:create_schema(Ns).
1925
delete_schema(Ns) ->
1926
mnesia_schema:delete_schema(Ns).
1929
mnesia_log:backup(Opaque).
1931
backup(Opaque, Mod) ->
1932
mnesia_log:backup(Opaque, Mod).
1934
traverse_backup(S, T, Fun, Acc) ->
1935
mnesia_bup:traverse_backup(S, T, Fun, Acc).
1937
traverse_backup(S, SM, T, TM, F, A) ->
1938
mnesia_bup:traverse_backup(S, SM, T, TM, F, A).
1940
install_fallback(Opaque) ->
1941
mnesia_bup:install_fallback(Opaque).
1943
install_fallback(Opaque, Mod) ->
1944
mnesia_bup:install_fallback(Opaque, Mod).
1946
uninstall_fallback() ->
1947
mnesia_bup:uninstall_fallback().
1949
uninstall_fallback(Args) ->
1950
mnesia_bup:uninstall_fallback(Args).
1952
activate_checkpoint(Args) ->
1953
mnesia_checkpoint:activate(Args).
1955
deactivate_checkpoint(Name) ->
1956
mnesia_checkpoint:deactivate(Name).
1958
backup_checkpoint(Name, Opaque) ->
1959
mnesia_log:backup_checkpoint(Name, Opaque).
1961
backup_checkpoint(Name, Opaque, Mod) ->
1962
mnesia_log:backup_checkpoint(Name, Opaque, Mod).
1964
restore(Opaque, Args) ->
1965
mnesia_schema:restore(Opaque, Args).
1967
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970
create_table(Arg) ->
1971
mnesia_schema:create_table(Arg).
1972
create_table(Name, Arg) when list(Arg) ->
1973
mnesia_schema:create_table([{name, Name}| Arg]);
1974
create_table(Name, Arg) ->
1975
{aborted, badarg, Name, Arg}.
1977
delete_table(Tab) ->
1978
mnesia_schema:delete_table(Tab).
1980
add_table_copy(Tab, N, S) ->
1981
mnesia_schema:add_table_copy(Tab, N, S).
1982
del_table_copy(Tab, N) ->
1983
mnesia_schema:del_table_copy(Tab, N).
1985
move_table_copy(Tab, From, To) ->
1986
mnesia_schema:move_table(Tab, From, To).
1988
add_table_index(Tab, Ix) ->
1989
mnesia_schema:add_table_index(Tab, Ix).
1990
del_table_index(Tab, Ix) ->
1991
mnesia_schema:del_table_index(Tab, Ix).
1993
transform_table(Tab, Fun, NewA) ->
1994
case catch val({Tab, record_name}) of
1996
mnesia:abort(Reason);
1998
mnesia_schema:transform_table(Tab, Fun, NewA, OldRN)
2001
transform_table(Tab, Fun, NewA, NewRN) ->
2002
mnesia_schema:transform_table(Tab, Fun, NewA, NewRN).
2004
change_table_copy_type(T, N, S) ->
2005
mnesia_schema:change_table_copy_type(T, N, S).
2008
mnesia_schema:clear_table(Tab).
2010
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011
%% Table mgt - user properties
2013
read_table_property(Tab, PropKey) ->
2014
val({Tab, user_property, PropKey}).
2016
write_table_property(Tab, Prop) ->
2017
mnesia_schema:write_table_property(Tab, Prop).
2019
delete_table_property(Tab, PropKey) ->
2020
mnesia_schema:delete_table_property(Tab, PropKey).
2022
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023
%% Table mgt - user properties
2025
change_table_frag(Tab, FragProp) ->
2026
mnesia_schema:change_table_frag(Tab, FragProp).
2028
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029
%% Table mgt - table load
2031
%% Dump a ram table to disc
2032
dump_tables(Tabs) ->
2033
mnesia_schema:dump_tables(Tabs).
2035
%% allow the user to wait for some tables to be loaded
2036
wait_for_tables(Tabs, Timeout) ->
2037
mnesia_controller:wait_for_tables(Tabs, Timeout).
2039
force_load_table(Tab) ->
2040
case mnesia_controller:force_load_table(Tab) of
2041
ok -> yes; % Backwards compatibility
2045
change_table_access_mode(T, Access) ->
2046
mnesia_schema:change_table_access_mode(T, Access).
2048
change_table_load_order(T, O) ->
2049
mnesia_schema:change_table_load_order(T, O).
2051
set_master_nodes(Nodes) when list(Nodes) ->
2052
UseDir = system_info(use_dir),
2053
IsRunning = system_info(is_running),
2056
CsPat = {{'_', cstruct}, '_'},
2057
Cstructs0 = ?ets_match_object(mnesia_gvar, CsPat),
2058
Cstructs = [Cs || {_, Cs} <- Cstructs0],
2059
log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning);
2063
mnesia_lib:lock_table(schema),
2065
case mnesia_schema:read_cstructs_from_disc() of
2067
log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning);
2071
mnesia_lib:unlock_table(schema),
2077
set_master_nodes(Nodes) ->
2078
{error, {bad_type, Nodes}}.
2080
log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning) ->
2082
Copies = mnesia_lib:copy_holders(Cs),
2083
Valid = mnesia_lib:intersect(Nodes, Copies),
2084
{Cs#cstruct.name, Valid}
2086
Args = lists:map(Fun, Cstructs),
2087
mnesia_recover:log_master_nodes(Args, UseDir, IsRunning).
2089
set_master_nodes(Tab, Nodes) when list(Nodes) ->
2090
UseDir = system_info(use_dir),
2091
IsRunning = system_info(is_running),
2094
case ?catch_val({Tab, cstruct}) of
2096
{error, {no_exists, Tab}};
2098
case Nodes -- mnesia_lib:copy_holders(Cs) of
2100
Args = [{Tab , Nodes}],
2101
mnesia_recover:log_master_nodes(Args, UseDir, IsRunning);
2103
{error, {no_exists, Tab, BadNodes}}
2109
mnesia_lib:lock_table(schema),
2111
case mnesia_schema:read_cstructs_from_disc() of
2113
case lists:keysearch(Tab, 2, Cstructs) of
2115
case Nodes -- mnesia_lib:copy_holders(Cs) of
2117
Args = [{Tab , Nodes}],
2118
mnesia_recover:log_master_nodes(Args, UseDir, IsRunning);
2120
{error, {no_exists, Tab, BadNodes}}
2123
{error, {no_exists, Tab}}
2128
mnesia_lib:unlock_table(schema),
2134
set_master_nodes(Tab, Nodes) ->
2135
{error, {bad_type, Tab, Nodes}}.
2137
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141
mnesia_controller:sync_dump_log(user).
2144
mnesia_subscr:subscribe(self(), What).
2146
unsubscribe(What) ->
2147
mnesia_subscr:unsubscribe(self(), What).
2149
report_event(Event) ->
2150
mnesia_lib:report_system_event({mnesia_user, Event}).
2152
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155
snmp_open_table(Tab, Us) ->
2156
mnesia_schema:add_snmp(Tab, Us).
2158
snmp_close_table(Tab) ->
2159
mnesia_schema:del_snmp(Tab).
2161
snmp_get_row(Tab, RowIndex) when atom(Tab), Tab /= schema ->
2162
dirty_rpc(Tab, mnesia_snmp_hook, get_row, [Tab, RowIndex]);
2163
snmp_get_row(Tab, _RowIndex) ->
2164
abort({bad_type, Tab}).
2166
snmp_get_next_index(Tab, RowIndex) when atom(Tab), Tab /= schema ->
2167
dirty_rpc(Tab, mnesia_snmp_hook, get_next_index, [Tab, RowIndex]);
2168
snmp_get_next_index(Tab, _RowIndex) ->
2169
abort({bad_type, Tab}).
2171
snmp_get_mnesia_key(Tab, RowIndex) when atom(Tab), Tab /= schema ->
2172
dirty_rpc(Tab, mnesia_snmp_hook, get_mnesia_key, [Tab, RowIndex]);
2173
snmp_get_mnesia_key(Tab, _RowIndex) ->
2174
abort({bad_type, Tab}).
2176
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2180
mnesia_text:load_textfile(F).
2181
dump_to_textfile(F) ->
2182
mnesia_text:dump_to_textfile(F).
2184
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2185
%% Mnemosyne exclusive
2187
get_activity_id() ->
2188
get(mnesia_activity_state).
2190
put_activity_id(Activity) ->
2191
mnesia_tm:put_activity_id(Activity).