mnesia_schema.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,011 行 · 第 1/5 页
ERL
2,011 行
{bad_type, Tab, {access_mode, Access}}), Snmp = Cs#cstruct.snmp, verify(true, mnesia_snmp_hook:check_ustruct(Snmp), {badarg, Tab, {snmp, Snmp}}), CheckProp = fun(Prop) when tuple(Prop), size(Prop) >= 1 -> ok; (Prop) -> mnesia:abort({bad_type, Tab, {user_properties, [Prop]}}) end, lists:foreach(CheckProp, Cs#cstruct.user_properties), case Cs#cstruct.cookie of {{MegaSecs, Secs, MicroSecs}, _Node} when integer(MegaSecs), integer(Secs), integer(MicroSecs), atom(node) -> ok; Cookie -> mnesia:abort({bad_type, Tab, {cookie, Cookie}}) end, case Cs#cstruct.version of {{Major, Minor}, _Detail} when integer(Major), integer(Minor) -> ok; Version -> mnesia:abort({bad_type, Tab, {version, Version}}) end.verify_nodes(Cs) -> Tab = Cs#cstruct.name, Ram = Cs#cstruct.ram_copies, Disc = Cs#cstruct.disc_copies, DiscOnly = Cs#cstruct.disc_only_copies, LoadOrder = Cs#cstruct.load_order, verify({alt, [nil, list]}, mnesia_lib:etype(Ram), {bad_type, Tab, {ram_copies, Ram}}), verify({alt, [nil, list]}, mnesia_lib:etype(Disc), {bad_type, Tab, {disc_copies, Disc}}), case Tab of schema -> verify([], DiscOnly, {bad_type, Tab, {disc_only_copies, DiscOnly}}); _ -> verify({alt, [nil, list]}, mnesia_lib:etype(DiscOnly), {bad_type, Tab, {disc_only_copies, DiscOnly}}) end, verify(integer, mnesia_lib:etype(LoadOrder), {bad_type, Tab, {load_order, LoadOrder}}), Nodes = Ram ++ Disc ++ DiscOnly, verify(list, mnesia_lib:etype(Nodes), {combine_error, Tab, [{ram_copies, []}, {disc_copies, []}, {disc_only_copies, []}]}), verify(false, has_duplicates(Nodes), {combine_error, Tab, Nodes}), AtomCheck = fun(N) -> verify(atom, mnesia_lib:etype(N), {bad_type, Tab, N}) end, lists:foreach(AtomCheck, Nodes). verify(Expected, Fun, Error) when function(Fun) -> do_verify(Expected, catch Fun(), Error);verify(Expected, Actual, Error) -> do_verify(Expected, Actual, Error).do_verify({alt, Values}, Value, Error) -> case lists:member(Value, Values) of true -> ok; false -> mnesia:abort(Error) end;do_verify(Value, Value, _) -> ok;do_verify(_Value, _, Error) -> mnesia:abort(Error).ensure_writable(Tab) -> case val({Tab, where_to_write}) of [] -> mnesia:abort({read_only, Tab}); _ -> ok end.%% Ensure that all replicas on disk full nodes are activeensure_active(Cs) -> ensure_active(Cs, active_replicas).ensure_active(Cs, What) -> Tab = Cs#cstruct.name, case val({Tab, What}) of [] -> mnesia:abort({no_exists, Tab}); _ -> ok end, Nodes = mnesia_lib:intersect(val({schema, disc_copies}), mnesia_lib:cs_to_nodes(Cs)), W = {Tab, What}, case Nodes -- val(W) of [] -> ok; Ns -> Expl = "All replicas on diskfull nodes are not active yet", case val({Tab, local_content}) of true -> case rpc:multicall(Ns, ?MODULE, is_remote_member, [W]) of {Replies, []} -> check_active(Replies, Expl, Tab); {_Replies, BadNs} -> mnesia:abort({not_active, Expl, Tab, BadNs}) end; false -> mnesia:abort({not_active, Expl, Tab, Ns}) end end.ensure_not_active(schema, Node) -> case lists:member(Node, val({schema, active_replicas})) of false -> ok; true -> Expl = "Mnesia is running", mnesia:abort({active, Expl, Node}) end.is_remote_member(Key) -> IsActive = lists:member(node(), val(Key)), {IsActive, node()}.check_active([{true, _Node} | Replies], Expl, Tab) -> check_active(Replies, Expl, Tab);check_active([{false, Node} | _Replies], Expl, Tab) -> mnesia:abort({not_active, Expl, Tab, [Node]});check_active([{badrpc, Reason} | _Replies], Expl, Tab) -> mnesia:abort({not_active, Expl, Tab, Reason});check_active([], _Expl, _Tab) -> ok.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Here's the real interface function to create a tablecreate_table(TabDef) -> schema_transaction(fun() -> do_multi_create_table(TabDef) end).%% And the corresponding do routines ....do_multi_create_table(TabDef) -> get_tid_ts_and_lock(schema, write), ensure_writable(schema), Cs = list2cs(TabDef), case Cs#cstruct.frag_properties of [] -> do_create_table(Cs); _Props -> CsList = mnesia_frag:expand_cstruct(Cs), lists:foreach(fun do_create_table/1, CsList) end, ok.do_create_table(Cs) -> {_Mod, _Tid, Ts} = get_tid_ts_and_lock(schema, none), Store = Ts#tidstore.store, do_insert_schema_ops(Store, make_create_table(Cs)).make_create_table(Cs) -> Tab = Cs#cstruct.name, verify(false, check_if_exists(Tab), {already_exists, Tab}), unsafe_make_create_table(Cs).% unsafe_do_create_table(Cs) ->% {_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, none),% Store = Ts#tidstore.store,% do_insert_schema_ops(Store, unsafe_make_create_table(Cs)).unsafe_make_create_table(Cs) -> {_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, none), verify_cstruct(Cs), Tab = Cs#cstruct.name, %% Check that we have all disc replica nodes running DiscNodes = Cs#cstruct.disc_copies ++ Cs#cstruct.disc_only_copies, RunningNodes = val({current, db_nodes}), CheckDisc = fun(N) -> verify(true, lists:member(N, RunningNodes), {not_active, Tab, N}) end, lists:foreach(CheckDisc, DiscNodes), Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(Cs), RunningNodes), Store = Ts#tidstore.store, mnesia_locker:wlock_no_exist(Tid, Store, Tab, Nodes), [{op, create_table, cs2list(Cs)}].check_if_exists(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), {_, _, Ts} = TidTs, Store = Ts#tidstore.store, ets:foldl( fun({op, create_table, [{name, T}|_]}, _Acc) when T==Tab -> true; ({op, delete_table, [{name,T}|_]}, _Acc) when T==Tab -> false; (_Other, Acc) -> Acc end, existed_before(Tab), Store).existed_before(Tab) -> ('EXIT' =/= element(1, ?catch_val({Tab,cstruct}))).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Delete a table entirely on all nodes.delete_table(Tab) -> schema_transaction(fun() -> do_delete_table(Tab) end).do_delete_table(schema) -> mnesia:abort({bad_type, schema});do_delete_table(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), ensure_writable(schema), insert_schema_ops(TidTs, make_delete_table(Tab, whole_table)).make_delete_table(Tab, Mode) -> case existed_before(Tab) of false -> %% Deleting a table that was created in this very %% schema transaction. Delete all ops in the Store %% that operate on this table. We cannot run a normal %% delete operation, since that involves checking live %% nodes etc. TidTs = get_tid_ts_and_lock(schema, write), {_, _, Ts} = TidTs, Store = Ts#tidstore.store, Deleted = ets:select_delete( Store, [{{op,'$1',[{name,Tab}|'_']}, [{'or', {'==','$1',create_table}, {'==','$1',delete_table}}], [true]}]), ets:select_delete( Store, [{{op,'$1',[{name,Tab}|'_'],'_'}, [{'or', {'==','$1',write_table_property}, {'==','$1',delete_table_property}}], [true]}]), case Deleted of 0 -> mnesia:abort({no_exists, Tab}); _ -> [] end; true -> case Mode of whole_table -> case val({Tab, frag_properties}) of [] -> [make_delete_table2(Tab)]; _Props -> %% Check if it is a base table mnesia_frag:lookup_frag_hash(Tab), %% Check for foreigners F = mnesia_frag:lookup_foreigners(Tab), verify([], F, {combine_error, Tab, "Too many foreigners", F}), [make_delete_table2(T) || T <- mnesia_frag:frag_names(Tab)] end; single_frag -> [make_delete_table2(Tab)] end end.make_delete_table2(Tab) -> get_tid_ts_and_lock(Tab, write), Cs = val({Tab, cstruct}), ensure_active(Cs), ensure_writable(Tab), {op, delete_table, cs2list(Cs)}.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Change fragmentation of a table change_table_frag(Tab, Change) -> schema_transaction(fun() -> do_change_table_frag(Tab, Change) end).do_change_table_frag(Tab, Change) when atom(Tab), Tab /= schema -> TidTs = get_tid_ts_and_lock(schema, write), Ops = mnesia_frag:change_table_frag(Tab, Change), [insert_schema_ops(TidTs, Op) || Op <- Ops], ok;do_change_table_frag(Tab, _Change) -> mnesia:abort({bad_type, Tab}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Clear a tableclear_table(Tab) -> schema_transaction(fun() -> do_clear_table(Tab) end).do_clear_table(schema) -> mnesia:abort({bad_type, schema});do_clear_table(Tab) -> TidTs = get_tid_ts_and_lock(schema, write), get_tid_ts_and_lock(Tab, write), insert_schema_ops(TidTs, make_clear_table(Tab)).make_clear_table(Tab) -> ensure_writable(schema), Cs = val({Tab, cstruct}), ensure_active(Cs), ensure_writable(Tab), [{op, clear_table, cs2list(Cs)}].%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%add_table_copy(Tab, Node, Storage) -> schema_transaction(fun() -> do_add_table_copy(Tab, Node, Storage) end).do_add_table_copy(Tab, Node, Storage) when atom(Tab), atom(Node) -> TidTs = get_tid_ts_and_lock(schema, write), insert_schema_ops(TidTs, make_add_table_copy(Tab, Node, Storage));do_add_table_copy(Tab,Node,_) -> mnesia:abort({badarg, Tab, Node}).make_add_table_copy(Tab, Node, Storage) -> ensure_writable(schema), Cs = incr_version(val({Tab, cstruct})), Ns = mnesia_lib:cs_to_nodes(Cs), verify(false, lists:member(Node, Ns), {already_exists, Tab, Node}), Cs2 = new_cs(Cs, Node, Storage, add), verify_cstruct(Cs2), %% Check storage and if node is running IsRunning = lists:member(Node, val({current, db_nodes})), if Storage == unknown -> mnesia:abort({badarg, Tab, Storage}); Tab == schema -> if Storage /= ram_copies -> mnesia:abort({badarg, Tab, Storage}); IsRunning == true -> mnesia:abort({already_exists, Tab, Node}); true -> ignore end; Storage == ram_copies -> ignore; IsRunning == true -> ignore; IsRunning == false -> mnesia:abort({not_active, schema, Node}) end, [{op, add_table_copy, Storage, Node, cs2list(Cs2)}].del_table_copy(Tab, Node) -> schema_transaction(fun() -> do_del_table_copy(Tab, Node) end).do_del_table_copy(Tab, Node) when atom(Node) -> TidTs = get_tid_ts_and_lock(schema, write),%% get_tid_ts_and_lock(Tab, write), insert_schema_ops(TidTs, make_del_table_copy(Tab, Node));do_del_table_copy(Tab, Node) -> mnesia:abort({badarg, Tab, Node}). make_del_table_copy(Tab, Node) -> ensure_writable(schema), Cs = incr_version(val({Tab, cstruct})), Storage = mnesia_lib:schema_cs_to_storage_type(Node, Cs), Cs2 = new_cs(Cs, Node, Storage, del), case mnesia_lib:cs_to_nodes(Cs2) of [] when Tab == schema -> mnesia:abort({combine_error, Tab, "Last replica"}); [] -> ensure_active(Cs), dbg_out("Last replica deleted in table ~p~n", [Tab]), make_delete_table(Tab, whole_table); _ when Tab == schema -> ensure_active(Cs2), ensure_not_active(Tab, Node), verify_cstruct(Cs2), Ops = remove_node_from_tabs(val({schema, tables}), Node), [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)} | Ops]; _ -> ensure_active(Cs), verify_cstruct(Cs2), [{op, del_table_copy, Storage, Node, cs2list(Cs2)}] end.remove_node_from_tabs([], _Node) -> [];remove_node_from_tabs([schema|Rest], Node) -> remove_node_from_tabs(Rest, Node);remove_node_from_tabs([Tab|Rest], Node) -> {Cs, IsFragModified} = mnesia_frag:remove_node(Node, incr_version(val({Tab, cstruct}))), case mnesia_lib:schema_cs_to_storage_type(Node, Cs) of unknown -> case IsFragModified of true -> [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} | remove_node_from_tabs(Rest, Node)]; false -> remove_node_from_tabs(Rest, Node) end; Storage -> Cs2 = new_cs(Cs, Node, Storage, del), case mnesia_lib:cs_to_nodes(Cs2) of [] -> [{op, delete_table, cs2list(Cs)} | remove_node_from_tabs(Rest, Node)];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?