diff options
Diffstat (limited to 'lib/mnesia')
55 files changed, 850 insertions, 326 deletions
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile index 82fcf66256..d9647fc081 100644 --- a/lib/mnesia/doc/src/Makefile +++ b/lib/mnesia/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2017. 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. @@ -49,16 +49,18 @@ XML_PART_FILES = \ 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 @@ -66,6 +68,8 @@ 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 = \ company.gif @@ -114,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 *~ diff --git a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc index 914e0e509c..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> diff --git a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc index 62759c624b..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> diff --git a/lib/mnesia/doc/src/company.erl b/lib/mnesia/doc/src/company.erl index 5a3b122394..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. diff --git a/lib/mnesia/doc/src/company_o.erl b/lib/mnesia/doc/src/company_o.erl index 650b6cdeca..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. diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 621b6047ee..11b0b8e987 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -32,7 +32,7 @@ <rev></rev> <file></file> </header> - <module>mnesia</module> + <module since="">mnesia</module> <modulesummary>A distributed telecommunications DBMS</modulesummary> <description> @@ -183,7 +183,7 @@ <funcs> <func> - <name>abort(Reason) -> transaction abort</name> + <name since="">abort(Reason) -> transaction abort</name> <fsummary>Terminates the current transaction.</fsummary> <desc> <p>Makes the transaction silently @@ -195,7 +195,7 @@ </desc> </func> <func> - <name>activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name> + <name since="">activate_checkpoint(Args) -> {ok,Name,Nodes} | {error,Reason}</name> <fsummary>Activates a checkpoint.</fsummary> <desc> <marker id="activate_checkpoint"></marker> @@ -259,7 +259,7 @@ </desc> </func> <func> - <name>activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">activity(AccessContext, Fun [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary> <desc> <marker id="activity_2_3"></marker> @@ -271,7 +271,7 @@ </desc> </func> <func> - <name>activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name> + <name since="">activity(AccessContext, Fun, Args, AccessMod) -> ResultOfFun | exit(Reason)</name> <fsummary>Executes <c>Fun</c> in <c>AccessContext</c>.</fsummary> <desc> <marker id="activity_4"></marker> @@ -403,7 +403,7 @@ </desc> </func> <func> - <name>add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name> + <name since="">add_table_copy(Tab, Node, Type) -> {aborted, R} | {atomic, ok}</name> <fsummary>Copies a table to a remote node.</fsummary> <desc> <marker id="add_table_copy"></marker> @@ -420,7 +420,7 @@ mnesia:add_table_copy(person, Node, disc_copies)</code> </desc> </func> <func> - <name>add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> + <name since="">add_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Creates an index for a table.</fsummary> <desc> <marker id="add_table_index"></marker> @@ -441,7 +441,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>all_keys(Tab) -> KeyList | transaction abort</name> + <name since="">all_keys(Tab) -> KeyList | transaction abort</name> <fsummary>Returns all keys in a table.</fsummary> <desc> <marker id="all_keys"></marker> @@ -453,7 +453,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">async_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary> <desc> <marker id="async_dirty"></marker> @@ -493,7 +493,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name> + <name since="">backup(Opaque [, BackupMod]) -> ok | {error,Reason}</name> <fsummary>Backs up all tables in the database.</fsummary> <desc> <marker id="backup"></marker> @@ -505,7 +505,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name> + <name since="">backup_checkpoint(Name, Opaque [, BackupMod]) -> ok | {error,Reason}</name> <fsummary>Backs up all tables in a checkpoint.</fsummary> <desc> <marker id="backup_checkpoint"></marker> @@ -520,7 +520,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name> + <name since="">change_config(Config, Value) -> {error, Reason} | {ok, ReturnValue}</name> <fsummary>Changes a configuration parameter.</fsummary> <desc> <marker id="change_config"></marker> @@ -554,7 +554,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_access_mode(Tab, AccessMode) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the access mode for the table.</fsummary> <desc> <marker id="change_table_access_mode"></marker> @@ -568,7 +568,7 @@ mnesia:add_table_index(person, age)</code> </desc> </func> <func> - <name>change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_copy_type(Tab, Node, To) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the storage type of a table.</fsummary> <desc> <marker id="change_table_copy_type"></marker> @@ -585,7 +585,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name> + <name since="">change_table_load_order(Tab, LoadOrder) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the load order priority for the table.</fsummary> <desc> <marker id="change_table_load_order"></marker> @@ -595,7 +595,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name> + <name since="OTP R14B03">change_table_majority(Tab, Majority) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes the majority check setting for the table.</fsummary> <desc> <p><c>Majority</c> must be a boolean. Default is <c>false</c>. @@ -607,7 +607,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>clear_table(Tab) -> {aborted, R} | {atomic, ok}</name> + <name since="">clear_table(Tab) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes all entries in a table.</fsummary> <desc> <marker id="clear_table"></marker> @@ -615,7 +615,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>create_schema(DiscNodes) -> ok | {error,Reason}</name> + <name since="">create_schema(DiscNodes) -> ok | {error,Reason}</name> <fsummary>Creates a new schema on the specified nodes.</fsummary> <desc> <marker id="create_schema"></marker> @@ -637,7 +637,7 @@ mnesia:change_table_copy_type(person, node(), disc_copies)</code> </desc> </func> <func> - <name>create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name> + <name since="">create_table(Name, TabDef) -> {atomic, ok} | {aborted, Reason}</name> <fsummary>Creates a Mnesia table called <c>Name</c>with properties as described by argument <c>TabDef</c>.</fsummary> <desc> <marker id="create_table"></marker> @@ -799,7 +799,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>deactivate_checkpoint(Name) -> ok | {error, Reason}</name> + <name since="">deactivate_checkpoint(Name) -> ok | {error, Reason}</name> <fsummary>Deactivates a checkpoint.</fsummary> <desc> <marker id="deactivate_checkpoint"></marker> @@ -811,7 +811,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name> + <name since="">del_table_copy(Tab, Node) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes the replica of table <c>Tab</c> at node <c>Node</c>.</fsummary> <desc> <marker id="del_table_copy"></marker> @@ -825,7 +825,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> + <name since="">del_table_index(Tab, AttrName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Deletes an index in a table.</fsummary> <desc> <marker id="del_table_index"></marker> @@ -834,7 +834,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete({Tab, Key}) -> transaction abort | ok</name> + <name since="">delete({Tab, Key}) -> transaction abort | ok</name> <fsummary>Deletes all records in table <c>Tab</c> with the key <c>Key</c>.</fsummary> <desc> <marker id="delete_2"></marker> @@ -842,7 +842,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete(Tab, Key, LockKind) -> transaction abort | ok</name> + <name since="">delete(Tab, Key, LockKind) -> transaction abort | ok</name> <fsummary>Deletes all records in table <c>Tab</c>with the key <c>Key</c>.</fsummary> <desc> <marker id="delete_3"></marker> @@ -857,7 +857,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_object(Record) -> transaction abort | ok</name> + <name since="">delete_object(Record) -> transaction abort | ok</name> <fsummary>Delete a record.</fsummary> <desc> <marker id="delete_object_1"></marker> @@ -866,7 +866,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_object(Tab, Record, LockKind) -> transaction abort | ok</name> + <name since="">delete_object(Tab, Record, LockKind) -> transaction abort | ok</name> <fsummary>Deletes a record.</fsummary> <desc> <marker id="delete_object_3"></marker> @@ -883,7 +883,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_schema(DiscNodes) -> ok | {error,Reason}</name> + <name since="">delete_schema(DiscNodes) -> ok | {error,Reason}</name> <fsummary>Deletes the schema on the given nodes.</fsummary> <desc> <marker id="delete_schema"></marker> @@ -904,7 +904,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name> + <name since="">delete_table(Tab) -> {aborted, Reason} | {atomic, ok}</name> <fsummary>Deletes permanently all replicas of table <c>Tab</c>.</fsummary> <desc> <marker id="delete_table"></marker> @@ -912,7 +912,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name> + <name since="">dirty_all_keys(Tab) -> KeyList | exit({aborted, Reason})</name> <fsummary>Dirty search for all record keys in table.</fsummary> <desc> <marker id="delete_all_keys"></marker> @@ -920,7 +920,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_delete({Tab, Key}) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <marker id="dirty_delete"></marker> @@ -928,14 +928,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_delete(Tab, Key) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:delete/3</c>.</p> </desc> </func> <func> - <name>dirty_delete_object(Record)</name> + <name since="">dirty_delete_object(Record)</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <marker id="dirty_delete_object_1"></marker> @@ -944,14 +944,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_delete_object(Tab, Record)</name> + <name since="">dirty_delete_object(Tab, Record)</name> <fsummary>Dirty delete of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:delete_object/3</c>.</p> </desc> </func> <func> - <name>dirty_first(Tab) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_first(Tab) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the key for the first record in a table.</fsummary> <desc> <marker id="dirty_first"></marker> @@ -967,7 +967,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_match_object(Pattern, Pos)</name> + <name since="">dirty_index_match_object(Pattern, Pos)</name> <fsummary>Dirty pattern match using index.</fsummary> <desc> <marker id="dirty_index_match_object_2"></marker> @@ -977,7 +977,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_match_object(Tab, Pattern, Pos)</name> + <name since="">dirty_index_match_object(Tab, Pattern, Pos)</name> <fsummary>Dirty pattern match using index.</fsummary> <desc> <p>Dirty equivalent of the function @@ -985,7 +985,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_index_read(Tab, SecondaryKey, Pos)</name> + <name since="">dirty_index_read(Tab, SecondaryKey, Pos)</name> <fsummary>Dirty read using index.</fsummary> <desc> <marker id="dirty_index_read"></marker> @@ -994,7 +994,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_last(Tab) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_last(Tab) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the key for the last record in a table.</fsummary> <desc> <marker id="dirty_last"></marker> @@ -1006,7 +1006,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_match_object(Pattern) -> RecordList | exit({aborted, Reason})</name> <fsummary>Dirty pattern match pattern.</fsummary> <desc> <marker id="dirty_match_object_1"></marker> @@ -1015,7 +1015,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_match_object(Tab, Pattern) -> RecordList | exit({aborted, Reason})</name> <fsummary>Dirty pattern match pattern.</fsummary> <desc> <p>Dirty equivalent of the function @@ -1023,7 +1023,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_next(Tab, Key) -> Key | exit({aborted, Reason})</name> <fsummary>Return the next key in a table.</fsummary> <desc> <marker id="dirty_next"></marker> @@ -1038,7 +1038,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name> + <name since="">dirty_prev(Tab, Key) -> Key | exit({aborted, Reason})</name> <fsummary>Returns the previous key in a table.</fsummary> <desc> <marker id="dirty_prev"></marker> @@ -1050,7 +1050,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_read({Tab, Key}) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty read of records.</fsummary> <desc> <marker id="dirty_read"></marker> @@ -1058,14 +1058,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_read(Tab, Key) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty read of records.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:read/3</c>.</p> </desc> </func> <func> - <name>dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name> + <name since="">dirty_select(Tab, MatchSpec) -> ValueList | exit({aborted, Reason}</name> <fsummary>Dirty matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="dirty_select"></marker> @@ -1073,7 +1073,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name> + <name since="">dirty_slot(Tab, Slot) -> RecordList | exit({aborted, Reason})</name> <fsummary>Returns the list of records that are associated with <c>Slot</c> in a table.</fsummary> <desc> <marker id="dirty_slot"></marker> @@ -1089,7 +1089,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name> + <name since="">dirty_update_counter({Tab, Key}, Incr) -> NewVal | exit({aborted, Reason})</name> <fsummary>Dirty update of a counter record.</fsummary> <desc> <marker id="dirty_update_counter"></marker> @@ -1097,7 +1097,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name> + <name since="">dirty_update_counter(Tab, Key, Incr) -> NewVal | exit({aborted, Reason})</name> <fsummary>Dirty update of a counter record.</fsummary> <desc> <p>Mnesia has no special counter records. However, @@ -1126,7 +1126,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_write(Record) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_write(Record) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty write of a record.</fsummary> <desc> <marker id="dirty_write_1"></marker> @@ -1135,14 +1135,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name> + <name since="">dirty_write(Tab, Record) -> ok | exit({aborted, Reason})</name> <fsummary>Dirty write of a record.</fsummary> <desc> <p>Dirty equivalent of the function <c>mnesia:write/3</c>.</p> </desc> </func> <func> - <name>dump_log() -> dumped</name> + <name since="">dump_log() -> dumped</name> <fsummary>Performs a user-initiated dump of the local log file.</fsummary> <desc> <marker id="dump_log"></marker> @@ -1156,7 +1156,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name> + <name since="">dump_tables(TabList) -> {atomic, ok} | {aborted, Reason}</name> <fsummary>Dumps all RAM tables to disc.</fsummary> <desc> <marker id="dump_tables"></marker> @@ -1168,7 +1168,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>dump_to_textfile(Filename)</name> + <name since="">dump_to_textfile(Filename)</name> <fsummary>Dumps local tables into a text file.</fsummary> <desc> <marker id="dump_to_textfile"></marker> @@ -1181,7 +1181,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>error_description(Error) -> String</name> + <name since="">error_description(Error) -> String</name> <fsummary>Returns a string describing a particular Mnesia error.</fsummary> <desc> <marker id="error_description"></marker> @@ -1259,7 +1259,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">ets(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a raw context that is not protected by a transaction.</fsummary> <desc> <marker id="ets"></marker> @@ -1278,7 +1278,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>first(Tab) -> Key | transaction abort</name> + <name since="">first(Tab) -> Key | transaction abort</name> <fsummary>Returns the key for the first record in a table.</fsummary> <desc> <marker id="first"></marker> @@ -1293,7 +1293,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>foldl(Function, Acc, Table) -> NewAcc | transaction abort</name> + <name since="">foldl(Function, Acc, Table) -> NewAcc | transaction abort</name> <fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary> <desc> <marker id="foldl"></marker> @@ -1306,7 +1306,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>foldr(Function, Acc, Table) -> NewAcc | transaction abort</name> + <name since="">foldr(Function, Acc, Table) -> NewAcc | transaction abort</name> <fsummary>Calls <c>Function</c> for each record in <c>Table</c>.</fsummary> <desc> <marker id="foldr"></marker> @@ -1317,7 +1317,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>force_load_table(Tab) -> yes | ErrorDescription</name> + <name since="">force_load_table(Tab) -> yes | ErrorDescription</name> <fsummary>Forces a table to be loaded into the system.</fsummary> <desc> <marker id="force_load_table"></marker> @@ -1335,7 +1335,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_match_object(Pattern, Pos) -> transaction abort | ObjList</name> + <name since="">index_match_object(Pattern, Pos) -> transaction abort | ObjList</name> <fsummary>Matches records and uses index information.</fsummary> <desc> <marker id="index_match_object_2"></marker> @@ -1345,7 +1345,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name> + <name since="">index_match_object(Tab, Pattern, Pos, LockKind) -> transaction abort | ObjList</name> <fsummary>Matches records and uses index information.</fsummary> <desc> <marker id="index_match_object_4"></marker> @@ -1377,7 +1377,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name> + <name since="">index_read(Tab, SecondaryKey, Pos) -> transaction abort | RecordList</name> <fsummary>Reads records through index table.</fsummary> <desc> <marker id="index_read"></marker> @@ -1397,7 +1397,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>info() -> ok</name> + <name since="">info() -> ok</name> <fsummary>Prints system information on the terminal.</fsummary> <desc> <marker id="info"></marker> @@ -1408,7 +1408,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <marker id="install_fallback_1"></marker> @@ -1417,7 +1417,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque), BackupMod) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <p>Calls <c>mnesia:install_fallback(Opaque, Args)</c>, where @@ -1425,7 +1425,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>install_fallback(Opaque, Args) -> ok | {error,Reason}</name> + <name since="">install_fallback(Opaque, Args) -> ok | {error,Reason}</name> <fsummary>Installs a backup as fallback.</fsummary> <desc> <p>Installs a backup as fallback. The fallback is used to @@ -1483,7 +1483,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>is_transaction() -> boolean</name> + <name since="">is_transaction() -> boolean</name> <fsummary>Checks if code is running in a transaction.</fsummary> <desc> <marker id="is_transaction"></marker> @@ -1492,7 +1492,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>last(Tab) -> Key | transaction abort</name> + <name since="">last(Tab) -> Key | transaction abort</name> <fsummary>Returns the key for the last record in a table.</fsummary> <desc> <p>Works exactly like @@ -1503,7 +1503,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>load_textfile(Filename)</name> + <name since="">load_textfile(Filename)</name> <fsummary>Loads tables from a text file.</fsummary> <desc> <marker id="load_textfile"></marker> @@ -1516,7 +1516,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name> + <name since="">lock(LockItem, LockKind) -> Nodes | ok | transaction abort</name> <fsummary>Explicit grab lock.</fsummary> <desc> <marker id="lock"></marker> @@ -1605,7 +1605,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>match_object(Pattern) -> transaction abort | RecList</name> + <name since="">match_object(Pattern) -> transaction abort | RecList</name> <fsummary>Matches <c>Pattern</c> for records.</fsummary> <desc> <marker id="match_object_1"></marker> @@ -1614,7 +1614,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name> + <name since="">match_object(Tab, Pattern, LockKind) -> transaction abort | RecList</name> <fsummary>Matches <c>Pattern</c> for records.</fsummary> <desc> <marker id="match_object_3"></marker> @@ -1639,7 +1639,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name> + <name since="">move_table_copy(Tab, From, To) -> {aborted, Reason} | {atomic, ok}</name> <fsummary>Moves the copy of table <c>Tab</c> from node <c>From</c> to node <c>To</c>.</fsummary> <desc> <marker id="move_table_copy"></marker> @@ -1653,7 +1653,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>next(Tab, Key) -> Key | transaction abort</name> + <name since="">next(Tab, Key) -> Key | transaction abort</name> <fsummary>Returns the next key in a table.</fsummary> <desc> <marker id="next"></marker> @@ -1665,7 +1665,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>prev(Tab, Key) -> Key | transaction abort</name> + <name since="">prev(Tab, Key) -> Key | transaction abort</name> <fsummary>Returns the previous key in a table.</fsummary> <desc> <p>Works exactly like @@ -1676,7 +1676,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read({Tab, Key}) -> transaction abort | RecordList</name> + <name since="">read({Tab, Key}) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <marker id="read_2"></marker> @@ -1684,14 +1684,14 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read(Tab, Key) -> transaction abort | RecordList</name> + <name since="">read(Tab, Key) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <p>Calls function <c>mnesia:read(Tab, Key, read)</c>.</p> </desc> </func> <func> - <name>read(Tab, Key, LockKind) -> transaction abort | RecordList</name> + <name since="">read(Tab, Key, LockKind) -> transaction abort | RecordList</name> <fsummary>Reads records(s) with a given key.</fsummary> <desc> <marker id="read_3"></marker> @@ -1716,7 +1716,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>read_lock_table(Tab) -> ok | transaction abort</name> + <name since="">read_lock_table(Tab) -> ok | transaction abort</name> <fsummary>Sets a read lock on an entire table.</fsummary> <desc> <marker id="read_lock_table"></marker> @@ -1725,7 +1725,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>report_event(Event) -> ok</name> + <name since="">report_event(Event) -> ok</name> <fsummary>Reports a user event to the Mnesia event handler.</fsummary> <desc> <marker id="report_event"></marker> @@ -1743,7 +1743,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name> + <name since="">restore(Opaque, Args) -> {atomic, RestoredTabs} |{aborted, Reason}</name> <fsummary>Online restore of backup.</fsummary> <desc> <marker id="restore"></marker> @@ -1803,7 +1803,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_delete({Tab, Key}) -> ok | transaction abort</name> + <name since="">s_delete({Tab, Key}) -> ok | transaction abort</name> <fsummary>Sets sticky lock and delete records.</fsummary> <desc> <marker id="s_delete"></marker> @@ -1812,7 +1812,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_delete_object(Record) -> ok | transaction abort</name> + <name since="">s_delete_object(Record) -> ok | transaction abort</name> <fsummary>Sets sticky lock and delete record.</fsummary> <desc> <marker id="s_delete_object"></marker> @@ -1822,7 +1822,7 @@ mnesia:create_table(person, </desc> </func> <func> - <name>s_write(Record) -> ok | transaction abort</name> + <name since="">s_write(Record) -> ok | transaction abort</name> <fsummary>Writes <c>Record</c> and sets sticky lock.</fsummary> <desc> <marker id="s_write"></marker> @@ -1832,21 +1832,21 @@ mnesia:create_table(person, </desc> </func> <func> - <name>schema() -> ok</name> + <name since="">schema() -> ok</name> <fsummary>Prints information about all table definitions on the terminal.</fsummary> <desc> <p>Prints information about all table definitions on the terminal.</p> </desc> </func> <func> - <name>schema(Tab) -> ok</name> + <name since="">schema(Tab) -> ok</name> <fsummary>Prints information about one table definition on the terminal.</fsummary> <desc> <p>Prints information about one table definition on the terminal.</p> </desc> </func> <func> - <name>select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name> + <name since="">select(Tab, MatchSpec [, Lock]) -> transaction abort | [Object]</name> <fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="select_2_3"></marker> @@ -1884,7 +1884,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> + <name since="">select(Tab, MatchSpec, NObjects, Lock) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> <fsummary>Matches the objects in <c>Tab</c> against <c>MatchSpec</c>.</fsummary> <desc> <marker id="select_4"></marker> @@ -1907,7 +1907,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> + <name since="">select(Cont) -> transaction abort | {[Object],Cont} | '$end_of_table'</name> <fsummary>Continues selecting objects.</fsummary> <desc> <p>Selects more objects with the match specification initiated @@ -1919,7 +1919,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_debug_level(Level) -> OldLevel</name> + <name since="">set_debug_level(Level) -> OldLevel</name> <fsummary>Changes the internal debug level of Mnesia.</fsummary> <desc> <marker id="set_debug_level"></marker> @@ -1930,7 +1930,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_master_nodes(MasterNodes) -> ok | {error, Reason}</name> + <name since="">set_master_nodes(MasterNodes) -> ok | {error, Reason}</name> <fsummary>Sets the master nodes for all tables.</fsummary> <desc> <marker id="set_master_nodes_1"></marker> @@ -1943,7 +1943,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name> + <name since="">set_master_nodes(Tab, MasterNodes) -> ok | {error, Reason}</name> <fsummary>Sets the master nodes for a table.</fsummary> <desc> <marker id="set_master_nodes_2"></marker> @@ -1968,14 +1968,14 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name> + <name since="">snmp_close_table(Tab) -> {aborted, R} | {atomic, ok}</name> <fsummary>Removes the possibility for SNMP to manipulate the table.</fsummary> <desc> <p>Removes the possibility for SNMP to manipulate the table.</p> </desc> </func> <func> - <name>snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name> + <name since="">snmp_get_mnesia_key(Tab, RowIndex) -> {ok, Key} | undefined</name> <fsummary>Gets the corresponding Mnesia key from an SNMP index.</fsummary> <type> <v>Tab ::= atom()</v> @@ -1990,7 +1990,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name> + <name since="">snmp_get_next_index(Tab, RowIndex) -> {ok, NextIndex} | endOfTable</name> <fsummary>Gets the index of the next lexicographical row.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2006,7 +2006,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name> + <name since="">snmp_get_row(Tab, RowIndex) -> {ok, Row} | undefined</name> <fsummary>Retrieves a row indexed by an SNMP index.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2019,7 +2019,7 @@ mnesia:select(Tab,[{MatchHead, [Guard], [Result]}]),</code> </desc> </func> <func> - <name>snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name> + <name since="">snmp_open_table(Tab, SnmpStruct) -> {aborted, R} | {atomic, ok}</name> <fsummary>Organizes a Mnesia table as an SNMP table.</fsummary> <type> <v>Tab ::= atom()</v> @@ -2073,10 +2073,17 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>start() -> ok | {error, Reason}</name> + <name since="">start() -> ok | {error, Reason}</name> <fsummary>Starts a local Mnesia system.</fsummary> <desc> <marker id="start"></marker> + <p>Mnesia startup is asynchronous. The function call + <c>mnesia:start()</c> returns the atom <c>ok</c> and then + starts to initialize the different tables. Depending on the + size of the database, this can take some time, and the + application programmer must wait for the tables that the + application needs before they can be used. This is achieved + by using the function <c>mnesia:wait_for_tables/2</c>.</p> <p>The startup procedure for a set of Mnesia nodes is a fairly complicated operation. A Mnesia system consists of a set of nodes, with Mnesia started locally on all @@ -2108,7 +2115,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>stop() -> stopped</name> + <name since="">stop() -> stopped</name> <fsummary>Stops Mnesia locally.</fsummary> <desc> <marker id="stop"></marker> @@ -2117,7 +2124,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> + <name since="">subscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> <fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary> <desc> <marker id="subscribe"></marker> @@ -2127,7 +2134,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> + <name since="">sync_dirty(Fun, [, Args]) -> ResultOfFun | exit(Reason)</name> <fsummary>Calls the <c>Fun</c> in a context that is not protected by a transaction.</fsummary> <desc> <marker id="sync_dirty"></marker> @@ -2143,7 +2150,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_log() -> ok | {error, Reason}</name> + <name since="OTP 17.0">sync_log() -> ok | {error, Reason}</name> <fsummary>Performs a file sync of the local log file.</fsummary> <desc> <p>Ensures that the local transaction log file is synced to disk. @@ -2153,7 +2160,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> + <name since="">sync_transaction(Fun, [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> <fsummary>Synchronously executes a transaction.</fsummary> <desc> <marker id="sync_transaction"></marker> @@ -2166,7 +2173,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>system_info(InfoKey) -> Info | exit({aborted, Reason})</name> + <name since="">system_info(InfoKey) -> Info | exit({aborted, Reason})</name> <fsummary>Returns information about the Mnesia system.</fsummary> <desc> <marker id="system_info"></marker> @@ -2353,7 +2360,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>table(Tab [,[Option]]) -> QueryHandle</name> + <name since="">table(Tab [,[Option]]) -> QueryHandle</name> <fsummary>Return a QLC query handle.</fsummary> <desc> <marker id="table"></marker> @@ -2408,7 +2415,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name> + <name since="">table_info(Tab, InfoKey) -> Info | exit({aborted, Reason})</name> <fsummary>Returns local information about table.</fsummary> <desc> <marker id="table_info"></marker> @@ -2560,7 +2567,7 @@ mnesia:create_table(employee, </desc> </func> <func> - <name>transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> + <name since="">transaction(Fun [[, Args], Retries]) -> {aborted, Reason} | {atomic, ResultOfFun}</name> <fsummary>Executes a transaction.</fsummary> <desc> <marker id="transaction"></marker> @@ -2628,7 +2635,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name> + <name since="">transform_table(Tab, Fun, NewAttributeList, NewRecordName) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes format on all records in table <c>Tab</c>.</fsummary> <desc> <marker id="transform_table_4"></marker> @@ -2649,7 +2656,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name> + <name since="">transform_table(Tab, Fun, NewAttributeList) -> {aborted, R} | {atomic, ok}</name> <fsummary>Changes format on all records in table <c>Tab</c>.</fsummary> <desc> <p>Calls <c>mnesia:transform_table(Tab, Fun, @@ -2658,7 +2665,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name> + <name since="">traverse_backup(Source, [SourceMod,] Target, [TargetMod,] Fun, Acc) -> {ok, LastAcc} | {error, Reason}</name> <fsummary>Traversal of a backup.</fsummary> <desc> <marker id="traverse_backup"></marker> @@ -2689,7 +2696,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>uninstall_fallback() -> ok | {error,Reason}</name> + <name since="">uninstall_fallback() -> ok | {error,Reason}</name> <fsummary>Uninstalls a fallback.</fsummary> <desc> <marker id="uninstall_fallback_0"></marker> @@ -2698,7 +2705,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>uninstall_fallback(Args) -> ok | {error,Reason}</name> + <name since="">uninstall_fallback(Args) -> ok | {error,Reason}</name> <fsummary>Uninstalls a fallback.</fsummary> <desc> <p>Deinstalls a fallback before it @@ -2725,7 +2732,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> + <name since="">unsubscribe(EventCategory) -> {ok, Node} | {error, Reason}</name> <fsummary>Subscribes to events of type <c>EventCategory</c>.</fsummary> <desc> <marker id="unsubscribe"></marker> @@ -2735,7 +2742,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name> + <name since="">wait_for_tables(TabList, Timeout) -> ok | {timeout, BadTabList} | {error, Reason}</name> <fsummary>Waits for tables to be accessible.</fsummary> <desc> <marker id="wait_for_tables"></marker> @@ -2746,7 +2753,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>wread({Tab, Key}) -> transaction abort | RecordList</name> + <name since="">wread({Tab, Key}) -> transaction abort | RecordList</name> <fsummary>Reads records with given key.</fsummary> <desc> <marker id="wread"></marker> @@ -2754,7 +2761,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write(Record) -> transaction abort | ok</name> + <name since="">write(Record) -> transaction abort | ok</name> <fsummary>Writes a record into the database.</fsummary> <desc> <marker id="write_1"></marker> @@ -2763,7 +2770,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write(Tab, Record, LockKind) -> transaction abort | ok</name> + <name since="">write(Tab, Record, LockKind) -> transaction abort | ok</name> <fsummary>Writes a record into the database.</fsummary> <desc> <marker id="write_3"></marker> @@ -2779,7 +2786,7 @@ raise(Name, Amount) -> </desc> </func> <func> - <name>write_lock_table(Tab) -> ok | transaction abort</name> + <name since="">write_lock_table(Tab) -> ok | transaction abort</name> <fsummary>Sets write lock on an entire table.</fsummary> <desc> <marker id="write_lock_table"></marker> diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml index 51b32129b6..ccaba412d0 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> @@ -34,7 +34,7 @@ <rev>A</rev> <file>mnesia_frag_hash.sgml</file> </header> - <module>mnesia_frag_hash</module> + <module since="">mnesia_frag_hash</module> <modulesummary>Defines mnesia_frag_hash callback behavior</modulesummary> <description> <p>This module defines a callback behavior for user-defined hash @@ -50,7 +50,7 @@ <funcs> <func> - <name>init_state(Tab, State) -> NewState | abort(Reason)</name> + <name since="">init_state(Tab, State) -> NewState | abort(Reason)</name> <fsummary>Initiates the hash state for a new table.</fsummary> <type> <v>Tab = atom()</v> @@ -72,7 +72,7 @@ </desc> </func> <func> - <name>add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> + <name since="">add_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> <fsummary>Starts when a new fragment is added to a fragmented table.</fsummary> <type> <v>State = term()</v> @@ -100,7 +100,7 @@ </desc> </func> <func> - <name>del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> + <name since="">del_frag(State) -> {NewState, IterFrags, AdditionalLockFrags} | abort(Reason)</name> <fsummary>Starts when a fragment is deleted from a fragmented table.</fsummary> <type> <v>State = term()</v> @@ -127,10 +127,10 @@ </desc> </func> <func> - <name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name> + <name since="">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> @@ -140,7 +140,7 @@ </desc> </func> <func> - <name>match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name> + <name since="">match_spec_to_frag_numbers(State, MatchSpec) -> FragNums | abort(Reason)</name> <fsummary>Resolves a <c>MatchSpec</c> into a list of fragment numbers.</fsummary> <type> <v>MatcSpec = ets_select_match_spec()</v> diff --git a/lib/mnesia/doc/src/mnesia_registry.xml b/lib/mnesia/doc/src/mnesia_registry.xml index a76f716981..18ddc4ab9e 100644 --- a/lib/mnesia/doc/src/mnesia_registry.xml +++ b/lib/mnesia/doc/src/mnesia_registry.xml @@ -34,7 +34,7 @@ <rev>A</rev> <file>mnesia_registry.sgml</file> </header> - <module>mnesia_registry</module> + <module since="">mnesia_registry</module> <modulesummary>Dump support for registries in erl_interface.</modulesummary> <description> <p>This module is usually part of the <c>erl_interface</c> @@ -57,7 +57,7 @@ <funcs> <func> - <name>create_table(Tab) -> ok | exit(Reason)</name> + <name since="">create_table(Tab) -> ok | exit(Reason)</name> <fsummary>Creates a registry table in Mnesia.</fsummary> <desc> <p>A wrapper function for <c>mnesia:create_table/2</c>, @@ -73,7 +73,7 @@ </desc> </func> <func> - <name>create_table(Tab, TabDef) -> ok | exit(Reason)</name> + <name since="">create_table(Tab, TabDef) -> ok | exit(Reason)</name> <fsummary>Creates a customized registry table in Mnesia.</fsummary> <desc> <p>A wrapper function for <c>mnesia:create_table/2</c>, diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 2b715f8f47..2d38e4d01c 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1996</year><year>2017</year> + <year>1996</year><year>2018</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -39,12 +39,103 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.15.3.2</title> + <section><title>Mnesia 4.16</title> <section><title>Fixed Bugs and Malfunctions</title> <list> <item> <p> + Optimize mnesia:read/1 if data have been written in the + same transaction.</p> + <p> + Own Id: OTP-15550 Aux Id: PR-2029 </p> + </item> + <item> + <p> + Fixed bugs in table index plugin handling.</p> + <p> + Own Id: OTP-15689 Aux Id: PR-1695 ERL-556 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Optimized dumping of tables with plugin backends.</p> + <p> + Own Id: OTP-15588 Aux Id: PR-2102 </p> + </item> + <item> + <p> + Include stacktrace in exception if a dirty activity + errors, thus if user have matched on the error thrown it + may not match any more.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-15804 Aux Id: PR-2216 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.15.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Avoid overload warnings caused by a race condition.</p> + <p> + Own Id: OTP-15619 Aux Id: ERIERL-310 </p> + </item> + </list> + </section> + +</section> + +<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> @@ -55,6 +146,21 @@ </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> @@ -690,7 +796,7 @@ <p> Returns the same value for mnesia_loader:disc_load_table/2 as - mnesia_loader:net_load_table/4 if a table copy can not be + mnesia_loader:net_load_table/4 if a table copy cannot be found. (Thanks to Uwe Dauernheim)</p> <p> Own Id: OTP-10015</p> diff --git a/lib/mnesia/examples/bench/README b/lib/mnesia/examples/bench/README index 5d31b5ba25..b8209b19b8 100644 --- a/lib/mnesia/examples/bench/README +++ b/lib/mnesia/examples/bench/README @@ -46,7 +46,7 @@ you need to: - put the $ERL_TOP/bin directory in your path on all nodes - bind IP adresses to hostnames (e.g via DNS or /etc/hosts) - - enable usage of rsh so it does not prompt for password + - enable usage of ssh so it does not prompt for password If you cannot achieve this, it is possible to run the benchmark anyway, but it requires more manual work to be done for each @@ -141,7 +141,7 @@ statistics_detail following atoms: normal, debug and debug2. debug enables a finer grain of statistics to be reported, but since it requires more counters, to be updated by the generator processes it may - cause slightly worse benchmark performace figures than the brief + cause slightly worse benchmark performance figures than the brief default case, that is normal. debug2 prints out the debug info and formats it according to LMC's benchmark program. @@ -160,7 +160,7 @@ n_fragments Defines how many fragments each table should be divided in. Default is 100. The fragments are evenly distributed over - all table nodes. The group table not devided in fragments. + all table nodes. The group table not divided in fragments. n_replicas diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl index 1842769778..02bc884e36 100644 --- a/lib/mnesia/src/mnesia.erl +++ b/lib/mnesia/src/mnesia.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. 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. @@ -160,7 +160,7 @@ {'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 index_attr() :: atom() | non_neg_integer() | {atom()}. -type write_locks() :: 'write' | 'sticky_write'. -type read_locks() :: 'read'. -type lock_kind() :: write_locks() | read_locks(). @@ -168,6 +168,9 @@ -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). @@ -177,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. @@ -278,7 +281,8 @@ stop() -> Other -> Other end. --spec change_config(Config::atom(), Value::_) -> ok | {error, term()}. +-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 -> @@ -779,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; @@ -830,18 +838,20 @@ read(Tid, Ts, Tab, Key, LockKind) tid -> Store = Ts#tidstore.store, Oid = {Tab, Key}, - Objs = - case LockKind of - read -> - mnesia_locker:rlock(Tid, Store, Oid); - write -> - mnesia_locker:rwlock(Tid, Store, Oid); - sticky_write -> - mnesia_locker:sticky_rwlock(Tid, Store, Oid); - _ -> - abort({bad_type, Tab, LockKind}) - end, - add_written(?ets_lookup(Store, Oid), Tab, Objs); + ObjsFun = + fun() -> + case LockKind of + read -> + mnesia_locker:rlock(Tid, Store, Oid); + write -> + mnesia_locker:rwlock(Tid, Store, Oid); + sticky_write -> + mnesia_locker:sticky_rwlock(Tid, Store, Oid); + _ -> + abort({bad_type, Tab, LockKind}) + end + end, + add_written(?ets_lookup(Store, Oid), Tab, ObjsFun, LockKind); _Protocol -> dirty_read(Tab, Key) end; @@ -1194,14 +1204,20 @@ add_previous(_Tid, Ts, _Type, Tab) -> %% This routine fixes up the return value from read/1 so that %% it is correct with respect to what this particular transaction %% has already written, deleted .... etc +%% The actual read from the table is not done if not needed due to local +%% transaction context, and if so, no extra read lock is needed either. -add_written([], _Tab, Objs) -> - Objs; % standard normal fast case -add_written(Written, Tab, Objs) -> +add_written([], _Tab, ObjsFun, _LockKind) -> + ObjsFun(); % standard normal fast case +add_written(Written, Tab, ObjsFun, LockKind) -> case val({Tab, setorbag}) of bag -> - add_written_to_bag(Written, Objs, []); + add_written_to_bag(Written, ObjsFun(), []); + _ when LockKind == read; + LockKind == write -> + add_written_to_set(Written); _ -> + _ = ObjsFun(), % Fall back to request new lock and read from source add_written_to_set(Written) end. @@ -1261,6 +1277,14 @@ match_object(Tid, Ts, Tab, Pat, LockKind) match_object(_Tid, _Ts, Tab, Pat, _LockKind) -> abort({bad_type, Tab, Pat}). +add_written_index(Store, Pos, Tab, Key, Objs) when is_integer(Pos) -> + Pat = setelement(Pos, val({Tab, wild_pattern}), Key), + add_written_match(Store, Pat, Tab, Objs); +add_written_index(Store, Pos, Tab, Key, Objs) when is_tuple(Pos) -> + IxF = mnesia_index:index_vals_f(val({Tab, storage_type}), Tab, Pos), + Ops = find_ops(Store, Tab, '_'), + add_ix_match(Ops, Objs, IxF, Key, val({Tab, setorbag})). + add_written_match(S, Pat, Tab, Objs) -> Ops = find_ops(S, Tab, Pat), FixedRes = add_match(Ops, Objs, val({Tab, setorbag})), @@ -1287,6 +1311,46 @@ add_match([{_Oid, Val, write}|R], Objs, bag) -> add_match([{Oid, Val, write}|R], Objs, set) -> add_match(R, [Val | deloid(Oid,Objs)],set). +add_ix_match([], Objs, _IxF, _Key, _Type) -> + Objs; +add_ix_match(Written, Objs, IxF, Key, ordered_set) -> + %% Must use keysort which is stable + add_ordered_match(lists:keysort(1, ix_filter_ops(IxF, Key, Written)), Objs, []); +add_ix_match([{Oid, _, delete}|R], Objs, IxF, Key, Type) -> + add_ix_match(R, deloid(Oid, Objs), IxF, Key, Type); +add_ix_match([{_Oid, Val, delete_object}|R], Objs, IxF, Key, Type) -> + case ix_match(Val, IxF, Key) of + true -> + add_ix_match(R, lists:delete(Val, Objs), IxF, Key, Type); + false -> + add_ix_match(R, Objs, IxF, Key, Type) + end; +add_ix_match([{_Oid, Val, write}|R], Objs, IxF, Key, bag) -> + case ix_match(Val, IxF, Key) of + true -> + add_ix_match(R, [Val | lists:delete(Val, Objs)], IxF, Key, bag); + false -> + add_ix_match(R, Objs, IxF, Key, bag) + end; +add_ix_match([{Oid, Val, write}|R], Objs, IxF, Key, set) -> + case ix_match(Val, IxF, Key) of + true -> + add_ix_match(R, [Val | deloid(Oid,Objs)],IxF,Key,set); + false -> + add_ix_match(R, Objs, IxF, Key, set) + end. + +ix_match(Val, IxF, Key) -> + lists:member(Key, IxF(Val)). + +ix_filter_ops(IxF, Key, Ops) -> + lists:filter( + fun({_Oid, Obj, write}) -> + ix_match(Obj, IxF, Key); + (_) -> + true + end, Ops). + %% For ordered_set only !! add_ordered_match(Written = [{{_, Key}, _, _}|_], [Obj|Objs], Acc) when Key > element(2, Obj) -> @@ -1625,6 +1689,16 @@ index_match_object(Tid, Ts, Tab, Pat, Attr, LockKind) dirty_index_match_object(Tab, Pat, Attr); % Should be optimized? tid -> case mnesia_schema:attr_tab_to_pos(Tab, Attr) of + {_} -> + case LockKind of + read -> + Store = Ts#tidstore.store, + mnesia_locker:rlock_table(Tid, Store, Tab), + Objs = dirty_match_object(Tab, Pat), + add_written_match(Store, Pat, Tab, Objs); + _ -> + abort({bad_type, Tab, LockKind}) + end; Pos when Pos =< tuple_size(Pat) -> case LockKind of read -> @@ -1672,8 +1746,8 @@ index_read(Tid, Ts, Tab, Key, Attr, LockKind) false -> Store = Ts#tidstore.store, Objs = mnesia_index:read(Tid, Store, Tab, Key, Pos), - Pat = setelement(Pos, val({Tab, wild_pattern}), Key), - add_written_match(Store, Pat, Tab, Objs); + add_written_index( + Ts#tidstore.store, Pos, Tab, Key, Objs); true -> abort({bad_type, Tab, Attr, Key}) end; @@ -1809,7 +1883,7 @@ remote_dirty_match_object(Tab, Pat) -> false -> mnesia_lib:db_match_object(Tab, Pat); true -> - PosList = val({Tab, index}), + PosList = regular_indexes(Tab), remote_dirty_match_object(Tab, Pat, PosList) end. @@ -1841,7 +1915,7 @@ remote_dirty_select(Tab, Spec) -> false -> mnesia_lib:db_select(Tab, Spec); true -> - PosList = val({Tab, index}), + PosList = regular_indexes(Tab), remote_dirty_select(Tab, Spec, PosList) end; _ -> @@ -1908,6 +1982,8 @@ dirty_index_match_object(Pat, _Attr) -> 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 + {_} -> + dirty_match_object(Tab, Pat); Pos when Pos =< tuple_size(Pat) -> case has_var(element(2, Pat)) of false -> @@ -2682,7 +2758,7 @@ del_table_index(Tab, Ix) -> -spec transform_table(Tab::table(), Fun, [Attr]) -> t_result(ok) when Attr :: atom(), - Fun:: fun((Record::tuple()) -> Transformed::tuple()). + 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) @@ -2693,7 +2769,7 @@ transform_table(Tab, Fun, NewA) -> -spec transform_table(Tab::table(), Fun, [Attr], RecName) -> t_result(ok) when RecName :: atom(), Attr :: atom(), - Fun:: fun((Record::tuple()) -> Transformed::tuple()). + Fun:: fun((Record::tuple()) -> Transformed::tuple()) | ignore. transform_table(Tab, Fun, NewA, NewRN) -> mnesia_schema:transform_table(Tab, Fun, NewA, NewRN). @@ -3238,3 +3314,7 @@ put_activity_id(Activity) -> mnesia_tm:put_activity_id(Activity). put_activity_id(Activity,Fun) -> mnesia_tm:put_activity_id(Activity,Fun). + +regular_indexes(Tab) -> + PosList = val({Tab, index}), + [P || P <- PosList, is_integer(P)]. diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl index da7e662288..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,6 +47,10 @@ -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, diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl index 34f16f178b..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) -> diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl index 8112378ffd..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-2017 +%% 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. @@ -1269,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 11185a1762..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-2017. 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. diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl index f0ed7aef4a..8ab11be2d3 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. @@ -67,10 +67,10 @@ get_log_writes() -> incr_log_writes() -> Left = mnesia_lib:incr_counter(trans_log_writes_left, -1), if - Left > 0 -> - ignore; + Left =:= 0 -> + adjust_log_writes(true); true -> - adjust_log_writes(true) + ignore end. adjust_log_writes(DoCast) -> @@ -191,8 +191,7 @@ 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(), + catch _:R:ST when R =/= fatal -> Reason = {"Transaction log dump error: ~tp~n", [{R, ST}]}, close_files(InPlace, {error, Reason}, InitBy), exit(Reason) @@ -273,17 +272,12 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) -> end end, D = Rec#commit.disc_copies, - ExtOps = commit_ext(Rec), insert_ops(Tid, disc_copies, D, InPlace, InitBy, LogV), - [insert_ops(Tid, Ext, Ops, InPlace, InitBy, LogV) || - {Ext, Ops} <- ExtOps, - storage_semantics(Ext) == disc_copies], + insert_ext_ops(Tid, commit_ext(Rec), InPlace, InitBy), case InitBy of startup -> DO = Rec#commit.disc_only_copies, - insert_ops(Tid, disc_only_copies, DO, InPlace, InitBy, LogV), - [insert_ops(Tid, Ext, Ops, InPlace, InitBy, LogV) || - {Ext, Ops} <- ExtOps, storage_semantics(Ext) == disc_only_copies]; + insert_ops(Tid, disc_only_copies, DO, InPlace, InitBy, LogV); _ -> ignore end. @@ -291,11 +285,8 @@ do_insert_rec(Tid, Rec, InPlace, InitBy, LogV) -> commit_ext(#commit{ext = []}) -> []; commit_ext(#commit{ext = Ext}) -> case lists:keyfind(ext_copies, 1, Ext) of - {_, C} -> - lists:foldl(fun({Ext0, Op}, D) -> - orddict:append(Ext0, Op, D) - end, orddict:new(), C); - false -> [] + {_, C} -> C; + false -> [] end. update(_Tid, [], _DumperMode) -> @@ -325,13 +316,27 @@ 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 ~tp ~tp", [{Reason,ST}, SchemaOps]) end. +insert_ext_ops(Tid, ExtOps, InPlace, InitBy) -> + %% Note: ext ops cannot be part of pre-4.3 logs, so there's no need + %% to support the old operation order, as in `insert_ops' + lists:foreach( + fun ({Ext, Op}) -> + case storage_semantics(Ext) of + Semantics when Semantics == disc_copies; + Semantics == disc_only_copies, InitBy == startup -> + insert_op(Tid, Ext, Op, InPlace, InitBy); + _Other -> + ok + end + end, + ExtOps). + insert_ops(_Tid, _Storage, [], _InPlace, _InitBy, _) -> ok; insert_ops(Tid, Storage, [Op], InPlace, InitBy, Ver) when Ver >= "4.3"-> insert_op(Tid, Storage, Op, InPlace, InitBy), @@ -1471,8 +1476,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_frag.erl b/lib/mnesia/src/mnesia_frag.erl index c39f30e140..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. @@ -1157,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. diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl index f8b3b9cd02..6f1c21e3b9 100644 --- a/lib/mnesia/src/mnesia_index.erl +++ b/lib/mnesia/src/mnesia_index.erl @@ -1,8 +1,8 @@ %% %% %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. %% 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% %% @@ -37,7 +37,7 @@ db_match_erase/2, get_index_table/2, get_index_table/3, - + tab2filename/2, init_index/2, init_indecies/3, @@ -45,6 +45,7 @@ del_transient/3, del_index_table/3, + index_vals_f/3, index_info/2, ext_index_instances/1]). @@ -60,9 +61,14 @@ read(Tid, Store, Tab, IxKey, Pos) -> ResList = mnesia_locker:ixrlock(Tid, Store, Tab, IxKey, Pos), %% Remove all tuples which don't include Ixkey, happens when Tab is a bag case val({Tab, setorbag}) of - bag -> + bag when is_integer(Pos) -> mnesia_lib:key_search_all(IxKey, Pos, ResList); - _ -> + bag when is_tuple(Pos) -> + TabStorage = val({Tab, storage_type}), + ValsF = index_vals_f(TabStorage, Tab, Pos), + [Obj || Obj <- ResList, + lists:member(IxKey, ValsF(Obj))]; + _ -> ResList end. @@ -136,7 +142,7 @@ del_object_index2([], _, _Storage, _Tab, _K, _Obj) -> ok; del_object_index2([{{Pos, Type}, Ixt} | Tail], SoB, Storage, Tab, K, Obj) -> ValsF = index_vals_f(Storage, Tab, Pos), case SoB of - bag -> + bag -> del_object_bag(Type, ValsF, Tab, K, Obj, Ixt); _ -> %% If set remove the tuple in index table del_ixes(Type, Ixt, ValsF, Obj, K) @@ -197,7 +203,7 @@ merge([], _, _, Ack) -> realkeys(Tab, Pos, IxKey) -> Index = get_index_table(Tab, Pos), db_get(Index, IxKey). % a list on the form [{IxKey, RealKey1} , .... - + dirty_select(Tab, Spec, Pos) when is_integer(Pos) -> %% Assume that we are on the node where the replica is %% Returns the records without applying the match spec @@ -233,7 +239,7 @@ dirty_read2(Tab, IxKey, Pos) -> end, Acc, mnesia_lib:db_get(Storage, Tab, K)) end, [], Keys)). -pick_index([{{{Pfx,_},IxType}, Ixt}|_], _Tab, {_} = Pfx) -> +pick_index([{{{Pfx,_,_},IxType}, Ixt}|_], _Tab, {_} = Pfx) -> {IxType, Ixt}; pick_index([{{Pos,IxType}, Ixt}|_], _Tab, Pos) -> {IxType, Ixt}; @@ -242,7 +248,7 @@ pick_index([_|T], Tab, Pos) -> pick_index([], Tab, Pos) -> mnesia:abort({no_exist, Tab, {index, Pos}}). - + %%%%%%% Creation, Init and deletion routines for index tables %% We can have several indexes on the same table @@ -387,12 +393,12 @@ init_ext_index(Tab, Storage, Alias, Mod, [{Pos,Type} | Tail]) -> create_fun(Cont, Tab, Pos) -> IxF = index_vals_f(disc_only_copies, Tab, Pos), fun(read) -> - Data = + Data = case Cont of {start, KeysPerChunk} -> mnesia_lib:db_init_chunk( disc_only_copies, Tab, KeysPerChunk); - '$end_of_table' -> + '$end_of_table' -> '$end_of_table'; _Else -> mnesia_lib:db_chunk(disc_only_copies, Cont) @@ -462,7 +468,7 @@ add_index_info(Tab, SetOrBag, IxElem) -> %% Check later if mnesia_tm is sensitive about the order mnesia_lib:set({Tab, index_info}, IndexInfo), mnesia_lib:set({Tab, index}, index_positions(IndexInfo)), - mnesia_lib:set({Tab, commit_work}, + mnesia_lib:set({Tab, commit_work}, mnesia_lib:sort_commit([IndexInfo | Commit])); {value, Old} -> %% We could check for consistency here @@ -470,7 +476,7 @@ add_index_info(Tab, SetOrBag, IxElem) -> mnesia_lib:set({Tab, index_info}, Index), mnesia_lib:set({Tab, index}, index_positions(Index)), NewC = lists:keyreplace(index, 1, Commit, Index), - mnesia_lib:set({Tab, commit_work}, + mnesia_lib:set({Tab, commit_work}, mnesia_lib:sort_commit(NewC)) end. @@ -488,19 +494,19 @@ del_index_info(Tab, Pos) -> element(1,P)=/=Pos end, Old#index.pos_list) of - [] -> + [] -> IndexInfo = index_info(Old#index.setorbag,[]), mnesia_lib:set({Tab, index_info}, IndexInfo), mnesia_lib:set({Tab, index}, index_positions(IndexInfo)), NewC = lists:keydelete(index, 1, Commit), - mnesia_lib:set({Tab, commit_work}, + mnesia_lib:set({Tab, commit_work}, mnesia_lib:sort_commit(NewC)); New -> Index = Old#index{pos_list = New}, mnesia_lib:set({Tab, index_info}, Index), mnesia_lib:set({Tab, index}, index_positions(Index)), NewC = lists:keyreplace(index, 1, Commit, Index), - mnesia_lib:set({Tab, commit_work}, + mnesia_lib:set({Tab, commit_work}, mnesia_lib:sort_commit(NewC)) end end. @@ -537,7 +543,7 @@ db_match_erase({{ext,_,_} = Ext, Ixt}, Pat) -> mnesia_lib:db_match_erase(Ext, Ixt, Pat); db_match_erase({dets, Ixt}, Pat) -> ok = dets:match_delete(Ixt, Pat). - + db_select({ram, Ixt}, Pat) -> ets:select(Ixt, Pat); db_select({{ext,_,_} = Ext, Ixt}, Pat) -> @@ -545,7 +551,7 @@ db_select({{ext,_,_} = Ext, Ixt}, Pat) -> db_select({dets, Ixt}, Pat) -> dets:select(Ixt, Pat). - + get_index_table(Tab, Pos) -> get_index_table(Tab, val({Tab, storage_type}), Pos). diff --git a/lib/mnesia/src/mnesia_late_loader.erl b/lib/mnesia/src/mnesia_late_loader.erl index e4f8dcf2b9..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. diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl index 53fdd76de8..6abc05fade 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,8 +460,8 @@ 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()}; @@ -469,7 +469,7 @@ pr_other(Var) -> end, 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 @@ -929,7 +929,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions"; error_desc(combine_error) -> "Table options were ilegally combined"; error_desc(bad_index) -> "Index already exists or was out of bounds"; error_desc(already_exists) -> "Some schema option we try to set is already on"; -error_desc(index_exists)-> "Some ops can not be performed on tabs with index"; +error_desc(index_exists)-> "Some ops cannot be performed on tabs with index"; error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item"; error_desc(system_limit) -> "Some system_limit was exhausted"; error_desc(mnesia_down) -> "A transaction involving objects at some remote " diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl index 39704c65f9..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. @@ -535,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. @@ -777,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. diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index 073b48abc0..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) -> diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl index a2de23a2a3..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. diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl index d792070332..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. diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl index 71952af31c..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-2017. 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. @@ -2695,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: '~tp' in '~tp'", - [Reason, erlang:get_stacktrace()]), + [Reason, Stacktrace]), exit({"Bad transform function", Tab, Fun, node(), Reason}) end end; diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl index dfaa20d2d3..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. diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl index 7d24d09472..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. diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl index ebf580d09e..8b79fca1d7 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. @@ -121,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) -> @@ -597,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 -> + catch _:Reason:Stacktrace -> dbg_out("Recovery of coordinator ~p failed: ~tp~n", - [Tid, {Reason, erlang:get_stacktrace()}]), + [Tid, {Reason, Stacktrace}]), Protocol = asym_trans, tell_outcome(Tid, Protocol, node(), CheckNodes, TellNodes) end, @@ -742,8 +743,9 @@ non_transaction(OldState, Fun, Args, ActivityKind, Mod) -> {aborted, Reason} -> mnesia:abort(Reason); Res -> Res catch - throw:Throw -> throw(Throw); - _:Reason -> exit(Reason) + throw:Throw -> throw(Throw); + error:Reason:ST -> exit({Reason, ST}); + exit:Reason -> exit(Reason) after case OldState of undefined -> erase(mnesia_activity_state); @@ -825,8 +827,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) @@ -1661,7 +1662,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) -> ?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]), try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of {Modified, C = #commit{}, DumperMode} -> - %% If we can not find any local unclear decision + %% If we cannot find any local unclear decision %% we should presume abort at startup recovery case lists:member(node(), DiscNs) of false -> @@ -1796,14 +1797,13 @@ 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: ~tp -> {'EXIT', ~tp}~n", [Tid, Op, {Reason, ST}]), do_update(Tid, Storage, Ops, OldRes) @@ -1914,11 +1914,10 @@ 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: ~tp -> {'EXIT', ~tp}~n", [Tid, Head, {Reason, ST}]) end, @@ -2212,7 +2211,7 @@ 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("~tp", [Call]), io_lib:format("~tp", [Curr]), Reds, LM) diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index 5b61b1af65..b43bc82801 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -53,7 +53,8 @@ MODULES= \ mnesia_measure_test \ mnesia_cost \ mnesia_dbn_meters \ - ext_test + ext_test \ + mnesia_index_plugin_test DocExamplesDir := ../doc/src/ diff --git a/lib/mnesia/test/README b/lib/mnesia/test/README index e0ced7399d..30a0d2fd64 100644 --- a/lib/mnesia/test/README +++ b/lib/mnesia/test/README @@ -51,7 +51,7 @@ stated as test suite configuration parameters, but by default the extra node names are generated. In this example the names will be: a, a1 and a2. It is enough to start the first node manually, the extra nodes will automatically be started if -neccessary. +necessary. The attached UNIX shell script mt, does not work on all platforms, but it may be used as a source for inspiration. It @@ -63,7 +63,7 @@ test cases (i.e. test cases that encountered an error). During development we want to be able to run the test cases in the debugger. This demands a little bit of preparations: - - Start the neccessary number of nodes (normally 3). + - Start the necessary number of nodes (normally 3). This may either be done by running the mt script or by starting the main node and then invoke mt:start_nodes() to start the extra nodes with slave. @@ -73,7 +73,7 @@ in the debugger. This demands a little bit of preparations: - Load all files that needs to be interpreted. This is typically all Mnesia files plus the test case. By invoking mnesia:ni() - and mnesia:ni([TestModule]) the neccessary modules will be + and mnesia:ni([TestModule]) the necessary modules will be loaded on all CONNECTED nodes. The test case execution is supervised in order to ensure that no test diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl index 279744dbb0..b41bf22efa 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. @@ -69,12 +69,13 @@ groups() -> %% covered. [{light, [], [{group, install}, {group, nice}, {group, evil}, - {group, mnesia_frag_test, light}, {group, qlc}, + {group, mnesia_frag_test, light}, {group, qlc}, {group, index_plugins}, {group, registry}, {group, config}, {group, examples}]}, {install, [], [{mnesia_install_test, all}]}, {nice, [], [{mnesia_nice_coverage_test, all}]}, {evil, [], [{mnesia_evil_coverage_test, all}]}, {qlc, [], [{mnesia_qlc_test, all}]}, + {index_plugins, [], [{mnesia_index_plugin_test, all}]}, {registry, [], [{mnesia_registry_test, all}]}, {config, [], [{mnesia_config_test, all}]}, {examples, [], [{mnesia_examples_test, all}]}, diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl index 58a5dc1d40..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. diff --git a/lib/mnesia/test/mnesia_bench_SUITE.erl b/lib/mnesia/test/mnesia_bench_SUITE.erl index 5cc01867c4..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. diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl index 7a2678cee3..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. diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl index 4d0dd7b0ee..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. diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl index 92124ebc65..984f43582c 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. @@ -48,7 +48,7 @@ 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]). + move_table_copy_3/1, move_table_copy_4/1, dirty_error_stacktrace/1]). -export([update_trans/3]). @@ -64,7 +64,7 @@ all() -> {group, dirty_update_counter}, {group, dirty_delete}, {group, dirty_delete_object}, {group, dirty_match_object}, {group, dirty_index}, - {group, dirty_iter}, {group, admin_tests}]. + {group, dirty_iter}, {group, admin_tests}, dirty_error_stacktrace]. groups() -> [{dirty_write, [], @@ -114,6 +114,36 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Errors in dirty activity should have stacktrace +dirty_error_stacktrace(Config) -> + %% Custom errors should have stacktrace + try + mnesia:async_dirty(fun() -> error(custom_error) end) + catch + exit:{custom_error, _} -> ok + end, + + %% Undef error should have unknown module and function in the stacktrace + try + mnesia:async_dirty(fun() -> unknown_module:unknown_fun(arg) end) + catch + exit:{undef, [{unknown_module, unknown_fun, [arg], []} | _]} -> ok + end, + + %% Exists don't have stacktrace + try + mnesia:async_dirty(fun() -> exit(custom_error) end) + catch + exit:custom_error -> ok + end, + + %% Aborts don't have a stacktrace (unfortunately) + try + mnesia:async_dirty(fun() -> mnesia:abort(custom_abort) end) + catch + exit:{aborted, custom_abort} -> ok + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Write records dirty diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl index c186f7330b..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. diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl index 1a561154a7..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. diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl index f1259abf90..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. diff --git a/lib/mnesia/test/mnesia_frag_test.erl b/lib/mnesia/test/mnesia_frag_test.erl index 7371792fda..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. diff --git a/lib/mnesia/test/mnesia_index_plugin_test.erl b/lib/mnesia/test/mnesia_index_plugin_test.erl new file mode 100644 index 0000000000..44fe047c50 --- /dev/null +++ b/lib/mnesia/test/mnesia_index_plugin_test.erl @@ -0,0 +1,261 @@ +%% +%% %CopyrightBegin% +%% +%% 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. +%% 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_index_plugin_test). +-author('[email protected]'). + +-export([init_per_testcase/2, end_per_testcase/2, + init_per_group/2, end_per_group/2, + init_per_suite/1, end_per_suite/1, + all/0, groups/0]). + +-export([ + add_rm_plugin/1, + tab_with_plugin_index/1, + tab_with_multiple_plugin_indexes/1, + ix_match_w_plugin/1, + ix_match_w_plugin_ordered/1, + ix_match_w_plugin_bag/1 + ]). + +-export([ix_prefixes/3, % test plugin + ix_prefixes2/3]). % test plugin 2 + +-include("mnesia_test_lib.hrl"). + +init_per_suite(Conf) -> + Conf. + +end_per_suite(Conf) -> + Conf. + +init_per_testcase(Func, Conf) -> + mnesia_test_lib:init_per_testcase(Func, Conf). + +end_per_testcase(Func, Conf) -> + mnesia_test_lib:end_per_testcase(Func, Conf). + +all() -> + [add_rm_plugin, + tab_with_plugin_index, + tab_with_multiple_plugin_indexes, + ix_match_w_plugin, + ix_match_w_plugin_ordered, + ix_match_w_plugin_bag]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +add_rm_plugin(suite) -> []; +add_rm_plugin(Config) when is_list(Config) -> + [N1, N2] = Nodes = ?acquire_nodes(2, Config), + ok = add_plugin(), + ok = rpc_check_plugin(N1), + ok = rpc_check_plugin(N2), + ok = add_plugin2(), + ok = del_plugin(), + ok = del_plugin2(), + ok = add_plugin(), + ok = add_plugin2(), + ok = del_plugin(), + ok = del_plugin2(), + ?verify_mnesia(Nodes, []). + +-define(PLUGIN1, {{pfx},?MODULE,ix_prefixes}). +-define(PLUGIN2, {{pfx2},?MODULE,ix_prefixes2}). + +add_plugin() -> + {atomic, ok} = mnesia_schema:add_index_plugin({pfx}, ?MODULE, ix_prefixes), + [?PLUGIN1] = mnesia_schema:index_plugins(), + ok. + +add_plugin2() -> + {atomic, ok} = mnesia_schema:add_index_plugin({pfx2}, ?MODULE, ix_prefixes2), + [?PLUGIN1, ?PLUGIN2] = lists:sort(mnesia_schema:index_plugins()), + ok. + +del_plugin() -> + {atomic, ok} = mnesia_schema:delete_index_plugin({pfx}), + [?PLUGIN2] = mnesia_schema:index_plugins(), + ok. + +del_plugin2() -> + {atomic, ok} = mnesia_schema:delete_index_plugin({pfx2}), + [] = mnesia_schema:index_plugins(), + ok. + +rpc_check_plugin(N) -> + [?PLUGIN1] = + rpc:call(N, mnesia_schema, index_plugins, []), + ok. + +tab_with_plugin_index(suite) -> []; +tab_with_plugin_index(Config) when is_list(Config) -> + [_N1] = Nodes = ?acquire_nodes(1, Config), + ok = add_plugin(), + {atomic, ok} = mnesia:create_table(t, [{attributes, [k,v1,v2]}, + {index, [{{pfx}, ordered}, + {v1, ordered}, + v2]}]), + [ok,ok,ok,ok] = + [mnesia:dirty_write({t, K, V1, V2}) + || {K,V1,V2} <- [{1,a,"123"}, + {2,b,"12345"}, + {3,c,"6789"}, + {4,d,nil}]], + [{t,1,a,"123"},{t,2,b,"12345"}] = + mnesia:dirty_index_read(t,<<"123">>,{pfx}), + [{t,3,c,"6789"}] = + mnesia:dirty_index_read(t,"6789",v2), + [{t,1,a,"123"}] = + mnesia:dirty_match_object({t,'_',a,"123"}), + [{t,1,a,"123"}] = + mnesia:dirty_select(t, [{ {t,'_',a,"123"}, [], ['$_']}]), + mnesia:dirty_delete(t,2), + [{t,1,a,"123"}] = + mnesia:dirty_index_read(t,<<"123">>,{pfx}), + ?verify_mnesia(Nodes, []). + +tab_with_multiple_plugin_indexes(suite) -> []; +tab_with_multiple_plugin_indexes(Config) when is_list(Config) -> + [_N1] = Nodes = ?acquire_nodes(1, Config), + ok = add_plugin(), + ok = add_plugin2(), + {atomic, ok} = + mnesia:create_table(u, [{attributes, [k,v1,v2]}, + {index, [{{pfx}, ordered}, + {{pfx2}, ordered}]}]), + [ok,ok,ok,ok] = + [mnesia:dirty_write({u, K, V1, V2}) + || {K,V1,V2} <- [{1,a,"123"}, + {2,b,"12345"}, + {3,c,"6789"}, + {4,d,nil}]], + [{u,1,a,"123"},{u,2,b,"12345"}] = + mnesia:dirty_index_read(u,<<"123">>,{pfx}), + [{u,1,a,"123"},{u,2,b,"12345"}] = + mnesia:dirty_index_read(u,<<"321">>,{pfx2}), + ?verify_mnesia(Nodes, []). + +ix_match_w_plugin(suite) -> []; +ix_match_w_plugin(Config) when is_list(Config) -> + [_N1] = Nodes = ?acquire_nodes(1, Config), + ok = add_plugin(), + {atomic, ok} = mnesia:create_table(im1, [{attributes, [k, v1, v2]}, + {index, [{{pfx}, ordered}, + {v1, ordered}]}]), + fill_and_test_index_match(im1, set), + ?verify_mnesia(Nodes, []). + + +ix_match_w_plugin_ordered(suite) -> []; +ix_match_w_plugin_ordered(Config) when is_list(Config) -> + [_N1] = Nodes = ?acquire_nodes(1, Config), + ok = add_plugin(), + {atomic, ok} = mnesia:create_table(im2, [{attributes, [k, v1, v2]}, + {type, ordered_set}, + {index, [{{pfx}, ordered}, + {v1, ordered}]}]), + fill_and_test_index_match(im2, ordered_set), + ?verify_mnesia(Nodes, []). + +ix_match_w_plugin_bag(suite) -> []; +ix_match_w_plugin_bag(Config) when is_list(Config) -> + [_N1] = Nodes = ?acquire_nodes(1, Config), + ok = add_plugin(), + {atomic, ok} = mnesia:create_table(im3, [{attributes, [k, v1, v2]}, + {type, bag}, + {index, [{{pfx}, ordered}, + {v1, ordered}]}]), + fill_and_test_index_match(im3, bag), + ?verify_mnesia(Nodes, []). + +fill_and_test_index_match(Tab, Type) -> + [ok,ok,ok,ok,ok,ok,ok,ok,ok] = + [mnesia:dirty_write({Tab, K, V1, V2}) + || {K,V1,V2} <- [{1,a,"123"}, + {2,b,"12345"}, + {3,c,"123"}, + {4,d,nil}, + {5,e,nil}, + {6,f,nil}, + {7,g,nil}, %% overwritten if not bag + {7,g,"234"}, + {8,h,"123"}]], + mnesia:activity( + transaction, + fun() -> + ok = mnesia:write({Tab, 1, aa, "1234"}), %% replaces if not bag + ok = mnesia:delete({Tab, 2}), + ok = mnesia:delete({Tab, 4}), + ok = mnesia:write({Tab, 6, ff, nil}), + ok = mnesia:write({Tab, 7, gg, "123"}), + ok = mnesia:write({Tab, 100, x, nil}), + ok = mnesia:delete_object({Tab,3,c,"123"}), + ok = mnesia:delete_object({Tab,5,e,nil}), + Res = mnesia:index_read(Tab, <<"123">>, {pfx}), + SetRes = [{Tab,1,aa,"1234"}, {Tab,7,gg,"123"}, {Tab,8,h,"123"}], + case Type of + set -> + SetRes = lists:sort(Res); + ordered_set -> + SetRes = Res; + bag -> + [{Tab,1,a,"123"}, {Tab,1,aa,"1234"}, + {Tab,7,gg,"123"}, {Tab,8,h,"123"}] = lists:sort(Res) + end + end). + +%% ============================================================ +%% +ix_prefixes(_Tab, _Pos, Obj) -> + lists:foldl( + fun(V, Acc) when is_list(V) -> + try Pfxs = prefixes(list_to_binary(V)), + Pfxs ++ Acc + catch + error:_ -> + Acc + end; + (V, Acc) when is_binary(V) -> + Pfxs = prefixes(V), + Pfxs ++ Acc; + (_, Acc) -> + Acc + end, [], tl(tuple_to_list(Obj))). + +ix_prefixes2(Tab, Pos, Obj) -> + [rev(P) || P <- ix_prefixes(Tab, Pos, Obj)]. + +rev(B) when is_binary(B) -> + list_to_binary(lists:reverse(binary_to_list(B))). + +prefixes(<<P:3/binary, _/binary>>) -> + [P]; +prefixes(_) -> + []. diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl index 3f67396eb0..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. diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl index 1c3ea5ec92..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. @@ -1563,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}, @@ -1598,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 eb82617b60..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. diff --git a/lib/mnesia/test/mnesia_measure_test.erl b/lib/mnesia/test/mnesia_measure_test.erl index 4e63eaee22..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. diff --git a/lib/mnesia/test/mnesia_nice_coverage_test.erl b/lib/mnesia/test/mnesia_nice_coverage_test.erl index 7c96d6e6a0..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. diff --git a/lib/mnesia/test/mnesia_qlc_test.erl b/lib/mnesia/test/mnesia_qlc_test.erl index 262a6b4abc..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. diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl index 82d6e6ac6a..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. @@ -730,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 08157f1be3..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. diff --git a/lib/mnesia/test/mnesia_schema_recovery_test.erl b/lib/mnesia/test/mnesia_schema_recovery_test.erl index 5e7627ca47..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. diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl index 0fabdc7929..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. @@ -470,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) -> @@ -774,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 c00a1ed51f..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. diff --git a/lib/mnesia/test/mt.erl b/lib/mnesia/test/mt.erl index 5a981bf539..037d6adb38 100644 --- a/lib/mnesia/test/mt.erl +++ b/lib/mnesia/test/mt.erl @@ -67,6 +67,7 @@ alias(recovery) -> mnesia_recovery_test; alias(registry) -> mnesia_registry_test; alias(suite) -> mnesia_SUITE; alias(trans) -> mnesia_trans_access_test; +alias(ixp) -> mnesia_index_plugin_test; alias(Other) -> Other. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 9079a6f02a..aa5d9adb6d 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.15.3.2 +MNESIA_VSN = 4.16 |
