diff options
Diffstat (limited to 'lib/mnesia')
71 files changed, 1744 insertions, 950 deletions
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile index 39f2b28637..d9647fc081 100644 --- a/lib/mnesia/doc/src/Makefile +++ b/lib/mnesia/doc/src/Makefile @@ -1,8 +1,8 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2016. All Rights Reserved. -# +# +# Copyright Ericsson AB 1997-2018. 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. # You may obtain a copy of the License at @@ -14,7 +14,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# +# # %CopyrightEnd% # @@ -44,39 +44,34 @@ XML_REF3_FILES = \ mnesia_registry.xml XML_PART_FILES = \ - part.xml \ - part_notes.xml \ - part_notes_history.xml + part.xml XML_CHAPTER_FILES = \ Mnesia_chap1.xml \ + Mnesia_overview.xml \ + Mnesia_chap8.xml \ + notes.xml + +XML_CHAPTER_GEN_FILES = \ Mnesia_chap2.xml \ Mnesia_chap3.xml \ Mnesia_chap4.xml \ Mnesia_chap5.xml \ Mnesia_chap7.xml \ - Mnesia_chap8.xml \ Mnesia_App_A.xml \ Mnesia_App_B.xml \ - Mnesia_App_C.xml \ - notes.xml + Mnesia_App_C.xml BOOK_FILES = book.xml - XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) +XML_GEN_FILES = $(XML_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) + GIF_FILES = \ - book.gif \ - company.gif \ - mnesia.gif \ - note.gif \ - notes.gif \ - ref_man.gif \ - user_guide.gif \ - warning.gif + company.gif XML_HTML_FILES = \ notes_history.xml @@ -89,7 +84,7 @@ HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) INFO_FILE = ../../info -EXTRA_FILES = summary.html.src \ +EXTRA_FILES = \ $(DEFAULT_GIF_FILES) \ $(DEFAULT_HTML_FILES) \ $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ @@ -102,10 +97,10 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf # ---------------------------------------------------- -# FLAGS +# FLAGS # ---------------------------------------------------- -XML_FLAGS += -DVIPS_FLAGS += +XML_FLAGS += +DVIPS_FLAGS += # ---------------------------------------------------- # Targets @@ -123,6 +118,7 @@ html: gifs $(HTML_REF_MAN_FILE) clean clean_docs: rm -rf $(HTMLDIR)/* + rm -rf $(XMLDIR) rm -f $(MAN3DIR)/* rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ @@ -134,11 +130,11 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%) $(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk sed -e 's;%VSN%;$(VSN);' $< > $@ -debug opt: +debug opt: # ---------------------------------------------------- # Release Target -# ---------------------------------------------------- +# ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk release_docs_spec: docs diff --git a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc index 37389ce5ae..8135e14301 100644 --- a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -327,7 +327,7 @@ <section> <title>Initial Database Content</title> <p>After the insertion of the employee named <c>klacke</c>, - the databse has the following records:</p> + the database has the following records:</p> <marker id="table2_1"></marker> <table> <row> diff --git a/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc index 8f1a4366ee..ffda739dfa 100644 --- a/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap3.xmlsrc @@ -348,7 +348,7 @@ skeppet %<input>erl -sname b -mnesia dir '"/ldisc/scratch/Mnesia.company"'</inpu <p>If the startup procedure fails, the function <seealso marker="mnesia#start/0">mnesia:start()</seealso> returns the cryptic tuple - <c>{error,{shutdown, {mnesia_sup,start,[normal,[]]}}}</c>. + <c>{error,{shutdown, {mnesia_sup,start_link,[normal,[]]}}}</c>. To get more information about the start failure, use command-line arguments <c>-boot start_sasl</c> as argument to the <c>erl</c> script.</p> diff --git a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc index a83d1d77d2..481e6651e6 100644 --- a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -226,8 +226,10 @@ not known beforehand, all fragments are searched for matching records.</p> <p>Notice that in <c>ordered_set</c> tables, the records - are ordered per fragment, and the the order is undefined in - results returned by <c>select</c> and <c>match_object</c>.</p> + are ordered per fragment, and the order is undefined in + results returned by <c>select</c> and <c>match_object</c>, + as well as <c>first</c>, <c>next</c>, <c>prev</c> and + <c>last</c>.</p> <p>The following code illustrates how a <c>Mnesia</c> table is converted to be a fragmented table and how more fragments are added later:</p> @@ -362,11 +364,6 @@ ok <seealso marker="mnesia_frag_hash">mnesia_frag_hash</seealso> callback behavior. This property can explicitly be set at table creation. Default is <c>mnesia_frag_hash</c>.</p> - <p>Older tables, that were created before the concept of - user-defined hash modules was introduced, use module - <c>mnesia_frag_old_hash</c> to be backwards compatible. - <c>mnesia_frag_old_hash</c> still uses the poor - deprecated function <c>erlang:hash/1</c>.</p> </item> <tag><c>{hash_state, Term}</c></tag> <item> diff --git a/lib/mnesia/doc/src/book.gif b/lib/mnesia/doc/src/book.gif Binary files differdeleted file mode 100644 index 94b3868792..0000000000 --- a/lib/mnesia/doc/src/book.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/company.erl b/lib/mnesia/doc/src/company.erl index 20e3235347..fc04aa77bf 100644 --- a/lib/mnesia/doc/src/company.erl +++ b/lib/mnesia/doc/src/company.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2018. 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. @@ -19,7 +19,12 @@ %% -module(company). --compile(export_all). +-export([init/0,insert_emp/3,mk_projs/2,females/0,all_females/0, + g/0,female_bosses/0, raise_females/1, over_write/2, raise/2, + bad_raise/2, get_emps/2, get_emps2/2, filter/2, filter_deps/3, + search_deps/3, bench1/0, dotimes/2, dist_init/0, remove_proj/1, + del_in_projs/1, sync/0, tabs/0, find_male_on_second_floor/0, + panic/1, fill_tables/0]). %0 diff --git a/lib/mnesia/doc/src/company_o.erl b/lib/mnesia/doc/src/company_o.erl index 7300e9d4bb..b4b3638596 100644 --- a/lib/mnesia/doc/src/company_o.erl +++ b/lib/mnesia/doc/src/company_o.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2018. 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. @@ -19,7 +19,11 @@ %% -module(company_o). --compile(export_all). + +-export([sinit/0, init/0,insert_emp/3,females/0, + female_bosses/0, raise_females/1, over_write/2, raise/2, + bad_raise/2, get_emps/2, get_emps2/2]). + -import(mnesia, [transaction/1]). diff --git a/lib/mnesia/doc/src/fascicules.xml b/lib/mnesia/doc/src/fascicules.xml deleted file mode 100644 index 37feca543f..0000000000 --- a/lib/mnesia/doc/src/fascicules.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> - -<fascicules> - <fascicule file="part" href="part_frame.html" entry="no"> - User's Guide - </fascicule> - <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> - Reference Manual - </fascicule> - <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> - Release Notes - </fascicule> - <fascicule file="" href="../../../../doc/print.html" entry="no"> - Off-Print - </fascicule> -</fascicules> - diff --git a/lib/mnesia/doc/src/mnesia.gif b/lib/mnesia/doc/src/mnesia.gif Binary files differdeleted file mode 100644 index fbbabee5aa..0000000000 --- a/lib/mnesia/doc/src/mnesia.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml index 51b32129b6..c233acdb05 100644 --- a/lib/mnesia/doc/src/mnesia_frag_hash.xml +++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2002</year> - <year>2016</year> + <year>2018</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -130,7 +130,7 @@ <name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name> <fsummary>Resolves the key of a record into a fragment number.</fsummary> <type> - <v>FragNum = integer()()</v> + <v>FragNum = integer()</v> <v>Reason = term()</v> </type> <desc> diff --git a/lib/mnesia/doc/src/note.gif b/lib/mnesia/doc/src/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/lib/mnesia/doc/src/note.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/notes.gif b/lib/mnesia/doc/src/notes.gif Binary files differdeleted file mode 100644 index e000cca26a..0000000000 --- a/lib/mnesia/doc/src/notes.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index e621bd593c..29c35d221c 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -4,14 +4,14 @@ <chapter> <header> <copyright> - <year>1996</year><year>2016</year> + <year>1996</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -39,7 +39,220 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.14.1</title> + <section><title>Mnesia 4.15.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed type spec for <c>mnesia:change_config/2</c>.</p> + <p> + Own Id: OTP-15201 Aux Id: PR-1881 </p> + </item> + <item> + <p> + When master node is set do not force a load from + ram_copies replica when there are no available + disc_copies, since that would load an empty table. Wait + until a disk replica is available or until user + explicitly force_loads the table.</p> + <p> + Own Id: OTP-15221 Aux Id: ERIERL-217 </p> + </item> + <item> + <p> + Allow to add replicas even if all other replicas are down + when the other replicas are not stored on disk.</p> + <p> + Own Id: OTP-15226 Aux Id: ERIERL-221 </p> + </item> + <item> + <p> + Fixed <c>mnesia:delete_object/1</c> bug, where + delete_object was deleting the record if it was written + in the same transaction even if it was written to a + different value.</p> + <p> + Own Id: OTP-15231 Aux Id: PR-1858 </p> + </item> + <item> + <p> + Fixed a bug where the bag table index data was not + deleted when objects were deleted.</p> + <p> + Own Id: OTP-15243</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Calls to <c>erlang:get_stacktrace()</c> are removed. + </p> + <p> + Own Id: OTP-14861</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When master node is set do not force a load from + ram_copies replica when there are no available + disc_copies, since that would load an empty table. Wait + until a disk replica is available or until user + explicitly force_loads the table.</p> + <p> + Own Id: OTP-15221 Aux Id: ERIERL-217 </p> + </item> + <item> + <p> + Allow to add replicas even if all other replicas are down + when the other replicase are not stored on disk.</p> + <p> + Own Id: OTP-15226 Aux Id: ERIERL-221 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Removed a quadratic behavior in startup. This change + implies that backend plugins (if used) must be set when + the schema is created or via configuration parameters + before mnesia is started.</p> + <p> + Own Id: OTP-14829 Aux Id: ERIERL-84 </p> + </item> + <item> + <p> + Bad timing could crash mnesia after a checkpoint was + deactivated and reactivated with the same checkpoint name + on different tables.</p> + <p> + Own Id: OTP-14841 Aux Id: ERIERL-113 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix backup error handling, the real failure reason was + not returned.</p> + <p> + Own Id: OTP-14776 Aux Id: ERIERL-103 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + General Unicode improvements.</p> + <p> + Own Id: OTP-14462</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Removed the wrapping of select continuations in extension + plugin handling. This might require the user to rewrite + user backend plugin if used.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-14039</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.14.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed crash in checkpoint handling when table was deleted + during backup.</p> + <p> + Own Id: OTP-14167</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.14.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A continuation returned by mnesia:select/[14] should be + reusable in different, non-transactional activities.</p> + <p> + Own Id: OTP-13944 Aux Id: PR-1184 </p> + </item> + <item> + <p> + Fixed crash when calling block_table multiple times. + Could happen when having locks for a long time and + restarting mnesia.</p> + <p> + Own Id: OTP-13970 Aux Id: Seq-13198 </p> + </item> + <item> + <p> + Change mnesia_tm process to have off-heap messages since + mnesia_tm can be the receiver of many non-synchronized + message from other nodes.</p> + <p> + Own Id: OTP-14074</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.14.1</title> <section><title>Improvements and New Features</title> <list> @@ -824,9 +1037,9 @@ </item> </list> </section> - - </section> - + + </section> + <section><title>Mnesia 4.4.13</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -895,7 +1108,7 @@ </section> <section><title>Mnesia 4.4.10</title> - + <section><title>Fixed Bugs and Malfunctions</title> <list> <item> @@ -925,7 +1138,7 @@ </item> </list> </section> - + </section> @@ -943,7 +1156,7 @@ </item> </list> </section> - + </section> <section><title>Mnesia 4.4.8</title> @@ -968,7 +1181,7 @@ </item> </list> </section> - + </section> <section><title>Mnesia 4.4.7</title> @@ -1002,7 +1215,7 @@ </section> - <section><title>Mnesia 4.4.6</title> + <section><title>Mnesia 4.4.6</title> <section><title>Fixed Bugs and Malfunctions</title> <list> <item> @@ -1193,9 +1406,4 @@ </section> </section> - <!-- section> - <title>Previous Notes</title> - <p>For information about older versions see <url href="part_notes_history_frame.html">release notes history</url>.</p> - </section --> </chapter> - diff --git a/lib/mnesia/doc/src/part_notes.xml b/lib/mnesia/doc/src/part_notes.xml deleted file mode 100644 index 1e4e4bc60a..0000000000 --- a/lib/mnesia/doc/src/part_notes.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>1997</year><year>2016</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - </legalnotice> - - <title>MNESIA Release Notes</title> - <prepared>Claes Wikström, Hans Nilsson and Håkan Mattsson</prepared> - <docno></docno> - <date>1997-05-27</date> - <rev>1.2</rev> - <file>part_notes.xml</file> - </header> - <description> - <p><em>Mnesia</em> is a Distributed DataBase Management - System (DBMS), appropriate for telecommunications applications and other - Erlang applications which require continuous operation and exhibit soft - real-time properties. </p> - <p>For information about older versions see - <url href="part_notes_history_frame.html">release notes history</url>.</p> - </description> - <xi:include href="notes.xml"/> -</part> - diff --git a/lib/mnesia/doc/src/part_notes_history.xml b/lib/mnesia/doc/src/part_notes_history.xml deleted file mode 100644 index a1c6f5aef0..0000000000 --- a/lib/mnesia/doc/src/part_notes_history.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE part SYSTEM "part.dtd"> - -<part> - <header> - <copyright> - <year>2004</year> - <year>2016</year> - <holder>Ericsson AB, All Rights Reserved</holder> - </copyright> - <legalnotice> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - The Initial Developer of the Original Code is Ericsson AB. - </legalnotice> - - <title>MNESIA Release Notes</title> - <prepared>Claes Wikström, Hans Nilsson and Håkan Mattsson</prepared> - <docno></docno> - <date>1997-05-27</date> - <rev>1.2</rev> - <file>part_notes_history.sgml</file> - </header> - <description> - <p><em>Mnesia</em> is a Distributed DataBase Management - System (DBMS), appropriate for telecommunications applications and other - Erlang applications which require continuous operation and exhibit soft - real-time properties. </p> - </description> - <include file="notes_history"></include> -</part> - diff --git a/lib/mnesia/doc/src/ref_man.gif b/lib/mnesia/doc/src/ref_man.gif Binary files differdeleted file mode 100644 index b13c4efd53..0000000000 --- a/lib/mnesia/doc/src/ref_man.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/summary.html.src b/lib/mnesia/doc/src/summary.html.src deleted file mode 100644 index 2941a2f46a..0000000000 --- a/lib/mnesia/doc/src/summary.html.src +++ /dev/null @@ -1 +0,0 @@ -A heavy duty real-time distributed database
\ No newline at end of file diff --git a/lib/mnesia/doc/src/user_guide.gif b/lib/mnesia/doc/src/user_guide.gif Binary files differdeleted file mode 100644 index e6275a803d..0000000000 --- a/lib/mnesia/doc/src/user_guide.gif +++ /dev/null diff --git a/lib/mnesia/doc/src/warning.gif b/lib/mnesia/doc/src/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/lib/mnesia/doc/src/warning.gif +++ /dev/null diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile index 08a00e6aba..7d316df263 100644 --- a/lib/mnesia/src/Makefile +++ b/lib/mnesia/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2017. 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. @@ -43,6 +43,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/mnesia-$(VSN) # ---------------------------------------------------- MODULES= \ mnesia \ + mnesia_app \ mnesia_backend_type \ mnesia_backup \ mnesia_bup \ @@ -54,7 +55,6 @@ MODULES= \ mnesia_ext_sup \ mnesia_frag \ mnesia_frag_hash \ - mnesia_frag_old_hash \ mnesia_index \ mnesia_kernel_sup \ mnesia_late_loader \ @@ -67,7 +67,6 @@ MODULES= \ mnesia_registry \ mnesia_schema\ mnesia_snmp_hook \ - mnesia_snmp_sup \ mnesia_subscr \ mnesia_sup \ mnesia_sp \ diff --git a/lib/mnesia/src/mnesia.app.src b/lib/mnesia/src/mnesia.app.src index 006ad4bac1..c755b4d4b9 100644 --- a/lib/mnesia/src/mnesia.app.src +++ b/lib/mnesia/src/mnesia.app.src @@ -3,6 +3,7 @@ {vsn, "%VSN%"}, {modules, [ mnesia, + mnesia_app, mnesia_backend_type, mnesia_backup, mnesia_bup, @@ -14,7 +15,6 @@ mnesia_ext_sup, mnesia_frag, mnesia_frag_hash, - mnesia_frag_old_hash, mnesia_index, mnesia_kernel_sup, mnesia_late_loader, @@ -27,7 +27,6 @@ mnesia_registry, mnesia_schema, mnesia_snmp_hook, - mnesia_snmp_sup, mnesia_subscr, mnesia_sup, mnesia_sp, @@ -49,7 +48,5 @@ mnesia_tm ]}, {applications, [kernel, stdlib]}, - {mod, {mnesia_sup, []}}, - {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-7.0"]}]}. - - + {mod, {mnesia_app, []}}, + {runtime_dependencies, ["stdlib-3.4","kernel-5.3","erts-9.0"]}]}. diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 9586adbf93..223dba3f90 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -138,6 +138,40 @@ -include("mnesia.hrl"). -import(mnesia_lib, [verbose/2]). +-type create_option() :: + {'access_mode', 'read_write' | 'read_only'} | + {'attributes', [atom()]} | + {'disc_copies', [node()]} | + {'disc_only_copies', [node]} | + {'index', [index_attr()]} | + {'load_order', non_neg_integer()} | + {'majority', boolean()} | + {'ram_copies', [node()]} | + {'record_name', atom()} | + {'snmp', SnmpStruct::term()} | + {'storage_properties', [{Backend::module(), [BackendProp::_]}]} | + {'type', 'set' | 'ordered_set' | 'bag'} | + {'local_content', boolean()} | + {'user_properties', proplists:proplist()}. + +-type t_result(Res) :: {'atomic', Res} | {'aborted', Reason::term()}. +-type activity() :: 'ets' | 'async_dirty' | 'sync_dirty' | 'transaction' | 'sync_transaction' | + {'transaction', Retries::non_neg_integer()} | + {'sync_transaction', Retries::non_neg_integer()}. +-type table() :: atom(). +-type storage_type() :: 'ram_copies' | 'disc_copies' | 'disc_only_copies'. +-type index_attr() :: atom() | non_neg_integer(). +-type write_locks() :: 'write' | 'sticky_write'. +-type read_locks() :: 'read'. +-type lock_kind() :: write_locks() | read_locks(). +-type select_continuation() :: term(). +-type snmp_struct() :: [{atom(), snmp_type() | tuple_of(snmp_type())}]. +-type snmp_type() :: 'fix_string' | 'string' | 'integer'. +-type tuple_of(_T) :: tuple(). +-type config_key() :: extra_db_nodes | dc_dump_limit. +-type config_value() :: [node()] | number(). +-type config_result() :: {ok, config_value()} | {error, term()}. + -define(DEFAULT_ACCESS, ?MODULE). %% Select @@ -146,8 +180,8 @@ %% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -196,7 +230,7 @@ e_has_var(X, Pos) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Start and stop - +-spec start() -> 'ok' | {'error', term()}. start() -> start([]). @@ -216,6 +250,7 @@ start_() -> {error, R} end. +-spec start([{Option::atom(), Value::_}]) -> 'ok' | {'error', term()}. start(ExtraEnv) when is_list(ExtraEnv) -> case mnesia_lib:ensure_loaded(?APPLICATION) of ok -> @@ -238,6 +273,7 @@ patched_start([Head | _]) -> patched_start([]) -> start_(). +-spec stop() -> 'stopped' | {'error', term()}. stop() -> case application:stop(?APPLICATION) of ok -> stopped; @@ -245,6 +281,8 @@ stop() -> Other -> Other end. +-spec change_config(Config::config_key(), Value::config_value()) -> + config_result(). change_config(extra_db_nodes, Ns) when is_list(Ns) -> mnesia_controller:connect_nodes(Ns); change_config(dc_dump_limit, N) when is_number(N), N > 0 -> @@ -273,6 +311,7 @@ kill() -> ms() -> [ mnesia, + mnesia_app, mnesia_backup, mnesia_bup, mnesia_checkpoint, @@ -282,7 +321,6 @@ ms() -> mnesia_loader, mnesia_frag, mnesia_frag_hash, - mnesia_frag_old_hash, mnesia_index, mnesia_kernel_sup, mnesia_late_loader, @@ -311,12 +349,12 @@ ms() -> %% Activity mgt -spec abort(_) -> no_return(). - abort(Reason = {aborted, _}) -> exit(Reason); abort(Reason) -> exit({aborted, Reason}). +-spec is_transaction() -> boolean(). is_transaction() -> case get(mnesia_activity_state) of {_, Tid, _Ts} when element(1,Tid) == tid -> @@ -325,29 +363,52 @@ is_transaction() -> false end. +-spec transaction(Fun) -> t_result(Res) when + Fun :: fun(() -> Res). transaction(Fun) -> transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, async). + +-spec transaction(Fun, Retries) -> t_result(Res) when + Fun :: fun(() -> Res), + Retries :: non_neg_integer() | 'infinity'; + (Fun, [Arg::_]) -> t_result(Res) when + Fun :: fun((...) -> Res). transaction(Fun, Retries) when is_integer(Retries), Retries >= 0 -> transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async); transaction(Fun, Retries) when Retries == infinity -> transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, async); transaction(Fun, Args) -> transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, async). + +-spec transaction(Fun, [Arg::_], Retries) -> t_result(Res) when + Fun :: fun((...) -> Res), + Retries :: non_neg_integer() | 'infinity'. transaction(Fun, Args, Retries) -> transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, async). +-spec sync_transaction(Fun) -> t_result(Res) when + Fun :: fun(() -> Res). sync_transaction(Fun) -> transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, sync). + +-spec sync_transaction(Fun, Retries) -> t_result(Res) when + Fun :: fun(() -> Res), + Retries :: non_neg_integer() | 'infinity'; + (Fun, [Arg::_]) -> t_result(Res) when + Fun :: fun((...) -> Res). sync_transaction(Fun, Retries) when is_integer(Retries), Retries >= 0 -> transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync); sync_transaction(Fun, Retries) when Retries == infinity -> transaction(get(mnesia_activity_state), Fun, [], Retries, ?DEFAULT_ACCESS, sync); sync_transaction(Fun, Args) -> transaction(get(mnesia_activity_state), Fun, Args, infinity, ?DEFAULT_ACCESS, sync). + +-spec sync_transaction(Fun, [Arg::_], Retries) -> t_result(Res) when + Fun :: fun((...) -> Res), + Retries :: non_neg_integer() | 'infinity'. sync_transaction(Fun, Args, Retries) -> transaction(get(mnesia_activity_state), Fun, Args, Retries, ?DEFAULT_ACCESS, sync). - transaction(State, Fun, Args, Retries, Mod, Kind) when is_function(Fun), is_list(Args), Retries == infinity, is_atom(Mod) -> mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind); @@ -363,28 +424,60 @@ non_transaction(State, Fun, Args, ActivityKind, Mod) non_transaction(_State, Fun, Args, _ActivityKind, _Mod) -> {aborted, {badarg, Fun, Args}}. +-spec async_dirty(Fun) -> Res | no_return() when + Fun :: fun(() -> Res). async_dirty(Fun) -> async_dirty(Fun, []). + +-spec async_dirty(Fun, [Arg::_]) -> Res | no_return() when + Fun :: fun((...) -> Res). async_dirty(Fun, Args) -> non_transaction(get(mnesia_activity_state), Fun, Args, async_dirty, ?DEFAULT_ACCESS). +-spec sync_dirty(Fun) -> Res | no_return() when + Fun :: fun(() -> Res). sync_dirty(Fun) -> sync_dirty(Fun, []). + +-spec sync_dirty(Fun, [Arg::_]) -> Res | no_return() when + Fun :: fun((...) -> Res). sync_dirty(Fun, Args) -> non_transaction(get(mnesia_activity_state), Fun, Args, sync_dirty, ?DEFAULT_ACCESS). +-spec ets(Fun) -> Res | no_return() when + Fun :: fun(() -> Res). ets(Fun) -> ets(Fun, []). + +-spec ets(Fun, [Arg::_]) -> Res | no_return() when + Fun :: fun((...) -> Res). ets(Fun, Args) -> non_transaction(get(mnesia_activity_state), Fun, Args, ets, ?DEFAULT_ACCESS). +-spec activity(Kind, Fun) -> t_result(Res) | Res when + Kind :: activity(), + Fun :: fun(() -> Res). activity(Kind, Fun) -> activity(Kind, Fun, []). + +-spec activity(Kind, Fun, [Arg::_]) -> t_result(Res) | Res when + Kind :: activity(), + Fun :: fun((...) -> Res); + (Kind, Fun, Mod) -> t_result(Res) | Res when + Kind :: activity(), + Fun :: fun(() -> Res), + Mod :: atom(). + activity(Kind, Fun, Args) when is_list(Args) -> activity(Kind, Fun, Args, mnesia_monitor:get_env(access_module)); activity(Kind, Fun, Mod) -> activity(Kind, Fun, [], Mod). +-spec activity(Kind, Fun, [Arg::_], Mod) -> t_result(Res) | Res when + Kind :: activity(), + Fun :: fun((...) -> Res), + Mod :: atom(). + activity(Kind, Fun, Args, Mod) -> State = get(mnesia_activity_state), case Kind of @@ -414,7 +507,11 @@ wrap_trans(State, Fun, Args, Retries, Mod, Kind) -> %% Nodes may either be a list of nodes or one node as an atom %% Mnesia on all Nodes must be connected to each other, but %% it is not neccessary that they are up and running. - +-spec lock(LockItem, LockKind) -> list() | tuple() | no_return() when + LockItem :: {'record', table(), Key::term()} | + {'table', table()} | + {'global', Key::term(), MnesiaNodes::[node()]}, + LockKind :: lock_kind() | 'load'. lock(LockItem, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -425,6 +522,9 @@ lock(LockItem, LockKind) -> abort(no_transaction) end. +-spec lock_table(Tab::table(), LockKind) -> [MnesiaNode] | no_return() when + MnesiaNode :: node(), + LockKind :: lock_kind() | load. lock_table(Tab, LockKind) -> lock({table, Tab}, LockKind). @@ -446,11 +546,13 @@ lock(Tid, Ts, LockItem, LockKind) -> end. %% Grab a read lock on a whole table +-spec read_lock_table(Tab::table()) -> ok. read_lock_table(Tab) -> lock({table, Tab}, read), ok. %% Grab a write lock on a whole table +-spec write_lock_table(Tab::table()) -> ok. write_lock_table(Tab) -> lock({table, Tab}, write), ok. @@ -515,17 +617,19 @@ good_global_nodes(Nodes) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Access within an activity - updates - +-spec write(Record::tuple()) -> 'ok'. write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), write(Tab, Val, write); write(Val) -> abort({bad_type, Val}). +-spec s_write(Record::tuple()) -> 'ok'. s_write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), write(Tab, Val, sticky_write). +-spec write(Tab::table(), Record::tuple(), LockKind::write_locks()) -> 'ok'. write(Tab, Val, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -572,16 +676,19 @@ write_to_store(Tab, Store, Oid, Val) -> end, ok. +-spec delete({Tab::table(), Key::_}) -> 'ok'. delete({Tab, Key}) -> delete(Tab, Key, write); delete(Oid) -> abort({bad_type, Oid}). +-spec s_delete({Tab::table(), Key::_}) -> 'ok'. s_delete({Tab, Key}) -> delete(Tab, Key, sticky_write); s_delete(Oid) -> abort({bad_type, Oid}). +-spec delete(Tab::table(), Key::_, LockKind::write_locks()) -> 'ok'. delete(Tab, Key, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -618,18 +725,21 @@ delete(Tid, Ts, Tab, Key, LockKind) delete(_Tid, _Ts, Tab, _Key, _LockKind) -> abort({bad_type, Tab}). +-spec delete_object(Rec::tuple()) -> 'ok'. delete_object(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), delete_object(Tab, Val, write); delete_object(Val) -> abort({bad_type, Val}). +-spec s_delete_object(Rec::tuple()) -> 'ok'. s_delete_object(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), delete_object(Tab, Val, sticky_write); s_delete_object(Val) -> abort({bad_type, Val}). +-spec delete_object(Tab::table(), Rec::tuple(), LockKind::write_locks()) -> 'ok'. delete_object(Tab, Val, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -673,12 +783,16 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) -> ?ets_insert(Store, {Oid, Val, delete_object}); _ -> case ?ets_match_object(Store, {Oid, '_', write}) of - [] -> - ?ets_match_delete(Store, {Oid, Val, '_'}), - ?ets_insert(Store, {Oid, Val, delete_object}); - _ -> - ?ets_delete(Store, Oid), - ?ets_insert(Store, {Oid, Oid, delete}) + [] -> + ?ets_match_delete(Store, {Oid, Val, '_'}), + ?ets_insert(Store, {Oid, Val, delete_object}); + Ops -> + case lists:member({Oid, Val, write}, Ops) of + true -> + ?ets_delete(Store, Oid), + ?ets_insert(Store, {Oid, Oid, delete}); + false -> ok + end end end, ok; @@ -689,19 +803,23 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Access within an activity - read +-spec read(Tab::table(), Key::_) -> [tuple()]. read(Tab, Key) -> read(Tab, Key, read). +-spec read({Tab::table(), Key::_}) -> [tuple()]. read({Tab, Key}) -> read(Tab, Key, read); read(Oid) -> abort({bad_type, Oid}). +-spec wread({Tab::table(), Key::_}) -> [tuple()]. wread({Tab, Key}) -> read(Tab, Key, write); wread(Oid) -> abort({bad_type, Oid}). +-spec read(Tab::table(), Key::_, LockKind::lock_kind()) -> [tuple()]. read(Tab, Key, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -738,6 +856,7 @@ read(Tid, Ts, Tab, Key, LockKind) read(_Tid, _Ts, Tab, _Key, _LockKind) -> abort({bad_type, Tab}). +-spec first(Tab::table()) -> Key::term(). first(Tab) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -765,6 +884,7 @@ first(Tid, Ts, Tab) first(_Tid, _Ts,Tab) -> abort({bad_type, Tab}). +-spec last(Tab::table()) -> Key::term(). last(Tab) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -792,6 +912,7 @@ last(Tid, Ts, Tab) last(_Tid, _Ts,Tab) -> abort({bad_type, Tab}). +-spec next(Tab::table(), Key::term()) -> NextKey::term(). next(Tab,Key) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS,Tid,Ts} -> @@ -818,6 +939,7 @@ next(Tid,Ts,Tab,Key) next(_Tid, _Ts,Tab,_) -> abort({bad_type, Tab}). +-spec prev(Tab::table(), Key::term()) -> PrevKey::term(). prev(Tab,Key) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS,Tid,Ts} -> @@ -952,6 +1074,8 @@ ts_keys_1([], Acc) -> %%%%%%%%%%%%%%%%%%%%% %% Iterators +-spec foldl(Fun, Acc0, Tab::table()) -> Acc when + Fun::fun((Record::tuple(), Acc0) -> Acc). foldl(Fun, Acc, Tab) -> foldl(Fun, Acc, Tab, read). @@ -992,6 +1116,8 @@ do_foldl(A, O, Tab, Key, Fun, Acc, Type, Stored) -> %% Type is set or bag {_, Tid, Ts} = get(mnesia_activity_state), do_foldl(Tid, Ts, Tab, dirty_next(Tab, Key), Fun, NewAcc, Type, NewStored). +-spec foldr(Fun, Acc0, Tab::table()) -> Acc when + Fun::fun((Record::tuple(), Acc0) -> Acc). foldr(Fun, Acc, Tab) -> foldr(Fun, Acc, Tab, read). foldr(Fun, Acc, Tab, LockKind) when is_function(Fun) -> @@ -1105,12 +1231,15 @@ add_written_to_bag([{_, _ , delete} | Tail], _Objs, _Ack) -> add_written_to_bag([{_, Val, delete_object} | Tail], Objs, Ack) -> add_written_to_bag(Tail, lists:delete(Val, Objs), lists:delete(Val, Ack)). +-spec match_object(Pattern::tuple()) -> [Record::tuple()]. match_object(Pat) when is_tuple(Pat), tuple_size(Pat) > 2 -> Tab = element(1, Pat), match_object(Tab, Pat, read); match_object(Pat) -> abort({bad_type, Pat}). +-spec match_object(Tab,Pattern,LockKind) -> [Record] when + Tab::table(),Pattern::tuple(),LockKind::lock_kind(),Record::tuple(). match_object(Tab, Pat, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1270,9 +1399,13 @@ deloid(Oid, [H | T]) -> %%%%%%%%%%%%%%%%%% % select - +-spec select(Tab, Spec) -> [Match] when + Tab::table(), Spec::ets:match_spec(), Match::term(). select(Tab, Pat) -> select(Tab, Pat, read). +-spec select(Tab, Spec, LockKind) -> [Match] when + Tab::table(), Spec::ets:match_spec(), + Match::term(),LockKind::lock_kind(). select(Tab, Pat, LockKind) when is_atom(Tab), Tab /= schema, is_list(Pat) -> case get(mnesia_activity_state) of @@ -1331,6 +1464,11 @@ select_lock(Tid,Ts,LockKind,Spec,Tab) -> end. %% Breakable Select +-spec select(Tab, Spec, N, LockKind) -> {[Match], Cont} | '$end_of_table' when + Tab::table(), Spec::ets:match_spec(), + Match::term(), N::non_neg_integer(), + LockKind::lock_kind(), + Cont::select_continuation(). select(Tab, Pat, NObjects, LockKind) when is_atom(Tab), Tab /= schema, is_list(Pat), is_integer(NObjects) -> case get(mnesia_activity_state) of @@ -1387,6 +1525,9 @@ fun_select(Tid, Ts, Tab, Spec, LockKind, TabPat, Init, NObjects, Node, Storage) select_state(Init(Spec),Def) end. +-spec select(Cont) -> {[Match], Cont} | '$end_of_table' when + Match::term(), + Cont::select_continuation(). select(Cont) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1409,8 +1550,14 @@ select_cont(Tid,_,State=#mnesia_select{tid=Tid,written=[]}) -> select_state(dirty_sel_cont(State),State); select_cont(Tid,_Ts,State=#mnesia_select{tid=Tid}) -> trans_select(dirty_sel_cont(State), State); -select_cont(_Tid2,_,#mnesia_select{tid=_Tid1}) -> % Missmatching tids +select_cont(Tid2,_,#mnesia_select{tid=_Tid1}) + when element(1,Tid2) == tid -> % Mismatching tids abort(wrong_transaction); +select_cont(Tid,Ts,State=#mnesia_select{}) -> + % Repair mismatching tids in non-transactional contexts + RepairedState = State#mnesia_select{tid = Tid, written = [], + spec = undefined, type = undefined}, + select_cont(Tid,Ts,RepairedState); select_cont(_,_,Cont) -> abort({badarg, Cont}). @@ -1430,6 +1577,7 @@ get_record_pattern([]) -> []; get_record_pattern([{M,C,_B}|R]) -> [{M,C,['$_']} | get_record_pattern(R)]. +-spec all_keys(Tab::table()) -> [Key::term()]. all_keys(Tab) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1454,12 +1602,20 @@ all_keys(Tid, Ts, Tab, LockKind) all_keys(_Tid, _Ts, Tab, _LockKind) -> abort({bad_type, Tab}). +-spec index_match_object(Pattern, Attr) -> [Record] when + Pattern::tuple(), Attr::index_attr(), Record::tuple(). index_match_object(Pat, Attr) when is_tuple(Pat), tuple_size(Pat) > 2 -> Tab = element(1, Pat), index_match_object(Tab, Pat, Attr, read); index_match_object(Pat, _Attr) -> abort({bad_type, Pat}). +-spec index_match_object(Tab, Pattern, Attr, LockKind) -> [Record] when + Tab::table(), + Pattern::tuple(), + Attr::index_attr(), + LockKind::lock_kind(), + Record::tuple(). index_match_object(Tab, Pat, Attr, LockKind) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1496,6 +1652,11 @@ index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind) index_match_object(_Tid, _Ts, Tab, Pat, _Attr, _LockKind) -> abort({bad_type, Tab, Pat}). +-spec index_read(Tab, Key, Attr) -> [Record] when + Tab::table(), + Key::term(), + Attr::index_attr(), + Record::tuple(). index_read(Tab, Key, Attr) -> case get(mnesia_activity_state) of {?DEFAULT_ACCESS, Tid, Ts} -> @@ -1535,13 +1696,14 @@ index_read(_Tid, _Ts, Tab, _Key, _Attr, _LockKind) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Dirty access regardless of activities - updates - +-spec dirty_write(Record::tuple()) -> 'ok'. dirty_write(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), dirty_write(Tab, Val); dirty_write(Val) -> abort({bad_type, Val}). +-spec dirty_write(Tab::table(), Record::tuple()) -> 'ok'. dirty_write(Tab, Val) -> do_dirty_write(async_dirty, Tab, Val). @@ -1553,11 +1715,13 @@ do_dirty_write(SyncMode, Tab, Val) do_dirty_write(_SyncMode, Tab, Val) -> abort({bad_type, Tab, Val}). +-spec dirty_delete({Tab::table(), Key::_}) -> 'ok'. dirty_delete({Tab, Key}) -> dirty_delete(Tab, Key); dirty_delete(Oid) -> abort({bad_type, Oid}). +-spec dirty_delete(Tab::table(), Key::_) -> 'ok'. dirty_delete(Tab, Key) -> do_dirty_delete(async_dirty, Tab, Key). @@ -1567,12 +1731,14 @@ do_dirty_delete(SyncMode, Tab, Key) when is_atom(Tab), Tab /= schema -> do_dirty_delete(_SyncMode, Tab, _Key) -> abort({bad_type, Tab}). +-spec dirty_delete_object(Record::tuple()) -> 'ok'. dirty_delete_object(Val) when is_tuple(Val), tuple_size(Val) > 2 -> Tab = element(1, Val), dirty_delete_object(Tab, Val); dirty_delete_object(Val) -> abort({bad_type, Val}). +-spec dirty_delete_object(Tab::table(), Record::tuple()) -> 'ok'. dirty_delete_object(Tab, Val) -> do_dirty_delete_object(async_dirty, Tab, Val). @@ -1590,12 +1756,15 @@ do_dirty_delete_object(_SyncMode, Tab, Val) -> abort({bad_type, Tab, Val}). %% A Counter is an Oid being {CounterTab, CounterName} - +-spec dirty_update_counter({Tab::table(), Key::_}, Incr::integer()) -> + NewVal::integer(). dirty_update_counter({Tab, Key}, Incr) -> dirty_update_counter(Tab, Key, Incr); dirty_update_counter(Counter, _Incr) -> abort({bad_type, Counter}). +-spec dirty_update_counter(Tab::table(), Key::_, Incr::integer()) -> + NewVal::integer(). dirty_update_counter(Tab, Key, Incr) -> do_dirty_update_counter(async_dirty, Tab, Key, Incr). @@ -1614,23 +1783,28 @@ do_dirty_update_counter(_SyncMode, Tab, _Key, Incr) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Dirty access regardless of activities - read +-spec dirty_read({Tab::table(), Key::_}) -> [tuple()]. dirty_read({Tab, Key}) -> dirty_read(Tab, Key); dirty_read(Oid) -> abort({bad_type, Oid}). +-spec dirty_read(Tab::table(), Key::_) -> [tuple()]. dirty_read(Tab, Key) when is_atom(Tab), Tab /= schema -> dirty_rpc(Tab, mnesia_lib, db_get, [Tab, Key]); dirty_read(Tab, _Key) -> abort({bad_type, Tab}). +-spec dirty_match_object(Pattern::tuple()) -> [Record::tuple()]. dirty_match_object(Pat) when is_tuple(Pat), tuple_size(Pat) > 2 -> Tab = element(1, Pat), dirty_match_object(Tab, Pat); dirty_match_object(Pat) -> abort({bad_type, Pat}). +-spec dirty_match_object(Tab,Pattern) -> [Record] when + Tab::table(), Pattern::tuple(), Record::tuple(). dirty_match_object(Tab, Pat) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> dirty_rpc(Tab, ?MODULE, remote_dirty_match_object, [Tab, Pat]); @@ -1660,6 +1834,8 @@ remote_dirty_match_object(Tab, Pat, []) -> remote_dirty_match_object(Tab, Pat, _PosList) -> abort({bad_type, Tab, Pat}). +-spec dirty_select(Tab, Spec) -> [Match] when + Tab::table(), Spec::ets:match_spec(), Match::term(). dirty_select(Tab, Spec) when is_atom(Tab), Tab /= schema, is_list(Spec) -> dirty_rpc(Tab, ?MODULE, remote_dirty_select, [Tab, Spec]); dirty_select(Tab, Spec) -> @@ -1708,6 +1884,7 @@ dirty_sel_cont(#mnesia_select{cont='$end_of_table'}) -> '$end_of_table'; dirty_sel_cont(#mnesia_select{node=Node,tab=Tab,storage=Type,cont=Cont,orig=Ms}) -> do_dirty_rpc(Tab,Node,mnesia_lib,db_select_cont,[Type,Cont,Ms]). +-spec dirty_all_keys(Tab::table()) -> [Key::term()]. dirty_all_keys(Tab) when is_atom(Tab), Tab /= schema -> case ?catch_val({Tab, wild_pattern}) of {'EXIT', _} -> @@ -1723,12 +1900,19 @@ dirty_all_keys(Tab) when is_atom(Tab), Tab /= schema -> dirty_all_keys(Tab) -> abort({bad_type, Tab}). +-spec dirty_index_match_object(Pattern, Attr) -> [Record] when + Pattern::tuple(), Attr::index_attr(), Record::tuple(). dirty_index_match_object(Pat, Attr) when is_tuple(Pat), tuple_size(Pat) > 2 -> Tab = element(1, Pat), dirty_index_match_object(Tab, Pat, Attr); dirty_index_match_object(Pat, _Attr) -> abort({bad_type, Pat}). +-spec dirty_index_match_object(Tab, Pattern, Attr) -> [Record] when + Tab::table(), + Pattern::tuple(), + Attr::index_attr(), + Record::tuple(). dirty_index_match_object(Tab, Pat, Attr) when is_atom(Tab), Tab /= schema, is_tuple(Pat), tuple_size(Pat) > 2 -> case mnesia_schema:attr_tab_to_pos(Tab, Attr) of @@ -1752,6 +1936,11 @@ dirty_index_match_object(Tab, Pat, Attr) dirty_index_match_object(Tab, Pat, _Attr) -> abort({bad_type, Tab, Pat}). +-spec dirty_index_read(Tab, Key, Attr) -> [Record] when + Tab::table(), + Key::term(), + Attr::index_attr(), + Record::tuple(). dirty_index_read(Tab, Key, Attr) when is_atom(Tab), Tab /= schema -> Pos = mnesia_schema:attr_tab_to_pos(Tab, Attr), case has_var(Key) of @@ -1763,26 +1952,31 @@ dirty_index_read(Tab, Key, Attr) when is_atom(Tab), Tab /= schema -> dirty_index_read(Tab, _Key, _Attr) -> abort({bad_type, Tab}). +%% do not use only for backwards compatibility dirty_slot(Tab, Slot) when is_atom(Tab), Tab /= schema, is_integer(Slot) -> dirty_rpc(Tab, mnesia_lib, db_slot, [Tab, Slot]); dirty_slot(Tab, Slot) -> abort({bad_type, Tab, Slot}). +-spec dirty_first(Tab::table()) -> Key::term(). dirty_first(Tab) when is_atom(Tab), Tab /= schema -> dirty_rpc(Tab, mnesia_lib, db_first, [Tab]); dirty_first(Tab) -> abort({bad_type, Tab}). +-spec dirty_last(Tab::table()) -> Key::term(). dirty_last(Tab) when is_atom(Tab), Tab /= schema -> dirty_rpc(Tab, mnesia_lib, db_last, [Tab]); dirty_last(Tab) -> abort({bad_type, Tab}). +-spec dirty_next(Tab::table(), Key::_) -> NextKey::term(). dirty_next(Tab, Key) when is_atom(Tab), Tab /= schema -> dirty_rpc(Tab, mnesia_lib, db_next_key, [Tab, Key]); dirty_next(Tab, _Key) -> abort({bad_type, Tab}). +-spec dirty_prev(Tab::table(), Key::_) -> PrevKey::term(). dirty_prev(Tab, Key) when is_atom(Tab), Tab /= schema -> dirty_rpc(Tab, mnesia_lib, db_prev_key, [Tab, Key]); dirty_prev(Tab, _Key) -> @@ -1833,7 +2027,7 @@ do_dirty_rpc(Tab, Node, M, F, Args) -> %% Info %% Info about one table --spec table_info(atom(), any()) -> any(). +-spec table_info(Tab::table(), Item::term()) -> Info::term(). table_info(Tab, Item) -> case get(mnesia_activity_state) of undefined -> @@ -1876,9 +2070,10 @@ any_table_info(Tab, Item) when is_atom(Tab) -> [] -> abort({no_exists, Tab, Item}); Props -> - lists:map(fun({setorbag, Type}) -> {type, Type}; - (Prop) -> Prop end, - Props) + Rename = fun ({setorbag, Type}) -> {type, Type}; + (Prop) -> Prop + end, + lists:sort(lists:map(Rename, Props)) end; name -> Tab; @@ -1921,16 +2116,20 @@ bad_info_reply(_Tab, memory) -> 0; bad_info_reply(Tab, Item) -> abort({no_exists, Tab, Item}). %% Raw info about all tables +-spec schema() -> ok. schema() -> mnesia_schema:info(). %% Raw info about one tables +-spec schema(Tab::table()) -> ok. schema(Tab) -> mnesia_schema:info(Tab). +-spec error_description(Error::term()) -> string(). error_description(Err) -> mnesia_lib:error_desc(Err). +-spec info() -> ok. info() -> case mnesia_lib:is_running() of yes -> @@ -2056,6 +2255,7 @@ display_tab_info() -> Rdisp = fun({Rpat, Rtabs}) -> io:format("~p = ~p~n", [Rpat, Rtabs]) end, lists:foreach(Rdisp, lists:sort(Repl)). +-spec get_backend_types() -> [BackendType::term()]. get_backend_types() -> case ?catch_val({schema, user_property, mnesia_backend_types}) of {'EXIT', _} -> @@ -2064,6 +2264,7 @@ get_backend_types() -> lists:sort(Ts) end. +-spec get_index_plugins() -> [IndexPlugins::term()]. get_index_plugins() -> case ?catch_val({schema, user_property, mnesia_index_plugins}) of {'EXIT', _} -> @@ -2091,9 +2292,9 @@ list_index_plugins([{N,M,F} | T] = Ps, Legend) -> lists:foldl(fun({N1,_,_}, Wa) -> erlang:max(Wa, length(pp_ix_name(N1))) end, 0, Ps)), - io:fwrite(Legend ++ "~-" ++ W ++ "s - ~s:~s~n", + io:fwrite(Legend ++ "~-" ++ W ++ "s - ~s:~ts~n", [pp_ix_name(N), atom_to_list(M), atom_to_list(F)]), - [io:fwrite(Indent ++ "~-" ++ W ++ "s - ~s:~s~n", + [io:fwrite(Indent ++ "~-" ++ W ++ "s - ~s:~ts~n", [pp_ix_name(N1), atom_to_list(M1), atom_to_list(F1)]) || {N1,M1,F1} <- T]. @@ -2112,6 +2313,7 @@ storage_count(T, {U, R, D, DO, Ext}) -> {ext, A, _} -> {U, R, D, DO, orddict:append(A, T, Ext)} end. +-spec system_info(Iterm::term()) -> Info::term(). system_info(Item) -> try system_info2(Item) catch _:Error -> abort(Error) @@ -2361,83 +2563,134 @@ load_mnesia_or_abort() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Database mgt +-spec create_schema(Ns::[node()]) -> 'ok' | {'error', Reason::term()}. create_schema(Ns) -> create_schema(Ns, []). +-spec create_schema(Ns::[node()], [Prop]) -> 'ok' | {'error', Reason::term()} when + Prop :: BackendType | IndexPlugin, + BackendType :: {backend_types, [{Name::atom(), Module::module()}]}, + IndexPlugin :: {index_plugins, [{{Name::atom()}, Module::module(), Function::atom()}]}. create_schema(Ns, Properties) -> mnesia_bup:create_schema(Ns, Properties). +-spec delete_schema(Ns::[node()]) -> 'ok' | {'error', Reason::term()}. delete_schema(Ns) -> mnesia_schema:delete_schema(Ns). +-spec add_backend_type(Name::atom(), Module::module()) -> t_result('ok'). add_backend_type(Alias, Module) -> mnesia_schema:add_backend_type(Alias, Module). +-spec backup(Dest::term()) -> 'ok' | {'error', Reason::term()}. backup(Opaque) -> mnesia_log:backup(Opaque). +-spec backup(Dest::term(), Mod::module()) -> + 'ok' | {'error', Reason::term()}. backup(Opaque, Mod) -> mnesia_log:backup(Opaque, Mod). +-spec traverse_backup(Src::term(), Dest::term(), Fun, Acc) -> + {'ok', Acc} | {'error', Reason::term()} when + Fun :: fun((Items, Acc) -> {Items,Acc}). traverse_backup(S, T, Fun, Acc) -> mnesia_bup:traverse_backup(S, T, Fun, Acc). +-spec traverse_backup(Src::term(), SrcMod::module(), + Dest::term(), DestMod::module(), + Fun, Acc) -> + {'ok', Acc} | {'error', Reason::term()} when + Fun :: fun((Items, Acc) -> {Items,Acc}). traverse_backup(S, SM, T, TM, F, A) -> mnesia_bup:traverse_backup(S, SM, T, TM, F, A). +-spec install_fallback(Src::term()) -> 'ok' | {'error', Reason::term()}. install_fallback(Opaque) -> mnesia_bup:install_fallback(Opaque). +-spec install_fallback(Src::term(), Mod::module()|[Opt]) -> + 'ok' | {'error', Reason::term()} when + Opt :: Module | Scope | Dir, + Module :: {'module', Mod::module()}, + Scope :: {'scope', 'global' | 'local'}, + Dir :: {'mnesia_dir', Dir::string()}. install_fallback(Opaque, Mod) -> mnesia_bup:install_fallback(Opaque, Mod). +-spec uninstall_fallback() -> 'ok' | {'error', Reason::term()}. uninstall_fallback() -> mnesia_bup:uninstall_fallback(). +-spec uninstall_fallback(Args) -> 'ok' | {'error', Reason::term()} when + Args :: [{'mnesia_dir', Dir::string()}]. uninstall_fallback(Args) -> mnesia_bup:uninstall_fallback(Args). +-spec activate_checkpoint([Arg]) -> {'ok', Name, [node()]} | {'error', Reason::term()} when + Arg :: {'name', Name} | {'max', [table()]} | {'min', [table()]} | + {'allow_remote', boolean()} | {'ram_overrides_dump', boolean()}. activate_checkpoint(Args) -> mnesia_checkpoint:activate(Args). +-spec deactivate_checkpoint(Name::_) -> 'ok' | {'error', Reason::term()}. deactivate_checkpoint(Name) -> mnesia_checkpoint:deactivate(Name). +-spec backup_checkpoint(Name::_, Dest::_) -> 'ok' | {'error', Reason::term()}. backup_checkpoint(Name, Opaque) -> mnesia_log:backup_checkpoint(Name, Opaque). +-spec backup_checkpoint(Name::_, Dest::_, Mod::module()) -> + 'ok' | {'error', Reason::term()}. backup_checkpoint(Name, Opaque, Mod) -> mnesia_log:backup_checkpoint(Name, Opaque, Mod). +-spec restore(Src::_, [Arg]) -> t_result([table()]) when + Op :: 'skip_tables' | 'clear_tables' | 'keep_tables' | 'restore_tables', + Arg :: {'module', module()} | {Op, [table()]} | {'default_op', Op}. restore(Opaque, Args) -> mnesia_schema:restore(Opaque, Args). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - +-spec create_table([Arg]) -> t_result('ok') when + Arg :: {'name', table()} | create_option(). create_table(Arg) -> mnesia_schema:create_table(Arg). + +-spec create_table(Name::table(), [create_option()]) -> t_result('ok'). create_table(Name, Arg) when is_list(Arg) -> mnesia_schema:create_table([{name, Name}| Arg]); create_table(Name, Arg) -> {aborted, badarg, Name, Arg}. +-spec delete_table(Tab::table()) -> t_result('ok'). delete_table(Tab) -> mnesia_schema:delete_table(Tab). +-spec add_table_copy(Tab::table(), N::node(), ST::storage_type()) -> t_result(ok). add_table_copy(Tab, N, S) -> mnesia_schema:add_table_copy(Tab, N, S). + +-spec del_table_copy(Tab::table(), N::node()) -> t_result(ok). del_table_copy(Tab, N) -> mnesia_schema:del_table_copy(Tab, N). +-spec move_table_copy(Tab::table(), From::node(), To::node()) -> t_result(ok). move_table_copy(Tab, From, To) -> mnesia_schema:move_table(Tab, From, To). +-spec add_table_index(Tab::table(), I::index_attr()) -> t_result(ok). add_table_index(Tab, Ix) -> mnesia_schema:add_table_index(Tab, Ix). +-spec del_table_index(Tab::table(), I::index_attr()) -> t_result(ok). del_table_index(Tab, Ix) -> mnesia_schema:del_table_index(Tab, Ix). +-spec transform_table(Tab::table(), Fun, [Attr]) -> t_result(ok) when + Attr :: atom(), + Fun:: fun((Record::tuple()) -> Transformed::tuple()) | ignore. transform_table(Tab, Fun, NewA) -> try val({Tab, record_name}) of OldRN -> mnesia_schema:transform_table(Tab, Fun, NewA, OldRN) @@ -2445,12 +2698,18 @@ transform_table(Tab, Fun, NewA) -> mnesia:abort(Reason) end. +-spec transform_table(Tab::table(), Fun, [Attr], RecName) -> t_result(ok) when + RecName :: atom(), + Attr :: atom(), + Fun:: fun((Record::tuple()) -> Transformed::tuple()) | ignore. transform_table(Tab, Fun, NewA, NewRN) -> mnesia_schema:transform_table(Tab, Fun, NewA, NewRN). +-spec change_table_copy_type(Tab::table(), Node::node(), To::storage_type()) -> t_result(ok). change_table_copy_type(T, N, S) -> mnesia_schema:change_table_copy_type(T, N, S). +-spec clear_table(Tab::table()) -> t_result(ok). clear_table(Tab) -> case get(mnesia_activity_state) of State = {Mod, Tid, _Ts} when element(1, Tid) =/= tid -> @@ -2480,19 +2739,22 @@ clear_table(Tid, Ts, Tab, Obj) when element(1, Tid) =:= tid -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - user properties - +-spec read_table_property(Tab::table(), PropKey::term()) -> Res::tuple(). read_table_property(Tab, PropKey) -> val({Tab, user_property, PropKey}). +-spec write_table_property(Tab::table(), Prop::tuple()) -> t_result(ok). write_table_property(Tab, Prop) -> mnesia_schema:write_table_property(Tab, Prop). +-spec delete_table_property(Tab::table(), PropKey::term()) -> t_result(ok). delete_table_property(Tab, PropKey) -> mnesia_schema:delete_table_property(Tab, PropKey). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Table mgt - user properties +-spec change_table_frag(Tab::table(), FP::term()) -> t_result(ok). change_table_frag(Tab, FragProp) -> mnesia_schema:change_table_frag(Tab, FragProp). @@ -2500,28 +2762,38 @@ change_table_frag(Tab, FragProp) -> %% Table mgt - table load %% Dump a ram table to disc +-spec dump_tables([Tab::table()]) -> t_result(ok). dump_tables(Tabs) -> mnesia_schema:dump_tables(Tabs). %% allow the user to wait for some tables to be loaded +-spec wait_for_tables([Tab::table()], TMO::timeout()) -> + 'ok' | {'timeout', [table()]} | {'error', Reason::term()}. wait_for_tables(Tabs, Timeout) -> mnesia_controller:wait_for_tables(Tabs, Timeout). +-spec force_load_table(Tab::table()) -> 'yes' | {'error', Reason::term()}. force_load_table(Tab) -> case mnesia_controller:force_load_table(Tab) of ok -> yes; % Backwards compatibility Other -> Other end. +-spec change_table_access_mode(Tab::table(), Mode) -> t_result(ok) when + Mode :: 'read_only'|'read_write'. change_table_access_mode(T, Access) -> mnesia_schema:change_table_access_mode(T, Access). +-spec change_table_load_order(Tab::table(), Order) -> t_result(ok) when + Order :: non_neg_integer(). change_table_load_order(T, O) -> mnesia_schema:change_table_load_order(T, O). +-spec change_table_majority(Tab::table(), M::boolean()) -> t_result(ok). change_table_majority(T, M) -> mnesia_schema:change_table_majority(T, M). +-spec set_master_nodes(Ns::[node()]) -> 'ok' | {'error', Reason::term()}. set_master_nodes(Nodes) when is_list(Nodes) -> UseDir = system_info(use_dir), IsRunning = system_info(is_running), @@ -2560,6 +2832,8 @@ log_valid_master_nodes(Cstructs, Nodes, UseDir, IsRunning) -> Args = lists:map(Fun, Cstructs), mnesia_recover:log_master_nodes(Args, UseDir, IsRunning). +-spec set_master_nodes(Tab::table(), Ns::[node()]) -> + 'ok' | {'error', Reason::term()}. set_master_nodes(Tab, Nodes) when is_list(Nodes) -> UseDir = system_info(use_dir), IsRunning = system_info(is_running), @@ -2610,31 +2884,39 @@ set_master_nodes(Tab, Nodes) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Misc admin - +-spec dump_log() -> 'dumped'. dump_log() -> mnesia_controller:sync_dump_log(user). +-spec sync_log() -> 'ok' | {'error', Reason::term()}. sync_log() -> mnesia_monitor:sync_log(latest_log). +-spec subscribe(What) -> {'ok', node()} | {'error', Reason::term()} when + What :: 'system' | 'activity' | {'table', table(), 'simple' | 'detailed'}. subscribe(What) -> mnesia_subscr:subscribe(self(), What). +-spec unsubscribe(What) -> {'ok', node()} | {'error', Reason::term()} when + What :: 'system' | 'activity' | {'table', table(), 'simple' | 'detailed'}. unsubscribe(What) -> mnesia_subscr:unsubscribe(self(), What). +-spec report_event(Event::_) -> 'ok'. report_event(Event) -> mnesia_lib:report_system_event({mnesia_user, Event}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Snmp - +-spec snmp_open_table(Tab::table(), Snmp::snmp_struct()) -> ok. snmp_open_table(Tab, Us) -> mnesia_schema:add_snmp(Tab, Us). +-spec snmp_close_table(Tab::table()) -> ok. snmp_close_table(Tab) -> mnesia_schema:del_snmp(Tab). +-spec snmp_get_row(Tab::table(), [integer()]) -> {'ok', Row::tuple()} | 'undefined'. snmp_get_row(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) -> case get(mnesia_activity_state) of {Mod, Tid, Ts=#tidstore{store=Store}} when element(1, Tid) =:= tid -> @@ -2670,7 +2952,7 @@ snmp_get_row(Tab, _RowIndex) -> abort({bad_type, Tab}). %%%%%%%%%%%%% - +-spec snmp_get_next_index(Tab::table(), [integer()]) -> {'ok', [integer()]} | 'endOfTable'. snmp_get_next_index(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) -> {Next,OrigKey} = dirty_rpc(Tab, mnesia_snmp_hook, get_next_index, [Tab, RowIndex]), case get(mnesia_activity_state) of @@ -2712,7 +2994,7 @@ get_ordered_snmp_key(_, []) -> endOfTable. %%%%%%%%%% - +-spec snmp_get_mnesia_key(Tab::table(), [integer()]) -> {'ok', Key::term()} | 'undefined'. snmp_get_mnesia_key(Tab, RowIndex) when is_atom(Tab), Tab /= schema, is_list(RowIndex) -> case get(mnesia_activity_state) of {_Mod, Tid, Ts} when element(1, Tid) =:= tid -> @@ -2776,17 +3058,27 @@ snmp_filter_key(undefined, RowIndex, Tab, Store) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Textfile access - +-spec load_textfile(File::file:filename()) -> t_result(ok) | {'error', term()}. load_textfile(F) -> mnesia_text:load_textfile(F). + +-spec dump_to_textfile(File :: file:filename()) -> 'ok' | 'error' | {'error', term()}. dump_to_textfile(F) -> mnesia_text:dump_to_textfile(F). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% QLC Handles %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec table(Tab::table()) -> qlc:query_handle(). table(Tab) -> table(Tab, []). + +-spec table(Tab::table(), Options) -> qlc:query_handle() when + Options :: Option | [Option], + Option :: MnesiaOpt | QlcOption, + MnesiaOpt :: {'traverse', SelectOp} | {lock, lock_kind()} | {n_objects, non_neg_integer()}, + SelectOp :: 'select' | {'select', ets:match_spec()}, + QlcOption :: {'key_equality', '==' | '=:='}. table(Tab,Opts) -> {[Trav,Lock,NObjects],QlcOptions0} = qlc_opts(Opts,[{traverse,select},{lock,read},{n_objects,100}]), diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl index 0716dd87c8..fe48a6fe3d 100644 --- a/lib/mnesia/src/mnesia.hrl +++ b/lib/mnesia/src/mnesia.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -47,14 +47,18 @@ -define(catch_val(Var), (try ?ets_lookup_element(mnesia_gvar, Var, 2) catch error:_ -> {'EXIT', {badarg, []}} end)). +-define(catch_val_and_stack(Var), + (try ?ets_lookup_element(mnesia_gvar, Var, 2) + catch error:_:_Stacktrace -> {'EXIT', _Stacktrace} end)). + %% It's important that counter is first, since we compare tid's --record(tid, +-record(tid, {counter, %% serial no for tid pid}). %% owner of tid --record(tidstore, +-record(tidstore, {store, %% current ets table for tid up_stores = [], %% list of upper layer stores for nested trans level = 1}). %% transaction level @@ -128,5 +132,4 @@ mnesia_lib:eval_debug_fun(I, C, ?FILE, ?LINE)). -else. -define(eval_debug_fun(I, C), ok). --endif. - +-endif. diff --git a/lib/mnesia/src/mnesia_app.erl b/lib/mnesia/src/mnesia_app.erl new file mode 100644 index 0000000000..4d89011db2 --- /dev/null +++ b/lib/mnesia/src/mnesia_app.erl @@ -0,0 +1,41 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2016. 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. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(mnesia_app). + +-behaviour(application). + +-export([start/2, stop/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% application callback functions + +start(normal, Args) -> + case mnesia_sup:start_link(Args) of + {ok, Pid} -> + {ok, Pid, {normal, Args}}; + Error -> + Error + end; +start(_, _) -> + {error, badarg}. + +stop(_StartArgs) -> + ok. diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 3e55deb958..e57fc5199d 100644 --- a/lib/mnesia/src/mnesia_bup.erl +++ b/lib/mnesia/src/mnesia_bup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -90,9 +90,9 @@ iterate(Mod, Fun, Opaque, Acc) -> catch throw:Err -> close_read(R2), Err; - _:Reason -> + _:Reason:Stacktrace -> close_read(R2), - {error, {Reason, erlang:get_stacktrace()}} + {error, {Reason, Stacktrace}} end catch throw:{error,_} = Err -> Err @@ -198,9 +198,9 @@ do_read_schema_section(R) -> try {R3, RawSchema} = safe_apply(R2, read, [R2#restore.bup_data]), do_read_schema_section(R3, verify_header(RawSchema), []) - catch T:E -> + catch T:E:S -> close_read(R2), - erlang:raise(T,E,erlang:get_stacktrace()) + erlang:raise(T,E,S) end. do_read_schema_section(R, {ok, B, C, []}, Acc) -> @@ -920,7 +920,7 @@ create_dat_files([{schema, Tab, TabDef} | Tail], Ext, LocalTabs) -> ok -> ok; {error, Reason} -> - mnesia_lib:fatal("Cannot rename file ~p -> ~p: ~p~n", + mnesia_lib:fatal("Cannot rename file ~tp -> ~tp: ~tp~n", [TmpFile, DclFile, Reason]) end end @@ -1016,7 +1016,7 @@ disc_only_swap_fun(disc_only_copies, Expunge, Open, Close) -> ok -> ok; {error, Reason} -> - mnesia_lib:fatal("Cannot rename file ~p -> ~p: ~p~n", + mnesia_lib:fatal("Cannot rename file ~tp -> ~tp: ~tp~n", [TmpFile, DatFile, Reason]) end end; diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl index 9eb939e8d3..3273d3d27e 100644 --- a/lib/mnesia/src/mnesia_checkpoint.erl +++ b/lib/mnesia/src/mnesia_checkpoint.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016 +%% Copyright Ericsson AB 1996-2018 %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -683,14 +683,14 @@ retainer_create(_Cp, R, Tab, Name, Ext = {ext, Alias, Mod}) -> Cs = val({Tab, cstruct}), Mod:load_table(Alias, T, {retainer, create_table}, mnesia_schema:cs2list(Cs)), - dbg_out("Checkpoint retainer created ~p ~p~n", [Name, Tab]), + dbg_out("Checkpoint retainer created ~p ~tp~n", [Name, Tab]), R#retainer{store = {Ext, T}, really_retain = true}; retainer_create(_Cp, R, Tab, Name, disc_only_copies) -> Fname = tab2retainer({Tab, Name}), file:delete(Fname), Args = [{file, Fname}, {type, set}, {keypos, 2}, {repair, false}], {ok, _} = mnesia_lib:dets_sync_open({Tab, Name}, Args), - dbg_out("Checkpoint retainer created ~p ~p~n", [Name, Tab]), + dbg_out("Checkpoint retainer created ~p ~tp~n", [Name, Tab]), R#retainer{store = {dets, {Tab, Name}}, really_retain = true}; retainer_create(Cp, R, Tab, Name, Storage) -> T = ?ets_new_table(mnesia_retainer, [set, public, {keypos, 2}]), @@ -698,7 +698,7 @@ retainer_create(Cp, R, Tab, Name, Storage) -> ReallyR = R#retainer.really_retain, ReallyCp = lists:member(Tab, Overriders), ReallyR2 = prepare_ram_tab(Tab, T, Storage, ReallyR, ReallyCp), - dbg_out("Checkpoint retainer created ~p ~p~n", [Name, Tab]), + dbg_out("Checkpoint retainer created ~p ~tp~n", [Name, Tab]), R#retainer{store = {ets, T}, really_retain = ReallyR2}. %% Copy the dumped table into retainer if needed @@ -849,7 +849,7 @@ retainer_loop(Cp = #checkpoint_args{is_activated=false, name=Name}) -> retainer_loop(Cp#checkpoint_args{iterators = Iters}); {system, From, Msg} -> - dbg_out("~p got {system, ~p, ~p}~n", [?MODULE, From, Msg]), + dbg_out("~p got {system, ~p, ~tp}~n", [?MODULE, From, Msg]), sys:handle_system_msg(Msg, From, Cp#checkpoint_args.supervisor, ?MODULE, [], Cp) end; @@ -857,9 +857,9 @@ retainer_loop(Cp = #checkpoint_args{is_activated=false, name=Name}) -> retainer_loop(Cp = #checkpoint_args{name=Name}) -> receive {_From, {retain, Tid, Tab, Key, OldRecs}} -> - R = val({Tab, {retainer, Name}}), + R = ?catch_val({Tab, {retainer, Name}}), PendingTab = Cp#checkpoint_args.pending_tab, - case R#retainer.really_retain of + case is_record(R, retainer) andalso R#retainer.really_retain of true -> Store = R#retainer.store, try true = ets:member(PendingTab, Tid), @@ -909,7 +909,7 @@ retainer_loop(Cp = #checkpoint_args{name=Name}) -> retainer_loop(Cp2); {From, {iter_end, Iter}} -> - retainer_fixtable(Iter#iter.oid_tab, false), + ?SAFE(retainer_fixtable(Iter#iter.oid_tab, false)), Iters = Cp#checkpoint_args.iterators -- [Iter], reply(From, Name, ok), retainer_loop(Cp#checkpoint_args{iterators = Iters}); @@ -938,11 +938,11 @@ retainer_loop(Cp = #checkpoint_args{name=Name}) -> retainer_loop(Cp#checkpoint_args{iterators = Iters}); {system, From, Msg} -> - dbg_out("~p got {system, ~p, ~p}~n", [?MODULE, From, Msg]), + dbg_out("~p got {system, ~p, ~tp}~n", [?MODULE, From, Msg]), sys:handle_system_msg(Msg, From, Cp#checkpoint_args.supervisor, ?MODULE, [], Cp); Msg -> - dbg_out("~p got ~p~n", [?MODULE, Msg]) + dbg_out("~p got ~tp~n", [?MODULE, Msg]) end. maybe_activate(Cp) @@ -971,7 +971,8 @@ do_stop(Cp) -> unset({checkpoint, Name}), lists:foreach(fun deactivate_tab/1, Cp#checkpoint_args.retainers), Iters = Cp#checkpoint_args.iterators, - lists:foreach(fun(I) -> retainer_fixtable(I#iter.oid_tab, false) end, Iters). + [?SAFE(retainer_fixtable(Tab, false)) || #iter{main_tab=Tab} <- Iters], + ok. deactivate_tab(R) -> Name = R#retainer.cp_name, @@ -1151,7 +1152,7 @@ do_change_copy(Cp, Tab, FromType, ToType) -> Cp#checkpoint_args{retainers = Rs, nodes = writers(Rs)}. check_iter(From, Iter) when Iter#iter.pid == From -> - retainer_fixtable(Iter#iter.oid_tab, false), + ?SAFE(retainer_fixtable(Iter#iter.oid_tab, false)), false; check_iter(_From, _Iter) -> true. @@ -1268,9 +1269,9 @@ system_code_change(Cp, _Module, _OldVsn, _Extra) -> %%%%%%%%%%%%%%%%%%%%%%%%%% +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); - _VaLuE_ -> _VaLuE_ + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); + Value -> Value end. - diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl index 4791e2e290..882de0d613 100644 --- a/lib/mnesia/src/mnesia_controller.erl +++ b/lib/mnesia/src/mnesia_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -185,9 +185,10 @@ max_loaders() -> worker_res }). +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -446,7 +447,7 @@ try_schedule_late_disc_load(Tabs, Reason, MsgTag) -> [BadNodes]), try_schedule_late_disc_load(Tabs, Reason, MsgTag); {aborted, AbortReason} -> - fatal("Cannot late_load_tables~p: ~p~n", + fatal("Cannot late_load_tables ~tp: ~tp~n", [[Tabs, Reason, MsgTag], AbortReason]) end. @@ -535,7 +536,7 @@ try_merge_schema(Nodes, Told0, UserFun) -> end, try_merge_schema(Nodes, Told, UserFun); {atomic, {"Cannot get cstructs", Node, Reason}} -> - dbg_out("Cannot get cstructs, Node ~p ~p~n", [Node, Reason]), + dbg_out("Cannot get cstructs, Node ~p ~tp~n", [Node, Reason]), timer:sleep(300), % Avoid a endless loop look alike try_merge_schema(Nodes, Told0, UserFun); {aborted, {shutdown, _}} -> %% One of the nodes is going down @@ -771,22 +772,6 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) -> noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]}) end; -handle_call({net_load, Tab, Cs}, From, State) -> - State2 = - case State#state.schema_is_merged of - true -> - Worker = #net_load{table = Tab, - opt_reply_to = From, - reason = {dumper,{add_table_copy, unknown}}, - cstruct = Cs - }, - add_worker(Worker, State); - false -> - reply(From, {not_loaded, schema_not_merged}), - State - end, - noreply(State2); - handle_call(Msg, From, State) when State#state.schema_is_merged /= true -> %% Buffer early messages Msgs = State#state.early_msgs, @@ -826,12 +811,12 @@ handle_call({del_other, Who}, _From, State = #state{others=Others0}) -> {reply, ok, State#state{others=Others}}; handle_call(Msg, _From, State) -> - error("~p got unexpected call: ~p~n", [?SERVER_NAME, Msg]), + error("~p got unexpected call: ~tp~n", [?SERVER_NAME, Msg]), noreply(State). late_disc_load(TabsR, Reason, RemoteLoaders, From, State = #state{loader_queue = LQ, late_loader_queue = LLQ}) -> - verbose("Intend to load tables: ~p~n", [TabsR]), + verbose("Intend to load tables: ~tp~n", [TabsR]), ?eval_debug_fun({?MODULE, late_disc_load}, [{tabs, TabsR}, {reason, Reason}, @@ -1118,7 +1103,7 @@ handle_cast({adopt_orphans, Node, Tabs}, State) -> noreply(State2); handle_cast(Msg, State) -> - error("~p got unexpected cast: ~p~n", [?SERVER_NAME, Msg]), + error("~p got unexpected cast: ~tp~n", [?SERVER_NAME, Msg]), noreply(State). handle_sync_tabs([Tab | Tabs], From) -> @@ -1166,7 +1151,7 @@ handle_info(#dumper_done{worker_pid=Pid, worker_res=Res}, State) -> State3 = opt_start_worker(State2), noreply(State3); true -> - fatal("Dumper failed: ~p~n state: ~p~n", [Res, State]), + fatal("Dumper failed: ~p~n state: ~tp~n", [Res, State]), {stop, fatal, State} end; @@ -1249,7 +1234,7 @@ handle_info(#sender_done{worker_pid=Pid, worker_res=Res}, State) -> true -> %% No need to send any message to the table receiver %% since it will soon get a mnesia_down anyway - fatal("Sender failed: ~p~n state: ~p~n", [Res, State]), + fatal("Sender failed: ~p~n state: ~tp~n", [Res, State]), {stop, fatal, State} end; @@ -1257,7 +1242,7 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> ?SAFE(set(mnesia_status, stopping)), case State#state.dumper_pid of undefined -> - dbg_out("~p was ~p~n", [?SERVER_NAME, R]), + dbg_out("~p was ~tp~n", [?SERVER_NAME, R]), {stop, shutdown, State}; _ -> noreply(State#state{is_stopping = true}) @@ -1266,12 +1251,12 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> handle_info({'EXIT', Pid, R}, State) when Pid == State#state.dumper_pid -> case State#state.dumper_queue of [#schema_commit_lock{}|Workers] -> %% Schema trans crashed or was killed - dbg_out("WARNING: Dumper ~p exited ~p~n", [Pid, R]), + dbg_out("WARNING: Dumper ~p exited ~tp~n", [Pid, R]), State2 = State#state{dumper_queue = Workers, dumper_pid = undefined}, State3 = opt_start_worker(State2), noreply(State3); _Other -> - fatal("Dumper or schema commit crashed: ~p~n state: ~p~n", [R, State]), + fatal("Dumper or schema commit crashed: ~p~n state: ~tp~n", [R, State]), {stop, fatal, State} end; @@ -1280,15 +1265,15 @@ handle_info(Msg = {'EXIT', Pid, R}, State) when R /= wait_for_tables_timeout -> true -> %% No need to send any message to the table receiver %% since it will soon get a mnesia_down anyway - fatal("Sender crashed: ~p~n state: ~p~n", [{Pid,R}, State]), + fatal("Sender crashed: ~p~n state: ~tp~n", [{Pid,R}, State]), {stop, fatal, State}; false -> case lists:keymember(Pid, 1, get_loaders(State)) of true -> - fatal("Loader crashed: ~p~n state: ~p~n", [R, State]), + fatal("Loader crashed: ~p~n state: ~tp~n", [R, State]), {stop, fatal, State}; false -> - error("~p got unexpected info: ~p~n", [?SERVER_NAME, Msg]), + error("~p got unexpected info: ~tp~n", [?SERVER_NAME, Msg]), noreply(State) end end; @@ -1308,7 +1293,7 @@ handle_info({'EXIT', Pid, wait_for_tables_timeout}, State) -> noreply(State); handle_info(Msg, State) -> - error("~p got unexpected info: ~p~n", [?SERVER_NAME, Msg]), + error("~p got unexpected info: ~tp~n", [?SERVER_NAME, Msg]), noreply(State). sync_tab_timeout(Pid, [{{sync_tab, Tab}, Pids} | Tail]) -> @@ -1456,7 +1441,8 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) -> L = [Tab | Local], orphan_tables(Tabs, Node, Ns, L, Remote); Masters -> - R = [{Tab, Masters} | Remote], + %% Do not disc_load table from RamCopyHolders + R = [{Tab, Masters -- RamCopyHolders} | Remote], orphan_tables(Tabs, Node, Ns, Local, R) end; _ -> @@ -1703,9 +1689,10 @@ add_active_replica(Tab, Node, Cs = #cstruct{}) -> block_table(Tab) -> Var = {Tab, where_to_commit}, - Old = val(Var), - New = {blocked, Old}, - set(Var, New). % where_to_commit + case is_tab_blocked(val(Var)) of + {true, _} -> ok; + {false, W2C} -> set(Var, mark_blocked_tab(true, W2C)) + end. unblock_table(Tab) -> call({unblock_table, Tab}). @@ -1887,7 +1874,7 @@ info_format(Tab, Size, Mem, Media) -> StrT = mnesia_lib:pad_name(atom_to_list(Tab), 15, []), StrS = mnesia_lib:pad_name(integer_to_list(Size), 8, []), StrM = mnesia_lib:pad_name(integer_to_list(Mem), 8, []), - io:format("~s: with ~s records occupying ~s ~s~n", + io:format("~ts: with ~s records occupying ~s ~s~n", [StrT, StrS, StrM, Media]). %% Handle early arrived messages @@ -2053,7 +2040,7 @@ opt_start_sender2([Sender|R], Pids, Kept, LoaderQ) -> Pid = spawn_link(?MODULE, send_and_reply,[self(), Sender]), opt_start_sender2(R,[{Pid,Sender}|Pids],Kept,LoaderQ); true -> - verbose("Send table failed ~p not active on this node ~n", [Tab]), + verbose("Send table failed ~tp not active on this node ~n", [Tab]), Sender#send_table.receiver_pid ! {copier_done, node()}, opt_start_sender2(R,Pids, Kept, LoaderQ) end. @@ -2160,6 +2147,15 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl {dumper,{add_table_copy,_}} -> true; _ -> false end, + + OnlyRamCopies = case Cs of + #cstruct{disc_copies = DC, + disc_only_copies = DOC, + external_copies = Ext} -> + [] =:= (DC ++ (DOC ++ Ext)) -- [node()]; + _ -> + false + end, if ReadNode == node() -> %% Already loaded locally @@ -2171,6 +2167,8 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl end; AccessMode == read_only, not AddTableCopy -> fun() -> disc_load_table(Tab, Reason, ReplyTo) end; + Active =:= [], AddTableCopy, OnlyRamCopies -> + fun() -> disc_load_table(Tab, Reason, ReplyTo) end; true -> fun() -> %% Either we cannot read the table yet @@ -2238,7 +2236,7 @@ disc_load_table(Tab, Reason, ReplyTo) -> Done#loader_done{is_loaded = false, reply = Res}; true -> - fatal("Cannot load table ~p from disc: ~p~n", [Tab, Res]) + fatal("Cannot load table ~tp from disc: ~tp~n", [Tab, Res]) end. filter_active(Tab) -> diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl index eb02a585a6..a2880d6cf4 100644 --- a/lib/mnesia/src/mnesia_dumper.erl +++ b/lib/mnesia/src/mnesia_dumper.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -191,9 +191,8 @@ do_perform_dump(Cont, InPlace, InitBy, Regulator, OldVersion) -> try insert_recs(Recs, InPlace, InitBy, Regulator, OldVersion) of Version -> do_perform_dump(C2, InPlace, InitBy, Regulator, Version) - catch _:R when R =/= fatal -> - ST = erlang:get_stacktrace(), - Reason = {"Transaction log dump error: ~p~n", [{R, ST}]}, + catch _:R:ST when R =/= fatal -> + Reason = {"Transaction log dump error: ~tp~n", [{R, ST}]}, close_files(InPlace, {error, Reason}, InitBy), exit(Reason) end; @@ -325,11 +324,10 @@ perform_update(Tid, SchemaOps, _DumperMode, _UseDir) -> ?eval_debug_fun({?MODULE, post_dump}, [InitBy]), close_files(InPlace, ok, InitBy), ok - catch _:Reason when Reason =/= fatal -> - ST = erlang:get_stacktrace(), + catch _:Reason:ST when Reason =/= fatal -> Error = {error, {"Schema update error", {Reason, ST}}}, close_files(InPlace, Error, InitBy), - fatal("Schema update error ~p ~p", [{Reason,ST}, SchemaOps]) + fatal("Schema update error ~tp ~tp", [{Reason,ST}, SchemaOps]) end. insert_ops(_Tid, _Storage, [], _InPlace, _InitBy, _) -> ok; @@ -1166,7 +1164,7 @@ needs_dump_ets(Tab) -> DcdF = mnesia_lib:tab2dcd(Tab), case file:read_file_info(DcdF) of {error, Reason} -> - mnesia_lib:dbg_out("File ~p info_error ~p ~n", + mnesia_lib:dbg_out("File ~tp info_error ~tp ~n", [DcdF, Reason]), true; {ok, DcdInfo} -> @@ -1205,7 +1203,7 @@ prepare_open(Tab, UpdateInPlace) -> Tmp = mnesia_lib:tab2tmp(Tab), try ok = mnesia_lib:copy_file(Dat, Tmp) catch error:Error -> - fatal("Cannot copy dets file ~p to ~p: ~p~n", + fatal("Cannot copy dets file ~tp to ~tp: ~tp~n", [Dat, Tmp, Error]) end, Tmp @@ -1441,7 +1439,7 @@ start_regulator() -> {ok, Pid} -> Pid; {error, Reason} -> - fatal("Failed to start ~n: ~p~n", [N, Reason]) + fatal("Failed to start ~n: ~tp~n", [N, Reason]) end end. @@ -1471,8 +1469,9 @@ regulate(RegulatorPid) -> {regulated, RegulatorPid} -> ok end. +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl index 7320d381ea..49b3990086 100644 --- a/lib/mnesia/src/mnesia_event.erl +++ b/lib/mnesia/src/mnesia_event.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2017. 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. @@ -103,18 +103,19 @@ handle_any_event({mnesia_system_event, Event}, State) -> handle_any_event({mnesia_table_event, Event}, State) -> handle_table_event(Event, State); handle_any_event(Msg, State) -> - report_error("~p got unexpected event: ~p~n", [?MODULE, Msg]), + report_error("~p got unexpected event: ~tp~n", [?MODULE, Msg]), {ok, State}. handle_table_event({Oper, Record, TransId}, State) -> - report_info("~p performed by ~p on record:~n\t~p~n", + report_info("~p performed by ~p on record:~n\t~tp~n", [Oper, TransId, Record]), {ok, State}. handle_system_event({mnesia_checkpoint_activated, _Checkpoint}, State) -> {ok, State}; -handle_system_event({mnesia_checkpoint_deactivated, _Checkpoint}, State) -> +handle_system_event({mnesia_checkpoint_deactivated, Checkpoint}, State) -> + report_error("Checkpoint '~p' has been deactivated, last table copy deleted.\n",[Checkpoint]), {ok, State}; handle_system_event({mnesia_up, Node}, State) -> @@ -154,7 +155,7 @@ handle_system_event({mnesia_down, Node}, State) -> end; handle_system_event({mnesia_overload, Details}, State) -> - report_warning("Mnesia is overloaded: ~w~n", [Details]), + report_warning("Mnesia is overloaded: ~tw~n", [Details]), {ok, State}; handle_system_event({mnesia_info, Format, Args}, State) -> @@ -174,16 +175,16 @@ handle_system_event({mnesia_fatal, Format, Args, BinaryCore}, State) -> {ok, State#state{dumped_core = true}}; handle_system_event({inconsistent_database, Reason, Node}, State) -> - report_error("mnesia_event got {inconsistent_database, ~w, ~w}~n", + report_error("mnesia_event got {inconsistent_database, ~tw, ~w}~n", [Reason, Node]), {ok, State}; handle_system_event({mnesia_user, Event}, State) -> - report_info("User event: ~p~n", [Event]), + report_info("User event: ~tp~n", [Event]), {ok, State}; handle_system_event(Msg, State) -> - report_error("mnesia_event got unexpected system event: ~p~n", [Msg]), + report_error("mnesia_event got unexpected system event: ~tp~n", [Msg]), {ok, State}. report_info(Format0, Args0) -> diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl index c6e812b36d..8f7dd321b0 100644 --- a/lib/mnesia/src/mnesia_frag.erl +++ b/lib/mnesia/src/mnesia_frag.erl @@ -1,7 +1,7 @@ %%% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. 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. @@ -58,9 +58,7 @@ -include("mnesia.hrl"). --define(OLD_HASH_MOD, mnesia_frag_old_hash). -define(DEFAULT_HASH_MOD, mnesia_frag_hash). -%%-define(DEFAULT_HASH_MOD, ?OLD_HASH_MOD). %% BUGBUG: New should be default -record(frag_state, {foreign_key, @@ -80,7 +78,7 @@ lock(ActivityId, Opaque, {table , Tab}, LockKind) -> case frag_names(Tab) of [Tab] -> - mnesia:lock(ActivityId, Opaque, {table, Tab}, LockKind); + mnesia:lock(ActivityId, Opaque, {table, Tab}, LockKind); Frags -> DeepNs = [mnesia:lock(ActivityId, Opaque, {table, F}, LockKind) || F <- Frags], @@ -321,7 +319,7 @@ init_select(Tid,Opaque,Tab,Pat,Limit,LockKind) -> {'EXIT', _} -> mnesia:select(Tid, Opaque, Tab, Pat, Limit,LockKind); FH -> - FragNumbers = verify_numbers(FH,Pat), + FragNumbers = verify_numbers(FH,Pat), Fun = fun(Num) -> Name = n_to_frag_name(Tab, Num), Node = val({Name, where_to_read}), @@ -336,19 +334,19 @@ init_select(Tid,Opaque,Tab,Pat,Limit,LockKind) -> end. select_cont(_Tid,_,{frag_cont, '$end_of_table', [],_}) -> '$end_of_table'; -select_cont(Tid,Ts,{frag_cont, '$end_of_table', [{Tab,Node,Type}|Rest],Args}) -> +select_cont(Tid,Ts,{frag_cont, '$end_of_table', [{Tab,Node,Type}|Rest],Args}) -> {Spec,LockKind,Limit} = Args, InitFun = fun(FixedSpec) -> mnesia:dirty_sel_init(Node,Tab,FixedSpec,Limit,Type) end, Res = mnesia:fun_select(Tid,Ts,Tab,Spec,LockKind,Tab,InitFun,Limit,Node,Type), frag_sel_cont(Res, Rest, Args); -select_cont(Tid,Ts,{frag_cont, Cont, TabL, Args}) -> +select_cont(Tid,Ts,{frag_cont, Cont, TabL, Args}) -> frag_sel_cont(mnesia:select_cont(Tid,Ts,Cont),TabL,Args); select_cont(Tid,Ts,Else) -> %% Not a fragmented table mnesia:select_cont(Tid,Ts,Else). frag_sel_cont('$end_of_table', [],_) -> '$end_of_table'; -frag_sel_cont('$end_of_table', TabL,Args) -> +frag_sel_cont('$end_of_table', TabL,Args) -> {[], {frag_cont, '$end_of_table', TabL,Args}}; frag_sel_cont({Recs,Cont}, TabL,Args) -> {Recs, {frag_cont, Cont, TabL,Args}}. @@ -358,9 +356,9 @@ do_select(ActivityId, Opaque, Tab, MatchSpec, LockKind) -> {'EXIT', _} -> mnesia:select(ActivityId, Opaque, Tab, MatchSpec, LockKind); FH -> - FragNumbers = verify_numbers(FH,MatchSpec), + FragNumbers = verify_numbers(FH,MatchSpec), Fun = fun(Num) -> - Name = n_to_frag_name(Tab, Num), + Name = n_to_frag_name(Tab, Num), Node = val({Name, where_to_read}), mnesia:lock(ActivityId, Opaque, {table, Name}, LockKind), {Name, Node} @@ -398,7 +396,7 @@ do_select(ActivityId, Opaque, Tab, MatchSpec, LockKind) -> verify_numbers(FH,MatchSpec) -> HashState = FH#frag_state.hash_state, - FragNumbers = + FragNumbers = case FH#frag_state.hash_module of HashMod when HashMod == ?DEFAULT_HASH_MOD -> ?DEFAULT_HASH_MOD:match_spec_to_frag_numbers(HashState, MatchSpec); @@ -434,7 +432,7 @@ local_select(ReplyTo, Ref, RemoteNameNodes, MatchSpec) -> end, unlink(ReplyTo), exit(normal). - + remote_select(ReplyTo, Ref, NameNodes, MatchSpec) -> do_remote_select(ReplyTo, Ref, NameNodes, MatchSpec). @@ -805,22 +803,22 @@ make_deactivate(Tab) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Add a fragment to a fragmented table and fill it with half of %% the records from one of the old fragments - + make_multi_add_frag(Tab, SortedNs) when is_list(SortedNs) -> verify_multi(Tab), Ops = make_add_frag(Tab, SortedNs), %% Propagate to foreigners MoreOps = [make_add_frag(T, SortedNs) || T <- lookup_foreigners(Tab)], - [Ops | MoreOps]; + [Ops | MoreOps]; make_multi_add_frag(Tab, SortedNs) -> mnesia:abort({bad_type, Tab, SortedNs}). verify_multi(Tab) -> FH = lookup_frag_hash(Tab), ForeignKey = FH#frag_state.foreign_key, - mnesia_schema:verify(undefined, ForeignKey, - {combine_error, Tab, + mnesia_schema:verify(undefined, ForeignKey, + {combine_error, Tab, "Op only allowed via foreign table", {foreign_key, ForeignKey}}). @@ -839,7 +837,7 @@ make_frag_names_and_acquire_locks(Tab, N, FragIndecies, DoNotLockN) -> end, FragNames = erlang:make_tuple(N, undefined), lists:foldl(Fun, FragNames, FragIndecies). - + make_add_frag(Tab, SortedNs) -> Cs = mnesia_schema:incr_version(val({Tab, cstruct})), mnesia_schema:ensure_active(Cs), @@ -849,8 +847,8 @@ make_add_frag(Tab, SortedNs) -> FragNames = make_frag_names_and_acquire_locks(Tab, N, WriteIndecies, true), NewFrag = element(N, FragNames), - NR = length(Cs#cstruct.ram_copies), - ND = length(Cs#cstruct.disc_copies), + NR = length(Cs#cstruct.ram_copies), + ND = length(Cs#cstruct.disc_copies), NDO = length(Cs#cstruct.disc_only_copies), NExt = length(Cs#cstruct.external_copies), NewCs = Cs#cstruct{name = NewFrag, @@ -859,7 +857,7 @@ make_add_frag(Tab, SortedNs) -> disc_copies = [], disc_only_copies = [], external_copies = []}, - + {NewCs2, _, _} = set_frag_nodes(NR, ND, NDO, NExt, NewCs, SortedNs, []), [NewOp] = mnesia_schema:make_create_table(NewCs2), @@ -944,7 +942,7 @@ do_split(FH, OldN, FragNames, [Rec | Recs], Ops) -> Key = element(2, Rec), NewOid = {NewFrag, Key}, OldOid = {OldFrag, Key}, - Ops2 = [{op, rec, unknown, {NewOid, [Rec], write}}, + Ops2 = [{op, rec, unknown, {NewOid, [Rec], write}}, {op, rec, unknown, {OldOid, [OldOid], delete}} | Ops], do_split(FH, OldN, FragNames, Recs, Ops2); _NewFrag -> @@ -958,7 +956,7 @@ do_split(_FH, _OldN, _FragNames, [], Ops) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Delete a fragment from a fragmented table %% and merge its records with another fragment - + make_multi_del_frag(Tab) -> verify_multi(Tab), Ops = make_del_frag(Tab), @@ -1064,7 +1062,7 @@ do_merge(FH, OldN, FragNames, [Rec | Recs], Ops) -> Key = element(2, Rec), NewOid = {NewFrag, Key}, OldOid = {OldFrag, Key}, - Ops2 = [{op, rec, unknown, {NewOid, [Rec], write}}, + Ops2 = [{op, rec, unknown, {NewOid, [Rec], write}}, {op, rec, unknown, {OldOid, [OldOid], delete}} | Ops], do_merge(FH, OldN, FragNames, Recs, Ops2); _NewFrag -> @@ -1077,7 +1075,7 @@ do_merge(FH, OldN, FragNames, [Rec | Recs], Ops) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Add a node to the node pool of a fragmented table - + make_multi_add_node(Tab, Node) -> verify_multi(Tab), Ops = make_add_node(Tab, Node), @@ -1085,7 +1083,7 @@ make_multi_add_node(Tab, Node) -> %% Propagate to foreigners MoreOps = [make_add_node(T, Node) || T <- lookup_foreigners(Tab)], [Ops | MoreOps]. - + make_add_node(Tab, Node) when is_atom(Node) -> Pool = lookup_prop(Tab, node_pool), case lists:member(Node, Pool) of @@ -1114,7 +1112,7 @@ make_multi_del_node(Tab, Node) -> %% Propagate to foreigners MoreOps = [make_del_node(T, Node) || T <- lookup_foreigners(Tab)], [Ops | MoreOps]. - + make_del_node(Tab, Node) when is_atom(Node) -> Cs = mnesia_schema:incr_version(val({Tab, cstruct})), mnesia_schema:ensure_active(Cs), @@ -1147,8 +1145,8 @@ remove_node(Node, Cs) -> case lists:member(Node, Pool) of true -> Pool2 = Pool -- [Node], - Props = lists:keyreplace(node_pool, 1, - Cs#cstruct.frag_properties, + Props = lists:keyreplace(node_pool, 1, + Cs#cstruct.frag_properties, {node_pool, Pool2}), {Cs#cstruct{frag_properties = Props}, true}; false -> @@ -1159,9 +1157,10 @@ remove_node(Node, Cs) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Helpers +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -1180,18 +1179,10 @@ props_to_frag_hash(Tab, Props) -> T when T == Tab -> Foreign = mnesia_schema:pick(Tab, foreign_key, Props, must), N = mnesia_schema:pick(Tab, n_fragments, Props, must), - case mnesia_schema:pick(Tab, hash_module, Props, undefined) of undefined -> - Split = mnesia_schema:pick(Tab, next_n_to_split, Props, must), - Doubles = mnesia_schema:pick(Tab, n_doubles, Props, must), - FH = {frag_hash, Foreign, N, Split, Doubles}, - HashState = ?OLD_HASH_MOD:init_state(Tab, FH), - #frag_state{foreign_key = Foreign, - n_fragments = N, - hash_module = ?OLD_HASH_MOD, - hash_state = HashState}; - HashMod -> + no_hash; + HashMod -> HashState = mnesia_schema:pick(Tab, hash_state, Props, must), #frag_state{foreign_key = Foreign, n_fragments = N, @@ -1216,13 +1207,9 @@ lookup_frag_hash(Tab) -> case ?catch_val({Tab, frag_hash}) of FH when is_record(FH, frag_state) -> FH; - {frag_hash, K, N, _S, _D} = FH -> + {frag_hash, _K, _N, _S, _D} -> %% Old style. Kept for backwards compatibility. - HashState = ?OLD_HASH_MOD:init_state(Tab, FH), - #frag_state{foreign_key = K, - n_fragments = N, - hash_module = ?OLD_HASH_MOD, - hash_state = HashState}; + mnesia:abort({no_hash, Tab, frag_properties, frag_hash}); {'EXIT', _} -> mnesia:abort({no_exists, Tab, frag_properties, frag_hash}) end. @@ -1249,10 +1236,10 @@ key_pos(FH) -> case FH#frag_state.foreign_key of undefined -> 2; - {_ForeignTab, Pos} -> + {_ForeignTab, Pos} -> Pos end. - + %% Returns name of fragment table key_to_frag_name({BaseTab, _} = Tab, Key) -> N = key_to_frag_number(Tab, Key), diff --git a/lib/mnesia/src/mnesia_frag_old_hash.erl b/lib/mnesia/src/mnesia_frag_old_hash.erl deleted file mode 100644 index b246c76236..0000000000 --- a/lib/mnesia/src/mnesia_frag_old_hash.erl +++ /dev/null @@ -1,133 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2016. 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. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% -%%%---------------------------------------------------------------------- -%%% Purpose : Implements hashing functionality for fragmented tables -%%%---------------------------------------------------------------------- - --module(mnesia_frag_old_hash). -%%-behaviour(mnesia_frag_hash). - --compile({nowarn_deprecated_function, {erlang,hash,2}}). - -%% Hashing callback functions --export([ - init_state/2, - add_frag/1, - del_frag/1, - key_to_frag_number/2, - match_spec_to_frag_numbers/2 - ]). - --record(old_hash_state, - {n_fragments, - next_n_to_split, - n_doubles}). - -%% Old style. Kept for backwards compatibility. --record(frag_hash, - {foreign_key, - n_fragments, - next_n_to_split, - n_doubles}). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -init_state(_Tab, InitialState) when InitialState == undefined -> - #old_hash_state{n_fragments = 1, - next_n_to_split = 1, - n_doubles = 0}; -init_state(_Tab, FH) when is_record(FH, frag_hash) -> - %% Old style. Kept for backwards compatibility. - #old_hash_state{n_fragments = FH#frag_hash.n_fragments, - next_n_to_split = FH#frag_hash.next_n_to_split, - n_doubles = FH#frag_hash.n_doubles}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -add_frag(State) when is_record(State, old_hash_state) -> - SplitN = State#old_hash_state.next_n_to_split, - P = SplitN + 1, - L = State#old_hash_state.n_doubles, - NewN = State#old_hash_state.n_fragments + 1, - State2 = case trunc(math:pow(2, L)) + 1 of - P2 when P2 == P -> - State#old_hash_state{n_fragments = NewN, - next_n_to_split = 1, - n_doubles = L + 1}; - _ -> - State#old_hash_state{n_fragments = NewN, - next_n_to_split = P} - end, - {State2, [SplitN], [NewN]}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -del_frag(State) when is_record(State, old_hash_state) -> - P = State#old_hash_state.next_n_to_split - 1, - L = State#old_hash_state.n_doubles, - N = State#old_hash_state.n_fragments, - if - P < 1 -> - L2 = L - 1, - MergeN = trunc(math:pow(2, L2)), - State2 = State#old_hash_state{n_fragments = N - 1, - next_n_to_split = MergeN, - n_doubles = L2}, - {State2, [N], [MergeN]}; - true -> - MergeN = P, - State2 = State#old_hash_state{n_fragments = N - 1, - next_n_to_split = MergeN}, - {State2, [N], [MergeN]} - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -key_to_frag_number(State, Key) when is_record(State, old_hash_state) -> - L = State#old_hash_state.n_doubles, - A = erlang:hash(Key, trunc(math:pow(2, L))), - P = State#old_hash_state.next_n_to_split, - if - A < P -> - erlang:hash(Key, trunc(math:pow(2, L + 1))); - true -> - A - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -match_spec_to_frag_numbers(State, MatchSpec) when is_record(State, old_hash_state) -> - case MatchSpec of - [{HeadPat, _, _}] when is_tuple(HeadPat), tuple_size(HeadPat) > 2 -> - KeyPat = element(2, HeadPat), - case has_var(KeyPat) of - false -> - [key_to_frag_number(State, KeyPat)]; - true -> - lists:seq(1, State#old_hash_state.n_fragments) - end; - _ -> - lists:seq(1, State#old_hash_state.n_fragments) - end. - -has_var(Pat) -> - mnesia:has_var(Pat). diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl index c79f790973..098265d5fc 100644 --- a/lib/mnesia/src/mnesia_index.erl +++ b/lib/mnesia/src/mnesia_index.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -155,7 +155,7 @@ del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) -> bag -> db_match_erase(Ixt, {IxK, Key}); ordered -> - db_erase(Ixt, {{IxK, Key}}) + db_erase(Ixt, {IxK, Key}) end; _ -> ok @@ -420,7 +420,7 @@ make_ram_index(Tab, Storage, [Pos | Tail]) -> add_ram_index(Tab, Storage, {Pos, _Pref}) -> Type = ordered, - verbose("Creating index for ~w ~p ~p~n", [Tab, Pos, Type]), + verbose("Creating index for ~tw ~p ~p~n", [Tab, Pos, Type]), SetOrBag = val({Tab, setorbag}), IxValsF = index_vals_f(Storage, Tab, Pos), IxFun = fun(Val, Key) -> {{Val, Key}} end, diff --git a/lib/mnesia/src/mnesia_kernel_sup.erl b/lib/mnesia/src/mnesia_kernel_sup.erl index c9af5c460a..a761d5eed0 100644 --- a/lib/mnesia/src/mnesia_kernel_sup.erl +++ b/lib/mnesia/src/mnesia_kernel_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2017. 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. @@ -43,7 +43,6 @@ init([]) -> worker_spec(mnesia_recover, timer:minutes(3), [gen_server]), worker_spec(mnesia_tm, timer:seconds(30), ProcLib), supervisor_spec(mnesia_checkpoint_sup), - supervisor_spec(mnesia_snmp_sup), worker_spec(mnesia_controller, timer:seconds(3), [gen_server]), worker_spec(mnesia_late_loader, timer:seconds(3), ProcLib) ], diff --git a/lib/mnesia/src/mnesia_late_loader.erl b/lib/mnesia/src/mnesia_late_loader.erl index e273329ffc..45afda6e4b 100644 --- a/lib/mnesia/src/mnesia_late_loader.erl +++ b/lib/mnesia/src/mnesia_late_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. 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. @@ -87,13 +87,13 @@ loop(State) -> loop(State); {system, From, Msg} -> - mnesia_lib:dbg_out("~p got {system, ~p, ~p}~n", + mnesia_lib:dbg_out("~p got {system, ~p, ~tp}~n", [?SERVER_NAME, From, Msg]), Parent = State#state.supervisor, sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], State); Msg -> - mnesia_lib:error("~p got unexpected message: ~p~n", + mnesia_lib:error("~p got unexpected message: ~tp~n", [?SERVER_NAME, Msg]), loop(State) end. diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl index 10e232c800..a884b8e086 100644 --- a/lib/mnesia/src/mnesia_lib.erl +++ b/lib/mnesia/src/mnesia_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -116,7 +116,7 @@ lock_table/1, mkcore/1, not_active_here/1, - other_val/1, + other_val/2, overload_read/0, overload_read/1, overload_set/2, @@ -435,8 +435,8 @@ validate_record(Tab, Obj) -> %% val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> other_val(Var, Stacktrace); _VaLuE_ -> _VaLuE_ end. @@ -446,9 +446,9 @@ set(Var, Val) -> unset(Var) -> ?ets_delete(mnesia_gvar, Var). -other_val(Var) -> +other_val(Var, Stacktrace) -> case other_val_1(Var) of - error -> pr_other(Var); + error -> pr_other(Var, Stacktrace); Val -> Val end. @@ -460,16 +460,16 @@ other_val_1(Var) -> _ -> error end. --spec pr_other(_) -> no_return(). -pr_other(Var) -> +-spec pr_other(_, _) -> no_return(). +pr_other(Var, Stacktrace) -> Why = case is_running() of no -> {node_not_running, node()}; _ -> {no_exists, Var} end, - verbose("~p (~p) val(mnesia_gvar, ~w) -> ~p ~p ~n", + verbose("~p (~tp) val(mnesia_gvar, ~tw) -> ~p ~tp ~n", [self(), process_info(self(), registered_name), - Var, Why, erlang:get_stacktrace()]), + Var, Why, Stacktrace]), mnesia:abort(Why). %% Some functions for list valued variables @@ -654,7 +654,7 @@ coredump() -> coredump(CrashInfo) -> Core = mkcore(CrashInfo), Out = core_file(), - important("Writing Mnesia core to file: ~p...~p~n", [Out, CrashInfo]), + important("Writing Mnesia core to file: ~tp...~tp~n", [Out, CrashInfo]), _ = file:write_file(Out, Core), Out. @@ -844,7 +844,7 @@ vcore() -> case file:list_dir(Cwd) of {ok, Files}-> CoreFiles = lists:sort(lists:zf(Filter, Files)), - show("Mnesia core files: ~p~n", [CoreFiles]), + show("Mnesia core files: ~tp~n", [CoreFiles]), vcore(lists:last(CoreFiles)); Error -> Error @@ -853,17 +853,17 @@ vcore() -> vcore(Bin) when is_binary(Bin) -> Core = binary_to_term(Bin), Fun = fun({Item, Info}) -> - show("***** ~p *****~n", [Item]), + show("***** ~tp *****~n", [Item]), case catch vcore_elem({Item, Info}) of {'EXIT', Reason} -> - show("{'EXIT', ~p}~n", [Reason]); + show("{'EXIT', ~tp}~n", [Reason]); _ -> ok end end, lists:foreach(Fun, Core); vcore(File) -> - show("~n***** Mnesia core: ~p *****~n", [File]), + show("~n***** Mnesia core: ~tp *****~n", [File]), case file:read_file(File) of {ok, Bin} -> vcore(Bin); @@ -879,7 +879,7 @@ vcore_elem({schema_file, {ok, B}}) -> vcore_elem({logfile, {ok, BinList}}) -> Fun = fun({F, Info}) -> - show("----- logfile: ~p -----~n", [F]), + show("----- logfile: ~tp -----~n", [F]), case Info of {ok, B} -> Fname = "/tmp/mnesia_vcore_elem.TMP", @@ -887,7 +887,7 @@ vcore_elem({logfile, {ok, BinList}}) -> mnesia_log:view(Fname), file:delete(Fname); _ -> - show("~p~n", [Info]) + show("~tp~n", [Info]) end end, lists:foreach(Fun, BinList); @@ -895,12 +895,12 @@ vcore_elem({logfile, {ok, BinList}}) -> vcore_elem({crashinfo, {Format, Args}}) -> show(Format, Args); vcore_elem({gvar, L}) -> - show("~p~n", [lists:sort(L)]); + show("~tp~n", [lists:sort(L)]); vcore_elem({transactions, Info}) -> mnesia_tm:display_info(user, Info); vcore_elem({_Item, Info}) -> - show("~p~n", [Info]). + show("~tp~n", [Info]). fix_error(X) -> set(last_error, X), %% for debugabililty @@ -1018,7 +1018,7 @@ report_system_event({'EXIT', Reason}, Event) -> end; Error -> - Msg = "Mnesia(~p): Cannot report event ~p: ~p (~p)~n", + Msg = "Mnesia(~tp): Cannot report event ~tp: ~tp (~tp)~n", error_logger:format(Msg, [node(), Event, Reason, Error]) end, ok; @@ -1192,25 +1192,15 @@ db_select(Storage, Tab, Pat) -> end. db_select_init({ext, Alias, Mod}, Tab, Pat, Limit) -> - case Mod:select(Alias, Tab, Pat, Limit) of - {Matches, Continuation} when is_list(Matches) -> - {Matches, {Alias, Continuation}}; - R -> - R - end; + Mod:select(Alias, Tab, Pat, Limit); db_select_init(disc_only_copies, Tab, Pat, Limit) -> dets:select(Tab, Pat, Limit); db_select_init(_, Tab, Pat, Limit) -> ets:select(Tab, Pat, Limit). -db_select_cont({ext, Alias, Mod}, Cont0, Ms) -> +db_select_cont({ext, _Alias, Mod}, Cont0, Ms) -> Cont = Mod:repair_continuation(Cont0, Ms), - case Mod:select(Cont) of - {Matches, Continuation} when is_list(Matches) -> - {Matches, {Alias, Continuation}}; - R -> - R - end; + Mod:select(Cont); db_select_cont(disc_only_copies, Cont0, Ms) -> Cont = dets:repair_continuation(Cont0, Ms), dets:select(Cont); diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index 71e5829c87..2cdae0c906 100644 --- a/lib/mnesia/src/mnesia_loader.erl +++ b/lib/mnesia/src/mnesia_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. 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. @@ -34,9 +34,10 @@ -include("mnesia.hrl"). +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -46,7 +47,7 @@ val(Var) -> disc_load_table(Tab, Reason) -> Storage = val({Tab, storage_type}), Type = val({Tab, setorbag}), - dbg_out("Getting table ~p (~p) from disc: ~p~n", + dbg_out("Getting table ~tp (~p) from disc: ~tp~n", [Tab, Storage, Reason]), ?eval_debug_fun({?MODULE, do_get_disc_copy}, [{tab, Tab}, @@ -56,7 +57,7 @@ disc_load_table(Tab, Reason) -> do_get_disc_copy2(Tab, Reason, Storage, Type). do_get_disc_copy2(Tab, _Reason, Storage, _Type) when Storage == unknown -> - verbose("Local table copy of ~p has recently been deleted, ignored.~n", + verbose("Local table copy of ~tp has recently been deleted, ignored.~n", [Tab]), {not_loaded, storage_unknown}; do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> @@ -66,7 +67,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies -> EtsOpts = proplists:get_value(ets, StorageProps, []), Args = [{keypos, 2}, public, named_table, Type | EtsOpts], case Reason of - {dumper, _} -> %% Resources already allocated + {dumper, DR} when is_atom(DR) -> %% Resources already allocated ignore; _ -> mnesia_monitor:mktab(Tab, Args), @@ -90,8 +91,8 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies -> EtsOpts = proplists:get_value(ets, StorageProps, []), Args = [{keypos, 2}, public, named_table, Type | EtsOpts], case Reason of - {dumper, _} -> %% Resources allready allocated - ignore; + {dumper, DR} when is_atom(DR) -> + ignore; %% Resources already allocated _ -> mnesia_monitor:mktab(Tab, Args), Fname = mnesia_lib:tab2dcd(Tab), @@ -130,7 +131,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies - {repair, mnesia_monitor:get_env(auto_repair)} | DetsOpts], case Reason of - {dumper, _} -> + {dumper, DR} when is_atom(DR) -> mnesia_index:init_index(Tab, Storage), snmpify(Tab, Storage), set({Tab, load_node}, node()), @@ -199,20 +200,20 @@ net_load_table(Tab, Reason, Ns, _Cs) -> try_net_load_table(Tab, Reason, Ns, val({Tab, cstruct})). try_net_load_table(Tab, _Reason, [], _Cs) -> - verbose("Copy failed. No active replicas of ~p are available.~n", [Tab]), + verbose("Copy failed. No active replicas of ~tp are available.~n", [Tab]), {not_loaded, none_active}; try_net_load_table(Tab, Reason, Ns, Cs) -> Storage = mnesia_lib:cs_to_storage_type(node(), Cs), do_get_network_copy(Tab, Reason, Ns, Storage, Cs). do_get_network_copy(Tab, _Reason, _Ns, unknown, _Cs) -> - verbose("Local table copy of ~p has recently been deleted, ignored.~n", [Tab]), + verbose("Local table copy of ~tp has recently been deleted, ignored.~n", [Tab]), {not_loaded, storage_unknown}; do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> [Node | Tail] = Ns, case lists:member(Node,val({current, db_nodes})) of true -> - dbg_out("Getting table ~p (~p) from node ~p: ~p~n", + dbg_out("Getting table ~tp (~p) from node ~p: ~tp~n", [Tab, Storage, Node, Reason]), ?eval_debug_fun({?MODULE, do_get_network_copy}, [{tab, Tab}, {reason, Reason}, @@ -222,7 +223,7 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) -> set({Tab, load_node}, Node), set({Tab, load_reason}, Reason), mnesia_controller:i_have_tab(Tab), - dbg_out("Table ~p copied from ~p to ~p~n", [Tab, Node, node()]), + dbg_out("Table ~tp copied from ~p to ~p~n", [Tab, Node, node()]), {loaded, ok}; Err = {error, _} when element(1, Reason) == dumper -> {not_loaded,Err}; @@ -286,12 +287,12 @@ init_receiver(Node, Tab,Storage,Cs,Reason) -> element(1,Reason) == dumper -> {error,Result}; {atomic, {error,Result}} -> - fatal("Cannot create table ~p: ~p~n", + fatal("Cannot create table ~tp: ~tp~n", [[Tab, Storage], Result]); {atomic, Result} -> Result; {aborted, nomore} -> restart; {aborted, _Reas} -> - verbose("Receiver failed on ~p from ~p:~nReason: ~p~n", + verbose("Receiver failed on ~tp from ~p:~nReason: ~tp~n", [Tab,Node,_Reas]), down %% either this node or sender is dying end, @@ -313,7 +314,7 @@ start_remote_sender(Node,Tab,Storage) -> {SenderPid, TabSize, DetsData}; %% Protocol conversion hack {copier_done, Node} -> - verbose("Sender of table ~p crashed on node ~p ~n", [Tab, Node]), + verbose("Sender of table ~tp crashed on node ~p ~n", [Tab, Node]), down(Tab, Storage) end. @@ -342,9 +343,12 @@ spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) -> Done = do_init_table(Tab,Storage,Cs, SenderPid,TabSize,DetsData, ReplyTo, Init), - ReplyTo ! {self(),Done}, - unlink(ReplyTo), - unlink(whereis(mnesia_controller)), + try + ReplyTo ! {self(),Done}, + unlink(ReplyTo), + unlink(whereis(mnesia_controller)) + catch _:_ -> ok %% avoid error reports when stopping down mnesia + end, exit(normal). wait_on_load_complete(Pid) -> @@ -371,7 +375,7 @@ do_init_table(Tab,Storage,Cs,SenderPid, tab_receiver(Node,Tab,Storage,Cs,OrigTabRec); Reason -> Msg = "[d]ets:init table failed", - verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]), + verbose("~ts: ~tp: ~tp~n", [Msg, Tab, Reason]), down(Tab, Storage) end; Error -> @@ -429,7 +433,7 @@ tab_receiver(Node, Tab, Storage, Cs, OrigTabRec) -> %% Protocol conversion hack {copier_done, Node} -> - verbose("Sender of table ~p crashed on node ~p ~n", [Tab, Node]), + verbose("Sender of table ~tp crashed on node ~p ~n", [Tab, Node]), down(Tab, Storage); {'EXIT', Pid, Reason} -> @@ -487,7 +491,7 @@ ext_load_table(Mod, Alias, Tab, Reason) -> ext_init_table(Action, Alias, Mod, Tab, Fun, State, Sender) -> case Fun(Action) of {copier_done, Node} -> - verbose("Receiver of table ~p crashed on ~p (more)~n", [Tab, Node]), + verbose("Receiver of table ~tp crashed on ~p (more)~n", [Tab, Node]), down(Tab, {ext,Alias,Mod}); {Data, NewFun} -> case Mod:receive_data(Data, Alias, Tab, Sender, State) of @@ -532,7 +536,7 @@ init_table(Tab, _, Fun, _DetsInfo,_) -> try true = ets:init_table(Tab, Fun), ok - catch _:Else -> {Else, erlang:get_stacktrace()} + catch _:Else:Stacktrace -> {Else, Stacktrace} end. @@ -550,7 +554,7 @@ finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) -> ok; {error, Reason} -> Msg = "Failed to handle last", - verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]), + verbose("~ts: ~tp: ~tp~n", [Msg, Tab, Reason]), down(Tab, Storage) end. @@ -774,9 +778,9 @@ do_send_table(Pid, Tab, Storage, RemoteS) -> throw:receiver_died -> cleanup_tab_copier(Pid, Storage, Tab), ok; - error:Reason -> %% Prepare failed + error:Reason:Stacktrace -> %% Prepare failed cleanup_tab_copier(Pid, Storage, Tab), - {error, {tab_copier, Tab, {Reason, erlang:get_stacktrace()}}} + {error, {tab_copier, Tab, {Reason, Stacktrace}}} after unlink(whereis(mnesia_tm)) end. @@ -856,7 +860,7 @@ send_more(Pid, N, Chunk, DataState, Tab, Storage) -> send_more(Pid, 1, NewChunk, Init(), Tab, Storage); {copier_done, Node} when Node == node(Pid)-> - verbose("Receiver of table ~p crashed on ~p (more)~n", [Tab, Node]), + verbose("Receiver of table ~tp crashed on ~p (more)~n", [Tab, Node]), throw(receiver_died) end. @@ -916,9 +920,15 @@ send_packet(_N, _Pid, _Chunk, DataState) -> finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) -> RecNode = node(Pid), DatBin = dat2bin(Tab, Storage, RemoteS), + Node = node(Pid), Trans = fun() -> NeedLock andalso mnesia:read_lock_table(Tab), + %% Check that receiver is still alive + receive {copier_done, Node} -> + throw(receiver_died) + after 0 -> ok + end, A = val({Tab, access_mode}), mnesia_controller:sync_and_block_table_whereabouts(Tab, RecNode, RemoteS, A), cleanup_tab_copier(Pid, Storage, Tab), @@ -927,8 +937,8 @@ finish_copy(Pid, Tab, Storage, RemoteS, NeedLock) -> receive {Pid, no_more} -> % Dont bother about the spurious 'more' message no_more; - {copier_done, Node} when Node == node(Pid)-> - verbose("Tab receiver ~p crashed (more): ~p~n", [Tab, Node]), + {copier_done, Node} -> + verbose("Tab receiver ~tp crashed (more): ~p~n", [Tab, Node]), receiver_died end end, diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 59fd89059f..f68626413e 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -97,10 +97,11 @@ init(Parent) -> end, loop(#state{supervisor = Parent}). +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); - _VaLuE_ -> _VaLuE_ + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); + Value -> Value end. reply(From, R) -> @@ -245,7 +246,7 @@ loop(State) -> do_stop(); {system, From, Msg} -> - verbose("~p got {system, ~p, ~p}~n", [?MODULE, From, Msg]), + verbose("~p got {system, ~p, ~tp}~n", [?MODULE, From, Msg]), Parent = State#state.supervisor, sys:handle_system_msg(Msg, From, Parent, ?MODULE, [], State); @@ -254,7 +255,7 @@ loop(State) -> loop(State); Msg -> - error("~p got unexpected message: ~p~n", [?MODULE, Msg]), + error("~p got unexpected message: ~tp~n", [?MODULE, Msg]), loop(State) end. diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl index 9536effd42..03411ace41 100644 --- a/lib/mnesia/src/mnesia_log.erl +++ b/lib/mnesia/src/mnesia_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -310,7 +310,7 @@ verify_no_exists(Fname) -> false -> ok; true -> - fatal("Log file exists: ~p~n", [Fname]) + fatal("Log file exists: ~tp~n", [Fname]) end. open_log(Name, Header, Fname) -> @@ -331,7 +331,7 @@ open_log(Name, Header, Fname, Exists, Repair) -> open_log(Name, Header, Fname, Exists, Repair, Mode) -> Args = [{file, Fname}, {name, Name}, {repair, Repair}, {mode, Mode}], -%% io:format("~p:open_log: ~p ~p~n", [?MODULE, Name, Fname]), +%% io:format("~p:open_log: ~tp ~tp~n", [?MODULE, Name, Fname]), case mnesia_monitor:open_log(Args) of {ok, Log} when Exists == true -> Log; @@ -344,19 +344,19 @@ open_log(Name, Header, Fname, Exists, Repair, Mode) -> write_header(Log, Header), Log; {repaired, Log, _Recover, BadBytes} -> - mnesia_lib:important("Data may be missing, log ~p repaired: Lost ~p bytes~n", + mnesia_lib:important("Data may be missing, log ~tp repaired: Lost ~p bytes~n", [Fname, BadBytes]), Log; {error, Reason = {file_error, _Fname, emfile}} -> - fatal("Cannot open log file ~p: ~p~n", [Fname, Reason]); + fatal("Cannot open log file ~tp: ~tp~n", [Fname, Reason]); {error, Reason} when Repair == true -> file:delete(Fname), - mnesia_lib:important("Data may be missing, Corrupt logfile deleted: ~p, ~p ~n", + mnesia_lib:important("Data may be missing, Corrupt logfile deleted: ~tp, ~tp ~n", [Fname, Reason]), %% Create a new open_log(Name, Header, Fname, false, false, read_write); {error, Reason} -> - fatal("Cannot open log file ~p: ~p~n", [Fname, Reason]) + fatal("Cannot open log file ~tp: ~tp~n", [Fname, Reason]) end. write_header(Log, Header) -> @@ -381,7 +381,7 @@ close_log(Log) -> {error, {read_only_mode, Log}} -> ok; {error, Reason} -> - mnesia_lib:important("Failed syncing ~p to_disk reason ~p ~n", + mnesia_lib:important("Failed syncing ~tp to_disk reason ~tp ~n", [Log, Reason]) end, mnesia_monitor:close_log(Log). @@ -464,13 +464,13 @@ chunk_log(_Log, eof) -> chunk_log(Log, Cont) -> case disk_log:chunk(Log, Cont) of {error, Reason} -> - fatal("Possibly truncated ~p file: ~p~n", + fatal("Possibly truncated ~tp file: ~tp~n", [Log, Reason]); {C2, Chunk, _BadBytes} -> %% Read_only case, should we warn about the bad log file? %% BUGBUG Should we crash if Repair == false ?? %% We got to check this !! - mnesia_lib:important("~p repaired, lost ~p bad bytes~n", [Log, _BadBytes]), + mnesia_lib:important("~tp repaired, lost ~p bad bytes~n", [Log, _BadBytes]), {C2, Chunk}; Other -> Other @@ -505,7 +505,7 @@ prepare_decision_log_dump(false, Prev) -> ok -> prepare_decision_log_dump(true, Prev); {error, Reason} -> - fatal("Cannot rename decision log file ~p -> ~p: ~p~n", + fatal("Cannot rename decision log file ~tp -> ~tp: ~tp~n", [decision_log_file(), Prev, Reason]) end; prepare_decision_log_dump(true, Prev) -> @@ -522,7 +522,7 @@ confirm_decision_log_dump() -> ok -> file:delete(previous_decision_log_file()); {error, Reason} -> - fatal("Cannot confirm decision log dump: ~p~n", + fatal("Cannot confirm decision log dump: ~tp~n", [Reason]) end. @@ -561,7 +561,7 @@ view() -> lists:foreach(fun(F) -> view(F) end, log_files()). view(File) -> - mnesia_lib:show("***** ~p ***** ~n", [File]), + mnesia_lib:show("***** ~tp ***** ~n", [File]), case exists(File) of false -> nolog; @@ -574,25 +574,25 @@ view(File) -> {repaired, _, _, _} -> view_file(start, N); {error, Reason} -> - error("Cannot open log ~p: ~p~n", [File, Reason]) + error("Cannot open log ~tp: ~tp~n", [File, Reason]) end end. view_file(C, Log) -> case disk_log:chunk(Log, C) of {error, Reason} -> - error("** Possibly truncated FILE ~p~n", [Reason]), + error("** Possibly truncated FILE ~tp~n", [Reason]), error; eof -> disk_log:close(Log), eof; {C2, Terms, _BadBytes} -> - dbg_out("Lost ~p bytes in ~p ~n", [_BadBytes, Log]), - lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, + dbg_out("Lost ~p bytes in ~tp ~n", [_BadBytes, Log]), + lists:foreach(fun(X) -> mnesia_lib:show("~tp~n", [X]) end, Terms), view_file(C2, Log); {C2, Terms} -> - lists:foreach(fun(X) -> mnesia_lib:show("~p~n", [X]) end, + lists:foreach(fun(X) -> mnesia_lib:show("~tp~n", [X]) end, Terms), view_file(C2, Log) end. @@ -750,12 +750,12 @@ abort_write_fun(B, What, Args) -> abort_write(B, What, Args, Reason) -> Mod = B#backup_args.module, Opaque = B#backup_args.opaque, - dbg_out("Failed to perform backup. M=~p:F=~p:A=~p -> ~p~n", + dbg_out("Failed to perform backup. M=~p:F=~tp:A=~tp -> ~tp~n", [Mod, What, Args, Reason]), - try apply(Mod, abort_write, [Opaque]) of - {ok, _Res} -> throw({error, Reason}) + try {ok, _Res} = apply(Mod, abort_write, [Opaque]) of + _ -> throw({error, Reason}) catch _:Other -> - error("Failed to abort backup. ~p:~p~p -> ~p~n", + error("Failed to abort backup. ~p:~tp~tp -> ~tp~n", [Mod, abort_write, [Opaque], Other]), throw({error, Reason}) end. @@ -802,7 +802,7 @@ select_source(Tab, Name, PrevName) -> {PrevName, retainer}; _ -> %% Do a full backup anyway - dbg_out("Incremental backup escalated to full backup: ~p~n", [Tab]), + dbg_out("Incremental backup escalated to full backup: ~tp~n", [Tab]), {Name, table} end end. diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl index ab78c9b13e..4cfe16dec0 100644 --- a/lib/mnesia/src/mnesia_monitor.erl +++ b/lib/mnesia/src/mnesia_monitor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. 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. @@ -169,7 +169,7 @@ check_protocol([{Node, {accept, Mon, Version, Protocol}} | Tail], Protocols) -> verbose("Failed to connect with ~p. ~p protocols rejected. " "expected version = ~p, expected protocol = ~p~n", [Node, Protocols, Version, Protocol]), - unlink(Mon), % Get rid of unneccessary link + unlink(Mon), % Get rid of unnecessary link check_protocol(Tail, Protocols) end; check_protocol([{Node, {reject, _Mon, Version, Protocol}} | Tail], Protocols) -> @@ -178,10 +178,10 @@ check_protocol([{Node, {reject, _Mon, Version, Protocol}} | Tail], Protocols) -> [Node, Protocols, Version, Protocol]), check_protocol(Tail, Protocols); check_protocol([{error, _Reason} | Tail], Protocols) -> - dbg_out("~p connect failed error: ~p~n", [?MODULE, _Reason]), + dbg_out("~p connect failed error: ~tp~n", [?MODULE, _Reason]), check_protocol(Tail, Protocols); check_protocol([{badrpc, _Reason} | Tail], Protocols) -> - dbg_out("~p connect failed badrpc: ~p~n", [?MODULE, _Reason]), + dbg_out("~p connect failed badrpc: ~tp~n", [?MODULE, _Reason]), check_protocol(Tail, Protocols); check_protocol([], [Protocol | _Protocols]) -> set(protocol_version, Protocol), @@ -246,10 +246,10 @@ start_proc(Who, Mod, Fun, Args) -> proc_lib:start_link(mnesia_sp, init_proc, Args2, infinity). terminate_proc(Who, R, State) when R /= shutdown, R /= killed -> - fatal("~p crashed: ~p state: ~p~n", [Who, R, State]); + fatal("~p crashed: ~p state: ~tp~n", [Who, R, State]); terminate_proc(Who, Reason, _State) -> - mnesia_lib:verbose("~p terminated: ~p~n", [Who, Reason]), + mnesia_lib:verbose("~p terminated: ~tp~n", [Who, Reason]), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -294,7 +294,7 @@ init([Parent]) -> {ok, #state{supervisor = Parent}} catch _:Reason -> - mnesia_lib:report_fatal("Bad configuration: ~p~n", [Reason]), + mnesia_lib:report_fatal("Bad configuration: ~tp~n", [Reason]), {stop, {bad_config, Reason}} end. @@ -333,7 +333,7 @@ handle_call({mktab, Tab, Args}, _From, State) -> catch error:ExitReason -> Msg = "Cannot create ets table", Reason = {system_limit, Msg, Tab, Args, ExitReason}, - fatal("~p~n", [Reason]), + fatal("~tp~n", [Reason]), {noreply, State} end; @@ -353,7 +353,7 @@ handle_call({open_dets, Tab, Args}, _From, State) -> {error, Reason} -> Msg = "Cannot open dets table", Error = {error, {Msg, Tab, Args, Reason}}, - fatal("~p~n", [Error]), + fatal("~tp~n", [Error]), {noreply, State} end; @@ -385,7 +385,7 @@ handle_call({reopen_log, Name, Fname, Head}, _From, State) -> {error, Reason} -> Msg = "Cannot rename disk_log file", Error = {error, {Msg, Name, Fname, Head, Reason}}, - fatal("~p~n", [Error]), + fatal("~tp~n", [Error]), {noreply, State} end; @@ -400,7 +400,7 @@ handle_call({close_log, Name}, _From, State) -> {error, Reason} -> Msg = "Cannot close disk_log file", Error = {error, {Msg, Name, Reason}}, - fatal("~p~n", [Error]), + fatal("~tp~n", [Error]), {noreply, State} end; @@ -461,7 +461,7 @@ handle_call(init, _From, State) -> {reply, EarlyNodes, State2}; handle_call(Msg, _From, State) -> - error("~p got unexpected call: ~p~n", [?MODULE, Msg]), + error("~p got unexpected call: ~tp~n", [?MODULE, Msg]), {noreply, State}. accept_protocol(Mon, Version, Protocol, From, State) -> @@ -535,7 +535,7 @@ handle_cast({inconsistent_database, Context, Node}, State) -> {noreply, State}; handle_cast(Msg, State) -> - error("~p got unexpected cast: ~p~n", [?MODULE, Msg]), + error("~p got unexpected cast: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- @@ -572,7 +572,7 @@ handle_info(Msg = {'EXIT',Pid,_}, State) -> %% We have probably got an exit signal from %% disk_log or dets Hint = "Hint: check that the disk still is writable", - fatal("~p got unexpected info: ~p; ~p~n", + fatal("~p got unexpected info: ~tp; ~p~n", [?MODULE, Msg, Hint]) end; @@ -599,13 +599,13 @@ handle_info({disk_log, _Node, Log, Info}, State) -> {truncated, _No} -> ok; _ -> - mnesia_lib:important("Warning Log file ~p error reason ~s~n", + mnesia_lib:important("Warning Log file ~tp error reason ~ts~n", [Log, disk_log:format_error(Info)]) end, {noreply, State}; handle_info(Msg, State) -> - error("~p got unexpected info (~p): ~p~n", [?MODULE, State, Msg]). + error("~p got unexpected info (~tp): ~tp~n", [?MODULE, State, Msg]). process_q(State = #state{mq=[]}) -> {noreply,State}; process_q(State = #state{mq=[{info,Msg}|R]}) -> diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl index b204fb282f..2ccea1ea6d 100644 --- a/lib/mnesia/src/mnesia_recover.erl +++ b/lib/mnesia/src/mnesia_recover.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -177,10 +177,10 @@ disconnect(Node) -> log_decision(D) -> cast({log_decision, D}). +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _Reason} -> - mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -762,7 +762,7 @@ handle_call(sync, _From, State) -> {reply, ok, State}; handle_call(Msg, _From, State) -> - error("~p got unexpected call: ~p~n", [?MODULE, Msg]), + error("~p got unexpected call: ~tp~n", [?MODULE, Msg]), {noreply, State}. do_log_mnesia_up(Node) -> @@ -881,7 +881,7 @@ handle_cast({log_dump_overload, Flag}, State) when is_boolean(Flag) -> {noreply, State#state{log_dump_overload = Flag}}; handle_cast(Msg, State) -> - error("~p got unexpected cast: ~p~n", [?MODULE, Msg]), + error("~p got unexpected cast: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- @@ -927,11 +927,11 @@ handle_info({force_decision, Tid}, State) -> end; handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor -> - mnesia_lib:dbg_out("~p was ~p~n",[?MODULE, R]), + mnesia_lib:dbg_out("~p was ~tp~n",[?MODULE, R]), {stop, shutdown, State}; handle_info(Msg, State) -> - error("~p got unexpected info: ~p~n", [?MODULE, Msg]), + error("~p got unexpected info: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 0e4017e4c3..ef38adca1e 100644 --- a/lib/mnesia/src/mnesia_schema.erl +++ b/lib/mnesia/src/mnesia_schema.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -181,9 +181,10 @@ exit_on_error({error, Reason}) -> exit_on_error(GoodRes) -> GoodRes. +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); Value -> Value end. @@ -386,7 +387,7 @@ delete_schema(Ns) when is_list(Ns), Ns /= [] -> [] -> ok; BadReplies -> - verbose("~s: ~p~n", [Reason, BadReplies]), + verbose("~s: ~tp~n", [Reason, BadReplies]), {error, {"All nodes not running", BadReplies}} end; {_Replies, BadNs} -> @@ -467,10 +468,10 @@ opt_create_dir(UseDir, Dir) when UseDir == true-> false -> case file:make_dir(Dir) of ok -> - verbose("Create Directory ~p~n", [Dir]), + verbose("Create Directory ~tp~n", [Dir]), ok; {error, Reason} -> - verbose("Cannot create mnesia dir ~p~n", [Reason]), + verbose("Cannot create mnesia dir ~tp~n", [Reason]), {error, {"Cannot create Mnesia dir", Dir, Reason}} end end; @@ -866,18 +867,18 @@ list2cs(List, ExtTypes) when is_list(List) -> is_list(DetsOpts) orelse mnesia:abort({badarg, Name, {dets, DetsOpts}}), [CheckProp(Prop, BadDetsOpts) || Prop <- DetsOpts], - case lists:keymember(mnesia, 1, application:which_applications()) of - true -> - Keys = check_keys(Name, List), - check_duplicates(Name, Keys); - false -> + case whereis(mnesia_controller) of + undefined -> %% check_keys/2 cannot be executed when mnesia is not %% running, due to it not being possible to read what ext %% backends are loaded. - %%% this doesn't work - disabled for now: - %%%Keys = check_keys(Name, List, record_info(fields, cstruct)), - %%%check_duplicates(Name, Keys) - ignore + %% this doesn't work - disabled for now: + %%Keys = check_keys(Name, List, record_info(fields, cstruct)), + %%check_duplicates(Name, Keys) + ignore; + Pid when is_pid(Pid) -> + Keys = check_keys(Name, List), + check_duplicates(Name, Keys) end, Cs0 = #cstruct{name = Name, @@ -952,19 +953,9 @@ get_index_plugins() -> get_schema_user_property(mnesia_index_plugins). get_schema_user_property(Key) -> - Tab = schema, - %% Must work reliably both within transactions and outside of transactions - Res = case get(mnesia_activity_state) of - undefined -> - dirty_read_table_property(Tab, Key); - _ -> - do_read_table_property(Tab, Key) - end, - case Res of - undefined -> - []; - {_, Types} -> - Types + case dirty_read_table_property(schema, Key) of + undefined -> []; + {_, Types} -> Types end. get_ext_types_disc() -> @@ -1470,7 +1461,7 @@ verify_backend_type(Name, Module) -> [] -> ok; _Other -> - io:fwrite(user, "Missing backend_type exports: ~p~n", [_Other]), + io:fwrite(user, "Missing backend_type exports: ~tp~n", [_Other]), mnesia:abort({bad_type, {backend_type,Name,Module}}) end. @@ -1776,7 +1767,7 @@ make_del_table_copy(Tab, Node) -> mnesia:abort({combine_error, Tab, "Last replica"}); [] -> ensure_active(Cs), - dbg_out("Last replica deleted in table ~p~n", [Tab]), + dbg_out("Last replica deleted in table ~tp~n", [Tab]), make_delete_table(Tab, whole_table); _ when Tab == schema -> %% ensure_active(Cs2), @@ -1941,7 +1932,7 @@ make_change_table_copy_type(Tab, Node, ToS) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% change index functions .... -%% Pos is allready added by 1 in both of these functions +%% Pos is already added by 1 in both of these functions add_table_index(Tab, Pos) -> schema_transaction(fun() -> do_add_table_index(Tab, Pos) end). @@ -2178,13 +2169,13 @@ do_write_table_property(Tab, Prop) -> case change_prop_in_existing_op(Tab, Prop, write_property, Store) of true -> dbg_out("change_prop_in_existing_op" - "(~p,~p,write_property,Store) -> true~n", + "(~tp,~p,write_property,Store) -> true~n", [Tab,Prop]), %% we have merged the table prop into the create_table op ok; false -> dbg_out("change_prop_in_existing_op" - "(~p,~p,write_property,Store) -> false~n", + "(~tp,~p,write_property,Store) -> false~n", [Tab,Prop]), %% this must be an existing table get_tid_ts_and_lock(Tab, none), @@ -2315,13 +2306,13 @@ do_delete_table_property(Tab, PropKey) -> 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", + "(~tp,~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", + "(~tp,~p,delete_property,Store) -> false~n", [Tab,PropKey]), %% this must be an existing table get_tid_ts_and_lock(Tab, none), @@ -2435,17 +2426,17 @@ prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) -> {sync_trans, CoordPid} -> {false, optional}; {mnesia_down, _Node} = Else -> - mnesia_lib:verbose("sync_op terminated due to ~p~n", [Else]), + mnesia_lib:verbose("sync_op terminated due to ~tp~n", [Else]), mnesia:abort(Else); {'EXIT', _, _} = Else -> - mnesia_lib:verbose("sync_op terminated due to ~p~n", [Else]), + mnesia_lib:verbose("sync_op terminated due to ~tp~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_lib:verbose("sync_op terminated due to ~tp~n", [Reason]), mnesia:abort(Reason); Pids -> [Pid ! {sync_trans, self()} || Pid <- Pids], @@ -2705,10 +2696,10 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) -> Objs -> mnesia_lib:db_fixtable(Storage, Tab, false), {true, Objs, mandatory} - catch _:Reason -> + catch _:Reason:Stacktrace -> mnesia_lib:db_fixtable(Storage, Tab, false), - mnesia_lib:important("Transform function failed: '~p' in '~p'", - [Reason, erlang:get_stacktrace()]), + mnesia_lib:important("Transform function failed: '~tp' in '~tp'", + [Reason, Stacktrace]), exit({"Bad transform function", Tab, Fun, node(), Reason}) end end; @@ -2719,7 +2710,7 @@ prepare_op(_Tid, {op, merge_schema, TabDef}, _WaitFor) -> ok -> {true, optional}; Error -> - verbose("Merge_Schema ~p failed on ~p: ~p~n", [_Tid,node(),Error]), + verbose("Merge_Schema ~p failed on ~p: ~tp~n", [_Tid,node(),Error]), mnesia:abort({bad_commit, Error}) end; prepare_op(_Tid, _Op, _WaitFor) -> @@ -3133,7 +3124,7 @@ ext_real_suffixes(Ext) -> [M || {_,M} <- Ext]) catch error:E -> - verbose("Cant find real ext suffixes (~p)~n", [E]), + verbose("Cant find real ext suffixes (~tp)~n", [E]), [] end. @@ -3142,7 +3133,7 @@ ext_tmp_suffixes(Ext) -> [M || {_,M} <- Ext]) catch error:E -> - verbose("Cant find tmp ext suffixes (~p)~n", [E]), + verbose("Cant find tmp ext suffixes (~tp)~n", [E]), [] end. @@ -3153,14 +3144,14 @@ info() -> info(Tab) -> Props = get_table_properties(Tab), - io:format("-- Properties for ~w table --- ~n",[Tab]), + io:format("-- Properties for ~tw table --- ~n",[Tab]), info2(Tab, Props). info2(Tab, [{cstruct, _V} | Tail]) -> % Ignore cstruct info2(Tab, Tail); info2(Tab, [{frag_hash, _V} | Tail]) -> % Ignore frag_hash info2(Tab, Tail); info2(Tab, [{P, V} | Tail]) -> - io:format("~-20w -> ~p~n",[P,V]), + io:format("~-20tw -> ~tp~n",[P,V]), info2(Tab, Tail); info2(_, []) -> io:format("~n", []). @@ -3726,7 +3717,7 @@ merge_versions(AnythingNew, Cs, RemoteCs, Force) -> ok; true -> Str = io_lib:format("Bad cookies. Cannot merge definitions of " - "table ~w. Local = ~w, Remote = ~w~n", + "table ~tw. Local = ~w, Remote = ~w~n", [Cs#cstruct.name, Cs, RemoteCs]), throw(Str) end, @@ -3746,7 +3737,7 @@ merge_versions(AnythingNew, Cs, RemoteCs, Force) -> do_merge_versions(AnythingNew, Cs, RemoteCs); true -> Str1 = io_lib:format("Cannot merge definitions of " - "table ~w. Local = ~w, Remote = ~w~n", + "table ~tw. Local = ~w, Remote = ~w~n", [Cs#cstruct.name, Cs, RemoteCs]), throw(Str1) end. diff --git a/lib/mnesia/src/mnesia_snmp_sup.erl b/lib/mnesia/src/mnesia_snmp_sup.erl deleted file mode 100644 index ed579d01c5..0000000000 --- a/lib/mnesia/src/mnesia_snmp_sup.erl +++ /dev/null @@ -1,43 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2016. 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. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% --module(mnesia_snmp_sup). - --behaviour(supervisor). - --export([start/0, init/1]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% top supervisor callback functions - -start() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% sub supervisor callback functions - -init([]) -> - Flags = {simple_one_for_one, 0, timer:hours(24)}, % Trust the top supervisor - MFA = {mnesia_snmp_hook, start, []}, - Modules = [?MODULE, mnesia_snmp_hook, supervisor], - KillAfter = mnesia_kernel_sup:supervisor_timeout(timer:seconds(3)), - Workers = [{?MODULE, MFA, transient, KillAfter, worker, Modules}], - {ok, {Flags, Workers}}. diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl index c2748f5bae..21a308cfb6 100644 --- a/lib/mnesia/src/mnesia_subscr.erl +++ b/lib/mnesia/src/mnesia_subscr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -264,7 +264,7 @@ handle_call({change, How}, _From, State) -> {reply, Reply, State}; handle_call(Msg, _From, State) -> - error("~p got unexpected call: ~p~n", [?MODULE, Msg]), + error("~p got unexpected call: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- @@ -274,7 +274,7 @@ handle_call(Msg, _From, State) -> %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_cast(Msg, State) -> - error("~p got unexpected cast: ~p~n", [?MODULE, Msg]), + error("~p got unexpected cast: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- @@ -292,7 +292,7 @@ handle_info({'EXIT', Pid, _Reason}, State) -> {noreply, State}; handle_info(Msg, State) -> - error("~p got unexpected info: ~p~n", [?MODULE, Msg]), + error("~p got unexpected info: ~tp~n", [?MODULE, Msg]), {noreply, State}. %%---------------------------------------------------------------------- diff --git a/lib/mnesia/src/mnesia_sup.erl b/lib/mnesia/src/mnesia_sup.erl index 4aece81308..3e5792900b 100644 --- a/lib/mnesia/src/mnesia_sup.erl +++ b/lib/mnesia/src/mnesia_sup.erl @@ -23,39 +23,21 @@ -module(mnesia_sup). --behaviour(application). -behaviour(supervisor). --export([start/0, start/2, init/1, stop/1, start_event/0, kill/0]). +-export([start_link/1, init/1, start_event/0, kill/0]). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% application and suprvisor callback functions - -start(normal, Args) -> - SupName = {local,?MODULE}, - case supervisor:start_link(SupName, ?MODULE, [Args]) of - {ok, Pid} -> - {ok, Pid, {normal, Args}}; - Error -> - Error - end; -start(_, _) -> - {error, badarg}. - -start() -> - SupName = {local,?MODULE}, - supervisor:start_link(SupName, ?MODULE, []). +start_link(Args) -> + supervisor:start_link({local,?MODULE}, ?MODULE, [Args]). -stop(_StartArgs) -> - ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% supervisor callback functions -init([]) -> % Supervisor - init(); -init([[]]) -> % Application +init([[]]) -> init(); init(BadArg) -> {error, {badarg, BadArg}}. - + init() -> Flags = {one_for_all, 0, 3600}, % Should be rest_for_one policy @@ -124,4 +106,3 @@ ensure_dead(Name) -> timer:sleep(10), ensure_dead(Name) end. - diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl index 21adca813a..cc21621ff4 100644 --- a/lib/mnesia/src/mnesia_text.erl +++ b/lib/mnesia/src/mnesia_text.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -87,18 +87,18 @@ validate_tab(_) -> error(badtab). make_tabs([{Tab, Def} | Tail]) -> try mnesia:table_info(Tab, where_to_read) of Node -> - io:format("** Table ~w already exists on ~p, just entering data~n", + io:format("** Table ~tw already exists on ~p, just entering data~n", [Tab, Node]), make_tabs(Tail) catch exit:_ -> %% non-existing table case mnesia:create_table(Tab, Def) of {aborted, Reason} -> - io:format("** Failed to create table ~w ~n" - "** Reason = ~w, Args = ~p~n", + io:format("** Failed to create table ~tw ~n" + "** Reason = ~tw, Args = ~tp~n", [Tab, Reason, Def]), [Tab | make_tabs(Tail)]; _ -> - io:format("New table ~w~n", [Tab]), + io:format("New table ~tw~n", [Tab]), make_tabs(Tail) end end; @@ -139,12 +139,12 @@ collect_data(Tabs, [{Line, Term} | Tail]) when is_tuple(Term) -> {value, _} -> [Term | collect_data(Tabs, Tail)]; _Other -> - io:format("Object:~p at line ~w unknown\n", [Term,Line]), + io:format("Object:~tp at line ~w unknown\n", [Term,Line]), error(undefined_object) end; collect_data(_Tabs, []) -> []; collect_data(_Tabs, [H|_T]) -> - io:format("Object:~p unknown\n", [H]), + io:format("Object:~tp unknown\n", [H]), error(undefined_object). error(What) -> throw({error, What}). @@ -178,7 +178,7 @@ read_term_from_stream(Stream, File, Line) -> {ok, {Line, Term}, EndLine}; {error, {NewLine,Mod,What}} -> Str = Mod:format_error(What), - io:format("Error in line:~p of:~p ~s\n", + io:format("Error in line:~p of:~tp ~ts\n", [NewLine, File, Str]), error end; diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index b116b48312..4b3fffc735 100644 --- a/lib/mnesia/src/mnesia_tm.erl +++ b/lib/mnesia/src/mnesia_tm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -80,6 +80,7 @@ start() -> init(Parent) -> register(?MODULE, self()), process_flag(trap_exit, true), + process_flag(message_queue_data, off_heap), %% Initialize the schema IgnoreFallback = mnesia_monitor:get_env(ignore_fallback_at_startup), @@ -120,10 +121,11 @@ init(Parent) -> proc_lib:init_ack(Parent, {ok, self()}), doit_loop(#state{supervisor = Parent}). +%% Local function in order to avoid external function call val(Var) -> - case ?catch_val(Var) of - {'EXIT', _} -> mnesia_lib:other_val(Var); - _VaLuE_ -> _VaLuE_ + case ?catch_val_and_stack(Var) of + {'EXIT', Stacktrace} -> mnesia_lib:other_val(Var, Stacktrace); + Value -> Value end. reply({From,Ref}, R) -> @@ -313,7 +315,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= ?eval_debug_fun({?MODULE, do_abort, pre}, [{tid, Tid}]), case gb_trees:lookup(Tid, Participants) of none -> - verbose("Tried to abort a non participant transaction ~p: ~p~n", + verbose("Tried to abort a non participant transaction ~p: ~tp~n", [Tid, Reason]), mnesia_locker:release_tid(Tid), doit_loop(State); @@ -416,7 +418,7 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= {From, {unblock_me, Tab}} -> case lists:member(Tab, State#state.blocked_tabs) of false -> - verbose("Wrong dirty Op blocked on ~p ~p ~p", + verbose("Wrong dirty Op blocked on ~p ~tp ~p", [node(), Tab, From]), reply(From, unblocked), doit_loop(State); @@ -465,11 +467,11 @@ doit_loop(#state{coordinators=Coordinators,participants=Participants,supervisor= end; {system, From, Msg} -> - dbg_out("~p got {system, ~p, ~p}~n", [?MODULE, From, Msg]), + dbg_out("~p got {system, ~p, ~tp}~n", [?MODULE, From, Msg]), sys:handle_system_msg(Msg, From, Sup, ?MODULE, [], State); Msg -> - verbose("** ERROR ** ~p got unexpected message: ~p~n", [?MODULE, Msg]), + verbose("** ERROR ** ~p got unexpected message: ~tp~n", [?MODULE, Msg]), doit_loop(State) end. @@ -555,7 +557,7 @@ handle_exit(Pid, Reason, State) -> %% We got exit from a local fool doit_loop(State); {P = #participant{}, _RestP} -> - fatal("Participant ~p in transaction ~p died ~p~n", + fatal("Participant ~p in transaction ~p died ~tp~n", [P#participant.pid, P#participant.tid, Reason]), NewPs = gb_trees:delete(P#participant.tid,State#state.participants), doit_loop(State#state{participants = NewPs}) @@ -596,9 +598,9 @@ recover_coordinator(Tid, Etabs) -> false -> %% When killed before store havn't been copied to ok %% to the new nested trans store. end - catch _:Reason -> - dbg_out("Recovery of coordinator ~p failed:~n", - [Tid, {Reason, erlang:get_stacktrace()}]), + catch _:Reason:Stacktrace -> + dbg_out("Recovery of coordinator ~p failed: ~tp~n", + [Tid, {Reason, Stacktrace}]), Protocol = asym_trans, tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes) end, @@ -824,8 +826,7 @@ execute_transaction(Fun, Args, Factor, Retries, Type) -> catch throw:Value -> %% User called throw Reason = {aborted, {throw, Value}}, return_abort(Fun, Args, Reason); - error:Reason -> - ST = erlang:get_stacktrace(), + error:Reason:ST -> check_exit(Fun, Args, Factor, Retries, {Reason,ST}, Type); _:Reason -> check_exit(Fun, Args, Factor, Retries, Reason, Type) @@ -940,7 +941,7 @@ decr(_X) -> 0. return_abort(Fun, Args, Reason) -> {_Mod, Tid, Ts} = get(mnesia_activity_state), - dbg_out("Transaction ~p calling ~p with ~p failed: ~n ~p~n", + dbg_out("Transaction ~p calling ~tp with ~tp failed: ~n ~tp~n", [Tid, Fun, Args, Reason]), OldStore = Ts#tidstore.store, Nodes = get_elements(nodes, OldStore), @@ -950,7 +951,7 @@ return_abort(Fun, Args, Reason) -> if Level == 1 -> mnesia_locker:async_release_tid(Nodes, Tid), - ?MODULE ! {delete_transaction, Tid}, + ?SAFE(?MODULE ! {delete_transaction, Tid}), erase(mnesia_activity_state), flush_downs(), ?SAFE(unlink(whereis(?MODULE))), @@ -1713,7 +1714,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> mnesia_schema:undo_prepare_commit(Tid, C0); Msg -> - verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n", + verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~tp~n", [Tid, Msg]) end; {Tid, {do_abort, Reason}} -> @@ -1729,7 +1730,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> Msg -> reply(Coord, {do_abort, Tid, self(), {bad_commit,internal}}), - verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~p~n", + verbose("** ERROR ** commit_participant ~p, got unexpected msg: ~tp~n", [Tid, Msg]) end catch _:Reason -> @@ -1795,15 +1796,14 @@ do_update(Tid, Storage, [Op | Ops], OldRes) -> try do_update_op(Tid, Storage, Op) of ok -> do_update(Tid, Storage, Ops, OldRes); NewRes -> do_update(Tid, Storage, Ops, NewRes) - catch _:Reason -> + catch _:Reason:ST -> %% This may only happen when we recently have %% deleted our local replica, changed storage_type %% or transformed table %% BUGBUG: Updates may be lost if storage_type is changed. %% Determine actual storage type and try again. %% BUGBUG: Updates may be lost if table is transformed. - ST = erlang:get_stacktrace(), - verbose("do_update in ~w failed: ~p -> {'EXIT', ~p}~n", + verbose("do_update in ~w failed: ~tp -> {'EXIT', ~tp}~n", [Tid, Op, {Reason, ST}]), do_update(Tid, Storage, Ops, OldRes) end; @@ -1913,12 +1913,11 @@ commit_clear([H|R], Tid, Storage, Tab, K, Obj) do_snmp(_, []) -> ok; do_snmp(Tid, [Head|Tail]) -> try mnesia_snmp_hook:update(Head) - catch _:Reason -> + catch _:Reason:ST -> %% This should only happen when we recently have %% deleted our local replica or recently deattached %% the snmp table - ST = erlang:get_stacktrace(), - verbose("do_snmp in ~w failed: ~p -> {'EXIT', ~p}~n", + verbose("do_snmp in ~w failed: ~tp -> {'EXIT', ~tp}~n", [Tid, Head, {Reason, ST}]) end, do_snmp(Tid, Tail). @@ -2150,7 +2149,7 @@ pr_participant(Stream, P) -> true -> Commit0 end, pr_tid(Stream, P#participant.tid), - io:format(Stream, "with participant objects ~p~n", [Commit]). + io:format(Stream, "with participant objects ~tp~n", [Commit]). pr_tid(Stream, Tid) -> @@ -2192,7 +2191,7 @@ search_pr_participant(S, [ P | Tail]) -> true -> Commit0 end, - io:format("~p~n", [Commit]), + io:format("~tp~n", [Commit]), search_pr_participant(S,Tail); %% !!!!! true -> search_pr_participant(S, Tail) @@ -2211,14 +2210,14 @@ display_pid_info(Pid) -> Other end, Reds = fetch(reductions, Info), - LM = length(fetch(messages, Info)), + LM = fetch(message_queue_len, Info), pformat(io_lib:format("~p", [Pid]), - io_lib:format("~p", [Call]), - io_lib:format("~p", [Curr]), Reds, LM) + io_lib:format("~tp", [Call]), + io_lib:format("~tp", [Curr]), Reds, LM) end. pformat(A1, A2, A3, A4, A5) -> - io:format( "~-12s ~-21s ~-21s ~9w ~4w~n", [A1,A2,A3,A4,A5]). + io:format( "~-12s ~-21ts ~-21ts ~9w ~4w~n", [A1,A2,A3,A4,A5]). fetch(Key, Info) -> case lists:keysearch(Key, 1, Info) of diff --git a/lib/mnesia/test/ext_test.erl b/lib/mnesia/test/ext_test.erl index 45ddb148bc..ad32245a11 100644 --- a/lib/mnesia/test/ext_test.erl +++ b/lib/mnesia/test/ext_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. 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. @@ -233,5 +233,5 @@ select_1({Acc, C}) -> select(ext_ets, Tab, Ms, Limit) when is_integer(Limit); Limit =:= infinity -> ets:select(mnesia_lib:val({?MODULE,Tab}), Ms, Limit). -repair_continuation({Alias, Cont}, Ms) -> - {Alias, ets:repair_continuation(Cont, Ms)}. +repair_continuation(Cont, Ms) -> + ets:repair_continuation(Cont, Ms). diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl index 3ec4847c5d..24c1def6da 100644 --- a/lib/mnesia/test/mnesia_SUITE.erl +++ b/lib/mnesia/test/mnesia_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -21,7 +21,12 @@ %% -module(mnesia_SUITE). -author('[email protected]'). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + suite/0, all/0, groups/0]). +-export([app/1, appup/1, clean_up_suite/1, silly/0]). + -include_lib("common_test/include/ct.hrl"). -include("mnesia_test_lib.hrl"). @@ -92,16 +97,8 @@ groups() -> %% benchmarks {heavy, [], [{group, measure}]}, {measure, [], [{mnesia_measure_test, all}]}, - {prediction, [], - [{group, mnesia_measure_test, prediction}]}, - {fairness, [], - [{group, mnesia_measure_test, fairness}]}, {benchmarks, [], [{group, mnesia_measure_test, benchmarks}]}, - {consumption, [], - [{group, mnesia_measure_test, consumption}]}, - {scalability, [], - [{group, mnesia_measure_test, scalability}]}, %% This test suite is an extract of the grand Mnesia suite %% it contains OTP R4B specific test cases {otp_r4b, [], diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl index cc32ba3826..4764f9e7c0 100644 --- a/lib/mnesia/test/mnesia_atomicity_test.erl +++ b/lib/mnesia/test/mnesia_atomicity_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -22,9 +22,37 @@ -module(mnesia_atomicity_test). -author('[email protected]'). -author('[email protected]'). --compile([export_all]). -include("mnesia_test_lib.hrl"). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). +-export([explicit_abort_in_middle_of_trans/1, + runtime_error_in_middle_of_trans/1, + mnesia_down_during_infinite_trans/1, + kill_self_in_middle_of_trans/1, throw_in_middle_of_trans/1, + lock_waiter_sw_r/1, lock_waiter_sw_rt/1, lock_waiter_sw_wt/1, + lock_waiter_wr_r/1, lock_waiter_srw_r/1, lock_waiter_sw_sw/1, + lock_waiter_sw_w/1, lock_waiter_sw_wr/1, lock_waiter_sw_srw/1, + lock_waiter_wr_wt/1, lock_waiter_srw_wt/1, + lock_waiter_wr_sw/1, lock_waiter_srw_sw/1, lock_waiter_wr_w/1, + lock_waiter_srw_w/1, lock_waiter_r_sw/1, lock_waiter_r_w/1, + lock_waiter_r_wt/1, lock_waiter_rt_sw/1, lock_waiter_rt_w/1, + lock_waiter_rt_wt/1, lock_waiter_wr_wr/1, + lock_waiter_srw_srw/1, lock_waiter_wt_r/1, lock_waiter_wt_w/1, + lock_waiter_wt_rt/1, lock_waiter_wt_wt/1, lock_waiter_wt_wr/1, + lock_waiter_wt_srw/1, lock_waiter_wt_sw/1, lock_waiter_w_wr/1, + lock_waiter_w_srw/1, lock_waiter_w_sw/1, lock_waiter_w_r/1, + lock_waiter_w_w/1, lock_waiter_w_rt/1, lock_waiter_w_wt/1, + restart_r_one/1, restart_w_one/1, restart_rt_one/1, + restart_wt_one/1, restart_wr_one/1, restart_sw_one/1, + restart_r_two/1, restart_w_two/1, restart_rt_two/1, + restart_wt_two/1, restart_wr_two/1, restart_sw_two/1 + ] + ). + +-export([perform_restarted_transaction/1, sync_tid_release/0]). + init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). diff --git a/lib/mnesia/test/mnesia_bench_SUITE.erl b/lib/mnesia/test/mnesia_bench_SUITE.erl index 7c86db383d..8a225629e6 100644 --- a/lib/mnesia/test/mnesia_bench_SUITE.erl +++ b/lib/mnesia/test/mnesia_bench_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2016. All Rights Reserved. +%% Copyright Ericsson AB 2012-2018. 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. @@ -21,7 +21,13 @@ %% -module(mnesia_bench_SUITE). -author('[email protected]'). --compile(export_all). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, + suite/0, all/0, groups/0]). + +-export([tpcb_conflict_ramcopies/1, tpcb_conflict_disk_only_copies/1]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}]. diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl index 2fe1bd34e6..46bafaf65c 100644 --- a/lib/mnesia/test/mnesia_consistency_test.erl +++ b/lib/mnesia/test/mnesia_consistency_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -21,7 +21,78 @@ %% -module(mnesia_consistency_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([consistency_after_change_table_copy_type/1, + consistency_after_rename_of_node/1, + consistency_after_restart_1_ram/1, + consistency_after_restart_1_disc/1, + consistency_after_restart_1_disc_only/1, + consistency_after_restart_2_ram/1, + consistency_after_restart_2_disc/1, + consistency_after_restart_2_disc_only/1, + consistency_after_dump_tables_1_ram/1, + consistency_after_dump_tables_2_ram/1, + consistency_after_add_replica_2_ram/1, + consistency_after_add_replica_2_disc/1, + consistency_after_add_replica_2_disc_only/1, + consistency_after_add_replica_3_ram/1, + consistency_after_add_replica_3_disc/1, + consistency_after_add_replica_3_disc_only/1, + consistency_after_del_replica_2_ram/1, + consistency_after_del_replica_2_disc/1, + consistency_after_del_replica_2_disc_only/1, + consistency_after_del_replica_3_ram/1, + consistency_after_del_replica_3_disc/1, + consistency_after_del_replica_3_disc_only/1, + consistency_after_move_replica_2_ram/1, + consistency_after_move_replica_2_disc/1, + consistency_after_move_replica_2_disc_only/1, + consistency_after_move_replica_3_ram/1, + consistency_after_move_replica_3_disc/1, + consistency_after_move_replica_3_disc_only/1, + consistency_after_transform_table_ram/1, + consistency_after_transform_table_disc/1, + consistency_after_transform_table_disc_only/1, + consistency_after_fallback_2_ram/1, + consistency_after_fallback_2_disc/1, + consistency_after_fallback_2_disc_only/1, + consistency_after_fallback_3_ram/1, + consistency_after_fallback_3_disc/1, + consistency_after_fallback_3_disc_only/1, + consistency_after_restore_clear_ram/1, + consistency_after_restore_clear_disc/1, + consistency_after_restore_clear_disc_only/1, + consistency_after_restore_recreate_ram/1, + consistency_after_restore_recreate_disc/1, + consistency_after_restore_recreate_disc_only/1, + updates_during_checkpoint_activation_1_ram/1, + updates_during_checkpoint_activation_1_disc/1, + updates_during_checkpoint_activation_1_disc_only/1, + updates_during_checkpoint_activation_2_ram/1, + updates_during_checkpoint_activation_2_disc/1, + updates_during_checkpoint_activation_2_disc_only/1, + updates_during_checkpoint_activation_3_ram/1, + updates_during_checkpoint_activation_3_disc/1, + updates_during_checkpoint_activation_3_disc_only/1, + updates_during_checkpoint_iteration_2_ram/1, + updates_during_checkpoint_iteration_2_disc/1, + updates_during_checkpoint_iteration_2_disc_only/1, + load_table_with_activated_checkpoint_ram/1, + load_table_with_activated_checkpoint_disc/1, + load_table_with_activated_checkpoint_disc_only/1, + add_table_copy_to_table_checkpoint_ram/1, + add_table_copy_to_table_checkpoint_disc/1, + add_table_copy_to_table_checkpoint_disc_only/1, + inst_fallback_process_dies/1, fatal_when_inconsistency/1, + after_delete/1,cause_switch_before/1, cause_switch_after/1, + cause_abort_before/1, cause_abort_after/1, + change_schema_before/1, change_schema_after/1]). + +-export([change_tab/3]). -include("mnesia_test_lib.hrl"). diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl index a3fc8dfe20..b5d5253147 100644 --- a/lib/mnesia/test/mnesia_cost.erl +++ b/lib/mnesia/test/mnesia_cost.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -20,7 +20,7 @@ %% -module(mnesia_cost). --compile(export_all). +-export([go/0, go/1]). %% This code exercises the mnesia system and produces a bunch %% of measurements on what various things cost @@ -156,64 +156,3 @@ do_dirty(I, F) when I /= 0 -> F(), do_dirty(I-1, F); do_dirty(_,_) -> ok. - - - -table_load([N1,N2| _ ] = Ns) -> - Nodes = [N1,N2], - rpc:multicall(Ns, mnesia, lkill, []), - ok = mnesia:delete_schema(Ns), - ok = mnesia:create_schema(Nodes), - rpc:multicall(Nodes, mnesia, start, []), - TabDef = [{disc_copies,[N1]},{ram_copies,[N2]}, - {attributes,record_info(fields,item)},{record_name,item}], - Tabs = [list_to_atom("tab" ++ integer_to_list(I)) || I <- lists:seq(1,400)], - - [mnesia:create_table(Tab,TabDef) || Tab <- Tabs], - -%% InitTab = fun(Tab) -> -%% mnesia:write_lock_table(Tab), -%% InitRec = fun(Key) -> mnesia:write(Tab,#item{a=Key},write) end, -%% lists:foreach(InitRec, lists:seq(1,100)) -%% end, -%% -%% {Time,{atomic,ok}} = timer:tc(mnesia,transaction, [fun() ->lists:foreach(InitTab, Tabs) end]), - mnesia:dump_log(), -%% io:format("Init took ~p msec ~n", [Time/1000]), - rpc:call(N2, mnesia, stop, []), timer:sleep(1000), - mnesia:stop(), timer:sleep(500), - %% Warmup - ok = mnesia:start([{no_table_loaders, 1}]), - timer:tc(mnesia, wait_for_tables, [Tabs, infinity]), - mnesia:dump_log(), - rpc:call(N2, mnesia, dump_log, []), - io:format("Initialized ~n",[]), - - mnesia:stop(), timer:sleep(1000), - ok = mnesia:start([{no_table_loaders, 1}]), - {T1, ok} = timer:tc(mnesia, wait_for_tables, [Tabs, infinity]), - io:format("Loading from disc with 1 loader ~p msec~n",[T1/1000]), - mnesia:stop(), timer:sleep(1000), - ok = mnesia:start([{no_table_loaders, 4}]), - {T2, ok} = timer:tc(mnesia, wait_for_tables, [Tabs, infinity]), - io:format("Loading from disc with 4 loader ~p msec~n",[T2/1000]), - - %% Warmup - rpc:call(N2, ?MODULE, remote_load, [Tabs,4]), - io:format("Initialized ~n",[]), - - - T3 = rpc:call(N2, ?MODULE, remote_load, [Tabs,1]), - io:format("Loading from net with 1 loader ~p msec~n",[T3/1000]), - - T4 = rpc:call(N2, ?MODULE, remote_load, [Tabs,4]), - io:format("Loading from net with 4 loader ~p msec~n",[T4/1000]), - - ok. - -remote_load(Tabs,Loaders) -> - ok = mnesia:start([{no_table_loaders, Loaders}]), -%% io:format("~p ~n", [mnesia_controller:get_info(500)]), - {Time, ok} = timer:tc(mnesia, wait_for_tables, [Tabs, infinity]), - timer:sleep(1000), mnesia:stop(), timer:sleep(1000), - Time. diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl index 6d970ac990..67ef1fe901 100644 --- a/lib/mnesia/test/mnesia_dirty_access_test.erl +++ b/lib/mnesia/test/mnesia_dirty_access_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,9 +21,37 @@ %% -module(mnesia_dirty_access_test). -author('[email protected]'). --compile([export_all]). -include("mnesia_test_lib.hrl"). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([dirty_write_ram/1, dirty_write_disc/1, dirty_write_disc_only/1, dirty_write_xets/1, + dirty_read_ram/1, dirty_read_disc/1, dirty_read_disc_only/1, dirty_read_xets/1, + dirty_update_counter_ram/1, dirty_update_counter_disc/1, + dirty_update_counter_disc_only/1, dirty_update_counter_xets/1, + dirty_delete_ram/1, dirty_delete_disc/1, dirty_delete_disc_only/1, dirty_delete_xets/1, + dirty_delete_object_ram/1, dirty_delete_object_disc/1, + dirty_delete_object_disc_only/1, dirty_delete_object_xets/1, + dirty_match_object_ram/1, dirty_match_object_disc/1, + dirty_match_object_disc_only/1, dirty_match_object_xets/1, + dirty_index_match_object_ram/1, dirty_index_match_object_disc/1, + dirty_index_match_object_disc_only/1, dirty_index_match_object_xets/1, + dirty_index_read_ram/1, dirty_index_read_disc/1, + dirty_index_read_disc_only/1, dirty_index_read_xets/1, + dirty_index_update_set_ram/1, dirty_index_update_set_disc/1, + dirty_index_update_set_disc_only/1, dirty_index_update_set_xets/1, + dirty_index_update_bag_ram/1, dirty_index_update_bag_disc/1, + dirty_index_update_bag_disc_only/1, dirty_index_update_bag_xets/1, + dirty_iter_ram/1, dirty_iter_disc/1, dirty_iter_disc_only/1,dirty_iter_xets/1, + del_table_copy_1/1, del_table_copy_2/1, del_table_copy_3/1, + add_table_copy_1/1, add_table_copy_2/1, add_table_copy_3/1, + add_table_copy_4/1, move_table_copy_1/1, move_table_copy_2/1, + move_table_copy_3/1, move_table_copy_4/1]). + +-export([update_trans/3]). + init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl index 97bc84a2d8..ccbfdc9738 100644 --- a/lib/mnesia/test/mnesia_durability_test.erl +++ b/lib/mnesia/test/mnesia_durability_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -21,7 +21,34 @@ %% -module(mnesia_durability_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([durability_of_disc_copies/1, + durability_of_disc_only_copies/1, + load_latest_data/1, load_local_contents_directly/1, + load_directly_when_all_are_ram_copiesA/1, + load_directly_when_all_are_ram_copiesB/1, + load_when_last_replica_becomes_available/1, + load_when_down_from_all_other_replica_nodes/1, + late_load_transforms_into_disc_load/1, + late_load_leads_to_hanging/1, + force_load_when_nobody_intents_to_load/1, + force_load_when_someone_has_decided_to_load/1, + force_load_when_someone_else_has_loaded/1, + force_load_when_we_has_loaded/1, + force_load_on_a_non_local_table/1, + force_load_when_the_table_does_not_exist/1, + late_load_all_ram_cs_ram_nodes1/1, + late_load_all_ram_cs_ram_nodes2/1, + master_nodes/1, starting_master_nodes/1, + master_on_non_local_tables/1, + remote_force_load_with_local_master_node/1, + master_node_with_ram_copy_2/1, master_node_with_ram_copy_3/1, + dump_ram_copies/1, dump_disc_copies/1, dump_disc_only/1]). + -include("mnesia_test_lib.hrl"). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -65,7 +92,8 @@ groups() -> {load_tables_with_master_tables, [], [master_nodes, starting_master_nodes, master_on_non_local_tables, - remote_force_load_with_local_master_node]}, + remote_force_load_with_local_master_node, + master_node_with_ram_copy_2, master_node_with_ram_copy_3]}, {durability_of_dump_tables, [], [dump_ram_copies, dump_disc_copies, dump_disc_only]}]. @@ -1139,6 +1167,107 @@ remote_force_load_with_local_master_node(Config) when is_list(Config) -> ?verify_mnesia(Nodes, []). +master_node_with_ram_copy_2(Config) when is_list(Config) -> + [A, B] = Nodes = ?acquire_nodes(2, Config), + Tab = ?FUNCTION_NAME, + ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A]}, {ram_copies, [B]}])), + ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))), + + %% Test that we don't load from ram_copies + ?match(stopped, rpc:call(A, mnesia, stop, [])), + ?match(stopped, rpc:call(B, mnesia, stop, [])), + ?match(ok, rpc:call(B, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])), + ?match(ok, rpc:call(A, mnesia, start, [])), + ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])), + ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])), + + %% Test that master_nodes set to ram_copy node require force_load + ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])), + ?match(stopped, rpc:call(A, mnesia, stop, [])), + ?match(stopped, rpc:call(B, mnesia, stop, [])), + ?match(ok, rpc:call(B, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])), + ?match(ok, rpc:call(A, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])), + + ?match(yes, rpc:call(A, mnesia, force_load_table, [Tab])), + ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 1000])), + ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])), + ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])), + + ?verify_mnesia(Nodes, []). + + +master_node_with_ram_copy_3(Config) when is_list(Config) -> + [A, B, C] = Nodes = ?acquire_nodes(3, Config), + Tab = ?FUNCTION_NAME, + ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A,C]}, {ram_copies, [B]}])), + ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))), + + %% Test that we don't load from ram_copies + ?match(stopped, rpc:call(A, mnesia, stop, [])), + ?match(stopped, rpc:call(C, mnesia, stop, [])), + ?match(stopped, rpc:call(B, mnesia, stop, [])), + ?match(ok, rpc:call(B, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])), + ?match(ok, rpc:call(A, mnesia, start, [])), + ?match(ok, rpc:call(C, mnesia, start, [])), + ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])), + ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])), + ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, init}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])), + + %% Test that master_nodes set to ram_copy node will wait until loaded + ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])), + ?match(stopped, rpc:call(A, mnesia, stop, [])), + ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])), + ?match(stopped, rpc:call(C, mnesia, stop, [])), + ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])), + ?match(stopped, rpc:call(B, mnesia, stop, [])), + ?match(ok, rpc:call(B, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])), + ?match(ok, rpc:call(A, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])), + ?match(ok, rpc:call(C, mnesia, start, [])), + ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])), + ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])), + ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])), + + %% Test that master_nodes set to ram_copy node requires force load + ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))), + ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])), + ?match(ok, rpc:call(C, mnesia, set_master_nodes, [[B]])), + + ?match(stopped, rpc:call(A, mnesia, stop, [])), + ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])), + ?match(stopped, rpc:call(C, mnesia, stop, [])), + ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])), + ?match(stopped, rpc:call(B, mnesia, stop, [])), + ?match(ok, rpc:call(B, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])), + ?match(ok, rpc:call(A, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])), + ?match(ok, rpc:call(C, mnesia, start, [])), + ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])), + ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])), + ?match(yes, rpc:call(C, mnesia, force_load_table, [Tab])), + + ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])), + ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])), + ?match(ok, rpc:call(C, mnesia, wait_for_tables, [[Tab], 3000])), + ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])), + ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])), + + ?verify_mnesia(Nodes, []). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1389,7 +1518,7 @@ do_disc_durability(Config,CopyType) -> [{Tab_bag, 22, a_2222}], [{Tab_bag, 33, a_3333}], [{Tab_set, counter, 10}]]), - timer:sleep(1000), %% Debugging strange msgs.. + timer:sleep(500), %% Debugging strange msgs.. ?log("Flushed ~p ~n", [mnesia_test_lib:flush()]), ?verify_mnesia(Nodes, []). diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl index e745ec9b04..45b11f2f3f 100644 --- a/lib/mnesia/test/mnesia_evil_backup.erl +++ b/lib/mnesia/test/mnesia_evil_backup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2017. 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. @@ -28,10 +28,23 @@ -module(mnesia_evil_backup). -author('[email protected]'). --compile(export_all). -include("mnesia_test_lib.hrl"). -%%-export([Function/Arity, ...]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([backup/1, bad_backup/1, global_backup_checkpoint/1, + traverse_backup/1, + selective_backup_checkpoint/1, + incremental_backup_checkpoint/1, install_fallback/1, + uninstall_fallback/1, local_fallback/1, + sops_with_checkpoint/1, + restore_errors/1, restore_clear/1, restore_keep/1, + restore_recreate/1, restore_clear_ram/1 + ]). + +-export([check_tab/2]). init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). @@ -723,18 +736,18 @@ bup_records(File, Mod) -> exit(Reason) end. -sops_with_checkpoint(doc) -> +sops_with_checkpoint(doc) -> ["Test schema operations during a checkpoint"]; sops_with_checkpoint(suite) -> []; sops_with_checkpoint(Config) when is_list(Config) -> - Ns = ?acquire_nodes(2, Config), - + Ns = [N1,N2] = ?acquire_nodes(2, Config), + ?match({ok, cp1, Ns}, mnesia:activate_checkpoint([{name, cp1},{max,mnesia:system_info(tables)}])), - Tab = tab, + Tab = tab, ?match({atomic, ok}, mnesia:create_table(Tab, [{disc_copies,Ns}])), OldRecs = [{Tab, K, -K} || K <- lists:seq(1, 5)], [mnesia:dirty_write(R) || R <- OldRecs], - + ?match({ok, cp2, Ns}, mnesia:activate_checkpoint([{name, cp2},{max,mnesia:system_info(tables)}])), File1 = "cp1_delete_me.BUP", ?match(ok, mnesia:dirty_write({Tab,6,-6})), @@ -742,16 +755,16 @@ sops_with_checkpoint(Config) when is_list(Config) -> ?match(ok, mnesia:dirty_write({Tab,7,-7})), File2 = "cp2_delete_me.BUP", ?match(ok, mnesia:backup_checkpoint(cp2, File2)), - + ?match(ok, mnesia:deactivate_checkpoint(cp1)), ?match(ok, mnesia:backup_checkpoint(cp2, File1)), ?match(ok, mnesia:dirty_write({Tab,8,-8})), - + ?match({atomic,ok}, mnesia:delete_table(Tab)), ?match({error,_}, mnesia:backup_checkpoint(cp2, File2)), ?match({'EXIT',_}, mnesia:dirty_write({Tab,9,-9})), - ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])), + ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])), Test = fun(N) when N > 5 -> ?error("To many records in backup ~p ~n", [N]); (N) -> case mnesia:dirty_read(Tab,N) of [{Tab,N,B}] when -B =:= N -> ok; @@ -759,8 +772,29 @@ sops_with_checkpoint(Config) when is_list(Config) -> end end, [Test(N) || N <- mnesia:dirty_all_keys(Tab)], - ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])), - + ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])), + + %% Mnesia crashes when deleting a table during backup + ?match([], mnesia_test_lib:stop_mnesia([N2])), + Tab2 = ram, + ?match({atomic, ok}, mnesia:create_table(Tab2, [{ram_copies,[N1]}])), + ?match({ok, cp3, _}, mnesia:activate_checkpoint([{name, cp3}, + {ram_overrides_dump,true}, + {min,[Tab2]}])), + Write = fun Loop (N) -> + case N > 0 of + true -> + mnesia:dirty_write({Tab2, N+100, N+100}), + Loop(N-1); + false -> + ok + end + end, + ok = Write(100000), + spawn_link(fun() -> ?match({atomic, ok},mnesia:delete_table(Tab2)) end), + + %% We don't check result here, depends on timing of above call + mnesia:backup_checkpoint(cp3, File2), file:delete(File1), file:delete(File2), - ?verify_mnesia(Ns, []). + ?verify_mnesia([N1], [N2]). diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 6e34040bc4..a451c8d0c8 100644 --- a/lib/mnesia/test/mnesia_evil_coverage_test.erl +++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -23,7 +23,33 @@ -author('[email protected]'). -include("mnesia_test_lib.hrl"). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([system_info/1, table_info/1, error_description/1, + db_node_lifecycle/1, evil_delete_db_node/1, start_and_stop/1, + checkpoint/1, table_lifecycle/1, storage_options/1, + add_copy_conflict/1, add_copy_when_going_down/1, + add_copy_with_down/1, + replica_management/1, clear_table_during_load/1, + schema_availability/1, local_content/1, + replica_location/1, user_properties/1, unsupp_user_props/1, + sorted_ets/1, index_cleanup/1, + change_table_access_mode/1, change_table_load_order/1, + set_master_nodes/1, offline_set_master_nodes/1, + dump_tables/1, dump_log/1, wait_for_tables/1, force_load_table/1, + snmp_open_table/1, snmp_close_table/1, snmp_get_next_index/1, + snmp_get_row/1, snmp_get_mnesia_key/1, snmp_update_counter/1, + snmp_order/1, subscribe_standard/1, subscribe_extended/1, + foldl/1, info/1, schema_0/1, schema_1/1, view_0/1, view_1/1, view_2/1, + lkill/1, kill/1, + record_name_dirty_access_ram/1, + record_name_dirty_access_disc/1, + record_name_dirty_access_disc_only/1, + record_name_dirty_access_xets/1]). + +-export([info_check/8, index_size/1]). -define(cleanup(N, Config), mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}], @@ -40,13 +66,14 @@ all() -> db_node_lifecycle, evil_delete_db_node, start_and_stop, checkpoint, table_lifecycle, storage_options, add_copy_conflict, - add_copy_when_going_down, replica_management, clear_table_during_load, + add_copy_when_going_down, add_copy_with_down, replica_management, + clear_table_during_load, schema_availability, local_content, {group, table_access_modifications}, replica_location, {group, table_sync}, user_properties, unsupp_user_props, {group, record_name}, {group, snmp_access}, {group, subscriptions}, {group, iteration}, - {group, debug_support}, sorted_ets, + {group, debug_support}, sorted_ets, index_cleanup, {mnesia_dirty_access_test, all}, {mnesia_trans_access_test, all}, {mnesia_evil_backup, all}]. @@ -707,6 +734,49 @@ add_copy_when_going_down(Config) -> ?match_receive({test,{aborted,_}}), ?verify_mnesia([Node2], []). +add_copy_with_down(suite) -> []; +add_copy_with_down(Config) -> + %% Allow add_table_copy() with ram_copies even all other replicas are down + Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config), + ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node3]}, {disc_copies, [Node2]}])), + stopped = rpc:call(Node2, mnesia, stop, []), + stopped = rpc:call(Node3, mnesia, stop, []), + ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)), + ?match({aborted, _}, mnesia:del_table_copy(a, Node2)), + ok = rpc:call(Node3, mnesia, start, []), + ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)), + ?match([], mnesia_test_lib:start_mnesia([Node2], [a])), + ?match({atomic, ok}, mnesia:change_table_copy_type(a, Node2, ram_copies)), + stopped = rpc:call(Node2, mnesia, stop, []), + stopped = rpc:call(Node3, mnesia, stop, []), + ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, ram_copies)), + ?match(ok, mnesia:dirty_write({a,1,1})), + ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])), + ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])), + + ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)), + stopped = rpc:call(Node2, mnesia, stop, []), + stopped = rpc:call(Node3, mnesia, stop, []), + ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_copies)), + ?match(ok, mnesia:dirty_write({a,1,1})), + ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])), + ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])), + + ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)), + stopped = rpc:call(Node2, mnesia, stop, []), + stopped = rpc:call(Node3, mnesia, stop, []), + ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_only_copies)), + ?match(ok, mnesia:dirty_write({a,1,1})), + ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])), + ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])), + ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])), + + ?verify_mnesia(Nodes, []). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Add, drop and move replicas, change storage types @@ -2489,3 +2559,55 @@ sorted_ets(Config) when is_list(Config) -> ?match({atomic, [{rec,1,1}, {rec,2,1}]}, mnesia:transaction(TestIt)). +index_cleanup(Config) when is_list(Config) -> + [N1, N2] = All = ?acquire_nodes(2, Config), + ?match({atomic, ok}, mnesia:create_table(i_set, [{type, set}, {ram_copies, [N1]}, {index, [val]}, + {disc_only_copies, [N2]}])), + ?match({atomic, ok}, mnesia:create_table(i_bag, [{type, bag}, {ram_copies, [N1]}, {index, [val]}, + {disc_only_copies, [N2]}])), + ?match({atomic, ok}, mnesia:create_table(i_oset, [{type, ordered_set}, {ram_copies, [N1, N2]}, + {index, [val]}])), + + Tabs = [i_set, i_bag, i_oset], + + Add = fun(Tab) -> + Write = fun(Tab) -> + Recs = [{Tab, N, N rem 5} || N <- lists:seq(1,10)], + [ok = mnesia:write(Rec) || Rec <- Recs], + Recs + end, + {atomic, Recs} = mnesia:sync_transaction(Write, [Tab]), + lists:sort(Recs) + end, + + IRead = fun(Tab) -> + Read = fun(Tab) -> + [mnesia:index_read(Tab, N, val) || N <- lists:seq(0,4)] + end, + {atomic, Recs} = mnesia:transaction(Read, [Tab]), + lists:sort(lists:flatten(Recs)) + end, + + Delete = fun(Rec) -> + Del = fun() -> mnesia:delete_object(Rec) end, + {atomic, ok} = mnesia:sync_transaction(Del), + ok + end, + + + Recs = [Add(Tab) || Tab <- Tabs], + ?match(Recs, [IRead(Tab) || Tab <- Tabs]), + [Delete(Rec) || Rec <- lists:flatten(Recs)], + + [?match({Tab,0}, {Tab,mnesia:table_info(Tab, size)}) || Tab <- Tabs], + + [?match({Tab,Node,0, _}, rpc:call(Node, ?MODULE, index_size, [Tab])) + || Node <- All, Tab <- Tabs], + ?verify_mnesia(All, []). + +index_size(Tab) -> + %% White box testing + case mnesia:table_info(Tab, index_info) of + {index, _, [{_, {ram, Ref}}=Dbg]} -> {Tab, node(), ets:info(Ref, size), Dbg}; + {index, _, [{_, {dets, Ref}}=Dbg]} -> {Tab, node(), dets:info(Ref, size), Dbg} + end. diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl index 808e62d9c2..3bbb6e4d77 100644 --- a/lib/mnesia/test/mnesia_examples_test.erl +++ b/lib/mnesia/test/mnesia_examples_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -21,7 +21,14 @@ %% -module(mnesia_examples_test). -author('[email protected]'). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). +-export([bup/1, company/1, meter/1, + replica_test/1, sticky_replica_test/1, dist_test/1, + conflict_test/1, frag_test/1, frag2_test/1, remote_test/1, + remote_frag2_test/1, opt_load/1]). + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> diff --git a/lib/mnesia/test/mnesia_frag_test.erl b/lib/mnesia/test/mnesia_frag_test.erl index 9f2102beb2..7b37fcb684 100644 --- a/lib/mnesia/test/mnesia_frag_test.erl +++ b/lib/mnesia/test/mnesia_frag_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2018. 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. @@ -23,7 +23,17 @@ -author('[email protected]'). -include("mnesia_test_lib.hrl"). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + + +-export([nice_single/1, nice_multi/1, nice_access/1, iter_access/1, + consistency/1, evil_create/1, evil_delete/1, evil_change/1, evil_combine/1, + evil_loop/1, evil_delete_db_node/1]). + + +-export([frag_dist/1]). init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). @@ -845,16 +855,7 @@ frag_rec_dist(Tab) -> Fun = fun() -> mnesia:table_info(Tab, frag_size) end, [Size || {_, Size} <- mnesia:activity(sync_dirty, Fun, mnesia_frag)]. -table_size(Tab) -> - Node = mnesia:table_info(Tab, where_to_read), - rpc:call(Node, mnesia, table_info, [Tab, size]). - sort_res(List) when is_list(List) -> lists:sort(List); sort_res(Else) -> Else. - -rev_res(List) when is_list(List) -> - lists:reverse(List); -rev_res(Else) -> - Else. diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl index 103f85b3d6..2aee5137c3 100644 --- a/lib/mnesia/test/mnesia_install_test.erl +++ b/lib/mnesia/test/mnesia_install_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,8 +21,13 @@ %% -module(mnesia_install_test). -author('[email protected]'). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([silly_durability/1, silly_move/1, silly_upgrade/1, conflict/1, dist/1, + silly/0, silly2/1]). --compile([export_all]). -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 63940ec05c..49bcec14af 100644 --- a/lib/mnesia/test/mnesia_isolation_test.erl +++ b/lib/mnesia/test/mnesia_isolation_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. 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. @@ -22,7 +22,36 @@ -module(mnesia_isolation_test). -author('[email protected]'). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([no_conflict/1, simple_queue_conflict/1, + advanced_queue_conflict/1, simple_deadlock_conflict/1, + advanced_deadlock_conflict/1, schema_deadlock/1, lock_burst/1, + nasty/1, basic_sticky_functionality/1, + unbound1/1, unbound2/1, + create_table/1, delete_table/1, move_table_copy/1, + add_table_index/1, del_table_index/1, transform_table/1, + snmp_open_table/1, snmp_close_table/1, + change_table_copy_type/1, change_table_access/1, + add_table_copy/1, del_table_copy/1, dump_tables/1, + del_table_copy_1/1, del_table_copy_2/1, del_table_copy_3/1, + add_table_copy_1/1, add_table_copy_2/1, add_table_copy_3/1, + add_table_copy_4/1, move_table_copy_1/1, move_table_copy_2/1, + move_table_copy_3/1, move_table_copy_4/1, + dirty_updates_visible_direct/1, + dirty_reads_regardless_of_trans/1, + trans_update_invisibible_outside_trans/1, + trans_update_visible_inside_trans/1, write_shadows/1, + delete_shadows/1, write_delete_shadows_bag/1, + write_delete_shadows_bag2/1, + shadow_search/1, snmp_shadows/1, + rr_kill_copy/1, foldl/1, first_next/1]). + +-export([do_fun/4, burst_counter/3, burst_incr/2, get_held/0, get_info/1, + get_sticky/0, op/4, update_own/3, update_shared/3]). + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> @@ -668,16 +697,6 @@ unbound2(Config) when is_list(Config) -> {B, {atomic, [{ul,{key,{17,42}},val}]}}]), ok. -receiver() -> - receive - {_Pid, begin_trans} -> - receiver(); - Else -> - Else - after - 10000 -> - timeout - end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1544,7 +1563,8 @@ trans_update_visible_inside_trans(Config) when is_list(Config) -> ?match({atomic, ok}, mnesia:create_table([{name, Tab}, {ram_copies, [Node1]}])), ValPos = 3, - RecA = {Tab, a, 1}, + RecA = {Tab, a, 1}, + RecA2 = {Tab, a, 2}, PatA = {Tab, '$1', 1}, RecB = {Tab, b, 3}, PatB = {Tab, '$1', 3}, @@ -1579,6 +1599,14 @@ trans_update_visible_inside_trans(Config) when is_list(Config) -> ?match([], mnesia:index_read(Tab, 3, ValPos)), %% delete_object + ?match(ok, mnesia:delete_object(RecA2)), + ?match([RecA], mnesia:read({Tab, a})), + ?match([RecA], mnesia:wread({Tab, a})), + ?match([RecA], mnesia:match_object(PatA)), + ?match([a], mnesia:all_keys(Tab)), + ?match([RecA], mnesia:index_match_object(PatA, ValPos)), + ?match([RecA], mnesia:index_read(Tab, 1, ValPos)), + ?match(ok, mnesia:delete_object(RecA)), ?match([], mnesia:read({Tab, a})), ?match([], mnesia:wread({Tab, a})), diff --git a/lib/mnesia/test/mnesia_majority_test.erl b/lib/mnesia/test/mnesia_majority_test.erl index 9811de6ae7..aae27e069e 100644 --- a/lib/mnesia/test/mnesia_majority_test.erl +++ b/lib/mnesia/test/mnesia_majority_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -21,7 +21,13 @@ %% -module(mnesia_majority_test). -author('[email protected]'). --compile(export_all). +-export([init_per_testcase/2, end_per_testcase/2, + all/0]). + +-export([write/1, wread/1, delete/1, clear_table/1, frag/1, + change_majority/1, frag_change_majority/1 + ]). + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> diff --git a/lib/mnesia/test/mnesia_measure_test.erl b/lib/mnesia/test/mnesia_measure_test.erl index ad71fafecb..8eb3590168 100644 --- a/lib/mnesia/test/mnesia_measure_test.erl +++ b/lib/mnesia/test/mnesia_measure_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,7 +21,15 @@ %% -module(mnesia_measure_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([cost/1, dbn_meters/1, + ram_tpcb/1, disc_tpcb/1, disc_only_tpcb/1, + ram_meter/1, disc_meter/1, disc_only_meter/1]). + -include("mnesia_test_lib.hrl"). @@ -39,41 +47,12 @@ end_per_testcase(Func, Conf) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> - [{group, prediction}, {group, consumption}, - {group, scalability}, {group, benchmarks}]. + [{group, benchmarks}]. groups() -> - [{prediction, [], - [reader_disturbed_by_node_down, - writer_disturbed_by_node_down, - reader_disturbed_by_node_up, - writer_disturbed_by_node_up, - reader_disturbed_by_schema_ops, - writer_disturbed_by_schema_ops, - reader_disturbed_by_checkpoint, - writer_disturbed_by_checkpoint, - reader_disturbed_by_dump_log, - writer_disturbed_by_dump_log, - reader_disturbed_by_backup, writer_disturbed_by_backup, - reader_disturbed_by_restore, - writer_disturbed_by_restore, {group, fairness}]}, - {fairness, [], - [reader_competing_with_reader, - reader_competing_with_writer, - writer_competing_with_reader, - writer_competing_with_writer]}, - {consumption, [], - [measure_resource_consumption, - determine_resource_leakage]}, - {scalability, [], - [determine_system_limits, performance_at_min_config, - performance_at_max_config, performance_at_full_load, - resource_consumption_at_min_config, - resource_consumption_at_max_config, - resource_consumption_at_full_load]}, - {benchmarks, [], + [{benchmarks, [], [{group, meter}, cost, dbn_meters, - measure_all_api_functions, {group, tpcb}]}, + {group, tpcb}]}, {tpcb, [], [ram_tpcb, disc_tpcb, disc_only_tpcb]}, {meter, [], [ram_meter, disc_meter, disc_only_meter]}]. diff --git a/lib/mnesia/test/mnesia_nice_coverage_test.erl b/lib/mnesia/test/mnesia_nice_coverage_test.erl index ffbe36e48d..f8c6b2ce20 100644 --- a/lib/mnesia/test/mnesia_nice_coverage_test.erl +++ b/lib/mnesia/test/mnesia_nice_coverage_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,7 +21,13 @@ %% -module(mnesia_nice_coverage_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([nice/1]). + -include("mnesia_test_lib.hrl"). -record(nice_tab, {key, val}). diff --git a/lib/mnesia/test/mnesia_qlc_test.erl b/lib/mnesia/test/mnesia_qlc_test.erl index 5067e86521..e66fd84995 100644 --- a/lib/mnesia/test/mnesia_qlc_test.erl +++ b/lib/mnesia/test/mnesia_qlc_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2018. 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. @@ -21,9 +21,18 @@ %% -module(mnesia_qlc_test). --compile(export_all). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([frag/1, info/1, mnesia_down/1, + dirty_nice_ram_copies/1, dirty_nice_disc_copies/1, + dirty_nice_disc_only_copies/1, + trans_nice_ram_copies/1, trans_nice_disc_copies/1, + trans_nice_disc_only_copies/1, atomic_eval/1, + nested_qlc/1 + ]). --export([all/0,groups/0,init_per_group/2,end_per_group/2]). -include("mnesia_test_lib.hrl"). -include_lib("stdlib/include/qlc.hrl"). diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl index 130b87346f..b5749408f8 100644 --- a/lib/mnesia/test/mnesia_recovery_test.erl +++ b/lib/mnesia/test/mnesia_recovery_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,7 +21,80 @@ %% -module(mnesia_recovery_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([coord_dies/1, after_full_disc_partition/1, + disc_less/1, garb_decision/1, + system_upgrade/1, + delete_during_start/1, + no_master_2/1, no_master_3/1, one_master_2/1, one_master_3/1, + two_master_2/1, two_master_3/1, all_master_2/1, + all_master_3/1, + dirty_read_during_down/1, trans_read_during_down/1, + mnesia_down_during_startup_disk_ram/1, + mnesia_down_during_startup_init_ram/1, + mnesia_down_during_startup_init_disc/1, + mnesia_down_during_startup_init_disc_only/1, + mnesia_down_during_startup_tm_ram/1, + mnesia_down_during_startup_tm_disc/1, + mnesia_down_during_startup_tm_disc_only/1, + with_checkpoint_same/1, with_checkpoint_other/1, + explicit_stop_during_snmp/1, + sym_trans_before_commit_kill_coord_node/1, + sym_trans_before_commit_kill_coord_pid/1, + sym_trans_before_commit_kill_part_after_ask/1, + sym_trans_before_commit_kill_part_before_ask/1, + sym_trans_after_commit_kill_coord_node/1, + sym_trans_after_commit_kill_coord_pid/1, + sym_trans_after_commit_kill_part_after_ask/1, + sym_trans_after_commit_kill_part_do_commit_pre/1, + sym_trans_after_commit_kill_part_do_commit_post/1, + sync_dirty_pre_kill_part/1, + sync_dirty_pre_kill_coord_node/1, + sync_dirty_pre_kill_coord_pid/1, + sync_dirty_post_kill_part/1, + sync_dirty_post_kill_coord_node/1, + sync_dirty_post_kill_coord_pid/1, + async_dirty_pre_kill_part/1, + async_dirty_pre_kill_coord_node/1, + async_dirty_pre_kill_coord_pid/1, + async_dirty_post_kill_part/1, + async_dirty_post_kill_coord_node/1, + async_dirty_post_kill_coord_pid/1, + asymtrans_part_ask/1, + asymtrans_part_commit_vote/1, + asymtrans_part_pre_commit/1, + asymtrans_part_log_commit/1, + asymtrans_part_do_commit/1, + asymtrans_coord_got_votes/1, + asymtrans_coord_pid_got_votes/1, + asymtrans_coord_log_commit_rec/1, + asymtrans_coord_pid_log_commit_rec/1, + asymtrans_coord_log_commit_dec/1, + asymtrans_coord_pid_log_commit_dec/1, + asymtrans_coord_rec_acc_pre_commit_log_commit/1, + asymtrans_coord_pid_rec_acc_pre_commit_log_commit/1, + asymtrans_coord_rec_acc_pre_commit_done_commit/1, + asymtrans_coord_pid_rec_acc_pre_commit_done_commit/1, + after_corrupt_files_decision_log_head/1, + after_corrupt_files_decision_log_tail/1, + after_corrupt_files_latest_log_head/1, + after_corrupt_files_latest_log_tail/1, + after_corrupt_files_table_dat_head/1, + after_corrupt_files_table_dat_tail/1, + after_corrupt_files_schema_dat_head/1, + after_corrupt_files_schema_dat_tail/1]). + +-export([reader/2, check/0, get_all_retainers/1, + verify_data/2, verify_where2read/1, + do_trans_loop/2, + start_stop/3, do_sym_trans/2, do_sync_dirty/2, do_async_dirty/2, + do_asym_trans/2, garb_handler/1, mymnesia_start/1 + ]). + -include("mnesia_test_lib.hrl"). -include_lib("kernel/include/file.hrl"). @@ -657,6 +730,7 @@ do_trans_loop2(Tab, Father) -> do_trans_loop2(Tab, Father); Else -> ?error("Transaction failed: ~p ~n", [Else]), + io:format("INFO: ~p~n",[erlang:process_info(self())]), Father ! test_done, exit(shutdown) end. diff --git a/lib/mnesia/test/mnesia_registry_test.erl b/lib/mnesia/test/mnesia_registry_test.erl index 3df37a2c8c..c15b8e97af 100644 --- a/lib/mnesia/test/mnesia_registry_test.erl +++ b/lib/mnesia/test/mnesia_registry_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. 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. @@ -21,7 +21,12 @@ %% -module(mnesia_registry_test). -author('[email protected]'). --compile([export_all]). +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([good_dump/1, bad_dump/1, dump_registry/2, restore_registry/2]). + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> diff --git a/lib/mnesia/test/mnesia_schema_recovery_test.erl b/lib/mnesia/test/mnesia_schema_recovery_test.erl index ca2dd74b34..e4199758c1 100644 --- a/lib/mnesia/test/mnesia_schema_recovery_test.erl +++ b/lib/mnesia/test/mnesia_schema_recovery_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2016. All Rights Reserved. +%% Copyright Ericsson AB 1998-2018. 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. @@ -21,7 +21,79 @@ %% -module(mnesia_schema_recovery_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([interrupted_before_create_ram/1, + interrupted_before_create_disc/1, + interrupted_before_create_do/1, + interrupted_before_create_nostore/1, + interrupted_before_delete_ram/1, + interrupted_before_delete_disc/1, + interrupted_before_delete_do/1, + interrupted_before_add_ram/1, + interrupted_before_add_disc/1, + interrupted_before_add_do/1, + interrupted_before_add_kill_copier/1, + interrupted_before_move_ram/1, + interrupted_before_move_disc/1, + interrupted_before_move_do/1, + interrupted_before_move_kill_copier/1, + interrupted_before_delcopy_ram/1, + interrupted_before_delcopy_disc/1, + interrupted_before_delcopy_do/1, + interrupted_before_delcopy_kill_copier/1, + interrupted_before_addindex_ram/1, + interrupted_before_addindex_disc/1, + interrupted_before_addindex_do/1, + interrupted_before_delindex_ram/1, + interrupted_before_delindex_disc/1, + interrupted_before_delindex_do/1, + interrupted_before_change_type_ram2disc/1, + interrupted_before_change_type_ram2do/1, + interrupted_before_change_type_disc2ram/1, + interrupted_before_change_type_disc2do/1, + interrupted_before_change_type_do2ram/1, + interrupted_before_change_type_do2disc/1, + interrupted_before_change_type_other_node/1, + interrupted_before_change_schema_type/1, + interrupted_after_create_ram/1, + interrupted_after_create_disc/1, + interrupted_after_create_do/1, + interrupted_after_create_nostore/1, + interrupted_after_delete_ram/1, + interrupted_after_delete_disc/1, + interrupted_after_delete_do/1, + interrupted_after_add_ram/1, + interrupted_after_add_disc/1, + interrupted_after_add_do/1, + interrupted_after_add_kill_copier/1, + interrupted_after_move_ram/1, + interrupted_after_move_disc/1, + interrupted_after_move_do/1, + interrupted_after_move_kill_copier/1, + interrupted_after_delcopy_ram/1, + interrupted_after_delcopy_disc/1, + interrupted_after_delcopy_do/1, + interrupted_after_delcopy_kill_copier/1, + interrupted_after_addindex_ram/1, + interrupted_after_addindex_disc/1, + interrupted_after_addindex_do/1, + interrupted_after_delindex_ram/1, + interrupted_after_delindex_disc/1, + interrupted_after_delindex_do/1, + interrupted_after_change_type_ram2disc/1, + interrupted_after_change_type_ram2do/1, + interrupted_after_change_type_disc2ram/1, + interrupted_after_change_type_disc2do/1, + interrupted_after_change_type_do2ram/1, + interrupted_after_change_type_do2disc/1, + interrupted_after_change_type_other_node/1, + interrupted_after_change_schema_type/1]). + + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index 6e84a27ec9..1cdac3cde6 100644 --- a/lib/mnesia/test/mnesia_test_lib.erl +++ b/lib/mnesia/test/mnesia_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -263,6 +263,7 @@ slave_start_link(Host, Name, Retries) -> Path = code:get_path(), ok = rpc:call(NewNode, file, set_cwd, [Cwd]), true = rpc:call(NewNode, code, set_path, [Path]), + ok = rpc:call(NewNode, error_logger, tty, [false]), spawn_link(NewNode, ?MODULE, slave_sup, []), rpc:multicall([node() | nodes()], global, sync, []), {ok, NewNode}; @@ -469,9 +470,9 @@ get_suite(Mod, {group, Suite}) -> {_, _, TCList} = lists:keyfind(Suite, 1, Groups), TCList catch - _:Reason -> + _:Reason:Stacktrace -> io:format("Not implemented ~p ~p (~p ~p)~n", - [Mod,Suite,Reason, erlang:get_stacktrace()]), + [Mod,Suite,Reason,Stacktrace]), 'NYI' end; get_suite(Mod, all) -> @@ -773,7 +774,7 @@ init_nodes([], _File, _Line) -> %% Returns [Name, Host] node_to_name_and_host(Node) -> - string:tokens(atom_to_list(Node), [$@]). + string:lexemes(atom_to_list(Node), [$@]). lookup_config(Key,Config) -> case lists:keysearch(Key,1,Config) of diff --git a/lib/mnesia/test/mnesia_test_lib.hrl b/lib/mnesia/test/mnesia_test_lib.hrl index ba7eb10ea2..b8eeb5783f 100644 --- a/lib/mnesia/test/mnesia_test_lib.hrl +++ b/lib/mnesia/test/mnesia_test_lib.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -55,25 +55,25 @@ ?error("Not Matching Actual result was:~n ~p~n",[_AR_0]), {fail,_AR_0} catch - exit:{aborted, _ER_1} when + exit:{aborted, _ER_1}:Stacktrace when element(1, _ER_1) =:= node_not_running; element(1, _ER_1) =:= bad_commit; element(1, _ER_1) =:= cyclic -> %% Need to re-raise these to restart transaction - erlang:raise(exit, {aborted, _ER_1}, erlang:get_stacktrace()); - exit:_AR_1 -> + erlang:raise(exit, {aborted, _ER_1}, Stacktrace); + exit:_AR_1:Stacktrace -> case fun(_AR_EXIT_) -> {'EXIT', _AR_EXIT_} end(_AR_1) of _AR_2 = ExpectedRes -> ?verbose("ok, ~n Result as expected:~p~n",[_AR_2]), {success,_AR_2}; _AR_2 -> ?error("Not Matching Actual result was:~n ~p~n ~p~n", - [_AR_2, erlang:get_stacktrace()]), + [_AR_2, Stacktrace]), {fail,_AR_2} end; - _T1_:_AR_1 -> + _T1_:_AR_1:Stacktrace -> ?error("Not Matching Actual result was:~n ~p~n ~p~n", - [{_T1_,_AR_1}, erlang:get_stacktrace()]), + [{_T1_,_AR_1}, Stacktrace]), {fail,{_T1_,_AR_1}} end end()). diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl index aa50ee4cb1..723a85fd2c 100644 --- a/lib/mnesia/test/mnesia_trans_access_test.erl +++ b/lib/mnesia/test/mnesia_trans_access_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -21,7 +21,28 @@ %% -module(mnesia_trans_access_test). -author('[email protected]'). --compile([export_all]). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + all/0, groups/0]). + +-export([write/1, read/1, wread/1, delete/1, delete_object/1, + match_object/1, select/1, select14/1, all_keys/1, transaction/1, + basic_nested/1, mix_of_nested_activities/1, + nested_trans_both_ok/1, nested_trans_child_dies/1, + nested_trans_parent_dies/1, nested_trans_both_dies/1, + index_match_object/1, index_read/1,index_write/1, + index_update_set/1, index_update_bag/1, + add_table_index_ram/1, add_table_index_disc/1, + add_table_index_disc_only/1, create_live_table_index_ram/1, + create_live_table_index_disc/1, + create_live_table_index_disc_only/1, del_table_index_ram/1, + del_table_index_disc/1, del_table_index_disc_only/1, + idx_schema_changes_ram/1, idx_schema_changes_disc/1, + idx_schema_changes_disc_only/1]). + +-export([do_nested/1]). + -include("mnesia_test_lib.hrl"). init_per_testcase(Func, Conf) -> @@ -307,6 +328,7 @@ select14(Config) when is_list(Config) -> %% Some Helpers Trans = fun(Fun) -> mnesia:transaction(Fun) end, + Dirty = fun(Fun) -> mnesia:async_dirty(Fun) end, LoopHelp = fun('$end_of_table',_) -> []; ({Recs,Cont},Fun) -> Sel = mnesia:select(Cont), @@ -334,8 +356,13 @@ select14(Config) when is_list(Config) -> ?match({atomic, [OneRec]}, Trans(fun() -> Loop(Tab, OnePat) end)), ?match({atomic, All}, Trans(fun() -> Loop(Tab, AllPat) end)), - {atomic,{_, Cont}} = Trans(fun() -> mnesia:select(Tab, OnePat, 1, read) end), - ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(Cont) end)), + {atomic,{_, ContOne}} = Trans(fun() -> mnesia:select(Tab, OnePat, 1, read) end), + ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(ContOne) end)), + ?match('$end_of_table', Dirty(fun() -> mnesia:select(ContOne) end)), + + {atomic,{_, ContAll}} = Trans(fun() -> mnesia:select(Tab, AllPat, 1, read) end), + ?match({aborted, wrong_transaction}, Trans(fun() -> mnesia:select(ContAll) end)), + ?match({[_], _}, Dirty(fun() -> mnesia:select(ContAll) end)), ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, {match, '$1', 2},1,read) end)), ?match({aborted, _}, Trans(fun() -> mnesia:select(Tab, [{'_', [], '$1'}],1,read) end)), diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index f08e364276..1cfb35c774 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.14.1 +MNESIA_VSN = 4.15.5 |