mnesia_schema.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 2,011 行 · 第 1/5 页

ERL
2,011
字号
merge_with_previous(write_property, Prop, Prev) ->    Key = element(1, Prop),    Prev1 = lists:keydelete(Key, 1, Prev),    lists:sort([Prop|Prev1]);merge_with_previous(delete_property, PropKey, Prev) ->    lists:keydelete(PropKey, 1, Prev).delete_table_property(Tab, PropKey) ->    schema_transaction(fun() -> do_delete_table_property(Tab, PropKey) end).do_delete_table_property(Tab, PropKey) ->    TidTs = get_tid_ts_and_lock(schema, write),    {_, _, Ts} = TidTs,    Store = Ts#tidstore.store,    case change_prop_in_existing_op(Tab, PropKey, delete_property, Store) of	true ->	    dbg_out("change_prop_in_existing_op"		    "(~p,~p,delete_property,Store) -> true~n",		    [Tab,PropKey]),	    %% we have merged the table prop into the create_table op	    ok;	false ->	    dbg_out("change_prop_in_existing_op"		    "(~p,~p,delete_property,Store) -> false~n",		    [Tab,PropKey]),	    %% this must be an existing table	    get_tid_ts_and_lock(Tab, none),	    insert_schema_ops(TidTs, 			      make_delete_table_properties(Tab, [PropKey]))    end.make_delete_table_properties(Tab, PropKeys) ->    ensure_writable(schema),    Cs = incr_version(val({Tab, cstruct})),    ensure_active(Cs),    make_delete_table_properties(Tab, PropKeys, Cs).make_delete_table_properties(Tab, [PropKey | PropKeys], Cs) ->    OldProps = Cs#cstruct.user_properties,    Props = lists:keydelete(PropKey, 1, OldProps),    Cs2 = Cs#cstruct{user_properties = Props},    verify_cstruct(Cs2),    [{op, delete_property, cs2list(Cs2), PropKey} |     make_delete_table_properties(Tab, PropKeys, Cs2)];make_delete_table_properties(_Tab, [], _Cs) ->    [].%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Ensure that the transaction can be committed even %% if the node crashes and Mnesia is restartedprepare_commit(Tid, Commit, WaitFor) ->    case Commit#commit.schema_ops of	[] ->	    {false, Commit, optional};	OrigOps ->	    {Modified, Ops, DumperMode} = 		prepare_ops(Tid, OrigOps, WaitFor, false, [], optional),	    InitBy = schema_prepare,	    GoodRes = {Modified, 		       Commit#commit{schema_ops = lists:reverse(Ops)},		       DumperMode},	    case DumperMode of		optional ->		    dbg_out("Transaction log dump skipped (~p): ~w~n",			    [DumperMode, InitBy]);		mandatory ->		    case mnesia_controller:sync_dump_log(InitBy) of			dumped ->			    GoodRes;			{error, Reason} ->			    mnesia:abort(Reason)		    end	    end,	    case Ops of		[] -> 		    ignore;		_ ->		    %% We need to grab a dumper lock here, the log may not		    %% be dumped by others, during the schema commit phase.		    mnesia_controller:wait_for_schema_commit_lock()	    end,	    GoodRes    end.prepare_ops(Tid, [Op | Ops], WaitFor, Changed, Acc, DumperMode) ->    case prepare_op(Tid, Op, WaitFor) of        {true, mandatory} -> 	    prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], mandatory);        {true, optional} -> 	    prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], DumperMode);        {true, Ops2, mandatory} -> 	    prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, mandatory);        {true, Ops2, optional} -> 	    prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, DumperMode);	{false, optional} -> 	    prepare_ops(Tid, Ops, WaitFor, true, Acc, DumperMode)    end;prepare_ops(_Tid, [], _WaitFor, Changed, Acc, DumperMode) ->    {Changed, Acc, DumperMode}.    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Prepare for commit%% returns true if Op should be included, i.e. unmodified%%         {true, Operation} if NewRecs should be included, i.e. modified%%         false if Op should NOT be included, i.e. modified%%prepare_op(_Tid, {op, rec, unknown, Rec}, _WaitFor) ->    {{Tab, Key}, Items, _Op} = Rec,    case val({Tab, storage_type}) of        unknown ->            {false, optional};        Storage ->            mnesia_tm:prepare_snmp(Tab, Key, Items), % May exit            {true, [{op, rec, Storage, Rec}], optional}    end;prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunning}, _WaitFor) ->    SchemaCs = list2cs(SchemaDef),    if 		Node == node() -> %% Announce has already run on local node 	    ignore;       %% from do_merge_schema	true ->	    NewNodes = mnesia_lib:uniq(Running++RemoteRunning) -- val({current,db_nodes}),	    mnesia_lib:set(prepare_op, {announce_im_running,NewNodes}),	    announce_im_running(NewNodes, SchemaCs)    end,    {false, optional};prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) ->        CoordPid ! {sync_trans, self()},    receive 	{sync_trans, CoordPid} ->	    {false, optional};	Else ->	    mnesia_lib:verbose("sync_op terminated due to ~p~n", [Else]),	    mnesia:abort(Else)    end;prepare_op(_Tid, {op, sync_trans}, {coord, Nodes}) ->        case receive_sync(Nodes, []) of	{abort, Reason} ->	    mnesia_lib:verbose("sync_op terminated due to ~p~n", [Reason]),	    mnesia:abort(Reason);	Pids ->	    [Pid ! {sync_trans, self()} || Pid <- Pids],	    {false, optional}    end;prepare_op(Tid, {op, create_table, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    Storage = mnesia_lib:cs_to_storage_type(node(), Cs),    UseDir = mnesia_monitor:use_dir(),    Tab = Cs#cstruct.name,    case Storage of        disc_copies when UseDir == false ->	    UseDirReason = {bad_type, Tab, Storage, node()},            mnesia:abort(UseDirReason);        disc_only_copies when UseDir == false ->	    UseDirReason = {bad_type, Tab, Storage, node()},            mnesia:abort(UseDirReason);	ram_copies ->	    mnesia_lib:set({Tab, create_table},true),	    create_ram_table(Tab, Cs#cstruct.type),	    insert_cstruct(Tid, Cs, false),	    {true, optional};	disc_copies ->	    mnesia_lib:set({Tab, create_table},true),	    create_ram_table(Tab, Cs#cstruct.type),	    create_disc_table(Tab),	    insert_cstruct(Tid, Cs, false),	    {true, optional};		disc_only_copies ->	    mnesia_lib:set({Tab, create_table},true),	    create_disc_only_table(Tab,Cs#cstruct.type),	    insert_cstruct(Tid, Cs, false),	    {true, optional};        unknown -> %% No replica on this node	    mnesia_lib:set({Tab, create_table},true),	    insert_cstruct(Tid, Cs, false),            {true, optional}    end;prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    Tab = Cs#cstruct.name,    if	Tab == schema ->	    {true, optional};		Node == node() ->	    case mnesia_lib:val({schema, storage_type}) of 		ram_copies when Storage /= ram_copies -> 		    Error = {combine_error, Tab, "has no disc", Node},		    mnesia:abort(Error);		_  ->		    ok	    end,   	    %% Tables are created by mnesia_loader get_network code	    insert_cstruct(Tid, Cs, true),	    case mnesia_controller:get_network_copy(Tab, Cs) of		{loaded, ok} ->		    {true, optional};		{not_loaded, ErrReason} ->		    Reason = {system_limit, Tab, {Node, ErrReason}},		    mnesia:abort(Reason)	    end;	Node /= node() ->	    %% Verify that ram table not has been dumped to disc	    if		Storage /= ram_copies ->		    case mnesia_lib:schema_cs_to_storage_type(node(), Cs) of			ram_copies ->			    Dat = mnesia_lib:tab2dcd(Tab),			    case mnesia_lib:exists(Dat) of				true ->				    mnesia:abort({combine_error, Tab, Storage,						  "Table dumped to disc", node()});				false ->				    ok			    end;			_ ->			    ok		    end;		true ->		    ok	    end,	    insert_cstruct(Tid, Cs, true),	    {true, optional}    end;prepare_op(Tid, {op, del_table_copy, _Storage, Node, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    Tab = Cs#cstruct.name,        if	%% Schema table lock is always required to run a schema op.	%% No need to look it.	node(Tid#tid.pid) == node(), Tab /= schema -> 	    Self = self(),	    Pid = spawn_link(fun() -> lock_del_table(Tab, Node, Cs, Self) end),	    put(mnesia_lock, Pid),	    receive 		{Pid, updated} -> 		    {true, optional};		{Pid, FailReason} ->		    mnesia:abort(FailReason);		{'EXIT', Pid, Reason} ->		    mnesia:abort(Reason)	    end;		true ->	    {true, optional}    end;prepare_op(_Tid, {op, change_table_copy_type,  N, FromS, ToS, TabDef}, _WaitFor)  when N == node() ->    Cs = list2cs(TabDef),    Tab = Cs#cstruct.name,    NotActive = mnesia_lib:not_active_here(Tab),        if 	NotActive == true ->	    mnesia:abort({not_active, Tab, node()});		Tab == schema ->	    	    case {FromS, ToS} of		{ram_copies, disc_copies} ->		    case mnesia:system_info(schema_location) of			opt_disc ->			    ignore;			_ ->			    mnesia:abort({combine_error,  Tab, node(),					  "schema_location must be opt_disc"})		    end,		    Dir = mnesia_lib:dir(),    		    case opt_create_dir(true, Dir) of			ok ->			    purge_dir(Dir, []),			    mnesia_log:purge_all_logs(),			    set(use_dir, true),			    mnesia_log:init(),			    Ns = val({current, db_nodes}), %mnesia_lib:running_nodes(),			    F = fun(U) -> mnesia_recover:log_mnesia_up(U) end,			    lists:foreach(F, Ns),			    mnesia_dumper:raw_named_dump_table(Tab, dmp),			    mnesia_checkpoint:tm_change_table_copy_type(Tab, FromS, ToS);			{error, Reason} ->			    mnesia:abort(Reason)		    end;		{disc_copies, ram_copies} ->		    Ltabs = val({schema, local_tables}) -- [schema],		    Dtabs = [L || L <- Ltabs,				  val({L, storage_type}) /= ram_copies],		    verify([], Dtabs, {"Disc resident tables", Dtabs, N});		_ ->		    mnesia:abort({combine_error, Tab, ToS})	    end;		FromS == ram_copies ->	    	    case mnesia_monitor:use_dir() of		true -> 		    Dat = mnesia_lib:tab2dcd(Tab),		    case mnesia_lib:exists(Dat) of			true ->			    mnesia:abort({combine_error, Tab, node(),					  "Table dump exists"});			false ->			    case ToS of 				disc_copies -> 				    mnesia_log:ets2dcd(Tab, dmp);				disc_only_copies ->				    mnesia_dumper:raw_named_dump_table(Tab, dmp)			    end,			    mnesia_checkpoint:tm_change_table_copy_type(Tab, FromS, ToS)		    end;		false ->		    mnesia:abort({has_no_disc, node()})	    end;		FromS == disc_copies, ToS == disc_only_copies ->	    mnesia_dumper:raw_named_dump_table(Tab, dmp);	FromS == disc_only_copies ->	    Type = Cs#cstruct.type,	    create_ram_table(Tab, Type),	    Datname = mnesia_lib:tab2dat(Tab),	    Repair = mnesia_monitor:get_env(auto_repair),	    case mnesia_lib:dets_to_ets(Tab, Tab, Datname, Type, Repair, no) of		loaded -> ok;		Reason ->		    Err = "Failed to copy disc data to ram",		    mnesia:abort({system_limit, Tab, {Err,Reason}})	    end;	true ->	    ignore    end,    {true, mandatory};prepare_op(_Tid, {op, change_table_copy_type,  N, _FromS, _ToS, _TabDef}, _WaitFor)  when N /= node() ->    {true, mandatory};prepare_op(_Tid, {op, delete_table, _TabDef}, _WaitFor) ->    {true, mandatory};prepare_op(_Tid, {op, dump_table, unknown, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    Tab = Cs#cstruct.name,    case lists:member(node(), Cs#cstruct.ram_copies) of        true ->	    case mnesia_monitor:use_dir() of		true -> 		    mnesia_log:ets2dcd(Tab, dmp),		    Size = mnesia:table_info(Tab, size),		    {true, [{op, dump_table, Size, TabDef}], optional};		false ->		    mnesia:abort({has_no_disc, node()})	    end;        false ->            {false, optional}    end;prepare_op(_Tid, {op, add_snmp, Ustruct, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    case mnesia_lib:cs_to_storage_type(node(), Cs) of        unknown ->            {true, optional};        Storage ->            Tab = Cs#cstruct.name,            Stab = mnesia_snmp_hook:create_table(Ustruct, Tab, Storage),            mnesia_lib:set({Tab, {index, snmp}}, Stab),            {true, optional}    end;prepare_op(_Tid, {op, transform, ignore, _TabDef}, _WaitFor) ->    {true, mandatory};   %% Apply schema changes only.prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) ->    Cs = list2cs(TabDef),    case mnesia_lib:cs_to_storage_type(node(), Cs) of        unknown ->            {true, mandatory};        Storage ->            Tab = Cs#cstruct.name,            RecName = Cs#cstruct.record_name,	    Type = Cs#cstruct.type,            NewArity = length(Cs#cstruct.attributes) + 1,	    mnesia_lib:db_fixtable(Storage, Tab, true),            Key = mnesia_lib:db_first(Tab),	    Op = {op, transform, Fun, TabDef},            case catch transform_objs(Fun, Tab, RecName, 				      Key, NewArity, Storage, Type, [Op]) of                {'EXIT', Reason} ->		    mnesia_lib:db_fixtable(Storage, Tab, false),                    exit({"Bad transform function", Tab, Fun, node(), Reason});                Objs ->		    mnesia_lib:db_fixtable(Storage, Tab, false),               

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?