aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mnesia
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mnesia')
-rw-r--r--lib/mnesia/doc/src/Makefile14
-rw-r--r--lib/mnesia/doc/src/company.erl45
-rw-r--r--lib/mnesia/doc/src/company_o.erl20
-rw-r--r--lib/mnesia/doc/src/notes.xml32
-rw-r--r--lib/mnesia/examples/Makefile10
-rw-r--r--lib/mnesia/include/Makefile4
-rw-r--r--lib/mnesia/src/Makefile8
-rw-r--r--lib/mnesia/src/mnesia_loader.erl2
-rw-r--r--lib/mnesia/src/mnesia_locker.erl181
-rw-r--r--lib/mnesia/test/Makefile38
-rw-r--r--lib/mnesia/test/mnesia_consistency_test.erl22
-rw-r--r--lib/mnesia/vsn.mk2
12 files changed, 230 insertions, 148 deletions
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile
index 1ac5760510..173e43ac1f 100644
--- a/lib/mnesia/doc/src/Makefile
+++ b/lib/mnesia/doc/src/Makefile
@@ -142,13 +142,13 @@ debug opt:
include $(ERL_TOP)/make/otp_release_targets.mk
release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
$(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+ $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
+ $(INSTALL_DATA) $(MAN3_FILES) "$(RELEASE_PATH)/man/man3"
release_spec:
diff --git a/lib/mnesia/doc/src/company.erl b/lib/mnesia/doc/src/company.erl
index 28c32ed513..eef5535ed3 100644
--- a/lib/mnesia/doc/src/company.erl
+++ b/lib/mnesia/doc/src/company.erl
@@ -1,19 +1,20 @@
-%% ``The contents of this file are subject to the Erlang Public License,
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%%
+%% 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/.
-%%
+%% retrieved online 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$
+%%
+%% %CopyrightEnd%
%%
-module(company).
@@ -83,16 +84,24 @@ g() -> l.
%3
female_bosses() ->
- Q = qlc:q( [{E#employee.name, Boss#employee.name} ||
- E <- mnesia:table(employee),
- Boss <- mnesia:table(employee),
- Atdep <- mnesia:table(at_dep),
- Mgr <- mnesia:table(manager),
- E#employee.sex == female,
- Atdep#at_dep.emp == E#employee.emp_no,
- Mgr#manager.emp == Boss#employee.emp_no,
- Atdep#at_dep.dept_id == Mgr#manager.dept]
+ H1 = qlc:q( [{Atdep#at_dep.dept_id,E} ||
+ E <- mnesia:table(employee),
+ E#employee.sex == female,
+ Atdep <- mnesia:table(at_dep),
+ Atdep#at_dep.emp == E#employee.emp_no]
+ ),
+
+ H2 = qlc:q( [{Mgr#manager.emp,E} ||
+ {AtdepDeptId, E} <- H1,
+ Mgr <- mnesia:table(manager),
+ AtdepDeptId == Mgr#manager.dept]
),
+
+ Q = qlc:q( [{E#employee.name, Boss#employee.name} ||
+ {MgrEmp,E} <- H2,
+ Boss <- mnesia:table(employee),
+ MgrEmp == Boss#employee.emp_no]
+ ),
mnesia:transaction(fun() -> qlc:e(Q) end).
%3
diff --git a/lib/mnesia/doc/src/company_o.erl b/lib/mnesia/doc/src/company_o.erl
index 3c7ad0d5e5..dffe9840bb 100644
--- a/lib/mnesia/doc/src/company_o.erl
+++ b/lib/mnesia/doc/src/company_o.erl
@@ -1,20 +1,22 @@
-%% ``The contents of this file are subject to the Erlang Public License,
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%%
+%% 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/.
-%%
+%% retrieved online 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$
%%
+%% %CopyrightEnd%
+%%
+
-module(company_o).
-compile(export_all).
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index a300fcc12d..612ccb5ee8 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,37 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.6</title>
+ <section><title>Mnesia 4.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Returns the same value for
+ mnesia_loader:disc_load_table/2 as
+ mnesia_loader:net_load_table/4 if a table copy can not be
+ found. (Thanks to Uwe Dauernheim)</p>
+ <p>
+ Own Id: OTP-10015</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved table lock algorithm.</p>
+ <p>
+ Own Id: OTP-9890</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/examples/Makefile b/lib/mnesia/examples/Makefile
index ff00ee76a5..5379761c64 100644
--- a/lib/mnesia/examples/Makefile
+++ b/lib/mnesia/examples/Makefile
@@ -78,9 +78,9 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) $(RELSYSDIR)/examples
- $(INSTALL_DIR) $(RELSYSDIR)/examples/bench
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples"
+ $(INSTALL_DATA) $(ERL_FILES) $(DATA_FILES) $(HRL_FILES) "$(RELSYSDIR)/examples"
+ $(INSTALL_DIR) "$(RELSYSDIR)/examples/bench"
(cd bench; $(INSTALL_DATA) \
Makefile \
README \
@@ -96,8 +96,8 @@ release_spec: opt
bench.config5 \
bench.config6 \
bench.config7 \
- $(RELSYSDIR)/examples/bench)
- (cd bench; $(INSTALL_SCRIPT) bench.sh $(RELSYSDIR)/examples/bench)
+ "$(RELSYSDIR)/examples/bench")
+ (cd bench; $(INSTALL_SCRIPT) bench.sh "$(RELSYSDIR)/examples/bench")
release_docs_spec:
diff --git a/lib/mnesia/include/Makefile b/lib/mnesia/include/Makefile
index f9b7d72abe..20f62b5460 100644
--- a/lib/mnesia/include/Makefile
+++ b/lib/mnesia/include/Makefile
@@ -54,8 +54,8 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/include
-# $(INSTALL_DATA) $(INCLUDE_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) "$(RELSYSDIR)/include"
+# $(INSTALL_DATA) $(INCLUDE_FILES) "$(RELSYSDIR)/include"
release_docs_spec:
diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile
index 1c8ec54605..1432eabc37 100644
--- a/lib/mnesia/src/Makefile
+++ b/lib/mnesia/src/Makefile
@@ -132,10 +132,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
+ $(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
release_docs_spec:
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index e443b54016..4ba400fbbf 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -57,7 +57,7 @@ disc_load_table(Tab, Reason) ->
do_get_disc_copy2(Tab, _Reason, Storage, _Type) when Storage == unknown ->
verbose("Local table copy of ~p has recently been deleted, ignored.~n",
[Tab]),
- {loaded, ok}; %% ?
+ {not_loaded, storage_unknown};
do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
%% NOW we create the actual table
Repair = mnesia_monitor:get_env(auto_repair),
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index de4811f8e4..a22c95d454 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
%%
%% 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
@@ -66,7 +66,7 @@
-record(queue, {oid, tid, op, pid, lucky}).
-%% mnesia_held_locks: contain {Oid, Op, Tid} entries (bag)
+%% mnesia_held_locks: contain {Oid, MaxLock, [{Op, Tid}]} entries
-define(match_oid_held_locks(Oid), {Oid, '_', '_'}).
%% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag)
-define(match_oid_tid_locks(Tid), {Tid, '_', '_'}).
@@ -83,7 +83,7 @@ start() ->
init(Parent) ->
register(?MODULE, self()),
process_flag(trap_exit, true),
- ?ets_new_table(mnesia_held_locks, [bag, private, named_table]),
+ ?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]),
?ets_new_table(mnesia_tid_locks, [bag, private, named_table]),
?ets_new_table(mnesia_sticky_locks, [set, private, named_table]),
?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]),
@@ -235,10 +235,17 @@ loop(State) ->
loop(State)
end.
-set_lock(Tid, Oid, Op) ->
- ?dbg("Granted ~p ~p ~p~n", [Tid,Oid,Op]),
- ?ets_insert(mnesia_held_locks, {Oid, Op, Tid}),
- ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}).
+set_lock(Tid, Oid, Op, []) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}),
+ ?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]});
+set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}),
+ ?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]});
+set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) ->
+ ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}),
+ ?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]});
+set_lock(Tid, Oid, Op, undefined) ->
+ set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Acquire locks
@@ -261,14 +268,14 @@ try_lock(Tid, Op, Pid, Oid) ->
try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) ->
case can_lock(Tid, Lock, Oid, {no, bad_luck}) of
- yes ->
- Reply = grant_lock(Tid, SimpleOp, Lock, Oid),
+ {yes, Default} ->
+ Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default),
reply(Pid, Reply);
- {no, Lucky} ->
+ {{no, Lucky},_} ->
C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky},
?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
reply(Pid, {not_granted, C});
- {queue, Lucky} ->
+ {{queue, Lucky},_} ->
?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
%% Append to queue: Nice place for trace output
?ets_insert(mnesia_lock_queue,
@@ -277,16 +284,16 @@ try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) ->
?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}})
end.
-grant_lock(Tid, read, Lock, Oid = {Tab, Key})
+grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default)
when Key /= ?ALL, Tab /= ?GLOBAL ->
case node(Tid#tid.pid) == node() of
true ->
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, lookup_in_client};
false ->
try
Val = mnesia_lib:db_get(Tab, Key), %% lookup as well
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, Val}
catch _:_Reason ->
%% Table has been deleted from this node,
@@ -296,19 +303,19 @@ grant_lock(Tid, read, Lock, Oid = {Tab, Key})
{not_granted, C}
end
end;
-grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}) ->
+grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}, Default) ->
try
Res = ix_read_res(Tab, IxKey,Pos),
- set_lock(Tid, Oid, Lock),
+ set_lock(Tid, Oid, Lock, Default),
{granted, Res, [?ALL]}
catch _:_ ->
{not_granted, {no_exists, Tab, {index, [Pos]}}}
end;
-grant_lock(Tid, read, Lock, Oid) ->
- set_lock(Tid, Oid, Lock),
+grant_lock(Tid, read, Lock, Oid, Default) ->
+ set_lock(Tid, Oid, Lock, Default),
{granted, ok};
-grant_lock(Tid, write, Lock, Oid) ->
- set_lock(Tid, Oid, Lock),
+grant_lock(Tid, write, Lock, Oid, Default) ->
+ set_lock(Tid, Oid, Lock, Default),
granted.
%% 1) Impose an ordering on all transactions favour old (low tid) transactions
@@ -318,55 +325,40 @@ grant_lock(Tid, write, Lock, Oid) ->
%% 3) TabLocks is the problem :-) They should not starve and not deadlock
%% handle tablocks in queue as they had locks on unlocked records.
-can_lock(Tid, read, {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
- %% The key is bound, no need for the other BIF
- Oid = {Tab, Key},
- ObjLocks = ?ets_match_object(mnesia_held_locks, {Oid, write, '_'}),
- TabLocks = ?ets_match_object(mnesia_held_locks, {{Tab, ?ALL}, write, '_'}),
- check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, read);
+can_lock(Tid, read, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
+ ObjLocks = ?ets_lookup(mnesia_held_locks, Oid),
+ TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}),
+ {check_lock(Tid, Oid,
+ filter_write(ObjLocks),
+ filter_write(TabLocks),
+ yes, AlreadyQ, read),
+ ObjLocks};
can_lock(Tid, read, Oid, AlreadyQ) -> % Whole tab
Tab = element(1, Oid),
ObjLocks = ?ets_match_object(mnesia_held_locks, {{Tab, '_'}, write, '_'}),
- check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read);
+ {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read), undefined};
-can_lock(Tid, write, {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
- Oid = {Tab, Key},
+can_lock(Tid, write, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL ->
ObjLocks = ?ets_lookup(mnesia_held_locks, Oid),
TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}),
- check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write);
+ {check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write), ObjLocks};
can_lock(Tid, write, Oid, AlreadyQ) -> % Whole tab
Tab = element(1, Oid),
ObjLocks = ?ets_match_object(mnesia_held_locks, ?match_oid_held_locks({Tab, '_'})),
- check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write).
+ {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write), undefined}.
+
+filter_write([{_, read, _}]) -> [];
+filter_write(Res) -> Res.
%% Check held locks for conflicting locks
-check_lock(Tid, Oid, [Lock | Locks], TabLocks, X, AlreadyQ, Type) ->
- case element(3, Lock) of
- Tid ->
- check_lock(Tid, Oid, Locks, TabLocks, X, AlreadyQ, Type);
- WaitForTid ->
- Queue = allowed_to_be_queued(WaitForTid,Tid),
- if Queue == true ->
- check_lock(Tid, Oid, Locks, TabLocks, {queue, WaitForTid}, AlreadyQ, Type);
- Tid#tid.pid == WaitForTid#tid.pid ->
- dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n",
- [Oid, Lock, Tid, WaitForTid]),
- %% Test..
- {Tab, _Key} = Oid,
- HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= [])
- orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []),
- if
- HaveQ ->
- {no, WaitForTid};
- true ->
- check_lock(Tid,Oid,Locks,TabLocks,{queue,WaitForTid},AlreadyQ,Type)
- end;
- %%{no, WaitForTid}; Safe solution
- true ->
- {no, WaitForTid}
- end
+check_lock(Tid, Oid, [{_, _, Lock} | Locks], TabLocks, _X, AlreadyQ, Type) ->
+ case can_queue(Lock, Tid, Oid, _X) of
+ {no, _} = Res ->
+ Res;
+ Res ->
+ check_lock(Tid, Oid, Locks, TabLocks, Res, AlreadyQ, Type)
end;
check_lock(_, _, [], [], X, {queue, bad_luck}, _) ->
@@ -375,8 +367,7 @@ check_lock(_, _, [], [], X, {queue, bad_luck}, _) ->
check_lock(_, _, [], [], X = {queue, _Tid}, _AlreadyQ, _) ->
X;
-check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) ->
- {Tab, Key} = Oid,
+check_lock(Tid, Oid = {Tab, Key}, [], [], X, AlreadyQ, Type) ->
if
Type == write ->
check_queue(Tid, Tab, X, AlreadyQ);
@@ -403,6 +394,26 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) ->
check_lock(Tid, Oid, [], TabLocks, X, AlreadyQ, Type) ->
check_lock(Tid, Oid, TabLocks, [], X, AlreadyQ, Type).
+can_queue([{_Op, Tid}|Locks], Tid, Oid, Res) ->
+ can_queue(Locks, Tid, Oid, Res);
+can_queue([{Op, WaitForTid}|Locks], Tid, Oid = {Tab, _}, _) ->
+ case allowed_to_be_queued(WaitForTid,Tid) of
+ true when Tid#tid.pid == WaitForTid#tid.pid ->
+ dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n",
+ [Oid, Op, Tid, WaitForTid]),
+ HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= [])
+ orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []),
+ case HaveQ of
+ true -> {no, WaitForTid};
+ false -> can_queue(Locks, Tid, Oid, {queue, WaitForTid})
+ end;
+ true ->
+ can_queue(Locks, Tid, Oid, {queue, WaitForTid});
+ false ->
+ {no, WaitForTid}
+ end;
+can_queue([], _, _, Res) -> Res.
+
%% True if WaitForTid > Tid -> % Important order
allowed_to_be_queued(WaitForTid, Tid) ->
case get(pid_sort_order) of
@@ -456,14 +467,14 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) ->
Op = {ix_read,IxKey, Pos},
Lock = read,
case can_lock(Tid, Lock, Oid, {no, bad_luck}) of
- yes ->
- Reply = grant_lock(Tid, Op, Lock, Oid),
+ {yes, Default} ->
+ Reply = grant_lock(Tid, Op, Lock, Oid, Default),
reply(From, Reply);
- {no, Lucky} ->
+ {{no, Lucky},_} ->
C = #cyclic{op = Op, lock = Lock, oid = Oid, lucky = Lucky},
?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
reply(From, {not_granted, C});
- {queue, Lucky} ->
+ {{queue, Lucky},_} ->
?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]),
%% Append to queue: Nice place for trace output
?ets_insert(mnesia_lock_queue,
@@ -520,14 +531,24 @@ release_locks([]) ->
release_lock({Tid, Oid, {queued, _}}) ->
?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = '_',
pid = '_', lucky = '_'});
-release_lock({Tid, Oid, Op}) ->
- if
- Op == write ->
- ?ets_delete(mnesia_held_locks, Oid);
- Op == read ->
- ets:delete_object(mnesia_held_locks, {Oid, Op, Tid})
+release_lock({_Tid, Oid, write}) ->
+ ?ets_delete(mnesia_held_locks, Oid);
+release_lock({Tid, Oid, read}) ->
+ case ?ets_lookup(mnesia_held_locks, Oid) of
+ [{Oid, Prev, Locks0}] ->
+ case remove_tid(Locks0, Tid, []) of
+ [] -> ?ets_delete(mnesia_held_locks, Oid);
+ Locks -> ?ets_insert(mnesia_held_locks, {Oid, Prev, Locks})
+ end;
+ [] -> ok
end.
+remove_tid([{_Op, Tid}|Ls], Tid, Acc) ->
+ remove_tid(Ls,Tid, Acc);
+remove_tid([Keep|Ls], Tid, Acc) ->
+ remove_tid(Ls,Tid, [Keep|Acc]);
+remove_tid([], _, Acc) -> Acc.
+
rearrange_queue([{_Tid, {Tab, Key}, _} | Locks]) ->
if
Key /= ?ALL->
@@ -592,18 +613,18 @@ try_waiter({queue, Oid, Tid, Op, ReplyTo, _}) ->
try_waiter(Oid, Op, SimpleOp, Lock, ReplyTo, Tid) ->
case can_lock(Tid, Lock, Oid, {queue, bad_luck}) of
- yes ->
+ {yes, Default} ->
%% Delete from queue: Nice place for trace output
?ets_match_delete(mnesia_lock_queue,
#queue{oid=Oid, tid = Tid, op = Op,
pid = ReplyTo, lucky = '_'}),
- Reply = grant_lock(Tid, SimpleOp, Lock, Oid),
+ Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default),
reply(ReplyTo,Reply),
locked;
- {queue, _Why} ->
+ {{queue, _Why}, _} ->
?dbg("Keep ~p ~p ~p ~p~n", [Tid, Oid, Lock, _Why]),
queued; % Keep waiter in queue
- {no, Lucky} ->
+ {{no, Lucky}, _} ->
C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky},
verbose("** WARNING ** Restarted transaction, possible deadlock in lock queue ~w: cyclic = ~w~n",
[Tid, C]),
@@ -1116,11 +1137,23 @@ rec_requests([], _Oid, _Store) ->
get_held_locks() ->
?MODULE ! {get_table, self(), mnesia_held_locks},
- receive {mnesia_held_locks, Locks} -> Locks end.
+ Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end,
+ rewrite_locks(Locks, []).
+
+rewrite_locks([{Oid, _, Ls}|Locks], Acc0) ->
+ Acc = rewrite_locks(Ls, Oid, Acc0),
+ rewrite_locks(Locks, Acc);
+rewrite_locks([], Acc) ->
+ lists:reverse(Acc).
+
+rewrite_locks([{Op, Tid}|Ls], Oid, Acc) ->
+ rewrite_locks(Ls, Oid, [{Oid, Op, Tid}|Acc]);
+rewrite_locks([], _, Acc) ->
+ Acc.
get_lock_queue() ->
?MODULE ! {get_table, self(), mnesia_lock_queue},
- Q = receive {mnesia_lock_queue, Locks} -> Locks end,
+ Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end,
[{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q].
do_stop() ->
diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile
index ae4c9626c7..0451da697d 100644
--- a/lib/mnesia/test/Makefile
+++ b/lib/mnesia/test/Makefile
@@ -52,24 +52,29 @@ MODULES= \
mnesia_cost \
mnesia_dbn_meters
-MnesiaExamplesDir := ../examples
+DocExamplesDir := ../doc/src/
-ExampleModules = \
+DocExampleModules = \
company \
company_o \
- bup \
- mnesia_meter \
- mnesia_tpcb
-ExamplesHrl = \
+ bup
+
+DocExamplesHrl = \
company.hrl \
company_o.hrl
-ERL_FILES= $(MODULES:%=%.erl) $(ExampleModules:%=$(MnesiaExamplesDir)/%.erl)
+ExamplesDir := ../examples/
+
+ExampleModules = \
+ mnesia_meter \
+ mnesia_tpcb
-HRL_FILES= mnesia_test_lib.hrl $(ExamplesHrl:%=$(MnesiaExamplesDir)/%)
+ERL_FILES= $(MODULES:%=%.erl) $(DocExampleModules:%=$(DocExamplesDir)/%.erl) $(ExampleModules:%=$(ExamplesDir)/%.erl)
+
+HRL_FILES= mnesia_test_lib.hrl $(DocExamplesHrl:%=$(DocExamplesDir)/%)
TARGET_FILES= \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(ExampleModules:%=$(EBIN)/%.$(EMULATOR))
+ $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(DocExampleModules:%=$(EBIN)/%.$(EMULATOR)) $(ExampleModules:%=$(EBIN)/%.$(EMULATOR))
INSTALL_PROGS= $(TARGET_FILES)
@@ -91,7 +96,10 @@ EBIN = .
tests debug opt: $(TARGET_FILES)
-$(EBIN)/%.beam: $(MnesiaExamplesDir)/%.erl
+$(EBIN)/%.beam: $(DocExamplesDir)/%.erl
+ $(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+
+$(EBIN)/%.beam: $(ExamplesDir)/%.erl
$(ERLC) -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
clean:
@@ -108,11 +116,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
release_tests_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
- $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) $(RELSYSDIR)
-# chmod -R u+w $(RELSYSDIR)
-# @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+ $(INSTALL_DIR) "$(RELSYSDIR)"
+ $(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) "$(RELSYSDIR)"
+# chmod -R u+w "$(RELSYSDIR)"
+# @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl
index f38e13f3a2..bb21723e27 100644
--- a/lib/mnesia/test/mnesia_consistency_test.erl
+++ b/lib/mnesia/test/mnesia_consistency_test.erl
@@ -100,7 +100,7 @@ groups() ->
{group, updates_during_checkpoint_iteration},
{group, load_table_with_activated_checkpoint},
{group,
- add_table_copy_to_table_with_activated_checkpoint}]},
+ add_table_copy_to_table_checkpoint}]},
{updates_during_checkpoint_activation, [],
[updates_during_checkpoint_activation_2_ram,
updates_during_checkpoint_activation_2_disc,
@@ -116,10 +116,10 @@ groups() ->
[load_table_with_activated_checkpoint_ram,
load_table_with_activated_checkpoint_disc,
load_table_with_activated_checkpoint_disc_only]},
- {add_table_copy_to_table_with_activated_checkpoint, [],
- [add_table_copy_to_table_with_activated_checkpoint_ram,
- add_table_copy_to_table_with_activated_checkpoint_disc,
- add_table_copy_to_table_with_activated_checkpoint_disc_only]},
+ {add_table_copy_to_table_checkpoint, [],
+ [add_table_copy_to_table_checkpoint_ram,
+ add_table_copy_to_table_checkpoint_disc,
+ add_table_copy_to_table_checkpoint_disc_only]},
{backup_consistency, [],
[{group, interupted_install_fallback},
{group, interupted_uninstall_fallback},
@@ -952,16 +952,16 @@ view(Source, Mod) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-add_table_copy_to_table_with_activated_checkpoint_ram(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_ram(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_ram(suite) -> [];
+add_table_copy_to_table_checkpoint_ram(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(ram_copies, Config).
-add_table_copy_to_table_with_activated_checkpoint_disc(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_disc(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_disc(suite) -> [];
+add_table_copy_to_table_checkpoint_disc(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(disc_copies, Config).
-add_table_copy_to_table_with_activated_checkpoint_disc_only(suite) -> [];
-add_table_copy_to_table_with_activated_checkpoint_disc_only(Config) when is_list(Config) ->
+add_table_copy_to_table_checkpoint_disc_only(suite) -> [];
+add_table_copy_to_table_checkpoint_disc_only(Config) when is_list(Config) ->
add_table_copy_to_table_with_activated_checkpoint(disc_only_copies, Config).
add_table_copy_to_table_with_activated_checkpoint(Type,Config) ->
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 080548acac..da292cbb43 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.6
+MNESIA_VSN = 4.7