aboutsummaryrefslogtreecommitdiffstats
path: root/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl')
-rw-r--r--lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl1092
1 files changed, 0 insertions, 1092 deletions
diff --git a/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl b/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl
deleted file mode 100644
index bbdb04589b..0000000000
--- a/lib/dialyzer/test/r9c_tests_SUITE_data/src/mnesia/mnesia_dumper.erl
+++ /dev/null
@@ -1,1092 +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_dumper.erl,v 1.1 2008/12/17 09:53:38 mikpe Exp $
-%%
--module(mnesia_dumper).
-
-%% The InitBy arg may be one of the following:
-%% scan_decisions Initial scan for decisions
-%% startup Initial dump during startup
-%% schema_prepare Dump initiated during schema transaction preparation
-%% schema_update Dump initiated during schema transaction commit
-%% fast_schema_update A schema_update, but ignores the log file
-%% user Dump initiated by user
-%% write_threshold Automatic dump caused by too many log writes
-%% time_threshold Automatic dump caused by timeout
-
-%% Public interface
--export([
- get_log_writes/0,
- incr_log_writes/0,
- raw_dump_table/2,
- raw_named_dump_table/2,
- start_regulator/0,
- opt_dump_log/1,
- update/3
- ]).
-
- %% Internal stuff
--export([regulator_init/1]).
-
--include("mnesia.hrl").
--include_lib("kernel/include/file.hrl").
-
--import(mnesia_lib, [fatal/2, dbg_out/2]).
-
--define(REGULATOR_NAME, mnesia_dumper_load_regulator).
--define(DumpToEtsMultiplier, 4).
-
--record(state, {initiated_by = nobody,
- dumper = nopid,
- regulator_pid,
- supervisor_pid,
- queue = [],
- timeout}).
-
-get_log_writes() ->
- Max = mnesia_monitor:get_env(dump_log_write_threshold),
- Prev = mnesia_lib:read_counter(trans_log_writes),
- Left = mnesia_lib:read_counter(trans_log_writes_left),
- Diff = Max - Left,
- Prev + Diff.
-
-incr_log_writes() ->
- Left = mnesia_lib:incr_counter(trans_log_writes_left, -1),
- if
- Left > 0 ->
- ignore;
- true ->
- adjust_log_writes(true)
- end.
-
-adjust_log_writes(DoCast) ->
- Token = {mnesia_adjust_log_writes, self()},
- case global:set_lock(Token, [node()], 1) of
- false ->
- ignore; %% Somebody else is sending a dump request
- true ->
- case DoCast of
- false ->
- ignore;
- true ->
- mnesia_controller:async_dump_log(write_threshold)
- end,
- Max = mnesia_monitor:get_env(dump_log_write_threshold),
- Left = mnesia_lib:read_counter(trans_log_writes_left),
- %% Don't care if we lost a few writes
- mnesia_lib:set_counter(trans_log_writes_left, Max),
- Diff = Max - Left,
- mnesia_lib:incr_counter(trans_log_writes, Diff),
- global:del_lock(Token, [node()])
- end.
-
-%% Returns 'ok' or exits
-opt_dump_log(InitBy) ->
- Reg = case whereis(?REGULATOR_NAME) of
- undefined ->
- nopid;
- Pid when pid(Pid) ->
- Pid
- end,
- perform_dump(InitBy, Reg).
-
-%% Scan for decisions
-perform_dump(InitBy, Regulator) when InitBy == scan_decisions ->
- ?eval_debug_fun({?MODULE, perform_dump}, [InitBy]),
-
- dbg_out("Transaction log dump initiated by ~w~n", [InitBy]),
- scan_decisions(mnesia_log:previous_log_file(), InitBy, Regulator),
- scan_decisions(mnesia_log:latest_log_file(), InitBy, Regulator);
-
-%% Propagate the log into the DAT-files
-perform_dump(InitBy, Regulator) ->
- ?eval_debug_fun({?MODULE, perform_dump}, [InitBy]),
- LogState = mnesia_log:prepare_log_dump(InitBy),
- dbg_out("Transaction log dump initiated by ~w: ~w~n",
- [InitBy, LogState]),
- adjust_log_writes(false),
- mnesia_recover:allow_garb(),
- case LogState of
- already_dumped ->
- dumped;
- {needs_dump, Diff} ->
- U = mnesia_monitor:get_env(dump_log_update_in_place),
- Cont = mnesia_log:init_log_dump(),
- case catch do_perform_dump(Cont, U, InitBy, Regulator, undefined) of
- ok ->
- ?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
- case mnesia_monitor:use_dir() of
- true ->
- mnesia_recover:dump_decision_tab();
- false ->
- mnesia_log:purge_some_logs()
- end,
- %% And now to the crucial point...
- mnesia_log:confirm_log_dump(Diff);
- {error, Reason} ->
- {error, Reason};
- {'EXIT', {Desc, Reason}} ->
- case mnesia_monitor:get_env(auto_repair) of
- true ->
- mnesia_lib:important(Desc, Reason),
- %% Ignore rest of the log
- mnesia_log:confirm_log_dump(Diff);
- false ->
- fatal(Desc, Reason)
- end
- end;
- {error, Reason} ->
- {error, {"Cannot prepare log dump", Reason}}
- end.
-
-scan_decisions(Fname, InitBy, Regulator) ->
- Exists = mnesia_lib:exists(Fname),
- case Exists of
- false ->
- ok;
- true ->
- Header = mnesia_log:trans_log_header(),
- Name = previous_log,
- mnesia_log:open_log(Name, Header, Fname, Exists,
- mnesia_monitor:get_env(auto_repair), read_only),
- Cont = start,
- Res = (catch do_perform_dump(Cont, false, InitBy, Regulator, undefined)),
- mnesia_log:close_log(Name),
- case Res of
- ok -> ok;
- {'EXIT', Reason} -> {error, Reason}
- end
- end.
-
-do_perform_dump(Cont, InPlace, InitBy, Regulator, OldVersion) ->
- case mnesia_log:chunk_log(Cont) of
- {C2, Recs} ->
- case catch insert_recs(Recs, InPlace, InitBy, Regulator, OldVersion) of
- {'EXIT', R} ->
- Reason = {"Transaction log dump error: ~p~n", [R]},
- close_files(InPlace, {error, Reason}, InitBy),
- exit(Reason);
- Version ->
- do_perform_dump(C2, InPlace, InitBy, Regulator, Version)
- end;
- eof ->
- close_files(InPlace, ok, InitBy),
- ok
- end.
-
-insert_recs([Rec | Recs], InPlace, InitBy, Regulator, LogV) ->
- regulate(Regulator),
- case insert_rec(Rec, InPlace, InitBy, LogV) of
- LogH when record(LogH, log_header) ->
- insert_recs(Recs, InPlace, InitBy, Regulator, LogH#log_header.log_version);
- _ ->
- insert_recs(Recs, InPlace, InitBy, Regulator, LogV)
- end;
-
-insert_recs([], _InPlace, _InitBy, _Regulator, Version) ->
- Version.
-
-insert_rec(Rec, _InPlace, scan_decisions, _LogV) ->
- if
- record(Rec, commit) ->
- ignore;
- record(Rec, log_header) ->
- ignore;
- true ->
- mnesia_recover:note_log_decision(Rec, scan_decisions)
- end;
-insert_rec(Rec, InPlace, InitBy, LogV) when record(Rec, commit) ->
- %% Determine the Outcome of the transaction and recover it
- D = Rec#commit.decision,
- case mnesia_recover:wait_for_decision(D, InitBy) of
- {Tid, committed} ->
- do_insert_rec(Tid, Rec, InPlace, InitBy, LogV);
- {Tid, aborted} ->
- mnesia_schema:undo_prepare_commit(Tid, Rec)
- end;
-insert_rec(H, _InPlace, _InitBy, _LogV) when record(H, log_header) ->
- CurrentVersion = mnesia_log:version(),
- if
- H#log_header.log_kind /= trans_log ->
- exit({"Bad kind of transaction log", H});
- H#log_header.log_version == CurrentVersion ->
- ok;
- H#log_header.log_version == "4.2" ->
- ok;
- H#log_header.log_version == "4.1" ->
- ok;
- H#log_header.log_version == "4.0" ->
- ok;
- true ->
- fatal("Bad version of transaction log: ~p~n", [H])
- end,
- H;
-
-insert_rec(_Rec, _InPlace, _InitBy, _LogV) ->
- ok.
-
-do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) ->
- case Rec#commit.schema_ops of
- [] ->
- ignore;
- SchemaOps ->
- case val({schema, storage_type}) of
- ram_copies ->
- insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy, LogV);
- Storage ->
- true = open_files(schema, Storage, InPlace, InitBy),
- insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy, LogV)
- end
- end,
- D = Rec#commit.disc_copies,
- insert_ops(Tid, disc_copies, D, InPlace, InitBy, LogV),
- case InitBy of
- startup ->
- DO = Rec#commit.disc_only_copies,
- insert_ops(Tid, disc_only_copies, DO, InPlace, InitBy, LogV);
- _ ->
- ignore
- end.
-
-
-update(_Tid, [], _DumperMode) ->
- dumped;
-update(Tid, SchemaOps, DumperMode) ->
- UseDir = mnesia_monitor:use_dir(),
- Res = perform_update(Tid, SchemaOps, DumperMode, UseDir),
- mnesia_controller:release_schema_commit_lock(),
- Res.
-
-perform_update(_Tid, _SchemaOps, mandatory, true) ->
- %% Force a dump of the transaction log in order to let the
- %% dumper perform needed updates
-
- InitBy = schema_update,
- ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]),
- opt_dump_log(InitBy);
-perform_update(Tid, SchemaOps, _DumperMode, _UseDir) ->
- %% No need for a full transaction log dump.
- %% Ignore the log file and perform only perform
- %% the corresponding updates.
-
- InitBy = fast_schema_update,
- InPlace = mnesia_monitor:get_env(dump_log_update_in_place),
- ?eval_debug_fun({?MODULE, dump_schema_op}, [InitBy]),
- case catch insert_ops(Tid, schema_ops, SchemaOps, InPlace, InitBy,
- mnesia_log:version()) of
- {'EXIT', Reason} ->
- Error = {error, {"Schema update error", Reason}},
- close_files(InPlace, Error, InitBy),
- fatal("Schema update error ~p ~p", [Reason, SchemaOps]);
- _ ->
- ?eval_debug_fun({?MODULE, post_dump}, [InitBy]),
- close_files(InPlace, ok, InitBy),
- ok
- end.
-
-insert_ops(_Tid, _Storage, [], _InPlace, _InitBy, _) -> ok;
-insert_ops(Tid, Storage, [Op], InPlace, InitBy, Ver) when Ver >= "4.3"->
- insert_op(Tid, Storage, Op, InPlace, InitBy),
- ok;
-insert_ops(Tid, Storage, [Op | Ops], InPlace, InitBy, Ver) when Ver >= "4.3"->
- insert_op(Tid, Storage, Op, InPlace, InitBy),
- insert_ops(Tid, Storage, Ops, InPlace, InitBy, Ver);
-insert_ops(Tid, Storage, [Op | Ops], InPlace, InitBy, Ver) when Ver < "4.3" ->
- insert_ops(Tid, Storage, Ops, InPlace, InitBy, Ver),
- insert_op(Tid, Storage, Op, InPlace, InitBy).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Normal ops
-
-disc_insert(_Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) ->
- case open_files(Tab, Storage, InPlace, InitBy) of
- true ->
- case Storage of
- disc_copies when Tab /= schema ->
- mnesia_log:append({?MODULE,Tab}, {{Tab, Key}, Val, Op}),
- ok;
- _ ->
- case Op of
- write ->
- ok = dets:insert(Tab, Val);
- delete ->
- ok = dets:delete(Tab, Key);
- update_counter ->
- {RecName, Incr} = Val,
- case catch dets:update_counter(Tab, Key, Incr) of
- CounterVal when integer(CounterVal) ->
- ok;
- _ ->
- Zero = {RecName, Key, 0},
- ok = dets:insert(Tab, Zero)
- end;
- delete_object ->
- ok = dets:delete_object(Tab, Val);
- clear_table ->
- ok = dets:match_delete(Tab, '_')
- end
- end;
- false ->
- ignore
- end.
-
-insert(Tid, Storage, Tab, Key, [Val | Tail], Op, InPlace, InitBy) ->
- insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy),
- insert(Tid, Storage, Tab, Key, Tail, Op, InPlace, InitBy);
-
-insert(_Tid, _Storage, _Tab, _Key, [], _Op, _InPlace, _InitBy) ->
- ok;
-
-insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy) ->
- Item = {{Tab, Key}, Val, Op},
- case InitBy of
- startup ->
- disc_insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy);
-
- _ when Storage == ram_copies ->
- mnesia_tm:do_update_op(Tid, Storage, Item),
- Snmp = mnesia_tm:prepare_snmp(Tab, Key, [Item]),
- mnesia_tm:do_snmp(Tid, Snmp);
-
- _ when Storage == disc_copies ->
- disc_insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy),
- mnesia_tm:do_update_op(Tid, Storage, Item),
- Snmp = mnesia_tm:prepare_snmp(Tab, Key, [Item]),
- mnesia_tm:do_snmp(Tid, Snmp);
-
- _ when Storage == disc_only_copies ->
- mnesia_tm:do_update_op(Tid, Storage, Item),
- Snmp = mnesia_tm:prepare_snmp(Tab, Key, [Item]),
- mnesia_tm:do_snmp(Tid, Snmp);
-
- _ when Storage == unknown ->
- ignore
- end.
-
-disc_delete_table(Tab, Storage) ->
- case mnesia_monitor:use_dir() of
- true ->
- if
- Storage == disc_only_copies; Tab == schema ->
- mnesia_monitor:unsafe_close_dets(Tab),
- Dat = mnesia_lib:tab2dat(Tab),
- file:delete(Dat);
- true ->
- DclFile = mnesia_lib:tab2dcl(Tab),
- case get({?MODULE,Tab}) of
- {opened_dumper, dcl} ->
- del_opened_tab(Tab),
- mnesia_log:unsafe_close_log(Tab);
- _ ->
- ok
- end,
- file:delete(DclFile),
- DcdFile = mnesia_lib:tab2dcd(Tab),
- file:delete(DcdFile),
- ok
- end,
- erase({?MODULE, Tab});
- false ->
- ignore
- end.
-
-disc_delete_indecies(_Tab, _Cs, Storage) when Storage /= disc_only_copies ->
- ignore;
-disc_delete_indecies(Tab, Cs, disc_only_copies) ->
- Indecies = Cs#cstruct.index,
- mnesia_index:del_transient(Tab, Indecies, disc_only_copies).
-
-insert_op(Tid, Storage, {{Tab, Key}, Val, Op}, InPlace, InitBy) ->
- %% Propagate to disc only
- disc_insert(Tid, Storage, Tab, Key, Val, Op, InPlace, InitBy);
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% NOTE that all operations below will only
-%% be performed if the dump is initiated by
-%% startup or fast_schema_update
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-insert_op(_Tid, schema_ops, _OP, _InPlace, Initby)
- when Initby /= startup,
- Initby /= fast_schema_update,
- Initby /= schema_update ->
- ignore;
-
-insert_op(Tid, _, {op, rec, Storage, Item}, InPlace, InitBy) ->
- {{Tab, Key}, ValList, Op} = Item,
- insert(Tid, Storage, Tab, Key, ValList, Op, InPlace, InitBy);
-
-insert_op(Tid, _, {op, change_table_copy_type, N, FromS, ToS, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Val = mnesia_schema:insert_cstruct(Tid, Cs, true), % Update ram only
- {schema, Tab, _} = Val,
- if
- InitBy /= startup ->
- mnesia_controller:add_active_replica(Tab, N, Cs);
- true ->
- ignore
- end,
- if
- N == node() ->
- Dmp = mnesia_lib:tab2dmp(Tab),
- Dat = mnesia_lib:tab2dat(Tab),
- Dcd = mnesia_lib:tab2dcd(Tab),
- Dcl = mnesia_lib:tab2dcl(Tab),
- case {FromS, ToS} of
- {ram_copies, disc_copies} when Tab == schema ->
- ok = ensure_rename(Dmp, Dat);
- {ram_copies, disc_copies} ->
- file:delete(Dcl),
- ok = ensure_rename(Dmp, Dcd);
- {disc_copies, ram_copies} when Tab == schema ->
- mnesia_lib:set(use_dir, false),
- mnesia_monitor:unsafe_close_dets(Tab),
- file:delete(Dat);
- {disc_copies, ram_copies} ->
- file:delete(Dcl),
- file:delete(Dcd);
- {ram_copies, disc_only_copies} ->
- ok = ensure_rename(Dmp, Dat),
- true = open_files(Tab, disc_only_copies, InPlace, InitBy),
- %% ram_delete_table must be done before init_indecies,
- %% it uses info which is reset in init_indecies,
- %% it doesn't matter, because init_indecies don't use
- %% the ram replica of the table when creating the disc
- %% index; Could be improved :)
- mnesia_schema:ram_delete_table(Tab, FromS),
- PosList = Cs#cstruct.index,
- mnesia_index:init_indecies(Tab, disc_only_copies, PosList);
- {disc_only_copies, ram_copies} ->
- mnesia_monitor:unsafe_close_dets(Tab),
- disc_delete_indecies(Tab, Cs, disc_only_copies),
- case InitBy of
- startup ->
- ignore;
- _ ->
- mnesia_controller:get_disc_copy(Tab)
- end,
- disc_delete_table(Tab, disc_only_copies);
- {disc_copies, disc_only_copies} ->
- ok = ensure_rename(Dmp, Dat),
- true = open_files(Tab, disc_only_copies, InPlace, InitBy),
- mnesia_schema:ram_delete_table(Tab, FromS),
- PosList = Cs#cstruct.index,
- mnesia_index:init_indecies(Tab, disc_only_copies, PosList),
- file:delete(Dcl),
- file:delete(Dcd);
- {disc_only_copies, disc_copies} ->
- mnesia_monitor:unsafe_close_dets(Tab),
- disc_delete_indecies(Tab, Cs, disc_only_copies),
- case InitBy of
- startup ->
- ignore;
- _ ->
- mnesia_log:ets2dcd(Tab),
- mnesia_controller:get_disc_copy(Tab),
- disc_delete_table(Tab, disc_only_copies)
- end
- end;
- true ->
- ignore
- end,
- S = val({schema, storage_type}),
- disc_insert(Tid, S, schema, Tab, Val, write, InPlace, InitBy);
-
-insert_op(Tid, _, {op, transform, _Fun, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- case mnesia_lib:cs_to_storage_type(node(), Cs) of
- disc_copies ->
- open_dcl(Cs#cstruct.name);
- _ ->
- ignore
- end,
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-%%% Operations below this are handled without using the logg.
-
-insert_op(Tid, _, {op, restore_recreate, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- Type = Cs#cstruct.type,
- Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
- %% Delete all possbibly existing files and tables
- disc_delete_table(Tab, Storage),
- disc_delete_indecies(Tab, Cs, Storage),
- case InitBy of
- startup ->
- ignore;
- _ ->
- mnesia_schema:ram_delete_table(Tab, Storage),
- mnesia_checkpoint:tm_del_copy(Tab, node())
- end,
- %% delete_cstruct(Tid, Cs, InPlace, InitBy),
- %% And create new ones..
- if
- (InitBy == startup) or (Storage == unknown) ->
- ignore;
- Storage == ram_copies ->
- Args = [{keypos, 2}, public, named_table, Type],
- mnesia_monitor:mktab(Tab, Args);
- Storage == disc_copies ->
- Args = [{keypos, 2}, public, named_table, Type],
- mnesia_monitor:mktab(Tab, Args),
- File = mnesia_lib:tab2dcd(Tab),
- FArg = [{file, File}, {name, {mnesia,create}},
- {repair, false}, {mode, read_write}],
- {ok, Log} = mnesia_monitor:open_log(FArg),
- mnesia_monitor:unsafe_close_log(Log);
- Storage == disc_only_copies ->
- File = mnesia_lib:tab2dat(Tab),
- file:delete(File),
- Args = [{file, mnesia_lib:tab2dat(Tab)},
- {type, mnesia_lib:disk_type(Tab, Type)},
- {keypos, 2},
- {repair, mnesia_monitor:get_env(auto_repair)}],
- mnesia_monitor:open_dets(Tab, Args)
- end,
- insert_op(Tid, ignore, {op, create_table, TabDef}, InPlace, InitBy);
-
-insert_op(Tid, _, {op, create_table, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, false, InPlace, InitBy),
- Tab = Cs#cstruct.name,
- Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
- case InitBy of
- startup ->
- case Storage of
- unknown ->
- ignore;
- ram_copies ->
- ignore;
- disc_copies ->
- Dcd = mnesia_lib:tab2dcd(Tab),
- case mnesia_lib:exists(Dcd) of
- true -> ignore;
- false ->
- mnesia_log:open_log(temp,
- mnesia_log:dcl_log_header(),
- Dcd,
- false,
- false,
- read_write),
- mnesia_log:unsafe_close_log(temp)
- end;
- _ ->
- Args = [{file, mnesia_lib:tab2dat(Tab)},
- {type, mnesia_lib:disk_type(Tab, Cs#cstruct.type)},
- {keypos, 2},
- {repair, mnesia_monitor:get_env(auto_repair)}],
- case mnesia_monitor:open_dets(Tab, Args) of
- {ok, _} ->
- mnesia_monitor:unsafe_close_dets(Tab);
- {error, Error} ->
- exit({"Failed to create dets table", Error})
- end
- end;
- _ ->
- Copies = mnesia_lib:copy_holders(Cs),
- Active = mnesia_lib:intersect(Copies, val({current, db_nodes})),
- [mnesia_controller:add_active_replica(Tab, N, Cs) || N <- Active],
-
- case Storage of
- unknown ->
- case Cs#cstruct.local_content of
- true ->
- ignore;
- false ->
- mnesia_lib:set_remote_where_to_read(Tab)
- end;
- _ ->
- case Cs#cstruct.local_content of
- true ->
- mnesia_lib:set_local_content_whereabouts(Tab);
- false ->
- mnesia_lib:set({Tab, where_to_read}, node())
- end,
- case Storage of
- ram_copies ->
- ignore;
- _ ->
- %% Indecies are still created by loader
- disc_delete_indecies(Tab, Cs, Storage)
- %% disc_delete_table(Tab, Storage)
- end,
-
- %% Update whereabouts and create table
- mnesia_controller:create_table(Tab)
- end
- end;
-
-insert_op(_Tid, _, {op, dump_table, Size, TabDef}, _InPlace, _InitBy) ->
- case Size of
- unknown ->
- ignore;
- _ ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- Dmp = mnesia_lib:tab2dmp(Tab),
- Dat = mnesia_lib:tab2dcd(Tab),
- case Size of
- 0 ->
- %% Assume that table files already are closed
- file:delete(Dmp),
- file:delete(Dat);
- _ ->
- ok = ensure_rename(Dmp, Dat)
- end
- end;
-
-insert_op(Tid, _, {op, delete_table, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- case mnesia_lib:cs_to_storage_type(node(), Cs) of
- unknown ->
- ignore;
- Storage ->
- disc_delete_table(Tab, Storage),
- disc_delete_indecies(Tab, Cs, Storage),
- case InitBy of
- startup ->
- ignore;
- _ ->
- mnesia_schema:ram_delete_table(Tab, Storage),
- mnesia_checkpoint:tm_del_copy(Tab, node())
- end
- end,
- delete_cstruct(Tid, Cs, InPlace, InitBy);
-
-insert_op(Tid, _, {op, clear_table, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- case mnesia_lib:cs_to_storage_type(node(), Cs) of
- unknown ->
- ignore;
- Storage ->
- Oid = '_', %%val({Tab, wild_pattern}),
- if Storage == disc_copies ->
- open_dcl(Cs#cstruct.name);
- true ->
- ignore
- end,
- insert(Tid, Storage, Tab, '_', Oid, clear_table, InPlace, InitBy)
- end;
-
-insert_op(Tid, _, {op, merge_schema, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, false, InPlace, InitBy);
-
-insert_op(Tid, _, {op, del_table_copy, Storage, Node, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- if
- Tab == schema, Storage == ram_copies ->
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
- Tab /= schema ->
- mnesia_controller:del_active_replica(Tab, Node),
- mnesia_lib:del({Tab, Storage}, Node),
- if
- Node == node() ->
- case Cs#cstruct.local_content of
- true -> mnesia_lib:set({Tab, where_to_read}, nowhere);
- false -> mnesia_lib:set_remote_where_to_read(Tab)
- end,
- mnesia_lib:del({schema, local_tables}, Tab),
- mnesia_lib:set({Tab, storage_type}, unknown),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy),
- disc_delete_table(Tab, Storage),
- disc_delete_indecies(Tab, Cs, Storage),
- mnesia_schema:ram_delete_table(Tab, Storage),
- mnesia_checkpoint:tm_del_copy(Tab, Node);
- true ->
- case val({Tab, where_to_read}) of
- Node ->
- mnesia_lib:set_remote_where_to_read(Tab);
- _ ->
- ignore
- end,
- insert_cstruct(Tid, Cs, true, InPlace, InitBy)
- end
- end;
-
-insert_op(Tid, _, {op, add_table_copy, _Storage, _Node, TabDef}, InPlace, InitBy) ->
- %% During prepare commit, the files was created
- %% and the replica was announced
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, add_snmp, _Us, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, del_snmp, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
- if
- InitBy /= startup,
- Storage /= unknown ->
- case ?catch_val({Tab, {index, snmp}}) of
- {'EXIT', _} ->
- ignore;
- Stab ->
- mnesia_snmp_hook:delete_table(Tab, Stab),
- mnesia_lib:unset({Tab, {index, snmp}})
- end;
- true ->
- ignore
- end,
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, add_index, Pos, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = insert_cstruct(Tid, Cs, true, InPlace, InitBy),
- Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
- case InitBy of
- startup when Storage == disc_only_copies ->
- mnesia_index:init_indecies(Tab, Storage, [Pos]);
- startup ->
- ignore;
- _ ->
- mnesia_index:init_indecies(Tab, Storage, [Pos])
- end;
-
-insert_op(Tid, _, {op, del_index, Pos, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- Storage = mnesia_lib:cs_to_storage_type(node(), Cs),
- case InitBy of
- startup when Storage == disc_only_copies ->
- mnesia_index:del_index_table(Tab, Storage, Pos);
- startup ->
- ignore;
- _ ->
- mnesia_index:del_index_table(Tab, Storage, Pos)
- end,
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, change_table_access_mode,TabDef, _OldAccess, _Access}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- case InitBy of
- startup -> ignore;
- _ -> mnesia_controller:change_table_access_mode(Cs)
- end,
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, change_table_load_order, TabDef, _OldLevel, _Level}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, delete_property, TabDef, PropKey}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- Tab = Cs#cstruct.name,
- mnesia_lib:unset({Tab, user_property, PropKey}),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, write_property, TabDef, _Prop}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy);
-
-insert_op(Tid, _, {op, change_table_frag, _Change, TabDef}, InPlace, InitBy) ->
- Cs = mnesia_schema:list2cs(TabDef),
- insert_cstruct(Tid, Cs, true, InPlace, InitBy).
-
-open_files(Tab, Storage, UpdateInPlace, InitBy)
- when Storage /= unknown, Storage /= ram_copies ->
- case get({?MODULE, Tab}) of
- undefined ->
- case ?catch_val({Tab, setorbag}) of
- {'EXIT', _} ->
- false;
- Type ->
- case Storage of
- disc_copies when Tab /= schema ->
- Bool = open_disc_copies(Tab, InitBy),
- Bool;
- _ ->
- Fname = prepare_open(Tab, UpdateInPlace),
- Args = [{file, Fname},
- {keypos, 2},
- {repair, mnesia_monitor:get_env(auto_repair)},
- {type, mnesia_lib:disk_type(Tab, Type)}],
- {ok, _} = mnesia_monitor:open_dets(Tab, Args),
- put({?MODULE, Tab}, {opened_dumper, dat}),
- true
- end
- end;
- already_dumped ->
- false;
- {opened_dumper, _} ->
- true
- end;
-open_files(_Tab, _Storage, _UpdateInPlace, _InitBy) ->
- false.
-
-open_disc_copies(Tab, InitBy) ->
- DclF = mnesia_lib:tab2dcl(Tab),
- DumpEts =
- case file:read_file_info(DclF) of
- {error, enoent} ->
- false;
- {ok, DclInfo} ->
- DcdF = mnesia_lib:tab2dcd(Tab),
- case file:read_file_info(DcdF) of
- {error, Reason} ->
- mnesia_lib:dbg_out("File ~p info_error ~p ~n",
- [DcdF, Reason]),
- true;
- {ok, DcdInfo} ->
- DcdInfo#file_info.size =<
- (DclInfo#file_info.size *
- ?DumpToEtsMultiplier)
- end
- end,
- if
- DumpEts == false; InitBy == startup ->
- mnesia_log:open_log({?MODULE,Tab},
- mnesia_log:dcl_log_header(),
- DclF,
- mnesia_lib:exists(DclF),
- mnesia_monitor:get_env(auto_repair),
- read_write),
- put({?MODULE, Tab}, {opened_dumper, dcl}),
- true;
- true ->
- mnesia_log:ets2dcd(Tab),
- put({?MODULE, Tab}, already_dumped),
- false
- end.
-
-%% Always opens the dcl file for writing overriding already_dumped
-%% mechanismen, used for schema transactions.
-open_dcl(Tab) ->
- case get({?MODULE, Tab}) of
- {opened_dumper, _} ->
- true;
- _ -> %% undefined or already_dumped
- DclF = mnesia_lib:tab2dcl(Tab),
- mnesia_log:open_log({?MODULE,Tab},
- mnesia_log:dcl_log_header(),
- DclF,
- mnesia_lib:exists(DclF),
- mnesia_monitor:get_env(auto_repair),
- read_write),
- put({?MODULE, Tab}, {opened_dumper, dcl}),
- true
- end.
-
-prepare_open(Tab, UpdateInPlace) ->
- Dat = mnesia_lib:tab2dat(Tab),
- case UpdateInPlace of
- true ->
- Dat;
- false ->
- Tmp = mnesia_lib:tab2tmp(Tab),
- case catch mnesia_lib:copy_file(Dat, Tmp) of
- ok ->
- Tmp;
- Error ->
- fatal("Cannot copy dets file ~p to ~p: ~p~n",
- [Dat, Tmp, Error])
- end
- end.
-
-del_opened_tab(Tab) ->
- erase({?MODULE, Tab}).
-
-close_files(UpdateInPlace, Outcome, InitBy) -> % Update in place
- close_files(UpdateInPlace, Outcome, InitBy, get()).
-
-close_files(InPlace, Outcome, InitBy, [{{?MODULE, Tab}, already_dumped} | Tail]) ->
- erase({?MODULE, Tab}),
- close_files(InPlace, Outcome, InitBy, Tail);
-close_files(InPlace, Outcome, InitBy, [{{?MODULE, Tab}, {opened_dumper, Type}} | Tail]) ->
- erase({?MODULE, Tab}),
- case val({Tab, storage_type}) of
- disc_only_copies when InitBy /= startup ->
- ignore;
- disc_copies when Tab /= schema ->
- mnesia_log:close_log({?MODULE,Tab});
- Storage ->
- do_close(InPlace, Outcome, Tab, Type, Storage)
- end,
- close_files(InPlace, Outcome, InitBy, Tail);
-
-close_files(InPlace, Outcome, InitBy, [_ | Tail]) ->
- close_files(InPlace, Outcome, InitBy, Tail);
-close_files(_, _, _InitBy, []) ->
- ok.
-
-%% If storage is unknown during close clean up files, this can happen if timing
-%% is right and dirty_write conflicts with schema operations.
-do_close(_, _, Tab, dcl, unknown) ->
- mnesia_log:close_log({?MODULE,Tab}),
- file:delete(mnesia_lib:tab2dcl(Tab));
-do_close(_, _, Tab, dcl, _) -> %% To be safe, can it happen?
- mnesia_log:close_log({?MODULE,Tab});
-
-do_close(InPlace, Outcome, Tab, dat, Storage) ->
- mnesia_monitor:close_dets(Tab),
- if
- Storage == unknown, InPlace == true ->
- file:delete(mnesia_lib:tab2dat(Tab));
- InPlace == true ->
- %% Update in place
- ok;
- Outcome == ok, Storage /= unknown ->
- %% Success: swap tmp files with dat files
- TabDat = mnesia_lib:tab2dat(Tab),
- ok = file:rename(mnesia_lib:tab2tmp(Tab), TabDat);
- true ->
- file:delete(mnesia_lib:tab2tmp(Tab))
- end.
-
-
-ensure_rename(From, To) ->
- case mnesia_lib:exists(From) of
- true ->
- file:rename(From, To);
- false ->
- case mnesia_lib:exists(To) of
- true ->
- ok;
- false ->
- {error, {rename_failed, From, To}}
- end
- end.
-
-insert_cstruct(Tid, Cs, KeepWhereabouts, InPlace, InitBy) ->
- Val = mnesia_schema:insert_cstruct(Tid, Cs, KeepWhereabouts),
- {schema, Tab, _} = Val,
- S = val({schema, storage_type}),
- disc_insert(Tid, S, schema, Tab, Val, write, InPlace, InitBy),
- Tab.
-
-delete_cstruct(Tid, Cs, InPlace, InitBy) ->
- Val = mnesia_schema:delete_cstruct(Tid, Cs),
- {schema, Tab, _} = Val,
- S = val({schema, storage_type}),
- disc_insert(Tid, S, schema, Tab, Val, delete, InPlace, InitBy),
- Tab.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Raw dump of table. Dumper must have unique access to the ets table.
-
-raw_named_dump_table(Tab, Ftype) ->
- case mnesia_monitor:use_dir() of
- true ->
- mnesia_lib:lock_table(Tab),
- TmpFname = mnesia_lib:tab2tmp(Tab),
- Fname =
- case Ftype of
- dat -> mnesia_lib:tab2dat(Tab);
- dmp -> mnesia_lib:tab2dmp(Tab)
- end,
- file:delete(TmpFname),
- file:delete(Fname),
- TabSize = ?ets_info(Tab, size),
- TabRef = Tab,
- DiskType = mnesia_lib:disk_type(Tab),
- Args = [{file, TmpFname},
- {keypos, 2},
- %% {ram_file, true},
- {estimated_no_objects, TabSize + 256},
- {repair, mnesia_monitor:get_env(auto_repair)},
- {type, DiskType}],
- case mnesia_lib:dets_sync_open(TabRef, Args) of
- {ok, TabRef} ->
- Storage = ram_copies,
- mnesia_lib:db_fixtable(Storage, Tab, true),
-
- case catch raw_dump_table(TabRef, Tab) of
- {'EXIT', Reason} ->
- mnesia_lib:db_fixtable(Storage, Tab, false),
- mnesia_lib:dets_sync_close(Tab),
- file:delete(TmpFname),
- mnesia_lib:unlock_table(Tab),
- exit({"Dump of table to disc failed", Reason});
- ok ->
- mnesia_lib:db_fixtable(Storage, Tab, false),
- mnesia_lib:dets_sync_close(Tab),
- mnesia_lib:unlock_table(Tab),
- ok = file:rename(TmpFname, Fname)
- end;
- {error, Reason} ->
- mnesia_lib:unlock_table(Tab),
- exit({"Open of file before dump to disc failed", Reason})
- end;
- false ->
- exit({has_no_disc, node()})
- end.
-
-raw_dump_table(DetsRef, EtsRef) ->
- dets:from_ets(DetsRef, EtsRef).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Load regulator
-%%
-%% This is a poor mans substitute for a fair scheduler algorithm
-%% in the Erlang emulator. The mnesia_dumper process performs many
-%% costly BIF invokations and must pay for this. But since the
-%% Emulator does not handle this properly we must compensate for
-%% this with some form of load regulation of ourselves in order to
-%% not steal all computation power in the Erlang Emulator ans make
-%% other processes starve. Hopefully this is a temporary solution.
-
-start_regulator() ->
- case mnesia_monitor:get_env(dump_log_load_regulation) of
- false ->
- nopid;
- true ->
- N = ?REGULATOR_NAME,
- case mnesia_monitor:start_proc(N, ?MODULE, regulator_init, [self()]) of
- {ok, Pid} ->
- Pid;
- {error, Reason} ->
- fatal("Failed to start ~n: ~p~n", [N, Reason])
- end
- end.
-
-regulator_init(Parent) ->
- %% No need for trapping exits.
- %% Using low priority causes the regulation
- process_flag(priority, low),
- register(?REGULATOR_NAME, self()),
- proc_lib:init_ack(Parent, {ok, self()}),
- regulator_loop().
-
-regulator_loop() ->
- receive
- {regulate, From} ->
- From ! {regulated, self()},
- regulator_loop();
- {stop, From} ->
- From ! {stopped, self()},
- exit(normal)
- end.
-
-regulate(nopid) ->
- ok;
-regulate(RegulatorPid) ->
- RegulatorPid ! {regulate, self()},
- receive
- {regulated, RegulatorPid} -> ok
- end.
-
-val(Var) ->
- case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
- Value -> Value
- end.