mnesia_lib.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,331 行 · 第 1/3 页
ERL
1,331 行
%% ``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$%%%% This module contains all sorts of various which doesn't fit%% anywhere else. Basically everything is exported.-module(mnesia_lib).-include("mnesia.hrl").-include_lib("kernel/include/file.hrl").-export([core_file/0]).-export([ active_tables/0, add/2, add_list/2, add_lsort/2, all_nodes/0,%% catch_val/1, cleanup_tmp_files/1, copy_file/2, copy_holders/1, coredump/0, coredump/1, create_counter/1, cs_to_nodes/1, cs_to_storage_type/2, dets_to_ets/6, db_chunk/2, db_init_chunk/1, db_init_chunk/2, db_init_chunk/3, db_erase/2, db_erase/3, db_erase_tab/1, db_erase_tab/2, db_first/1, db_first/2, db_last/1, db_last/2, db_fixtable/3, db_get/2, db_get/3, db_match_erase/2, db_match_erase/3, db_match_object/2, db_match_object/3, db_next_key/2, db_next_key/3, db_prev_key/2, db_prev_key/3, db_put/2, db_put/3, db_select/2, db_select/3, db_select_init/4, db_select_cont/3, db_slot/2, db_slot/3, db_update_counter/3, db_update_counter/4, dbg_out/2, del/2, dets_sync_close/1, dets_sync_open/2, dets_sync_open/3, dir/0, dir/1, dir_info/0, dirty_rpc_error_tag/1, dist_coredump/0, disk_type/1, disk_type/2, elems/2, ensure_loaded/1, error/2, error_desc/1, etype/1, exists/1, fatal/2, get_node_number/0, fix_error/1, important/2, incr_counter/1, incr_counter/2, intersect/2, is_running/0, is_running/1, is_running_remote/0, is_string/1, key_search_delete/3, key_search_all/3, last_error/0, local_active_tables/0, lock_table/1, mkcore/1, not_active_here/1, other_val/2, pad_name/3, random_time/2, read_counter/1, readable_indecies/1, remote_copy_holders/1, report_fatal/2, report_system_event/1, running_nodes/0, running_nodes/1, schema_cs_to_storage_type/2, search_delete/2, set/2, set_counter/2, set_local_content_whereabouts/1, set_remote_where_to_read/1, set_remote_where_to_read/2, show/1, show/2, sort_commit/1, storage_type_at_node/2, swap_tmp_files/1, tab2dat/1, tab2dmp/1, tab2tmp/1, tab2dcd/1, tab2dcl/1, to_list/1, union/2, uniq/1, unlock_table/1, unset/1, update_counter/2, val/1, vcore/0, vcore/1, verbose/2, view/0, view/1, view/2, warning/2, is_debug_compiled/0, activate_debug_fun/5, deactivate_debug_fun/3, eval_debug_fun/4, scratch_debug_fun/0 ]). search_delete(Obj, List) -> search_delete(Obj, List, [], none).search_delete(Obj, [Obj|Tail], Ack, _Res) -> search_delete(Obj, Tail, Ack, Obj);search_delete(Obj, [H|T], Ack, Res) -> search_delete(Obj, T, [H|Ack], Res);search_delete(_, [], Ack, Res) -> {Res, Ack}.key_search_delete(Key, Pos, TupleList) -> key_search_delete(Key, Pos, TupleList, none, []).key_search_delete(Key, Pos, [H|T], _Obj, Ack) when element(Pos, H) == Key -> key_search_delete(Key, Pos, T, H, Ack);key_search_delete(Key, Pos, [H|T], Obj, Ack) -> key_search_delete(Key, Pos, T, Obj, [H|Ack]);key_search_delete(_, _, [], Obj, Ack) -> {Obj, Ack}.key_search_all(Key, Pos, TupleList) -> key_search_all(Key, Pos, TupleList, []).key_search_all(Key, N, [H|T], Ack) when element(N, H) == Key -> key_search_all(Key, N, T, [H|Ack]);key_search_all(Key, N, [_|T], Ack) -> key_search_all(Key, N, T, Ack);key_search_all(_, _, [], Ack) -> Ack.intersect(L1, L2) -> L2 -- (L2 -- L1).elems(I, [H|T]) -> [element(I, H) | elems(I, T)];elems(_, []) -> [].%% sort_commit see to that checkpoint info is always first in %% commit_work structure the other info don't need to be sorted.sort_commit(List) -> sort_commit2(List, []).sort_commit2([{checkpoints, ChkpL}| Rest], Acc) -> [{checkpoints, ChkpL}| Rest] ++ Acc;sort_commit2([H | R], Acc) -> sort_commit2(R, [H | Acc]);sort_commit2([], Acc) -> Acc. is_string([H|T]) -> if 0 =< H, H < 256, integer(H) -> is_string(T); true -> false end;is_string([]) -> true.%%%union([H|L1], L2) -> case lists:member(H, L2) of true -> union(L1, L2); false -> [H | union(L1, L2)] end;union([], L2) -> L2.uniq([]) -> [];uniq(List) -> [H|T] = lists:sort(List), uniq1(H, T, []).uniq1(H, [H|R], Ack) -> uniq1(H, R, Ack);uniq1(Old, [H|R], Ack) -> uniq1(H, R, [Old|Ack]);uniq1(Old, [], Ack) -> [Old| Ack].to_list(X) when list(X) -> X;to_list(X) -> atom_to_list(X).all_nodes() -> Ns = mnesia:system_info(db_nodes) ++ mnesia:system_info(extra_db_nodes), mnesia_lib:uniq(Ns).running_nodes() -> running_nodes(all_nodes()).running_nodes(Ns) -> {Replies, _BadNs} = rpc:multicall(Ns, ?MODULE, is_running_remote, []), [N || {GoodState, N} <- Replies, GoodState == true].is_running_remote() -> IsRunning = is_running(), {IsRunning == yes, node()}.is_running(Node) when atom(Node) -> case rpc:call(Node, ?MODULE, is_running, []) of {badrpc, _} -> no; X -> X end.is_running() -> case ?catch_val(mnesia_status) of {'EXIT', _} -> no; running -> yes; starting -> starting; stopping -> stopping end.show(X) -> show(X, []).show(F, A) -> io:format(user, F, A).pad_name([Char | Chars], Len, Tail) -> [Char | pad_name(Chars, Len - 1, Tail)];pad_name([], Len, Tail) when Len =< 0 -> Tail;pad_name([], Len, Tail) -> [$ | pad_name([], Len - 1, Tail)]. %% Some utility functions .....active_here(Tab) -> case val({Tab, where_to_read}) of Node when Node == node() -> true; _ -> false end.not_active_here(Tab) -> not active_here(Tab).exists(Fname) -> case file:rawopen(Fname, read) of {ok, F} ->file:close(F), true; _ -> false end.dir() -> mnesia_monitor:get_env(dir).dir(Fname) -> filename:join([dir(), to_list(Fname)]).tab2dat(Tab) -> %% DETS files dir(lists:concat([Tab, ".DAT"])).tab2tmp(Tab) -> dir(lists:concat([Tab, ".TMP"])).tab2dmp(Tab) -> %% Dumped ets tables dir(lists:concat([Tab, ".DMP"])).tab2dcd(Tab) -> %% Disc copies data dir(lists:concat([Tab, ".DCD"])).tab2dcl(Tab) -> %% Disc copies log dir(lists:concat([Tab, ".DCL"])).storage_type_at_node(Node, Tab) -> search_key(Node, [{disc_copies, val({Tab, disc_copies})}, {ram_copies, val({Tab, ram_copies})}, {disc_only_copies, val({Tab, disc_only_copies})}]).cs_to_storage_type(Node, Cs) -> search_key(Node, [{disc_copies, Cs#cstruct.disc_copies}, {ram_copies, Cs#cstruct.ram_copies}, {disc_only_copies, Cs#cstruct.disc_only_copies}]).schema_cs_to_storage_type(Node, Cs) -> case cs_to_storage_type(Node, Cs) of unknown when Cs#cstruct.name == schema -> ram_copies; Other -> Other end.search_key(Key, [{Val, List} | Tail]) -> case lists:member(Key, List) of true -> Val; false -> search_key(Key, Tail) end;search_key(_Key, []) -> unknown.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ops, we've got some global variables here :-)%% They are%%%% {Tab, setorbag}, -> set | bag%% {Tab, storage_type} -> disc_copies |ram_copies | unknown (**)%% {Tab, disc_copies} -> node list (from schema)%% {Tab, ram_copies}, -> node list (from schema)%% {Tab, arity}, -> number%% {Tab, attributes}, -> atom list%% {Tab, wild_pattern}, -> record tuple with '_'s%% {Tab, {index, Pos}} -> ets table%% {Tab, index} -> integer list%% {Tab, cstruct} -> cstruct structure%%%% The following fields are dynamic according to the%% the current node/table situation%% {Tab, where_to_write} -> node list%% {Tab, where_to_read} -> node | nowhere%%%% {schema, tables} -> tab list%% {schema, local_tables} -> tab list (**)%%%% {current, db_nodes} -> node list%%%% dir -> directory path (**)%% mnesia_status -> status | running | stopping (**)%% (**) == (Different on all nodes)%%val(Var) -> case ?catch_val(Var) of {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_); _VaLuE_ -> _VaLuE_ end.set(Var, Val) -> ?ets_insert(mnesia_gvar, {Var, Val}).unset(Var) -> ?ets_delete(mnesia_gvar, Var).other_val(Var, Other) -> case Var of {_, where_to_read} -> nowhere; {_, where_to_write} -> []; {_, active_replicas} -> []; _ -> pr_other(Var, Other) end.pr_other(Var, Other) -> Why = case is_running() of no -> {node_not_running, node()}; _ -> {no_exists, Var} end, verbose("~p (~p) val(mnesia_gvar, ~w) -> ~p ~p ~n", [self(), process_info(self(), registered_name), Var, Other, Why]), case Other of {badarg, [{ets, lookup_element, _}|_]} -> exit(Why); _ -> erlang:fault(Why) end.%% Some functions for list valued variablesadd(Var, Val) -> L = val(Var), set(Var, [Val | lists:delete(Val, L)]).add_list(Var, List) -> L = val(Var), set(Var, union(L, List)).del(Var, Val) -> L = val(Var), set(Var, lists:delete(Val, L)).%% LSort -> [node()| Sorted] == Locker sortedadd_lsort(Var, Val) when node() == Val -> L = val(Var), set(Var, [Val | lists:delete(Val, L)]);add_lsort(Var,Val) -> case val(Var) of [Head|Rest] when Head == node() -> set(Var,[Head|lsort_add(Val,Rest)]); List -> set(Var,lsort_add(Val,List)) end.lsort_add(Val,List) -> case ordsets:is_element(Val,List) of true -> List; false -> ordsets:add_element(Val,List) end.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?