diff options
Diffstat (limited to 'lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia.erl')
-rw-r--r-- | lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia.erl | 2191 |
1 files changed, 0 insertions, 2191 deletions
diff --git a/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia.erl b/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia.erl deleted file mode 100644 index 956f4f5395..0000000000 --- a/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia.erl +++ /dev/null @@ -1,2191 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. -%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id: mnesia.erl,v 1.2 2010/03/04 13:54:19 maria Exp $ -%% -%% This module exports the public interface of the Mnesia DBMS engine - --module(mnesia). -%-behaviour(mnesia_access). - --export([ - %% Start, stop and debugging - start/0, start/1, stop/0, % Not for public use - set_debug_level/1, lkill/0, kill/0, % Not for public use - ms/0, nc/0, nc/1, ni/0, ni/1, % Not for public use - change_config/2, - - %% Activity mgt - abort/1, transaction/1, transaction/2, transaction/3, - sync_transaction/1, sync_transaction/2, sync_transaction/3, - async_dirty/1, async_dirty/2, sync_dirty/1, sync_dirty/2, ets/1, ets/2, - activity/2, activity/3, activity/4, % Not for public use - - %% Access within an activity - Lock acquisition - lock/2, lock/4, - read_lock_table/1, - write_lock_table/1, - - %% Access within an activity - Updates - write/1, s_write/1, write/3, write/5, - delete/1, s_delete/1, delete/3, delete/5, - delete_object/1, s_delete_object/1, delete_object/3, delete_object/5, - - %% Access within an activity - Reads - read/1, wread/1, read/3, read/5, - match_object/1, match_object/3, match_object/5, - select/2, select/3, select/5, - all_keys/1, all_keys/4, - index_match_object/2, index_match_object/4, index_match_object/6, - index_read/3, index_read/6, - - %% Iterators within an activity - foldl/3, foldl/4, foldr/3, foldr/4, - - %% Dirty access regardless of activities - Updates - dirty_write/1, dirty_write/2, - dirty_delete/1, dirty_delete/2, - dirty_delete_object/1, dirty_delete_object/2, - dirty_update_counter/2, dirty_update_counter/3, - - %% Dirty access regardless of activities - Read - dirty_read/1, dirty_read/2, - dirty_select/2, - dirty_match_object/1, dirty_match_object/2, dirty_all_keys/1, - dirty_index_match_object/2, dirty_index_match_object/3, - dirty_index_read/3, dirty_slot/2, - dirty_first/1, dirty_next/2, dirty_last/1, dirty_prev/2, - - %% Info - table_info/2, table_info/4, schema/0, schema/1, - error_description/1, info/0, system_info/1, - system_info/0, % Not for public use - - %% Database mgt - create_schema/1, delete_schema/1, - backup/1, backup/2, traverse_backup/4, traverse_backup/6, - install_fallback/1, install_fallback/2, - uninstall_fallback/0, uninstall_fallback/1, - activate_checkpoint/1, deactivate_checkpoint/1, - backup_checkpoint/2, backup_checkpoint/3, restore/2, - - %% Table mgt - create_table/1, create_table/2, delete_table/1, - add_table_copy/3, del_table_copy/2, move_table_copy/3, - add_table_index/2, del_table_index/2, - transform_table/3, transform_table/4, - change_table_copy_type/3, - read_table_property/2, write_table_property/2, delete_table_property/2, - change_table_frag/2, - clear_table/1, - - %% Table load - dump_tables/1, wait_for_tables/2, force_load_table/1, - change_table_access_mode/2, change_table_load_order/2, - set_master_nodes/1, set_master_nodes/2, - - %% Misc admin - dump_log/0, subscribe/1, unsubscribe/1, report_event/1, - - %% Snmp - snmp_open_table/2, snmp_close_table/1, - snmp_get_row/2, snmp_get_next_index/2, snmp_get_mnesia_key/2, - - %% Textfile access - load_textfile/1, dump_to_textfile/1, - - %% Mnemosyne exclusive - get_activity_id/0, put_activity_id/1, % Not for public use - - %% Mnesia internal functions - dirty_rpc/4, % Not for public use - has_var/1, fun_select/7, - foldl/6, foldr/6, - - %% Module internal callback functions - remote_dirty_match_object/2, % Not for public use - remote_dirty_select/2 % Not for public use - ]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --include("mnesia.hrl"). --import(mnesia_lib, [verbose/2]). - --define(DEFAULT_ACCESS, ?MODULE). - -%% Select --define(PATTERN_TO_OBJECT_MATCH_SPEC(Pat), [{Pat,[],['$_']}]). --define(PATTERN_TO_BINDINGS_MATCH_SPEC(Pat), [{Pat,[],['$$']}]). - -%% Local function in order to avoid external function call -val(Var) -> - case ?catch_val(Var) of - {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason); - Value -> Value - end. - -is_dollar_digits(Var) -> - case atom_to_list(Var) of - [$$ | Digs] -> - is_digits(Digs); - _ -> - false - end. - -is_digits([Dig | Tail]) -> - if - $0 =< Dig, Dig =< $9 -> - is_digits(Tail); - true -> - false - end; -is_digits([]) -> - true. - -has_var(X) when atom(X) -> - if - X == '_' -> - true; - atom(X) -> - is_dollar_digits(X); - true -> - false - end; -has_var(X) when tuple(X) -> - e_has_var(X, size(X)); -has_var([H|T]) -> - case has_var(H) of - false -> has_var(T); - Other -> Other - end; -has_var(_) -> false. - -e_has_var(_, 0) -> false; -e_has_var(X, Pos) -> - case has_var(element(Pos, X))of - false -> e_has_var(X, Pos-1); - Other -> Other - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Start and stop - -start() -> - {Time , Res} = timer:tc(application, start, [?APPLICATION, temporary]), - - Secs = Time div 1000000, - case Res of - ok -> - verbose("Mnesia started, ~p seconds~n",[ Secs]), - ok; - {error, {already_started, mnesia}} -> - verbose("Mnesia already started, ~p seconds~n",[ Secs]), - ok; - {error, R} -> - verbose("Mnesia failed to start, ~p seconds: ~p~n",[ Secs, R]), - {error, R} - end. - -start(ExtraEnv) when list(ExtraEnv) -> - case mnesia_lib:ensure_loaded(?APPLICATION) of - ok -> - patched_start(ExtraEnv); - Error -> - Error - end; -start(ExtraEnv) -> - {error, {badarg, ExtraEnv}}. - -patched_start([{Env, Val} | Tail]) when atom(Env) -> - case mnesia_monitor:patch_env(Env, Val) of - {error, Reason} -> - {error, Reason}; - _NewVal -> - patched_start(Tail) - end; -patched_start([Head | _]) -> - {error, {bad_type, Head}}; -patched_start([]) -> - start(). - -stop() -> - case application:stop(?APPLICATION) of - ok -> stopped; - {error, {not_started, ?APPLICATION}} -> stopped; - Other -> Other - end. - -change_config(extra_db_nodes, Ns) when list(Ns) -> - mnesia_controller:connect_nodes(Ns); -change_config(BadKey, _BadVal) -> - {error, {badarg, BadKey}}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Debugging - -set_debug_level(Level) -> - mnesia_subscr:set_debug_level(Level). - -lkill() -> - mnesia_sup:kill(). - -kill() -> - rpc:multicall(mnesia_sup, kill, []). - -ms() -> - [ - mnesia, - mnesia_backup, - mnesia_bup, - mnesia_checkpoint, - mnesia_checkpoint_sup, - mnesia_controller, - mnesia_dumper, - mnesia_loader, - mnesia_frag, - mnesia_frag_hash, - mnesia_frag_old_hash, - mnesia_index, - mnesia_kernel_sup, - mnesia_late_loader, - mnesia_lib, - mnesia_log, - mnesia_registry, - mnesia_schema, - mnesia_snmp_hook, - mnesia_snmp_sup, - mnesia_subscr, - mnesia_sup, - mnesia_text, - mnesia_tm, - mnesia_recover, - mnesia_locker, - - %% Keep these last in the list, so - %% mnesia_sup kills these last - mnesia_monitor, - mnesia_event - ]. - -nc() -> - Mods = ms(), - nc(Mods). - -nc(Mods) when list(Mods)-> - [Mod || Mod <- Mods, ok /= load(Mod, compile)]. - -ni() -> - Mods = ms(), - ni(Mods). - -ni(Mods) when list(Mods) -> - [Mod || Mod <- Mods, ok /= load(Mod, interpret)]. - -load(Mod, How) when atom(Mod) -> - case try_load(Mod, How) of - ok -> - ok; - _ -> - mnesia_lib:show( "~n RETRY ~p FROM: ", [Mod]), - Abs = mod2abs(Mod), - load(Abs, How) - end; -load(Abs, How) -> - case try_load(Abs, How) of - ok -> - ok; - {error, Reason} -> - mnesia_lib:show( " *** ERROR *** ~p~n", [Reason]), - {error, Reason} - end. - -try_load(Mod, How) -> - mnesia_lib:show( " ~p ", [Mod]), - Flags = [{d, debug}], - case How of - compile -> - case catch c:nc(Mod, Flags) of - {ok, _} -> ok; - Other -> {error, Other} - end; - interpret -> - case catch int:ni(Mod, Flags) of - {module, _} -> ok; - Other -> {error, Other} - end - end. - -mod2abs(Mod) -> - ModString = atom_to_list(Mod), - SubDir = - case lists:suffix("test", ModString) of - true -> test; - false -> src - end, - filename:join([code:lib_dir(?APPLICATION), SubDir, ModString]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Activity mgt - -abort(Reason) -> - exit({aborted, Reason}). - -transaction(Fun) -> - transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, async). -transaction(Fun, Retries) when integer(Retries), Retries >= 0 -> - transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async); -transaction(Fun, Retries) when Retries == infinity -> - transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async); -transaction(Fun, Args) -> - transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, async). -transaction(Fun, Args, Retries) -> - transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, async). - -sync_transaction(Fun) -> - transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, sync). -sync_transaction(Fun, Retries) when integer(Retries), Retries >= 0 -> - transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync); -sync_transaction(Fun, Retries) when Retries == infinity -> - transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync); -sync_transaction(Fun, Args) -> - transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, sync). -sync_transaction(Fun, Args, Retries) -> - transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, sync). - - -transaction(State, Fun, Args, Retries, Mod, Kind) - when function(Fun), list(Args), Retries == infinity, atom(Mod) -> - mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind); -transaction(State, Fun, Args, Retries, Mod, Kind) - when function(Fun), list(Args), integer(Retries), Retries >= 0, atom(Mod) -> - mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind); -transaction(_State, Fun, Args, Retries, Mod, _Kind) -> - {aborted, {badarg, Fun, Args, Retries, Mod}}. - -non_transaction(State, Fun, Args, ActivityKind, Mod) - when function(Fun), list(Args), atom(Mod) -> - mnesia_tm:non_transaction(State, Fun, Args, ActivityKind, Mod); -non_transaction(_State, Fun, Args, _ActivityKind, _Mod) -> - {aborted, {badarg, Fun, Args}}. - -async_dirty(Fun) -> - async_dirty(Fun, []). -async_dirty(Fun, Args) -> - non_transaction(get(mnesia_activity_state), Fun, Args, async_dirty, ?DEFAULT_ACCESS). - -sync_dirty(Fun) -> - sync_dirty(Fun, []). -sync_dirty(Fun, Args) -> - non_transaction(get(mnesia_activity_state), Fun, Args, sync_dirty, ?DEFAULT_ACCESS). - -ets(Fun) -> - ets(Fun, []). -ets(Fun, Args) -> - non_transaction(get(mnesia_activity_state), Fun, Args, ets, ?DEFAULT_ACCESS). - -activity(Kind, Fun) -> - activity(Kind, Fun, []). -activity(Kind, Fun, Args) when list(Args) -> - activity(Kind, Fun, Args, mnesia_monitor:get_env(access_module)); -activity(Kind, Fun, Mod) -> - activity(Kind, Fun, [], Mod). - -activity(Kind, Fun, Args, Mod) -> - State = get(mnesia_activity_state), - case Kind of - ets -> non_transaction(State, Fun, Args, Kind, Mod); - async_dirty -> non_transaction(State, Fun, Args, Kind, Mod); - sync_dirty -> non_transaction(State, Fun, Args, Kind, Mod); - transaction -> wrap_trans(State, Fun, Args, infinity, Mod, async); - {transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, async); - sync_transaction -> wrap_trans(State, Fun, Args, infinity, Mod, sync); - {sync_transaction, Retries} -> wrap_trans(State, Fun, Args, Retries, Mod, sync); - _ -> {aborted, {bad_type, Kind}} - end. - -wrap_trans(State, Fun, Args, Retries, Mod, Kind) -> - case transaction(State, Fun, Args, Retries, Mod, Kind) of - {'atomic', GoodRes} -> GoodRes; - BadRes -> exit(BadRes) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Access within an activity - lock acquisition - -%% Grab a lock on an item in the global lock table -%% Item may be any term. Lock may be write or read. -%% write lock is set on all the given nodes -%% read lock is only set on the first node -%% Nodes may either be a list of nodes or one node as an atom -%% Mnesia on all Nodes must be connected to each other, but -%% it is not neccessary that they are up and running. - -lock(LockItem, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - lock(Tid, Ts, LockItem, LockKind); - {Mod, Tid, Ts} -> - Mod:lock(Tid, Ts, LockItem, LockKind); - _ -> - abort(no_transaction) - end. - -lock(Tid, Ts, LockItem, LockKind) -> - case element(1, Tid) of - tid -> - case LockItem of - {record, Tab, Key} -> - lock_record(Tid, Ts, Tab, Key, LockKind); - {table, Tab} -> - lock_table(Tid, Ts, Tab, LockKind); - {global, GlobalKey, Nodes} -> - global_lock(Tid, Ts, GlobalKey, LockKind, Nodes); - _ -> - abort({bad_type, LockItem}) - end; - _Protocol -> - [] - end. - -%% Grab a read lock on a whole table -read_lock_table(Tab) -> - lock({table, Tab}, read), - ok. - -%% Grab a write lock on a whole table -write_lock_table(Tab) -> - lock({table, Tab}, write), - ok. - -lock_record(Tid, Ts, Tab, Key, LockKind) when atom(Tab) -> - Store = Ts#tidstore.store, - Oid = {Tab, Key}, - case LockKind of - read -> - mnesia_locker:rlock(Tid, Store, Oid); - write -> - mnesia_locker:wlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_wlock(Tid, Store, Oid); - none -> - []; - _ -> - abort({bad_type, Tab, LockKind}) - end; -lock_record(_Tid, _Ts, Tab, _Key, _LockKind) -> - abort({bad_type, Tab}). - -lock_table(Tid, Ts, Tab, LockKind) when atom(Tab) -> - Store = Ts#tidstore.store, - case LockKind of - read -> - mnesia_locker:rlock_table(Tid, Store, Tab); - write -> - mnesia_locker:wlock_table(Tid, Store, Tab); - sticky_write -> - mnesia_locker:sticky_wlock_table(Tid, Store, Tab); - none -> - []; - _ -> - abort({bad_type, Tab, LockKind}) - end; -lock_table(_Tid, _Ts, Tab, _LockKind) -> - abort({bad_type, Tab}). - -global_lock(Tid, Ts, Item, Kind, Nodes) when list(Nodes) -> - case element(1, Tid) of - tid -> - Store = Ts#tidstore.store, - GoodNs = good_global_nodes(Nodes), - if - Kind /= read, Kind /= write -> - abort({bad_type, Kind}); - true -> - mnesia_locker:global_lock(Tid, Store, Item, Kind, GoodNs) - end; - _Protocol -> - [] - end; -global_lock(_Tid, _Ts, _Item, _Kind, Nodes) -> - abort({bad_type, Nodes}). - -good_global_nodes(Nodes) -> - Recover = [node() | val(recover_nodes)], - mnesia_lib:intersect(Nodes, Recover). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Access within an activity - updates - -write(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - write(Tab, Val, write); -write(Val) -> - abort({bad_type, Val}). - -s_write(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - write(Tab, Val, sticky_write). - -write(Tab, Val, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - write(Tid, Ts, Tab, Val, LockKind); - {Mod, Tid, Ts} -> - Mod:write(Tid, Ts, Tab, Val, LockKind); - _ -> - abort(no_transaction) - end. - -write(Tid, Ts, Tab, Val, LockKind) - when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 -> - case element(1, Tid) of - ets -> - ?ets_insert(Tab, Val), - ok; - tid -> - Store = Ts#tidstore.store, - Oid = {Tab, element(2, Val)}, - case LockKind of - write -> - mnesia_locker:wlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_wlock(Tid, Store, Oid); - _ -> - abort({bad_type, Tab, LockKind}) - end, - write_to_store(Tab, Store, Oid, Val); - Protocol -> - do_dirty_write(Protocol, Tab, Val) - end; -write(_Tid, _Ts, Tab, Val, LockKind) -> - abort({bad_type, Tab, Val, LockKind}). - -write_to_store(Tab, Store, Oid, Val) -> - case ?catch_val({Tab, record_validation}) of - {RecName, Arity, Type} - when size(Val) == Arity, RecName == element(1, Val) -> - case Type of - bag -> - ?ets_insert(Store, {Oid, Val, write}); - _ -> - ?ets_delete(Store, Oid), - ?ets_insert(Store, {Oid, Val, write}) - end, - ok; - {'EXIT', _} -> - abort({no_exists, Tab}); - _ -> - abort({bad_type, Val}) - end. - -delete({Tab, Key}) -> - delete(Tab, Key, write); -delete(Oid) -> - abort({bad_type, Oid}). - -s_delete({Tab, Key}) -> - delete(Tab, Key, sticky_write); -s_delete(Oid) -> - abort({bad_type, Oid}). - -delete(Tab, Key, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - delete(Tid, Ts, Tab, Key, LockKind); - {Mod, Tid, Ts} -> - Mod:delete(Tid, Ts, Tab, Key, LockKind); - _ -> - abort(no_transaction) - end. - -delete(Tid, Ts, Tab, Key, LockKind) - when atom(Tab), Tab /= schema -> - case element(1, Tid) of - ets -> - ?ets_delete(Tab, Key), - ok; - tid -> - Store = Ts#tidstore.store, - Oid = {Tab, Key}, - case LockKind of - write -> - mnesia_locker:wlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_wlock(Tid, Store, Oid); - _ -> - abort({bad_type, Tab, LockKind}) - end, - ?ets_delete(Store, Oid), - ?ets_insert(Store, {Oid, Oid, delete}), - ok; - Protocol -> - do_dirty_delete(Protocol, Tab, Key) - end; -delete(_Tid, _Ts, Tab, _Key, _LockKind) -> - abort({bad_type, Tab}). - -delete_object(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - delete_object(Tab, Val, write); -delete_object(Val) -> - abort({bad_type, Val}). - -s_delete_object(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - delete_object(Tab, Val, sticky_write); -s_delete_object(Val) -> - abort({bad_type, Val}). - -delete_object(Tab, Val, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - delete_object(Tid, Ts, Tab, Val, LockKind); - {Mod, Tid, Ts} -> - Mod:delete_object(Tid, Ts, Tab, Val, LockKind); - _ -> - abort(no_transaction) - end. - -delete_object(Tid, Ts, Tab, Val, LockKind) - when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 -> - case element(1, Tid) of - ets -> - ?ets_match_delete(Tab, Val), - ok; - tid -> - Store = Ts#tidstore.store, - Oid = {Tab, element(2, Val)}, - case LockKind of - write -> - mnesia_locker:wlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_wlock(Tid, Store, Oid); - _ -> - abort({bad_type, Tab, LockKind}) - end, - case val({Tab, setorbag}) of - bag -> - ?ets_match_delete(Store, {Oid, Val, '_'}), - ?ets_insert(Store, {Oid, Val, delete_object}); - _ -> - case ?ets_match_object(Store, {Oid, '_', write}) of - [] -> - ?ets_match_delete(Store, {Oid, Val, '_'}), - ?ets_insert(Store, {Oid, Val, delete_object}); - _ -> - ?ets_delete(Store, Oid), - ?ets_insert(Store, {Oid, Oid, delete}) - end - end, - ok; - Protocol -> - do_dirty_delete_object(Protocol, Tab, Val) - end; -delete_object(_Tid, _Ts, Tab, _Key, _LockKind) -> - abort({bad_type, Tab}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Access within an activity - read - -read({Tab, Key}) -> - read(Tab, Key, read); -read(Oid) -> - abort({bad_type, Oid}). - -wread({Tab, Key}) -> - read(Tab, Key, write); -wread(Oid) -> - abort({bad_type, Oid}). - -read(Tab, Key, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - read(Tid, Ts, Tab, Key, LockKind); - {Mod, Tid, Ts} -> - Mod:read(Tid, Ts, Tab, Key, LockKind); - _ -> - abort(no_transaction) - end. - -read(Tid, Ts, Tab, Key, LockKind) - when atom(Tab), Tab /= schema -> - case element(1, Tid) of - ets -> - ?ets_lookup(Tab, Key); - tid -> - Store = Ts#tidstore.store, - Oid = {Tab, Key}, - Objs = - case LockKind of - read -> - mnesia_locker:rlock(Tid, Store, Oid); - write -> - mnesia_locker:rwlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_rwlock(Tid, Store, Oid); - _ -> - abort({bad_type, Tab, LockKind}) - end, - add_written(?ets_lookup(Store, Oid), Tab, Objs); - _Protocol -> - dirty_read(Tab, Key) - end; -read(_Tid, _Ts, Tab, _Key, _LockKind) -> - abort({bad_type, Tab}). - -%%%%%%%%%%%%%%%%%%%%% -%% Iterators - -foldl(Fun, Acc, Tab) -> - foldl(Fun, Acc, Tab, read). - -foldl(Fun, Acc, Tab, LockKind) when function(Fun) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - foldl(Tid, Ts, Fun, Acc, Tab, LockKind); - {Mod, Tid, Ts} -> - Mod:foldl(Tid, Ts, Fun, Acc, Tab, LockKind); - _ -> - abort(no_transaction) - end. - -foldl(ActivityId, Opaque, Fun, Acc, Tab, LockKind) -> - {Type, Prev} = init_iteration(ActivityId, Opaque, Tab, LockKind), - Res = (catch do_foldl(ActivityId, Opaque, Tab, dirty_first(Tab), Fun, Acc, Type, Prev)), - close_iteration(Res, Tab). - -do_foldl(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) -> - lists:foldl(fun(Key, Acc) -> - lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)) - end, RAcc, Stored); -do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, Stored); -do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)), - do_foldl(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored); -do_foldl(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]); -do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - NewStored = ordsets:del_element(Key, Stored), - do_foldl(A, O, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored). - -foldr(Fun, Acc, Tab) -> - foldr(Fun, Acc, Tab, read). -foldr(Fun, Acc, Tab, LockKind) when function(Fun) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - foldr(Tid, Ts, Fun, Acc, Tab, LockKind); - {Mod, Tid, Ts} -> - Mod:foldr(Tid, Ts, Fun, Acc, Tab, LockKind); - _ -> - abort(no_transaction) - end. - -foldr(ActivityId, Opaque, Fun, Acc, Tab, LockKind) -> - {Type, TempPrev} = init_iteration(ActivityId, Opaque, Tab, LockKind), - Prev = - if - Type == ordered_set -> - lists:reverse(TempPrev); - true -> %% Order doesn't matter for set and bag - TempPrev %% Keep the order so we can use ordsets:del_element - end, - Res = (catch do_foldr(ActivityId, Opaque, Tab, dirty_last(Tab), Fun, Acc, Type, Prev)), - close_iteration(Res, Tab). - -do_foldr(A, O, Tab, '$end_of_table', Fun, RAcc, _Type, Stored) -> - lists:foldl(fun(Key, Acc) -> - lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)) - end, RAcc, Stored); -do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H == Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, Stored); -do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H > Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, H, read)), - do_foldr(A, O, Tab, Key, Fun, NewAcc, ordered_set, Stored); -do_foldr(A, O, Tab, Key, Fun, Acc, ordered_set, [H | Stored]) when H < Key -> - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, ordered_set, [H |Stored]); -do_foldr(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag - NewAcc = lists:foldl(Fun, Acc, read(A, O, Tab, Key, read)), - NewStored = ordsets:del_element(Key, Stored), - do_foldr(A, O, Tab, dirty_prev(Tab, Key), Fun, NewAcc, Type, NewStored). - -init_iteration(ActivityId, Opaque, Tab, LockKind) -> - lock(ActivityId, Opaque, {table, Tab}, LockKind), - Type = val({Tab, setorbag}), - Previous = add_previous(ActivityId, Opaque, Type, Tab), - St = val({Tab, storage_type}), - if - St == unknown -> - ignore; - true -> - mnesia_lib:db_fixtable(St, Tab, true) - end, - {Type, Previous}. - -close_iteration(Res, Tab) -> - case val({Tab, storage_type}) of - unknown -> - ignore; - St -> - mnesia_lib:db_fixtable(St, Tab, false) - end, - case Res of - {'EXIT', {aborted, What}} -> - abort(What); - {'EXIT', What} -> - abort(What); - _ -> - Res - end. - -add_previous(_ActivityId, non_transaction, _Type, _Tab) -> - []; -add_previous(_Tid, Ts, _Type, Tab) -> - Previous = ?ets_match(Ts#tidstore.store, {{Tab, '$1'}, '_', write}), - lists:sort(lists:concat(Previous)). - -%% This routine fixes up the return value from read/1 so that -%% it is correct with respect to what this particular transaction -%% has already written, deleted .... etc - -add_written([], _Tab, Objs) -> - Objs; % standard normal fast case -add_written(Written, Tab, Objs) -> - case val({Tab, setorbag}) of - bag -> - add_written_to_bag(Written, Objs, []); - _ -> - add_written_to_set(Written) - end. - -add_written_to_set(Ws) -> - case lists:last(Ws) of - {_, _, delete} -> []; - {_, Val, write} -> [Val]; - {_, _, delete_object} -> [] - end. - -add_written_to_bag([{_, Val, write} | Tail], Objs, Ack) -> - add_written_to_bag(Tail, lists:delete(Val, Objs), [Val | Ack]); -add_written_to_bag([], Objs, Ack) -> - Objs ++ lists:reverse(Ack); %% Oldest write first as in ets -add_written_to_bag([{_, _ , delete} | Tail], _Objs, _Ack) -> - %% This transaction just deleted all objects - %% with this key - add_written_to_bag(Tail, [], []); -add_written_to_bag([{_, Val, delete_object} | Tail], Objs, Ack) -> - add_written_to_bag(Tail, lists:delete(Val, Objs), lists:delete(Val, Ack)). - -match_object(Pat) when tuple(Pat), size(Pat) > 2 -> - Tab = element(1, Pat), - match_object(Tab, Pat, read); -match_object(Pat) -> - abort({bad_type, Pat}). - -match_object(Tab, Pat, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - match_object(Tid, Ts, Tab, Pat, LockKind); - {Mod, Tid, Ts} -> - Mod:match_object(Tid, Ts, Tab, Pat, LockKind); - _ -> - abort(no_transaction) - end. - -match_object(Tid, Ts, Tab, Pat, LockKind) - when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 -> - case element(1, Tid) of - ets -> - mnesia_lib:db_match_object(ram_copies, Tab, Pat); - tid -> - Key = element(2, Pat), - case has_var(Key) of - false -> lock_record(Tid, Ts, Tab, Key, LockKind); - true -> lock_table(Tid, Ts, Tab, LockKind) - end, - Objs = dirty_match_object(Tab, Pat), - add_written_match(Ts#tidstore.store, Pat, Tab, Objs); - _Protocol -> - dirty_match_object(Tab, Pat) - end; -match_object(_Tid, _Ts, Tab, Pat, _LockKind) -> - abort({bad_type, Tab, Pat}). - -add_written_match(S, Pat, Tab, Objs) -> - Ops = find_ops(S, Tab, Pat), - add_match(Ops, Objs, val({Tab, setorbag})). - -find_ops(S, Tab, Pat) -> - GetWritten = [{{{Tab, '_'}, Pat, write}, [], ['$_']}, - {{{Tab, '_'}, '_', delete}, [], ['$_']}, - {{{Tab, '_'}, Pat, delete_object}, [], ['$_']}], - ets:select(S, GetWritten). - -add_match([], Objs, _Type) -> - Objs; -add_match(Written, Objs, ordered_set) -> - %% Must use keysort which is stable - add_ordered_match(lists:keysort(1,Written), Objs, []); -add_match([{Oid, _, delete}|R], Objs, Type) -> - add_match(R, deloid(Oid, Objs), Type); -add_match([{_Oid, Val, delete_object}|R], Objs, Type) -> - add_match(R, lists:delete(Val, Objs), Type); -add_match([{_Oid, Val, write}|R], Objs, bag) -> - add_match(R, [Val | lists:delete(Val, Objs)], bag); -add_match([{Oid, Val, write}|R], Objs, set) -> - add_match(R, [Val | deloid(Oid,Objs)],set). - -%% For ordered_set only !! -add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc) - when Key > element(2, Obj) -> - add_ordered_match(Written, Objs, [Obj|Acc]); -add_ordered_match([{{_, Key}, Val, write}|Rest], Objs =[Obj|_], Acc) - when Key < element(2, Obj) -> - add_ordered_match(Rest, [Val|Objs],Acc); -add_ordered_match([{{_, Key}, _, _DelOP}|Rest], Objs =[Obj|_], Acc) - when Key < element(2, Obj) -> - add_ordered_match(Rest,Objs,Acc); -%% Greater than last object -add_ordered_match([{_, Val, write}|Rest], [], Acc) -> - add_ordered_match(Rest, [Val], Acc); -add_ordered_match([_|Rest], [], Acc) -> - add_ordered_match(Rest, [], Acc); -%% Keys are equal from here -add_ordered_match([{_, Val, write}|Rest], [_Obj|Objs], Acc) -> - add_ordered_match(Rest, [Val|Objs], Acc); -add_ordered_match([{_, _Val, delete}|Rest], [_Obj|Objs], Acc) -> - add_ordered_match(Rest, Objs, Acc); -add_ordered_match([{_, Val, delete_object}|Rest], [Val|Objs], Acc) -> - add_ordered_match(Rest, Objs, Acc); -add_ordered_match([{_, _, delete_object}|Rest], Objs, Acc) -> - add_ordered_match(Rest, Objs, Acc); -add_ordered_match([], Objs, Acc) -> - lists:reverse(Acc, Objs). - - -%%%%%%%%%%%%%%%%%% -% select - -select(Tab, Pat) -> - select(Tab, Pat, read). -select(Tab, Pat, LockKind) - when atom(Tab), Tab /= schema, list(Pat) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - select(Tid, Ts, Tab, Pat, LockKind); - {Mod, Tid, Ts} -> - Mod:select(Tid, Ts, Tab, Pat, LockKind); - _ -> - abort(no_transaction) - end; -select(Tab, Pat, _Lock) -> - abort({badarg, Tab, Pat}). - -select(Tid, Ts, Tab, Spec, LockKind) -> - SelectFun = fun(FixedSpec) -> dirty_select(Tab, FixedSpec) end, - fun_select(Tid, Ts, Tab, Spec, LockKind, Tab, SelectFun). - -fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, SelectFun) -> - case element(1, Tid) of - ets -> - mnesia_lib:db_select(ram_copies, Tab, Spec); - tid -> - Store = Ts#tidstore.store, - Written = ?ets_match_object(Store, {{TabPat, '_'}, '_', '_'}), - %% Avoid table lock if possible - case Spec of - [{HeadPat,_, _}] when tuple(HeadPat), size(HeadPat) > 2 -> - Key = element(2, HeadPat), - case has_var(Key) of - false -> lock_record(Tid, Ts, Tab, Key, LockKind); - true -> lock_table(Tid, Ts, Tab, LockKind) - end; - _ -> - lock_table(Tid, Ts, Tab, LockKind) - end, - case Written of - [] -> - %% Nothing changed in the table during this transaction, - %% Simple case get results from [d]ets - SelectFun(Spec); - _ -> - %% Hard (slow case) records added or deleted earlier - %% in the transaction, have to cope with that. - Type = val({Tab, setorbag}), - FixedSpec = get_record_pattern(Spec), - TabRecs = SelectFun(FixedSpec), - FixedRes = add_match(Written, TabRecs, Type), - CMS = ets:match_spec_compile(Spec), -% case Type of -% ordered_set -> -% ets:match_spec_run(lists:sort(FixedRes), CMS); -% _ -> -% ets:match_spec_run(FixedRes, CMS) -% end - ets:match_spec_run(FixedRes, CMS) - end; - _Protocol -> - SelectFun(Spec) - end. - -get_record_pattern([]) -> - []; -get_record_pattern([{M,C,_B}|R]) -> - [{M,C,['$_']} | get_record_pattern(R)]. - -deloid(_Oid, []) -> - []; -deloid({Tab, Key}, [H | T]) when element(2, H) == Key -> - deloid({Tab, Key}, T); -deloid(Oid, [H | T]) -> - [H | deloid(Oid, T)]. - -all_keys(Tab) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - all_keys(Tid, Ts, Tab, read); - {Mod, Tid, Ts} -> - Mod:all_keys(Tid, Ts, Tab, read); - _ -> - abort(no_transaction) - end. - -all_keys(Tid, Ts, Tab, LockKind) - when atom(Tab), Tab /= schema -> - Pat0 = val({Tab, wild_pattern}), - Pat = setelement(2, Pat0, '$1'), - Keys = select(Tid, Ts, Tab, [{Pat, [], ['$1']}], LockKind), - case val({Tab, setorbag}) of - bag -> - mnesia_lib:uniq(Keys); - _ -> - Keys - end; -all_keys(_Tid, _Ts, Tab, _LockKind) -> - abort({bad_type, Tab}). - -index_match_object(Pat, Attr) when tuple(Pat), size(Pat) > 2 -> - Tab = element(1, Pat), - index_match_object(Tab, Pat, Attr, read); -index_match_object(Pat, _Attr) -> - abort({bad_type, Pat}). - -index_match_object(Tab, Pat, Attr, LockKind) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind); - {Mod, Tid, Ts} -> - Mod:index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind); - _ -> - abort(no_transaction) - end. - -index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind) - when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 -> - case element(1, Tid) of - ets -> - dirty_index_match_object(Tab, Pat, Attr); % Should be optimized? - tid -> - case mnesia_schema:attr_tab_to_pos(Tab, Attr) of - Pos when Pos =< size(Pat) -> - case LockKind of - read -> - Store = Ts#tidstore.store, - mnesia_locker:rlock_table(Tid, Store, Tab), - Objs = dirty_index_match_object(Tab, Pat, Attr), - add_written_match(Store, Pat, Tab, Objs); - _ -> - abort({bad_type, Tab, LockKind}) - end; - BadPos -> - abort({bad_type, Tab, BadPos}) - end; - _Protocol -> - dirty_index_match_object(Tab, Pat, Attr) - end; -index_match_object(_Tid, _Ts, Tab, Pat, _Attr, _LockKind) -> - abort({bad_type, Tab, Pat}). - -index_read(Tab, Key, Attr) -> - case get(mnesia_activity_state) of - {?DEFAULT_ACCESS, Tid, Ts} -> - index_read(Tid, Ts, Tab, Key, Attr, read); - {Mod, Tid, Ts} -> - Mod:index_read(Tid, Ts, Tab, Key, Attr, read); - _ -> - abort(no_transaction) - end. - -index_read(Tid, Ts, Tab, Key, Attr, LockKind) - when atom(Tab), Tab /= schema -> - case element(1, Tid) of - ets -> - dirty_index_read(Tab, Key, Attr); % Should be optimized? - tid -> - Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr), - case LockKind of - read -> - case has_var(Key) of - false -> - Store = Ts#tidstore.store, - Objs = mnesia_index:read(Tid, Store, Tab, Key, Pos), - Pat = setelement(Pos, val({Tab, wild_pattern}), Key), - add_written_match(Store, Pat, Tab, Objs); - true -> - abort({bad_type, Tab, Attr, Key}) - end; - _ -> - abort({bad_type, Tab, LockKind}) - end; - _Protocol -> - dirty_index_read(Tab, Key, Attr) - end; -index_read(_Tid, _Ts, Tab, _Key, _Attr, _LockKind) -> - abort({bad_type, Tab}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Dirty access regardless of activities - updates - -dirty_write(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - dirty_write(Tab, Val); -dirty_write(Val) -> - abort({bad_type, Val}). - -dirty_write(Tab, Val) -> - do_dirty_write(async_dirty, Tab, Val). - -do_dirty_write(SyncMode, Tab, Val) - when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 -> - case ?catch_val({Tab, record_validation}) of - {RecName, Arity, _Type} - when size(Val) == Arity, RecName == element(1, Val) -> - Oid = {Tab, element(2, Val)}, - mnesia_tm:dirty(SyncMode, {Oid, Val, write}); - {'EXIT', _} -> - abort({no_exists, Tab}); - _ -> - abort({bad_type, Val}) - end; -do_dirty_write(_SyncMode, Tab, Val) -> - abort({bad_type, Tab, Val}). - -dirty_delete({Tab, Key}) -> - dirty_delete(Tab, Key); -dirty_delete(Oid) -> - abort({bad_type, Oid}). - -dirty_delete(Tab, Key) -> - do_dirty_delete(async_dirty, Tab, Key). - -do_dirty_delete(SyncMode, Tab, Key) when atom(Tab), Tab /= schema -> - Oid = {Tab, Key}, - mnesia_tm:dirty(SyncMode, {Oid, Oid, delete}); -do_dirty_delete(_SyncMode, Tab, _Key) -> - abort({bad_type, Tab}). - -dirty_delete_object(Val) when tuple(Val), size(Val) > 2 -> - Tab = element(1, Val), - dirty_delete_object(Tab, Val); -dirty_delete_object(Val) -> - abort({bad_type, Val}). - -dirty_delete_object(Tab, Val) -> - do_dirty_delete_object(async_dirty, Tab, Val). - -do_dirty_delete_object(SyncMode, Tab, Val) - when atom(Tab), Tab /= schema, tuple(Val), size(Val) > 2 -> - Oid = {Tab, element(2, Val)}, - mnesia_tm:dirty(SyncMode, {Oid, Val, delete_object}); -do_dirty_delete_object(_SyncMode, Tab, Val) -> - abort({bad_type, Tab, Val}). - -%% A Counter is an Oid being {CounterTab, CounterName} - -dirty_update_counter({Tab, Key}, Incr) -> - dirty_update_counter(Tab, Key, Incr); -dirty_update_counter(Counter, _Incr) -> - abort({bad_type, Counter}). - -dirty_update_counter(Tab, Key, Incr) -> - do_dirty_update_counter(async_dirty, Tab, Key, Incr). - -do_dirty_update_counter(SyncMode, Tab, Key, Incr) - when atom(Tab), Tab /= schema, integer(Incr) -> - case ?catch_val({Tab, record_validation}) of - {RecName, 3, set} -> - Oid = {Tab, Key}, - mnesia_tm:dirty(SyncMode, {Oid, {RecName, Incr}, update_counter}); - _ -> - abort({combine_error, Tab, update_counter}) - end; -do_dirty_update_counter(_SyncMode, Tab, _Key, Incr) -> - abort({bad_type, Tab, Incr}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Dirty access regardless of activities - read - -dirty_read({Tab, Key}) -> - dirty_read(Tab, Key); -dirty_read(Oid) -> - abort({bad_type, Oid}). - -dirty_read(Tab, Key) - when atom(Tab), Tab /= schema -> -%% case catch ?ets_lookup(Tab, Key) of -%% {'EXIT', _} -> - %% Bad luck, we have to perform a real lookup - dirty_rpc(Tab, mnesia_lib, db_get, [Tab, Key]); -%% Val -> -%% Val -%% end; -dirty_read(Tab, _Key) -> - abort({bad_type, Tab}). - -dirty_match_object(Pat) when tuple(Pat), size(Pat) > 2 -> - Tab = element(1, Pat), - dirty_match_object(Tab, Pat); -dirty_match_object(Pat) -> - abort({bad_type, Pat}). - -dirty_match_object(Tab, Pat) - when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 -> - dirty_rpc(Tab, ?MODULE, remote_dirty_match_object, [Tab, Pat]); -dirty_match_object(Tab, Pat) -> - abort({bad_type, Tab, Pat}). - -remote_dirty_match_object(Tab, Pat) -> - Key = element(2, Pat), - case has_var(Key) of - false -> - mnesia_lib:db_match_object(Tab, Pat); - true -> - PosList = val({Tab, index}), - remote_dirty_match_object(Tab, Pat, PosList) - end. - -remote_dirty_match_object(Tab, Pat, [Pos | Tail]) when Pos =< size(Pat) -> - IxKey = element(Pos, Pat), - case has_var(IxKey) of - false -> - mnesia_index:dirty_match_object(Tab, Pat, Pos); - true -> - remote_dirty_match_object(Tab, Pat, Tail) - end; -remote_dirty_match_object(Tab, Pat, []) -> - mnesia_lib:db_match_object(Tab, Pat); -remote_dirty_match_object(Tab, Pat, _PosList) -> - abort({bad_type, Tab, Pat}). - -dirty_select(Tab, Spec) when atom(Tab), Tab /= schema, list(Spec) -> - dirty_rpc(Tab, ?MODULE, remote_dirty_select, [Tab, Spec]); -dirty_select(Tab, Spec) -> - abort({bad_type, Tab, Spec}). - -remote_dirty_select(Tab, Spec) -> - case Spec of - [{HeadPat, _, _}] when tuple(HeadPat), size(HeadPat) > 2 -> - Key = element(2, HeadPat), - case has_var(Key) of - false -> - mnesia_lib:db_select(Tab, Spec); - true -> - PosList = val({Tab, index}), - remote_dirty_select(Tab, Spec, PosList) - end; - _ -> - mnesia_lib:db_select(Tab, Spec) - end. - -remote_dirty_select(Tab, [{HeadPat,_, _}] = Spec, [Pos | Tail]) - when tuple(HeadPat), size(HeadPat) > 2, Pos =< size(Spec) -> - Key = element(Pos, HeadPat), - case has_var(Key) of - false -> - Recs = mnesia_index:dirty_select(Tab, Spec, Pos), - %% Returns the records without applying the match spec - %% The actual filtering is handled by the caller - CMS = ets:match_spec_compile(Spec), - case val({Tab, setorbag}) of - ordered_set -> - ets:match_spec_run(lists:sort(Recs), CMS); - _ -> - ets:match_spec_run(Recs, CMS) - end; - true -> - remote_dirty_select(Tab, Spec, Tail) - end; -remote_dirty_select(Tab, Spec, _) -> - mnesia_lib:db_select(Tab, Spec). - -dirty_all_keys(Tab) when atom(Tab), Tab /= schema -> - case ?catch_val({Tab, wild_pattern}) of - {'EXIT', _} -> - abort({no_exists, Tab}); - Pat0 -> - Pat = setelement(2, Pat0, '$1'), - Keys = dirty_select(Tab, [{Pat, [], ['$1']}]), - case val({Tab, setorbag}) of - bag -> mnesia_lib:uniq(Keys); - _ -> Keys - end - end; -dirty_all_keys(Tab) -> - abort({bad_type, Tab}). - -dirty_index_match_object(Pat, Attr) when tuple(Pat), size(Pat) > 2 -> - Tab = element(1, Pat), - dirty_index_match_object(Tab, Pat, Attr); -dirty_index_match_object(Pat, _Attr) -> - abort({bad_type, Pat}). - -dirty_index_match_object(Tab, Pat, Attr) - when atom(Tab), Tab /= schema, tuple(Pat), size(Pat) > 2 -> - case mnesia_schema:attr_tab_to_pos(Tab, Attr) of - Pos when Pos =< size(Pat) -> - case has_var(element(2, Pat)) of - false -> - dirty_match_object(Tab, Pat); - true -> - Elem = element(Pos, Pat), - case has_var(Elem) of - false -> - dirty_rpc(Tab, mnesia_index, dirty_match_object, - [Tab, Pat, Pos]); - true -> - abort({bad_type, Tab, Attr, Elem}) - end - end; - BadPos -> - abort({bad_type, Tab, BadPos}) - end; -dirty_index_match_object(Tab, Pat, _Attr) -> - abort({bad_type, Tab, Pat}). - -dirty_index_read(Tab, Key, Attr) when atom(Tab), Tab /= schema -> - Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr), - case has_var(Key) of - false -> - mnesia_index:dirty_read(Tab, Key, Pos); - true -> - abort({bad_type, Tab, Attr, Key}) - end; -dirty_index_read(Tab, _Key, _Attr) -> - abort({bad_type, Tab}). - -dirty_slot(Tab, Slot) when atom(Tab), Tab /= schema, integer(Slot) -> - dirty_rpc(Tab, mnesia_lib, db_slot, [Tab, Slot]); -dirty_slot(Tab, Slot) -> - abort({bad_type, Tab, Slot}). - -dirty_first(Tab) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_lib, db_first, [Tab]); -dirty_first(Tab) -> - abort({bad_type, Tab}). - -dirty_last(Tab) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_lib, db_last, [Tab]); -dirty_last(Tab) -> - abort({bad_type, Tab}). - -dirty_next(Tab, Key) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_lib, db_next_key, [Tab, Key]); -dirty_next(Tab, _Key) -> - abort({bad_type, Tab}). - -dirty_prev(Tab, Key) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_lib, db_prev_key, [Tab, Key]); -dirty_prev(Tab, _Key) -> - abort({bad_type, Tab}). - - -dirty_rpc(Tab, M, F, Args) -> - Node = val({Tab, where_to_read}), - do_dirty_rpc(Tab, Node, M, F, Args). - -do_dirty_rpc(_Tab, nowhere, _, _, Args) -> - mnesia:abort({no_exists, Args}); -do_dirty_rpc(Tab, Node, M, F, Args) -> - case rpc:call(Node, M, F, Args) of - {badrpc,{'EXIT', {undef, [{ M, F, _} | _]}}} - when M == ?MODULE, F == remote_dirty_select -> - %% Oops, the other node has not been upgraded - %% to 4.0.3 yet. Lets do it the old way. - %% Remove this in next release. - do_dirty_rpc(Tab, Node, mnesia_lib, db_select, Args); - {badrpc, Reason} -> - erlang:yield(), %% Do not be too eager - case mnesia_controller:call({check_w2r, Node, Tab}) of % Sync - NewNode when NewNode == Node -> - ErrorTag = mnesia_lib:dirty_rpc_error_tag(Reason), - mnesia:abort({ErrorTag, Args}); - NewNode -> - case get(mnesia_activity_state) of - {_Mod, Tid, _Ts} when record(Tid, tid) -> - %% In order to perform a consistent - %% retry of a transaction we need - %% to acquire the lock on the NewNode. - %% In this context we do neither know - %% the kind or granularity of the lock. - %% --> Abort the transaction - mnesia:abort({node_not_running, Node}); - _ -> - %% Splendid! A dirty retry is safe - %% 'Node' probably went down now - %% Let mnesia_controller get broken link message first - do_dirty_rpc(Tab, NewNode, M, F, Args) - end - end; - Other -> - Other - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Info - -%% Info about one table -table_info(Tab, Item) -> - case get(mnesia_activity_state) of - undefined -> - any_table_info(Tab, Item); - {?DEFAULT_ACCESS, _Tid, _Ts} -> - any_table_info(Tab, Item); - {Mod, Tid, Ts} -> - Mod:table_info(Tid, Ts, Tab, Item); - _ -> - abort(no_transaction) - end. - -table_info(_Tid, _Ts, Tab, Item) -> - any_table_info(Tab, Item). - - -any_table_info(Tab, Item) when atom(Tab) -> - case Item of - master_nodes -> - mnesia_recover:get_master_nodes(Tab); -% checkpoints -> -% case ?catch_val({Tab, commit_work}) of -% [{checkpoints, List} | _] -> List; -% No_chk when list(No_chk) -> []; -% Else -> info_reply(Else, Tab, Item) -% end; - size -> - raw_table_info(Tab, Item); - memory -> - raw_table_info(Tab, Item); - type -> - case ?catch_val({Tab, setorbag}) of - {'EXIT', _} -> - bad_info_reply(Tab, Item); - Val -> - Val - end; - all -> - case mnesia_schema:get_table_properties(Tab) of - [] -> - abort({no_exists, Tab, Item}); - Props -> - lists:map(fun({setorbag, Type}) -> {type, Type}; - (Prop) -> Prop end, - Props) - end; - _ -> - case ?catch_val({Tab, Item}) of - {'EXIT', _} -> - bad_info_reply(Tab, Item); - Val -> - Val - end - end; -any_table_info(Tab, _Item) -> - abort({bad_type, Tab}). - -raw_table_info(Tab, Item) -> - case ?catch_val({Tab, storage_type}) of - ram_copies -> - info_reply(catch ?ets_info(Tab, Item), Tab, Item); - disc_copies -> - info_reply(catch ?ets_info(Tab, Item), Tab, Item); - disc_only_copies -> - info_reply(catch dets:info(Tab, Item), Tab, Item); - unknown -> - bad_info_reply(Tab, Item); - {'EXIT', _} -> - bad_info_reply(Tab, Item) - end. - -info_reply({'EXIT', _Reason}, Tab, Item) -> - bad_info_reply(Tab, Item); -info_reply({error, _Reason}, Tab, Item) -> - bad_info_reply(Tab, Item); -info_reply(Val, _Tab, _Item) -> - Val. - -bad_info_reply(_Tab, size) -> 0; -bad_info_reply(_Tab, memory) -> 0; -bad_info_reply(Tab, Item) -> abort({no_exists, Tab, Item}). - -%% Raw info about all tables -schema() -> - mnesia_schema:info(). - -%% Raw info about one tables -schema(Tab) -> - mnesia_schema:info(Tab). - -error_description(Err) -> - mnesia_lib:error_desc(Err). - -info() -> - case mnesia_lib:is_running() of - yes -> - TmInfo = mnesia_tm:get_info(10000), - Held = system_info(held_locks), - Queued = system_info(lock_queue), - - io:format("---> Processes holding locks <--- ~n", []), - lists:foreach(fun(L) -> io:format("Lock: ~p~n", [L]) end, - Held), - - io:format( "---> Processes waiting for locks <--- ~n", []), - lists:foreach(fun({Oid, Op, _Pid, Tid, OwnerTid}) -> - io:format("Tid ~p waits for ~p lock " - "on oid ~p owned by ~p ~n", - [Tid, Op, Oid, OwnerTid]) - end, Queued), - mnesia_tm:display_info(group_leader(), TmInfo), - - Pat = {'_', unclear, '_'}, - Uncertain = ets:match_object(mnesia_decision, Pat), - - io:format( "---> Uncertain transactions <--- ~n", []), - lists:foreach(fun({Tid, _, Nodes}) -> - io:format("Tid ~w waits for decision " - "from ~w~n", - [Tid, Nodes]) - end, Uncertain), - - mnesia_controller:info(), - display_system_info(Held, Queued, TmInfo, Uncertain); - _ -> - mini_info() - end, - ok. - -mini_info() -> - io:format("===> System info in version ~p, debug level = ~p <===~n", - [system_info(version), system_info(debug)]), - Not = - case system_info(use_dir) of - true -> ""; - false -> "NOT " - end, - - io:format("~w. Directory ~p is ~sused.~n", - [system_info(schema_location), system_info(directory), Not]), - io:format("use fallback at restart = ~w~n", - [system_info(fallback_activated)]), - Running = system_info(running_db_nodes), - io:format("running db nodes = ~w~n", [Running]), - All = mnesia_lib:all_nodes(), - io:format("stopped db nodes = ~w ~n", [All -- Running]). - -display_system_info(Held, Queued, TmInfo, Uncertain) -> - mini_info(), - display_tab_info(), - S = fun(Items) -> [system_info(I) || I <- Items] end, - - io:format("~w transactions committed, ~w aborted, " - "~w restarted, ~w logged to disc~n", - S([transaction_commits, transaction_failures, - transaction_restarts, transaction_log_writes])), - - {Active, Pending} = - case TmInfo of - {timeout, _} -> {infinity, infinity}; - {info, P, A} -> {length(A), length(P)} - end, - io:format("~w held locks, ~w in queue; " - "~w local transactions, ~w remote~n", - [length(Held), length(Queued), Active, Pending]), - - Ufold = fun({_, _, Ns}, {C, Old}) -> - New = [N || N <- Ns, not lists:member(N, Old)], - {C + 1, New ++ Old} - end, - {Ucount, Unodes} = lists:foldl(Ufold, {0, []}, Uncertain), - io:format("~w transactions waits for other nodes: ~p~n", - [Ucount, Unodes]). - -display_tab_info() -> - MasterTabs = mnesia_recover:get_master_node_tables(), - io:format("master node tables = ~p~n", [lists:sort(MasterTabs)]), - - Tabs = system_info(tables), - - {Unknown, Ram, Disc, DiscOnly} = - lists:foldl(fun storage_count/2, {[], [], [], []}, Tabs), - - io:format("remote = ~p~n", [lists:sort(Unknown)]), - io:format("ram_copies = ~p~n", [lists:sort(Ram)]), - io:format("disc_copies = ~p~n", [lists:sort(Disc)]), - io:format("disc_only_copies = ~p~n", [lists:sort(DiscOnly)]), - - Rfoldl = fun(T, Acc) -> - Rpat = - case val({T, access_mode}) of - read_only -> - lists:sort([{A, read_only} || A <- val({T, active_replicas})]); - read_write -> - table_info(T, where_to_commit) - end, - case lists:keysearch(Rpat, 1, Acc) of - {value, {_Rpat, Rtabs}} -> - lists:keyreplace(Rpat, 1, Acc, {Rpat, [T | Rtabs]}); - false -> - [{Rpat, [T]} | Acc] - end - end, - Repl = lists:foldl(Rfoldl, [], Tabs), - Rdisp = fun({Rpat, Rtabs}) -> io:format("~p = ~p~n", [Rpat, Rtabs]) end, - lists:foreach(Rdisp, lists:sort(Repl)). - -storage_count(T, {U, R, D, DO}) -> - case table_info(T, storage_type) of - unknown -> {[T | U], R, D, DO}; - ram_copies -> {U, [T | R], D, DO}; - disc_copies -> {U, R, [T | D], DO}; - disc_only_copies -> {U, R, D, [T | DO]} - end. - -system_info(Item) -> - case catch system_info2(Item) of - {'EXIT',Error} -> abort(Error); - Other -> Other - end. - -system_info2(all) -> - Items = system_info_items(mnesia_lib:is_running()), - [{I, system_info(I)} || I <- Items]; - -system_info2(db_nodes) -> - DiscNs = ?catch_val({schema, disc_copies}), - RamNs = ?catch_val({schema, ram_copies}), - if - list(DiscNs), list(RamNs) -> - DiscNs ++ RamNs; - true -> - case mnesia_schema:read_nodes() of - {ok, Nodes} -> Nodes; - {error,Reason} -> exit(Reason) - end - end; -system_info2(running_db_nodes) -> - case ?catch_val({current, db_nodes}) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_lib:running_nodes(); - Other -> - Other - end; - -system_info2(extra_db_nodes) -> - case ?catch_val(extra_db_nodes) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_monitor:get_env(extra_db_nodes); - Other -> - Other - end; - -system_info2(directory) -> - case ?catch_val(directory) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_monitor:get_env(dir); - Other -> - Other - end; - -system_info2(use_dir) -> - case ?catch_val(use_dir) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_monitor:use_dir(); - Other -> - Other - end; - -system_info2(schema_location) -> - case ?catch_val(schema_location) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_monitor:get_env(schema_location); - Other -> - Other - end; - -system_info2(fallback_activated) -> - case ?catch_val(fallback_activated) of - {'EXIT',_} -> - %% Ensure that we access the intended Mnesia - %% directory. This function may not be called - %% during startup since it will cause the - %% application_controller to get into deadlock - load_mnesia_or_abort(), - mnesia_bup:fallback_exists(); - Other -> - Other - end; - -system_info2(version) -> - case ?catch_val(version) of - {'EXIT', _} -> - Apps = application:loaded_applications(), - case lists:keysearch(?APPLICATION, 1, Apps) of - {value, {_Name, _Desc, Version}} -> - Version; - false -> - %% Ensure that it does not match - {mnesia_not_loaded, node(), now()} - end; - Version -> - Version - end; - -system_info2(access_module) -> mnesia_monitor:get_env(access_module); -system_info2(auto_repair) -> mnesia_monitor:get_env(auto_repair); -system_info2(is_running) -> mnesia_lib:is_running(); -system_info2(backup_module) -> mnesia_monitor:get_env(backup_module); -system_info2(event_module) -> mnesia_monitor:get_env(event_module); -system_info2(debug) -> mnesia_monitor:get_env(debug); -system_info2(dump_log_load_regulation) -> mnesia_monitor:get_env(dump_log_load_regulation); -system_info2(dump_log_write_threshold) -> mnesia_monitor:get_env(dump_log_write_threshold); -system_info2(dump_log_time_threshold) -> mnesia_monitor:get_env(dump_log_time_threshold); -system_info2(dump_log_update_in_place) -> - mnesia_monitor:get_env(dump_log_update_in_place); -system_info2(dump_log_update_in_place) -> - mnesia_monitor:get_env(dump_log_update_in_place); -system_info2(max_wait_for_decision) -> mnesia_monitor:get_env(max_wait_for_decision); -system_info2(embedded_mnemosyne) -> mnesia_monitor:get_env(embedded_mnemosyne); -system_info2(ignore_fallback_at_startup) -> mnesia_monitor:get_env(ignore_fallback_at_startup); -system_info2(fallback_error_function) -> mnesia_monitor:get_env(fallback_error_function); -system_info2(log_version) -> mnesia_log:version(); -system_info2(protocol_version) -> mnesia_monitor:protocol_version(); -system_info2(schema_version) -> mnesia_schema:version(); %backward compatibility -system_info2(tables) -> val({schema, tables}); -system_info2(local_tables) -> val({schema, local_tables}); -system_info2(master_node_tables) -> mnesia_recover:get_master_node_tables(); -system_info2(subscribers) -> mnesia_subscr:subscribers(); -system_info2(checkpoints) -> mnesia_checkpoint:checkpoints(); -system_info2(held_locks) -> mnesia_locker:get_held_locks(); -system_info2(lock_queue) -> mnesia_locker:get_lock_queue(); -system_info2(transactions) -> mnesia_tm:get_transactions(); -system_info2(transaction_failures) -> mnesia_lib:read_counter(trans_failures); -system_info2(transaction_commits) -> mnesia_lib:read_counter(trans_commits); -system_info2(transaction_restarts) -> mnesia_lib:read_counter(trans_restarts); -system_info2(transaction_log_writes) -> mnesia_dumper:get_log_writes(); - -system_info2(Item) -> exit({badarg, Item}). - -system_info_items(yes) -> - [ - access_module, - auto_repair, - backup_module, - checkpoints, - db_nodes, - debug, - directory, - dump_log_load_regulation, - dump_log_time_threshold, - dump_log_update_in_place, - dump_log_write_threshold, - embedded_mnemosyne, - event_module, - extra_db_nodes, - fallback_activated, - held_locks, - ignore_fallback_at_startup, - fallback_error_function, - is_running, - local_tables, - lock_queue, - log_version, - master_node_tables, - max_wait_for_decision, - protocol_version, - running_db_nodes, - schema_location, - schema_version, - subscribers, - tables, - transaction_commits, - transaction_failures, - transaction_log_writes, - transaction_restarts, - transactions, - use_dir, - version - ]; -system_info_items(no) -> - [ - auto_repair, - backup_module, - db_nodes, - debug, - directory, - dump_log_load_regulation, - dump_log_time_threshold, - dump_log_update_in_place, - dump_log_write_threshold, - event_module, - extra_db_nodes, - ignore_fallback_at_startup, - fallback_error_function, - is_running, - log_version, - max_wait_for_decision, - protocol_version, - running_db_nodes, - schema_location, - schema_version, - use_dir, - version - ]. - -system_info() -> - IsRunning = mnesia_lib:is_running(), - case IsRunning of - yes -> - TmInfo = mnesia_tm:get_info(10000), - Held = system_info(held_locks), - Queued = system_info(lock_queue), - Pat = {'_', unclear, '_'}, - Uncertain = ets:match_object(mnesia_decision, Pat), - display_system_info(Held, Queued, TmInfo, Uncertain); - _ -> - mini_info() - end, - IsRunning. - -load_mnesia_or_abort() -> - case mnesia_lib:ensure_loaded(?APPLICATION) of - ok -> - ok; - {error, Reason} -> - abort(Reason) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Database mgt - -create_schema(Ns) -> - mnesia_bup:create_schema(Ns). - -delete_schema(Ns) -> - mnesia_schema:delete_schema(Ns). - -backup(Opaque) -> - mnesia_log:backup(Opaque). - -backup(Opaque, Mod) -> - mnesia_log:backup(Opaque, Mod). - -traverse_backup(S, T, Fun, Acc) -> - mnesia_bup:traverse_backup(S, T, Fun, Acc). - -traverse_backup(S, SM, T, TM, F, A) -> - mnesia_bup:traverse_backup(S, SM, T, TM, F, A). - -install_fallback(Opaque) -> - mnesia_bup:install_fallback(Opaque). - -install_fallback(Opaque, Mod) -> - mnesia_bup:install_fallback(Opaque, Mod). - -uninstall_fallback() -> - mnesia_bup:uninstall_fallback(). - -uninstall_fallback(Args) -> - mnesia_bup:uninstall_fallback(Args). - -activate_checkpoint(Args) -> - mnesia_checkpoint:activate(Args). - -deactivate_checkpoint(Name) -> - mnesia_checkpoint:deactivate(Name). - -backup_checkpoint(Name, Opaque) -> - mnesia_log:backup_checkpoint(Name, Opaque). - -backup_checkpoint(Name, Opaque, Mod) -> - mnesia_log:backup_checkpoint(Name, Opaque, Mod). - -restore(Opaque, Args) -> - mnesia_schema:restore(Opaque, Args). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Table mgt - -create_table(Arg) -> - mnesia_schema:create_table(Arg). -create_table(Name, Arg) when list(Arg) -> - mnesia_schema:create_table([{name, Name}| Arg]); -create_table(Name, Arg) -> - {aborted, badarg, Name, Arg}. - -delete_table(Tab) -> - mnesia_schema:delete_table(Tab). - -add_table_copy(Tab, N, S) -> - mnesia_schema:add_table_copy(Tab, N, S). -del_table_copy(Tab, N) -> - mnesia_schema:del_table_copy(Tab, N). - -move_table_copy(Tab, From, To) -> - mnesia_schema:move_table(Tab, From, To). - -add_table_index(Tab, Ix) -> - mnesia_schema:add_table_index(Tab, Ix). -del_table_index(Tab, Ix) -> - mnesia_schema:del_table_index(Tab, Ix). - -transform_table(Tab, Fun, NewA) -> - case catch val({Tab, record_name}) of - {'EXIT', Reason} -> - mnesia:abort(Reason); - OldRN -> - mnesia_schema:transform_table(Tab, Fun, NewA, OldRN) - end. - -transform_table(Tab, Fun, NewA, NewRN) -> - mnesia_schema:transform_table(Tab, Fun, NewA, NewRN). - -change_table_copy_type(T, N, S) -> - mnesia_schema:change_table_copy_type(T, N, S). - -clear_table(Tab) -> - mnesia_schema:clear_table(Tab). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Table mgt - user properties - -read_table_property(Tab, PropKey) -> - val({Tab, user_property, PropKey}). - -write_table_property(Tab, Prop) -> - mnesia_schema:write_table_property(Tab, Prop). - -delete_table_property(Tab, PropKey) -> - mnesia_schema:delete_table_property(Tab, PropKey). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Table mgt - user properties - -change_table_frag(Tab, FragProp) -> - mnesia_schema:change_table_frag(Tab, FragProp). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Table mgt - table load - -%% Dump a ram table to disc -dump_tables(Tabs) -> - mnesia_schema:dump_tables(Tabs). - -%% allow the user to wait for some tables to be loaded -wait_for_tables(Tabs, Timeout) -> - mnesia_controller:wait_for_tables(Tabs, Timeout). - -force_load_table(Tab) -> - case mnesia_controller:force_load_table(Tab) of - ok -> yes; % Backwards compatibility - Other -> Other - end. - -change_table_access_mode(T, Access) -> - mnesia_schema:change_table_access_mode(T, Access). - -change_table_load_order(T, O) -> - mnesia_schema:change_table_load_order(T, O). - -set_master_nodes(Nodes) when list(Nodes) -> - UseDir = system_info(use_dir), - IsRunning = system_info(is_running), - case IsRunning of - yes -> - CsPat = {{'_', cstruct}, '_'}, - Cstructs0 = ?ets_match_object(mnesia_gvar, CsPat), - Cstructs = [Cs || {_, Cs} <- Cstructs0], - log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning); - _NotRunning -> - case UseDir of - true -> - mnesia_lib:lock_table(schema), - Res = - case mnesia_schema:read_cstructs_from_disc() of - {ok, Cstructs} -> - log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning); - {error, Reason} -> - {error, Reason} - end, - mnesia_lib:unlock_table(schema), - Res; - false -> - ok - end - end; -set_master_nodes(Nodes) -> - {error, {bad_type, Nodes}}. - -log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning) -> - Fun = fun(Cs) -> - Copies = mnesia_lib:copy_holders(Cs), - Valid = mnesia_lib:intersect(Nodes, Copies), - {Cs#cstruct.name, Valid} - end, - Args = lists:map(Fun, Cstructs), - mnesia_recover:log_master_nodes(Args, UseDir, IsRunning). - -set_master_nodes(Tab, Nodes) when list(Nodes) -> - UseDir = system_info(use_dir), - IsRunning = system_info(is_running), - case IsRunning of - yes -> - case ?catch_val({Tab, cstruct}) of - {'EXIT', _} -> - {error, {no_exists, Tab}}; - Cs -> - case Nodes -- mnesia_lib:copy_holders(Cs) of - [] -> - Args = [{Tab , Nodes}], - mnesia_recover:log_master_nodes(Args, UseDir, IsRunning); - BadNodes -> - {error, {no_exists, Tab, BadNodes}} - end - end; - _NotRunning -> - case UseDir of - true -> - mnesia_lib:lock_table(schema), - Res = - case mnesia_schema:read_cstructs_from_disc() of - {ok, Cstructs} -> - case lists:keysearch(Tab, 2, Cstructs) of - {value, Cs} -> - case Nodes -- mnesia_lib:copy_holders(Cs) of - [] -> - Args = [{Tab , Nodes}], - mnesia_recover:log_master_nodes(Args, UseDir, IsRunning); - BadNodes -> - {error, {no_exists, Tab, BadNodes}} - end; - false -> - {error, {no_exists, Tab}} - end; - {error, Reason} -> - {error, Reason} - end, - mnesia_lib:unlock_table(schema), - Res; - false -> - ok - end - end; -set_master_nodes(Tab, Nodes) -> - {error, {bad_type, Tab, Nodes}}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Misc admin - -dump_log() -> - mnesia_controller:sync_dump_log(user). - -subscribe(What) -> - mnesia_subscr:subscribe(self(), What). - -unsubscribe(What) -> - mnesia_subscr:unsubscribe(self(), What). - -report_event(Event) -> - mnesia_lib:report_system_event({mnesia_user, Event}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Snmp - -snmp_open_table(Tab, Us) -> - mnesia_schema:add_snmp(Tab, Us). - -snmp_close_table(Tab) -> - mnesia_schema:del_snmp(Tab). - -snmp_get_row(Tab, RowIndex) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_snmp_hook, get_row, [Tab, RowIndex]); -snmp_get_row(Tab, _RowIndex) -> - abort({bad_type, Tab}). - -snmp_get_next_index(Tab, RowIndex) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_snmp_hook, get_next_index, [Tab, RowIndex]); -snmp_get_next_index(Tab, _RowIndex) -> - abort({bad_type, Tab}). - -snmp_get_mnesia_key(Tab, RowIndex) when atom(Tab), Tab /= schema -> - dirty_rpc(Tab, mnesia_snmp_hook, get_mnesia_key, [Tab, RowIndex]); -snmp_get_mnesia_key(Tab, _RowIndex) -> - abort({bad_type, Tab}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Textfile access - -load_textfile(F) -> - mnesia_text:load_textfile(F). -dump_to_textfile(F) -> - mnesia_text:dump_to_textfile(F). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Mnemosyne exclusive - -get_activity_id() -> - get(mnesia_activity_state). - -put_activity_id(Activity) -> - mnesia_tm:put_activity_id(Activity). |