aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia')
-rw-r--r--lib/mnesia/doc/src/notes.xml34
-rw-r--r--lib/mnesia/examples/bench/bench_generate.erl40
-rw-r--r--lib/mnesia/examples/mnesia_tpcb.erl39
-rw-r--r--lib/mnesia/src/mnesia_bup.erl14
-rw-r--r--lib/mnesia/src/mnesia_index.erl27
-rw-r--r--lib/mnesia/src/mnesia_lib.erl15
-rw-r--r--lib/mnesia/test/mnesia_atomicity_test.erl4
-rw-r--r--lib/mnesia/test/mnesia_config_test.erl4
-rw-r--r--lib/mnesia/test/mnesia_consistency_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_cost.erl10
-rw-r--r--lib/mnesia/test/mnesia_dbn_meters.erl55
-rw-r--r--lib/mnesia/test/mnesia_dirty_access_test.erl19
-rw-r--r--lib/mnesia/test/mnesia_evil_backup.erl12
-rw-r--r--lib/mnesia/test/mnesia_isolation_test.erl4
-rw-r--r--lib/mnesia/test/mnesia_test_lib.erl4
-rw-r--r--lib/mnesia/test/mnesia_tpcb.erl71
-rw-r--r--lib/mnesia/vsn.mk2
17 files changed, 211 insertions, 145 deletions
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index c4f937f183..8650e03a60 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -39,7 +39,39 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.13</title>
+ <section><title>Mnesia 4.13.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a process and file descriptor leak in
+ mnesia:restore/2.</p>
+ <p>
+ Own Id: OTP-13025 Aux Id: seq12957 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.13.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved index updates to avoid a timing glitch in
+ dirty_index_read.</p>
+ <p>
+ Own Id: OTP-12972</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/examples/bench/bench_generate.erl b/lib/mnesia/examples/bench/bench_generate.erl
index 7a701812a7..e838f07fbb 100644
--- a/lib/mnesia/examples/bench/bench_generate.erl
+++ b/lib/mnesia/examples/bench/bench_generate.erl
@@ -153,9 +153,7 @@ generator_init(Monitor, C) ->
process_flag(trap_exit, true),
Tables = mnesia:system_info(tables),
ok = mnesia:wait_for_tables(Tables, infinity),
- {_Mega, Sec, Micro} = erlang:now(),
- Uniq = lists:sum(binary_to_list(term_to_binary(make_ref()))),
- random:seed(Uniq, Sec, Micro),
+ rand:seed(exsplus),
Counters = reset_counters(C, C#config.statistics_detail),
SessionTab = ets:new(bench_sessions, [public, {keypos, 1}]),
generator_loop(Monitor, C, SessionTab, Counters).
@@ -189,9 +187,9 @@ generator_loop(Monitor, C, SessionTab, Counters) ->
after 0 ->
{Name, {Nodes, Activity, Wlock}, Fun, CommitSessions} =
gen_trans(C, SessionTab),
- Before = erlang:now(),
+ Before = erlang:monotonic_time(),
Res = call_worker(Nodes, Activity, Fun, Wlock, mnesia_frag),
- After = erlang:now(),
+ After = erlang:monotonic_time(),
Elapsed = elapsed(Before, After),
post_eval(Monitor, C, Elapsed, Res, Name, CommitSessions, SessionTab, Counters)
end.
@@ -253,10 +251,8 @@ worker_loop(Parent) ->
end.
-elapsed({Before1, Before2, Before3}, {After1, After2, After3}) ->
- After = After1 * 1000000000000 + After2 * 1000000 + After3,
- Before = Before1 * 1000000000000 + Before2 * 1000000 + Before3,
- After - Before.
+elapsed(Before, After) ->
+ erlang:convert_time_unit(After-Before, native, micro_seconds).
%% Lookup counters
get_counters(_C, {table, Tab}) ->
@@ -351,7 +347,7 @@ commit_session(Fun) when is_function(Fun, 0) ->
%% Randlomly choose a transaction type according to benchmar spec
gen_trans(C, SessionTab) when C#config.generator_profile == random ->
- case random:uniform(100) of
+ case rand:uniform(100) of
Rand when Rand > 0, Rand =< 25 -> gen_t1(C, SessionTab);
Rand when Rand > 25, Rand =< 50 -> gen_t2(C, SessionTab);
Rand when Rand > 50, Rand =< 70 -> gen_t3(C, SessionTab);
@@ -369,7 +365,7 @@ gen_trans(C, SessionTab) ->
end.
gen_t1(C, _SessionTab) ->
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
SubscrKey = bench_trans:number_to_key(SubscrId, C),
Location = 4711,
ChangedBy = <<4711:(8*25)>>,
@@ -381,7 +377,7 @@ gen_t1(C, _SessionTab) ->
}.
gen_t2(C, _SessionTab) ->
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
SubscrKey = bench_trans:number_to_key(SubscrId, C),
{t2,
nearest_node(SubscrId, sync_dirty, C),
@@ -395,9 +391,9 @@ gen_t3(C, SessionTab) ->
'$end_of_table' ->
%% This generator does not have any session,
%% try reading someone elses session details
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
SubscrKey = bench_trans:number_to_key(SubscrId, C),
- ServerId = random:uniform(C#config.n_servers) - 1,
+ ServerId = rand:uniform(C#config.n_servers) - 1,
ServerBit = 1 bsl ServerId,
{t3,
nearest_node(SubscrId, transaction, C),
@@ -419,12 +415,12 @@ gen_t4(C, SessionTab) ->
%% This generator may already have sessions,
%% create a new session and hope that no other
%% generator already has occupied it
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
SubscrKey = bench_trans:number_to_key(SubscrId, C),
- ServerId = random:uniform(C#config.n_servers) - 1,
+ ServerId = rand:uniform(C#config.n_servers) - 1,
ServerBit = 1 bsl ServerId,
Details = <<4711:(8*2000)>>,
- DoRollback = (random:uniform(100) =< 2),
+ DoRollback = (rand:uniform(100) =< 2),
Insert = fun() -> ets:insert(SessionTab, {{SubscrId, SubscrKey, ServerId}, self()}) end,
{t4,
nearest_node(SubscrId, transaction, C),
@@ -437,11 +433,11 @@ gen_t5(C, SessionTab) ->
'$end_of_table' ->
%% This generator does not have any session,
%% try to delete someone elses session details
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
SubscrKey = bench_trans:number_to_key(SubscrId, C),
- ServerId = random:uniform(C#config.n_servers) - 1,
+ ServerId = rand:uniform(C#config.n_servers) - 1,
ServerBit = 1 bsl ServerId,
- DoRollback = (random:uniform(100) =< 2),
+ DoRollback = (rand:uniform(100) =< 2),
{t5,
nearest_node(SubscrId, transaction, C),
fun(Wlock) -> bench_trans:delete_session_from_server(Wlock, SubscrKey, ServerBit, ServerId, DoRollback) end,
@@ -451,7 +447,7 @@ gen_t5(C, SessionTab) ->
%% This generator do have at least one session,
%% delete it.
ServerBit = 1 bsl ServerId,
- DoRollback = (random:uniform(100) =< 2),
+ DoRollback = (rand:uniform(100) =< 2),
Delete = fun() -> ets:delete(SessionTab, {SubscrId, SubscrKey, ServerId}) end,
{t5,
nearest_node(SubscrId, transaction, C),
@@ -461,7 +457,7 @@ gen_t5(C, SessionTab) ->
end.
gen_ping(C, _SessionTab) ->
- SubscrId = random:uniform(C#config.n_subscribers) - 1,
+ SubscrId = rand:uniform(C#config.n_subscribers) - 1,
{ping,
nearest_node(SubscrId, transaction, C),
fun(_Wlock) -> {do_commit, true, []} end,
diff --git a/lib/mnesia/examples/mnesia_tpcb.erl b/lib/mnesia/examples/mnesia_tpcb.erl
index fde6cf402e..c6eda1c448 100644
--- a/lib/mnesia/examples/mnesia_tpcb.erl
+++ b/lib/mnesia/examples/mnesia_tpcb.erl
@@ -164,7 +164,7 @@
-record(history,
{
history_id = {0, 0}, % {DriverId, DriverLocalHistoryid}
- time_stamp = now(), % Time point during active transaction
+ time_stamp = erlang:system_time(), % Time point during active transaction
branch_id = 0, % Branch associated with teller
teller_id = 0, % Teller invlolved in transaction
account_id = 0, % Account updated by transaction
@@ -412,9 +412,8 @@ config(remote_frag2_test, ReplicaType) ->
config(conflict_benchmark, ReplicaType) ->
Remote = nodes(),
Local = node(),
- Nodes = [Local | Remote],
- [{seed, {1326,448637,337711}},
- {db_nodes, Nodes},
+ Nodes = [Local | Remote],
+ [{db_nodes, Nodes},
{driver_nodes, Nodes},
{replica_nodes, Nodes},
{n_drivers_per_node, 10},
@@ -758,7 +757,7 @@ reporter_init(Starter, RC) ->
replica_type = Type
},
Drivers = start_drivers(RC, TC),
- Now = now_to_micros(erlang:now()),
+ Now = erlang:monotonic_time(),
State = #reporter_state{driver_pids = Drivers,
run_config = RC,
starter_pid = Starter,
@@ -896,7 +895,7 @@ add_time(Acc, New) ->
-define(AVOID_DIV_ZERO(_What_), try (_What_) catch _:_ -> 0 end).
show_report(State) ->
- Now = now_to_micros(erlang:now()),
+ Now = erlang:timestamp(),
Iters = State#reporter_state.n_iters,
Cfg = State#reporter_state.run_config,
Time = State#reporter_state.curr,
@@ -924,14 +923,14 @@ show_report(State) ->
case Cfg#run_config.send_bench_report of
true ->
ct_event:notify(
- #event{name = benchmark_data,
+ #event{name = benchmark_data,
data = [{suite,"mnesia_tpcb"},
{value,Tps}]});
_ ->
ok
end,
- State#reporter_state{prev_tps = Tps, prev_micros = Now}.
+ State#reporter_state{prev_tps = Tps, prev_micros = Now}.
signed_diff(Iters, Curr, Prev) ->
case Iters > 1 of
@@ -941,11 +940,6 @@ signed_diff(Iters, Curr, Prev) ->
sign(N) when N > 0 -> {"+", N};
sign(N) -> {"", N}.
-
-now_to_micros({Mega, Secs, Micros}) ->
- DT = calendar:now_to_datetime({Mega, Secs, 0}),
- S = calendar:datetime_to_gregorian_seconds(DT),
- (S * ?SECOND) + Micros.
start_drivers(RC, TC) ->
LastHistoryId = table_info(history, size),
@@ -998,13 +992,11 @@ alloc_local_branches([], Specs, OrphanBranches) ->
{Specs, OrphanBranches}.
driver_init(DS, AllBranches) ->
- case (DS#driver_state.run_config)#run_config.seed of
- undefined ->
- Seed = erlang:now();
- Seed ->
- Seed
+ Seed = case (DS#driver_state.run_config)#run_config.seed of
+ undefined -> rand:seed(exsplus);
+ ExpSeed -> rand:seed(ExpSeed)
end,
-
+
DS2 =
if
DS#driver_state.n_local_branches =:= 0 ->
@@ -1058,14 +1050,7 @@ calc_trans(DS) ->
%% Generate teller_id, account_id and delta
%% Time the TPC-B transaction
time_trans(DS) ->
- OldSeed = get(random_seed), % Avoid interference with Mnesia
- put(random_seed, DS#driver_state.seed),
- Random = random:uniform(),
- NewSeed = get(random_seed),
- case OldSeed of
- undefined -> erase(random_seed);
- _ -> put(random_seed, OldSeed)
- end,
+ {Random, NewSeed} = rand:uniform_s(DS#driver_state.seed),
TC = DS#driver_state.tab_config,
RC = DS#driver_state.run_config,
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 0e653f2bc4..1f150ae38b 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -157,10 +157,11 @@ fallback_to_schema(Fname) ->
read_schema(Mod, Opaque) ->
R = #restore{bup_module = Mod, bup_data = Opaque},
try read_schema_section(R) of
- {_, {_Header, Schema, _}} -> Schema
+ {R2, {_Header, Schema, _}} ->
+ close_read(R2),
+ Schema
catch throw:{error,_} = Error ->
Error
- after close_read(R)
end.
%% Open backup media and extract schema
@@ -173,8 +174,13 @@ read_schema_section(R) ->
do_read_schema_section(R) ->
R2 = safe_apply(R, open_read, [R#restore.bup_data]),
- {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]),
- do_read_schema_section(R3, verify_header(RawSchema), []).
+ try
+ {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]),
+ do_read_schema_section(R3, verify_header(RawSchema), [])
+ catch T:E ->
+ close_read(R2),
+ erlang:raise(T,E,erlang:get_stacktrace())
+ end.
do_read_schema_section(R, {ok, B, C, []}, Acc) ->
case safe_apply(R, read, [R#restore.bup_data]) of
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 81ed5a8f1a..0c882c0df6 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -70,17 +70,24 @@ add_index(Index, Tab, Key, Obj, Old) ->
add_index2([{Pos, Ixt} |Tail], bag, Tab, K, Obj, OldRecs) ->
db_put(Ixt, {element(Pos, Obj), K}),
add_index2(Tail, bag, Tab, K, Obj, OldRecs);
-add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs) ->
+add_index2([{Pos, Ixt} |Tail], Type, Tab, K, Obj, OldRecs0) ->
%% Remove old tuples in index if Tab is updated
- case OldRecs of
- undefined ->
- Old = mnesia_lib:db_get(Tab, K),
- del_ixes(Ixt, Old, Pos, K);
- Old ->
- del_ixes(Ixt, Old, Pos, K)
- end,
- db_put(Ixt, {element(Pos, Obj), K}),
- add_index2(Tail, Type, Tab, K, Obj, OldRecs);
+ OldRecs1 = case OldRecs0 of
+ undefined -> mnesia_lib:db_get(Tab, K);
+ _ -> OldRecs0
+ end,
+ IdxVal = element(Pos, Obj),
+ case [Old || Old <- OldRecs1, element(Pos, Old) =/= IdxVal] of
+ [] when OldRecs1 =:= [] -> %% Write
+ db_put(Ixt, {element(Pos, Obj), K}),
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ [] -> %% when OldRecs1 =/= [] Update without modifying index field
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0);
+ OldRecs -> %% Update
+ db_put(Ixt, {element(Pos, Obj), K}),
+ del_ixes(Ixt, OldRecs, Pos, K),
+ add_index2(Tail, Type, Tab, K, Obj, OldRecs0)
+ end;
add_index2([], _, _Tab, _K, _Obj, _) -> ok.
delete_index(Index, Tab, K) ->
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 77c7a7638d..4e761d2bed 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -921,20 +921,7 @@ random_time(Retries, _Counter0) ->
UpperLimit = 500,
Dup = Retries * Retries,
MaxIntv = trunc(UpperLimit * (1-(50/((Dup)+50)))),
-
- case get(random_seed) of
- undefined ->
- _ = random:seed(erlang:unique_integer(),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Time = Dup + random:uniform(MaxIntv),
- %% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]),
- Time;
- _ ->
- Time = Dup + random:uniform(MaxIntv),
- %% dbg_out("---random_test rs ~w max ~w val ~w---~n", [Retries, MaxIntv, Time]),
- Time
- end.
+ Dup + rand:uniform(MaxIntv).
report_system_event(Event0) ->
Event = {mnesia_system_event, Event0},
diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl
index 1d9d9c35bc..e3e0eaaf75 100644
--- a/lib/mnesia/test/mnesia_atomicity_test.erl
+++ b/lib/mnesia/test/mnesia_atomicity_test.erl
@@ -557,8 +557,8 @@ start_lock_waiter(BlockOpA, BlockOpB, Config) ->
?verify_mnesia([N1], [N2]).
mk_tab_name(Prefix) ->
- {Mega, Sec, Micro} = erlang:now(),
- list_to_atom(lists:concat([Prefix , Mega, '_', Sec, '_', Micro])).
+ Count = erlang:unique_integer([monotonic,positive]),
+ list_to_atom(lists:concat([Prefix , '_', Count])).
lock_waiter_fun(Op, TabName, Val) ->
case Op of
diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl
index c8a6a000c6..089fbc06dc 100644
--- a/lib/mnesia/test/mnesia_config_test.erl
+++ b/lib/mnesia/test/mnesia_config_test.erl
@@ -1206,7 +1206,7 @@ dynamic_ext(Config) when is_list(Config) ->
end,
[Check(Test) || Test <- [{tab1, ram_copies},{tab2, disc_copies},{tab3, disc_only_copies}]],
- T = now(),
+ T = erlang:unique_integer(),
?match(ok, mnesia:dirty_write({tab0, 42, T})),
?match(ok, mnesia:dirty_write({tab1, 42, T})),
?match(ok, mnesia:dirty_write({tab2, 42, T})),
@@ -1284,7 +1284,7 @@ check_storage(Me, Orig, Other) ->
mnesia_test_lib:kill_mnesia([Orig]),
mnesia_test_lib:kill_mnesia(Other),
- T = now(),
+ T = erlang:unique_integer(),
?match(ok, rpc:call(Me, mnesia, dirty_write, [{tab2, 42, T}])),
?match(stopped, rpc:call(Me, mnesia, stop, [])),
?match(ok, rpc:call(Me, mnesia, start, [])),
diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl
index 087aef86c9..279e7bc1ec 100644
--- a/lib/mnesia/test/mnesia_consistency_test.erl
+++ b/lib/mnesia/test/mnesia_consistency_test.erl
@@ -696,7 +696,7 @@ consistency_after_restore(ReplicaType, Op, Config) ->
?verify_mnesia(Nodes, []).
change_tab(Father, Tab, Test) ->
- Key = random:uniform(20),
+ Key = rand:uniform(20),
Update = fun() ->
case mnesia:read({Tab, Key}) of
[{Tab, Key, 1}] ->
diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl
index ff0108ced1..714dbaef27 100644
--- a/lib/mnesia/test/mnesia_cost.erl
+++ b/lib/mnesia/test/mnesia_cost.erl
@@ -108,11 +108,11 @@ run(What, OtherInfo, Ops, F) ->
run(t, What, OtherInfo, Ops, F).
run(How, What, OtherInfo, Ops, F) ->
- T1 = erlang:now(),
+ T1 = erlang:monotonic_time(),
statistics(runtime),
do_times(How, ?TIMES, F),
{_, RunTime} = statistics(runtime),
- T2 = erlang:now(),
+ T2 = erlang:monotonic_time(),
RealTime = subtr(T1, T2),
report(How, What, OtherInfo, Ops, RunTime, RealTime).
@@ -140,11 +140,7 @@ report(dirty, What, OtherInfo, Ops, RunTime, RealTime) ->
subtr(Before, After) ->
- E =(element(1,After)*1000000000000
- +element(2,After)*1000000+element(3,After)) -
- (element(1,Before)*1000000000000
- +element(2,Before)*1000000+element(3,Before)),
- E div 1000.
+ erlang:convert_time_unit(After-Before, native, milli_seconds).
do_times(t, I, F) ->
do_trans_times(I, F);
diff --git a/lib/mnesia/test/mnesia_dbn_meters.erl b/lib/mnesia/test/mnesia_dbn_meters.erl
index f97bd973fc..5c3ea08a1d 100644
--- a/lib/mnesia/test/mnesia_dbn_meters.erl
+++ b/lib/mnesia/test/mnesia_dbn_meters.erl
@@ -93,7 +93,7 @@ some_meters() ->
report_meter(Meter) ->
Times = 100,
Micros = repeat_meter(Meter,{atomic,{0,ignore}},Times) div Times,
- io:format("\t~-30w ~-10w micro seconds (mean of ~p repetitions)~n",[Meter,Micros,Times]).
+ io:format("\t~-30w ~-10w nano seconds (mean of ~p repetitions)~n",[Meter,Micros,Times]).
repeat_meter(_Meter,{atomic,{Micros,_Result}},0) ->
Micros;
@@ -110,9 +110,9 @@ meter(create) ->
Key = 1,
mnesia:transaction(fun() -> mnesia:delete({simple,Key}) end),
Fun = fun() ->
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:write(#simple{key=Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -121,9 +121,9 @@ meter(open_safe_read) ->
Key = 2,
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:read({simple,Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -132,9 +132,9 @@ meter(open_dirty_read) ->
Key = 21,
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:dirty_read({simple,Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -144,9 +144,9 @@ meter(get_int) ->
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
[Simple] = mnesia:read({simple,Key}),
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
Int = Simple#simple.val,
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,Int)
end,
mnesia:transaction(Fun);
@@ -155,9 +155,9 @@ meter(open_update) ->
Key = 3,
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:wread({simple,Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -167,9 +167,9 @@ meter(put_int) ->
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
[Simple] = mnesia:wread({simple,Key}),
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = Simple#simple{val=7},
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -179,10 +179,10 @@ meter(put_int_and_copy) ->
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
[Simple] = mnesia:wread({simple,Key}),
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
Simple2 = Simple#simple{val=17},
R = mnesia:write(Simple2),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -191,15 +191,15 @@ meter(dirty_put_int_and_copy) ->
Key = 55,
mnesia:dirty_write(#simple{key=Key}),
[Simple] = mnesia:dirty_read({simple,Key}),
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
Simple2 = Simple#simple{val=17},
R = mnesia:dirty_write(Simple2),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
{atomic,elapsed_time(BeforeT,AfterT,R)};
meter(start_trans) ->
- BeforeT = erlang:now(),
- {atomic,AfterT} = mnesia:transaction(fun() -> erlang:now() end),
+ BeforeT = erlang:monotonic_time(),
+ {atomic,AfterT} = mnesia:transaction(fun() -> erlang:monotonic_time() end),
{atomic,elapsed_time(BeforeT,AfterT,ok)};
meter(commit_one_update) ->
@@ -209,19 +209,19 @@ meter(commit_one_update) ->
[Simple] = mnesia:wread({simple,Key}),
Simple2 = Simple#simple{val=27},
_R = mnesia:write(Simple2),
- erlang:now()
+ erlang:monotonic_time()
end,
{atomic,BeforeT} = mnesia:transaction(Fun),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
{atomic,elapsed_time(BeforeT,AfterT,ok)};
meter(delete) ->
Key = 7,
mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end),
Fun = fun() ->
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:delete({simple,Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
elapsed_time(BeforeT,AfterT,R)
end,
mnesia:transaction(Fun);
@@ -229,15 +229,12 @@ meter(delete) ->
meter(dirty_delete) ->
Key = 75,
mnesia:dirty_write(#simple{key=Key}),
- BeforeT = erlang:now(),
+ BeforeT = erlang:monotonic_time(),
R = mnesia:dirty_delete({simple,Key}),
- AfterT = erlang:now(),
+ AfterT = erlang:monotonic_time(),
{atomic, elapsed_time(BeforeT,AfterT,R)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Calculate the elapsed time
elapsed_time(BeforeT,AfterT,Result) ->
- {(element(1,AfterT)*1000000000000
- +element(2,AfterT)*1000000+element(3,AfterT)) -
- (element(1,BeforeT)*1000000000000
- +element(2,BeforeT)*1000000+element(3,BeforeT)),Result}.
+ {erlang:convert_time_unit(AfterT-BeforeT, native, nano_seconds),Result}.
diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl
index 89aff2b3b8..0d57e5a1b1 100644
--- a/lib/mnesia/test/mnesia_dirty_access_test.erl
+++ b/lib/mnesia/test/mnesia_dirty_access_test.erl
@@ -401,9 +401,26 @@ dirty_index_read(Config, Storage) ->
?match({'EXIT', _}, mnesia:dirty_index_read(Tab, 2, BadValPos)),
?match({'EXIT', _}, mnesia:dirty_index_read(foo, 2, ValPos)),
?match({'EXIT', _}, mnesia:dirty_index_read([], 2, ValPos)),
-
+
+ mnesia:dirty_write({Tab, 5, 1}),
+ ?match(ok, index_read_loop(Tab, 0)),
+
?verify_mnesia(Nodes, []).
+
+index_read_loop(Tab, N) when N =< 1000 ->
+ spawn_link(fun() ->
+ mnesia:transaction(fun() -> mnesia:write({Tab, 5, 1}) end)
+ end),
+ case mnesia:dirty_match_object({Tab, '_', 1}) of
+ [{Tab, 5, 1}] ->
+ index_read_loop(Tab, N+1);
+ Other -> {N, Other}
+ end;
+index_read_loop(_, _) ->
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl
index 5392267f79..e605fa7926 100644
--- a/lib/mnesia/test/mnesia_evil_backup.erl
+++ b/lib/mnesia/test/mnesia_evil_backup.erl
@@ -229,10 +229,16 @@ restore(Config, Op) ->
[mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)],
[mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)],
[mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)],
- _Res11 = [{Tab1, N, N+1} || N <- lists:seq(1, 11)],
+
Res21 = [{Tab2, N, N+1} || N <- lists:seq(1, 11)],
Res31 = [[{Tab3, N, N+1}, {Tab3, N, N+44}] || N <- lists:seq(1, 10)],
-
+ Check = fun() ->
+ [disk_log:pid2name(X) ||
+ X <- processes(), Data <- [process_info(X, [current_function])],
+ Data =/= undefined,
+ element(1, element(2, lists:keyfind(current_function, 1, Data)))=:= disk_log]
+ end,
+ Before = Check(),
?match({atomic, [Tab1]}, Restore(File1, [{Op, [Tab1]},
{skip_tables, Tabs -- [Tab1]}])),
case Op of
@@ -319,6 +325,8 @@ restore(Config, Op) ->
end,
?match(ok, file:delete(File1)),
?match(ok, file:delete(File2)),
+ ?match([], Check() -- Before),
+
?verify_mnesia(Nodes, []).
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index 6abb1f7cdc..b66da6e390 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1127,7 +1127,9 @@ update_shared(Tab, Me, Acc) ->
0 ->
case mnesia:transaction(Update) of
{atomic, {ok,Term,W2}} ->
- io:format("~p:~p:(~p,~p) ~w@~w~n", [erlang:now(),node(),Me,Acc,Term,W2]),
+ io:format("~p:~p:(~p,~p) ~w@~w~n",
+ [erlang:unique_integer([monotonic,positive]),
+ node(),Me,Acc,Term,W2]),
update_shared(Tab, Me, Acc+1);
Else ->
?error("Trans failed on ~p with ~p~n"
diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl
index 035d6bde87..9d3b277e07 100644
--- a/lib/mnesia/test/mnesia_test_lib.erl
+++ b/lib/mnesia/test/mnesia_test_lib.erl
@@ -238,8 +238,8 @@ slave_start_link() ->
slave_start_link(Node) ->
[Local, Host] = node_to_name_and_host(Node),
- {Mega, Sec, Micro} = erlang:now(),
- List = [Local, "_", Mega, "_", Sec, "_", Micro],
+ Count = erlang:unique_integer([positive]),
+ List = [Local, "_", Count],
Name = list_to_atom(lists:concat(List)),
slave_start_link(list_to_atom(Host), Name).
diff --git a/lib/mnesia/test/mnesia_tpcb.erl b/lib/mnesia/test/mnesia_tpcb.erl
index 3f936591b0..c6eda1c448 100644
--- a/lib/mnesia/test/mnesia_tpcb.erl
+++ b/lib/mnesia/test/mnesia_tpcb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -100,9 +100,13 @@
replica_test/1,
sticky_replica_test/1,
remote_test/1,
- remote_frag2_test/1
+ remote_frag2_test/1,
+
+ conflict_benchmark/1
]).
+-include_lib("common_test/include/ct_event.hrl").
+
-define(SECOND, 1000000).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -160,7 +164,7 @@
-record(history,
{
history_id = {0, 0}, % {DriverId, DriverLocalHistoryid}
- time_stamp = now(), % Time point during active transaction
+ time_stamp = erlang:system_time(), % Time point during active transaction
branch_id = 0, % Branch associated with teller
teller_id = 0, % Teller invlolved in transaction
account_id = 0, % Account updated by transaction
@@ -192,8 +196,10 @@
driver_nodes = [node()],
n_drivers_per_node = 1,
use_running_mnesia = false,
+ seed,
stop_after = timer:minutes(15), % Minimum 15 min
report_interval = timer:minutes(1),
+ send_bench_report = false,
use_sticky_locks = false,
spawn_near_branch = false,
activity_type = transaction,
@@ -398,8 +404,29 @@ config(remote_frag2_test, ReplicaType) ->
{stop_after, timer:minutes(1)},
{report_interval, timer:seconds(10)},
{reuse_history_id, true}
+ ];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Ten drivers per node, tables replicated to all nodes, single branch
+
+config(conflict_benchmark, ReplicaType) ->
+ Remote = nodes(),
+ Local = node(),
+ Nodes = [Local | Remote],
+ [{db_nodes, Nodes},
+ {driver_nodes, Nodes},
+ {replica_nodes, Nodes},
+ {n_drivers_per_node, 10},
+ {n_branches, 1},
+ {n_accounts_per_branch, 10},
+ {replica_type, ReplicaType},
+ {stop_after, timer:minutes(1)},
+ {report_interval, timer:seconds(10)},
+ {send_bench_report, true},
+ {reuse_history_id, true}
].
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start(What, ReplicaType) ->
@@ -423,6 +450,9 @@ remote_test(ReplicaType) ->
remote_frag2_test(ReplicaType) ->
start(remote_frag2_test, ReplicaType).
+conflict_benchmark(ReplicaType) ->
+ start(config(conflict_benchmark, ReplicaType)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Args is a list of {Key, Val} tuples where Key is a field name
%% in either the record tab_config or run_config. Unknown keys are ignored.
@@ -727,7 +757,7 @@ reporter_init(Starter, RC) ->
replica_type = Type
},
Drivers = start_drivers(RC, TC),
- Now = now_to_micros(erlang:now()),
+ Now = erlang:monotonic_time(),
State = #reporter_state{driver_pids = Drivers,
run_config = RC,
starter_pid = Starter,
@@ -865,8 +895,9 @@ add_time(Acc, New) ->
-define(AVOID_DIV_ZERO(_What_), try (_What_) catch _:_ -> 0 end).
show_report(State) ->
- Now = now_to_micros(erlang:now()),
+ Now = erlang:timestamp(),
Iters = State#reporter_state.n_iters,
+ Cfg = State#reporter_state.run_config,
Time = State#reporter_state.curr,
Max = Time#time.max_time,
N = Time#time.n_trans,
@@ -889,6 +920,16 @@ show_report(State) ->
"duration of longest transaction was ~p milliseconds~n",
[Tps, BruttoTps, Max div 1000])
end,
+ case Cfg#run_config.send_bench_report of
+ true ->
+ ct_event:notify(
+ #event{name = benchmark_data,
+ data = [{suite,"mnesia_tpcb"},
+ {value,Tps}]});
+ _ ->
+ ok
+ end,
+
State#reporter_state{prev_tps = Tps, prev_micros = Now}.
signed_diff(Iters, Curr, Prev) ->
@@ -899,11 +940,6 @@ signed_diff(Iters, Curr, Prev) ->
sign(N) when N > 0 -> {"+", N};
sign(N) -> {"", N}.
-
-now_to_micros({Mega, Secs, Micros}) ->
- DT = calendar:now_to_datetime({Mega, Secs, 0}),
- S = calendar:datetime_to_gregorian_seconds(DT),
- (S * ?SECOND) + Micros.
start_drivers(RC, TC) ->
LastHistoryId = table_info(history, size),
@@ -956,7 +992,11 @@ alloc_local_branches([], Specs, OrphanBranches) ->
{Specs, OrphanBranches}.
driver_init(DS, AllBranches) ->
- Seed = erlang:now(),
+ Seed = case (DS#driver_state.run_config)#run_config.seed of
+ undefined -> rand:seed(exsplus);
+ ExpSeed -> rand:seed(ExpSeed)
+ end,
+
DS2 =
if
DS#driver_state.n_local_branches =:= 0 ->
@@ -1010,14 +1050,7 @@ calc_trans(DS) ->
%% Generate teller_id, account_id and delta
%% Time the TPC-B transaction
time_trans(DS) ->
- OldSeed = get(random_seed), % Avoid interference with Mnesia
- put(random_seed, DS#driver_state.seed),
- Random = random:uniform(),
- NewSeed = get(random_seed),
- case OldSeed of
- undefined -> erase(random_seed);
- _ -> put(random_seed, OldSeed)
- end,
+ {Random, NewSeed} = rand:uniform_s(DS#driver_state.seed),
TC = DS#driver_state.tab_config,
RC = DS#driver_state.run_config,
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 79dd495c4b..0fe5b5db8b 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.13
+MNESIA_VSN = 4.13.2