diff --git a/libmariadb b/libmariadb index e9868bfce0d30..d1387356292fb 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit e9868bfce0d30e789d89272f190c1fcb64f78904 +Subproject commit d1387356292fb840c7736aeb8f449310c3139087 diff --git a/mysql-test/r/check_constraint.result b/mysql-test/r/check_constraint.result index 1743bb9704716..7447550ed0937 100644 --- a/mysql-test/r/check_constraint.result +++ b/mysql-test/r/check_constraint.result @@ -140,3 +140,7 @@ create table t1 (a int, b int, check(a>0)); alter table t1 drop column a; ERROR 42S22: Unknown column 'a' in 'CHECK' drop table t1; +create table t1 (a int check (@b in (select user from mysql.user))); +ERROR HY000: Function or expression 'select ...' cannot be used in the CHECK clause of `a` +create table t1 (a int check (a > @b)); +ERROR HY000: Function or expression '@b' cannot be used in the CHECK clause of `a` diff --git a/mysql-test/suite/innodb/r/log_file.result b/mysql-test/suite/innodb/r/log_file.result index 352e4b76cf1f1..918faec8adae5 100644 --- a/mysql-test/suite/innodb/r/log_file.result +++ b/mysql-test/suite/innodb/r/log_file.result @@ -207,7 +207,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS -FOUND /Expected to open 3 undo tablespaces but was able to find only 1 undo tablespaces/ in mysqld.1.err +FOUND /InnoDB: Unable to open undo tablespace.*undo002/ in mysqld.1.err bak_ib_logfile0 bak_ib_logfile1 bak_ib_logfile2 @@ -244,7 +244,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS -FOUND /Expected to open 3 undo tablespaces but was able to find only 0 undo tablespaces/ in mysqld.1.err +FOUND /InnoDB: Unable to open undo tablespace.*undo001/ in mysqld.1.err bak_ib_logfile0 bak_ib_logfile1 bak_ib_logfile2 diff --git a/mysql-test/suite/innodb/t/log_file.test b/mysql-test/suite/innodb/t/log_file.test index c50257a69bed8..e0f4b85c6825b 100644 --- a/mysql-test/suite/innodb/t/log_file.test +++ b/mysql-test/suite/innodb/t/log_file.test @@ -41,7 +41,7 @@ AND support IN ('YES', 'DEFAULT', 'ENABLED'); --let $ibp=$ibp --innodb-data-file-path=ibdata1:16M;ibdata2:10M:autoextend --echo # Start mysqld without the possibility to create innodb_undo_tablespaces ---let $restart_parameters= $ibp --innodb-undo-tablespaces=3 +--let $restart_parameters= $ibp --mkdir $bugdir/undo002 --source include/restart_mysqld.inc eval $check_no_innodb; @@ -172,7 +172,7 @@ let SEARCH_PATTERN=undo tablespace .*undo003.* exists\. Creating system tablespa --source include/start_mysqld.inc eval $check_no_innodb; --source include/shutdown_mysqld.inc -let SEARCH_PATTERN=Expected to open 3 undo tablespaces but was able to find only 1 undo tablespaces; +let SEARCH_PATTERN=InnoDB: Unable to open undo tablespace.*undo002; --source include/search_pattern_in_file.inc # clean up & Restore --source ../include/log_file_cleanup.inc @@ -184,7 +184,7 @@ let SEARCH_PATTERN=Expected to open 3 undo tablespaces but was able to find only --source include/start_mysqld.inc eval $check_no_innodb; --source include/shutdown_mysqld.inc -let SEARCH_PATTERN=Expected to open 3 undo tablespaces but was able to find only 0 undo tablespaces; +let SEARCH_PATTERN=InnoDB: Unable to open undo tablespace.*undo001; --source include/search_pattern_in_file.inc # clean up & Restore diff --git a/mysql-test/suite/innodb_zip/disabled.def b/mysql-test/suite/innodb_zip/disabled.def index 294204f409c4f..8b137891791fe 100644 --- a/mysql-test/suite/innodb_zip/disabled.def +++ b/mysql-test/suite/innodb_zip/disabled.def @@ -1 +1 @@ -cmp_per_index: MDEV-11629 + diff --git a/mysql-test/suite/innodb_zip/r/cmp_per_index.result b/mysql-test/suite/innodb_zip/r/cmp_per_index.result index 5b899e9ff7105..b380071c623aa 100644 --- a/mysql-test/suite/innodb_zip/r/cmp_per_index.result +++ b/mysql-test/suite/innodb_zip/r/cmp_per_index.result @@ -39,13 +39,13 @@ BEGIN; COMMIT; ALTER TABLE t DROP INDEX c; GRANT USAGE ON *.* TO 'tuser01'@'localhost' IDENTIFIED BY 'cDJvI9s_Uq'; -Warnings: -Level Warning -Code 1287 -Message Using GRANT for creating new user is deprecated and will be removed in future release. Create new user with CREATE USER statement. FLUSH PRIVILEGES; +connect con1,localhost,tuser01,cDJvI9s_Uq,; +connection con1; SELECT * FROM information_schema.innodb_cmp_per_index; ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +connection default; +disconnect con1; DROP USER 'tuser01'@'localhost'; SELECT database_name, @@ -70,7 +70,6 @@ index_name PRIMARY compress_ops 65 compress_ops_ok 65 uncompress_ops 0 -# restart SET GLOBAL innodb_cmp_per_index_enabled=ON; SELECT COUNT(*) FROM t; COUNT(*) 128 @@ -86,9 +85,15 @@ FROM information_schema.innodb_cmp_per_index ORDER BY 1, 2, 3; database_name test table_name t +index_name b +compress_ops 0 +compress_ops_ok 0 +uncompress_ops 6 +database_name test +table_name t index_name PRIMARY compress_ops 0 compress_ops_ok 0 -uncompress_ops 9 +uncompress_ops 5 DROP TABLE t; SET GLOBAL innodb_cmp_per_index_enabled=default; diff --git a/mysql-test/suite/innodb_zip/t/cmp_per_index.opt b/mysql-test/suite/innodb_zip/t/cmp_per_index.opt new file mode 100644 index 0000000000000..a031a64fc6ca8 --- /dev/null +++ b/mysql-test/suite/innodb_zip/t/cmp_per_index.opt @@ -0,0 +1,2 @@ +--innodb_log_compressed_pages=on +--innodb_cmp_per_index_reset diff --git a/mysql-test/suite/vcol/r/wrong_arena.result b/mysql-test/suite/vcol/r/wrong_arena.result index 8a07c828288bf..e86026852e4b1 100644 --- a/mysql-test/suite/vcol/r/wrong_arena.result +++ b/mysql-test/suite/vcol/r/wrong_arena.result @@ -40,12 +40,6 @@ connection default; select * from t1; a b c d e 2010-10-10 10:10:10 1 0 0 NULL -Warnings: -Warning 1292 Incorrect datetime value: '1' -Warning 1292 Incorrect datetime value: '2' -Warning 1292 Incorrect datetime value: '1' -Warning 1292 Incorrect datetime value: '1' -Warning 1292 Incorrect datetime value: '2' drop table t1; connect con1, localhost, root; create table t1 (a datetime, diff --git a/mysql-test/suite/vcol/t/wrong_arena.test b/mysql-test/suite/vcol/t/wrong_arena.test index 484f1fe685df6..340634422ae65 100644 --- a/mysql-test/suite/vcol/t/wrong_arena.test +++ b/mysql-test/suite/vcol/t/wrong_arena.test @@ -16,11 +16,15 @@ create table t1 (a datetime, ); show create table t1; connect con1, localhost, root; +disable_warnings; insert t1 (a) values ('2010-10-10 10:10:10'); +enable_warnings; select * from t1; disconnect con1; connection default; +disable_warnings; select * from t1; +enable_warnings; drop table t1; connect con1, localhost, root; diff --git a/mysql-test/t/check_constraint.test b/mysql-test/t/check_constraint.test index 7c5d30b6cd328..437463ee45736 100644 --- a/mysql-test/t/check_constraint.test +++ b/mysql-test/t/check_constraint.test @@ -86,3 +86,11 @@ create table t1 (a int, b int, check(a>0)); --error ER_BAD_FIELD_ERROR alter table t1 drop column a; drop table t1; + +# +# MDEV-12421 Check constraint with query crashes server and renders DB unusable +# +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create table t1 (a int check (@b in (select user from mysql.user))); +--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED +create table t1 (a int check (a > @b)); diff --git a/mysql-test/t/mdev-504.test b/mysql-test/t/mdev-504.test index 76232927cd98d..551c21c37d015 100644 --- a/mysql-test/t/mdev-504.test +++ b/mysql-test/t/mdev-504.test @@ -1,5 +1,5 @@ --source include/not_valgrind.inc ---disable_ps_protocol +--source include/no_protocol.inc SET GLOBAL net_write_timeout = 900; diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 9e012b646966c..d83c483018333 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -137,8 +137,8 @@ ELSE() INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/aws_sdk_cpp/include) ENDIF() -MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc - COMPONENT aws-key-management) ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") -TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS}) +MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc + LINK_LIBRARIES ${AWS_SDK_LIBS} + COMPONENT aws-key-management) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 18bc19bb85eff..6564504eff471 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4667,7 +4667,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE *table, table_list.view= (LEX*) share->is_view; res= schema_table->process_table(thd, &table_list, table, res, db_name, table_name); - free_root(&tbl.mem_root, MYF(0)); + closefrm(&tbl); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 595218023eb06..e030ecde0864d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5985,8 +5985,8 @@ field_list_item: ; column_def: - field_spec opt_check_constraint - { $$= $1; $$->check_constraint= $2; } + field_spec + { $$= $1; } | field_spec references { $$= $1; } ; @@ -6124,11 +6124,13 @@ field_spec: lex->init_last_field(f, $1.str, NULL); $$= f; } - field_type_or_serial + field_type_or_serial opt_check_constraint { LEX *lex=Lex; $$= $2; + $$->check_constraint= $4; + if ($$->check(thd)) MYSQL_YYABORT; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3dc22fe58d857..6aacdd48ad853 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -22140,7 +22140,7 @@ innobase_undo_logs_init_default_max() { MYSQL_SYSVAR_NAME(undo_logs).max_val = MYSQL_SYSVAR_NAME(undo_logs).def_val - = static_cast(srv_available_undo_logs); + = srv_available_undo_logs; } /**************************************************************************** diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index e469cd90737e0..eb08c47896522 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -334,9 +334,6 @@ extern my_bool srv_undo_log_truncate; /* Enables or disables this prefix optimization. Disabled by default. */ extern my_bool srv_prefix_index_cluster_optimization; -/** UNDO logs not redo logged, these logs reside in the temp tablespace.*/ -extern const ulong srv_tmp_undo_logs; - /** Default size of UNDO tablespace while it is created new. */ extern const ulint SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; @@ -518,7 +515,8 @@ extern uint srv_spin_wait_delay; extern ibool srv_priority_boost; extern ulint srv_truncated_status_writes; -extern ulint srv_available_undo_logs; +/** Number of initialized rollback segments for persistent undo log */ +extern ulong srv_available_undo_logs; #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG extern my_bool srv_ibuf_disable_background_merge; diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index e17d11b383e75..95774cbf476e6 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -85,16 +85,6 @@ trx_rsegf_undo_find_free( /*=====================*/ trx_rsegf_t* rsegf, /*!< in: rollback segment header */ mtr_t* mtr); /*!< in: mtr */ -/** Get a rollback segment. -@param[in] id rollback segment id -@return rollback segment */ -UNIV_INLINE -trx_rseg_t* -trx_rseg_get_on_id(ulint id) -{ - ut_a(id < TRX_SYS_N_RSEGS); - return(trx_sys->rseg_array[id]); -} /** Creates a rollback segment header. This function is called only when a new rollback segment is created in @@ -119,14 +109,14 @@ trx_rseg_array_init(); void trx_rseg_mem_free(trx_rseg_t* rseg); -/********************************************************************* -Creates a rollback segment. */ +/** Create a persistent rollback segment. +@param[in] space_id system or undo tablespace id */ trx_rseg_t* -trx_rseg_create( -/*============*/ - ulint space_id, /*!< in: id of UNDO tablespace */ - ulint nth_free_slot); /*!< in: allocate nth free slot. - 0 means next free slots. */ +trx_rseg_create(ulint space_id); + +/** Create the temporary rollback segments. */ +void +trx_temp_rseg_create(); /******************************************************************** Get the number of unique rollback tablespaces in use except space id 0. @@ -205,6 +195,14 @@ struct trx_rseg_t { /** If true, then skip allocating this rseg as it reside in UNDO-tablespace marked for truncate. */ bool skip_allocation; + + /** @return whether the rollback segment is persistent */ + bool is_persistent() const + { + ut_ad(space == SRV_TMP_SPACE_ID + || space <= srv_undo_tablespaces); + return(space != SRV_TMP_SPACE_ID); + } }; /* Undo log segment slot in a rollback segment header */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 8ebb74e3d86f8..b867600653d8c 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -75,17 +75,10 @@ Creates and initializes the transaction system at the database creation. */ void trx_sys_create_sys_pages(void); /*==========================*/ -/****************************************************************//** -Looks for a free slot for a rollback segment in the trx system file copy. -@return slot index or ULINT_UNDEFINED if not found */ +/** @return an unallocated rollback segment slot in the TRX_SYS header +@retval ULINT_UNDEFINED if not found */ ulint -trx_sysf_rseg_find_free( -/*====================*/ - mtr_t* mtr, /*!< in/out: mtr */ - bool include_tmp_slots, /*!< in: if true, report slots reserved - for temp-tablespace as free slots. */ - ulint nth_free_slots); /*!< in: allocate nth free slot. - 0 means next free slot. */ +trx_sysf_rseg_find_free(mtr_t* mtr); /**********************************************************************//** Gets a pointer to the transaction system file copy and x-locks its page. @return pointer to system file copy, page x-locked */ @@ -160,14 +153,6 @@ trx_sys_get_max_trx_id(void); extern uint trx_rseg_n_slots_debug; #endif -/*****************************************************************//** -Check if slot-id is reserved slot-id for noredo rsegs. */ -UNIV_INLINE -bool -trx_sys_is_noredo_rseg_slot( -/*========================*/ - ulint slot_id); /*!< in: slot_id to check */ - /*****************************************************************//** Writes a trx id to an index page. In case that the id size changes in some future version, this function should be used instead of @@ -319,16 +304,10 @@ trx_sys_file_format_max_set( ulint format_id, /*!< in: file format id */ const char** name); /*!< out: max file format name or NULL if not needed. */ -/********************************************************************* -Creates the rollback segments -@return number of rollback segments that are active. */ -ulint -trx_sys_create_rsegs( -/*=================*/ - ulint n_spaces, /*!< number of tablespaces for UNDO logs */ - ulint n_rsegs, /*!< number of rollback segments to create */ - ulint n_tmp_rsegs); /*!< number of rollback segments reserved for - temp-tables. */ +/** Create the rollback segments. +@return whether the creation succeeded */ +bool +trx_sys_create_rsegs(); /*****************************************************************//** Get the number of transaction in the system, independent of their state. @return count of transactions in trx_sys_t::trx_list */ @@ -556,13 +535,15 @@ struct trx_sys_t { transactions which exist or existed */ #endif /* UNIV_DEBUG */ - char pad1[64]; /*!< To avoid false sharing */ + /** Avoid false sharing */ + const char pad1[CACHE_LINE_SIZE]; trx_ut_list_t rw_trx_list; /*!< List of active and committed in memory read-write transactions, sorted on trx id, biggest first. Recovered transactions are always on this list. */ - char pad2[64]; /*!< To avoid false sharing */ + /** Avoid false sharing */ + const char pad2[CACHE_LINE_SIZE]; trx_ut_list_t mysql_trx_list; /*!< List of transactions created for MySQL. All user transactions are on mysql_trx_list. The rw_trx_list @@ -582,7 +563,13 @@ struct trx_sys_t { to ensure right order of removal and consistent snapshot. */ - char pad3[64]; /*!< To avoid false sharing */ + /** Avoid false sharing */ + const char pad3[CACHE_LINE_SIZE]; + /** Temporary rollback segments */ + trx_rseg_t* temp_rsegs[TRX_SYS_N_RSEGS]; + /** Avoid false sharing */ + const char pad4[CACHE_LINE_SIZE]; + trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS]; /*!< Pointer array to rollback segments; NULL if slot not in use; diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic index f03535c53b311..1c805ead4b31d 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -191,18 +191,6 @@ trx_write_trx_id( mach_write_to_6(ptr, id); } -/*****************************************************************//** -Check if slot-id is reserved slot-id for noredo rsegs. */ -UNIV_INLINE -bool -trx_sys_is_noredo_rseg_slot( -/*========================*/ - ulint slot_id) /*!< in: slot_id to check */ -{ - /* Slots allocated from temp-tablespace are no-redo slots. */ - return(slot_id > 0 && slot_id < (srv_tmp_undo_logs + 1)); -} - /*****************************************************************//** Reads a trx id from an index page. In case that the id size changes in some future version, this function should be used instead of diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 7da3bfb5459d4..d0a67a7ed284b 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -507,14 +507,6 @@ trx_id_t trx_get_id_for_print( const trx_t* trx); -/****************************************************************//** -Assign a transaction temp-tablespace bound rollback-segment. */ -void -trx_assign_rseg( -/*============*/ - trx_t* trx); /*!< transaction that involves write - to temp-table. */ - /** Create the trx_t pool */ void trx_pool_init(); @@ -869,12 +861,6 @@ struct trx_rsegs_t { trx_temp_undo_t m_noredo; }; -enum trx_rseg_type_t { - TRX_RSEG_TYPE_NONE = 0, /*!< void rollback segment type. */ - TRX_RSEG_TYPE_REDO, /*!< redo rollback segment. */ - TRX_RSEG_TYPE_NOREDO /*!< non-redo rollback segment. */ -}; - struct TrxVersion { TrxVersion(trx_t* trx); @@ -1295,6 +1281,22 @@ struct trx_t { { return(has_logged_persistent() || rsegs.m_noredo.undo); } + + /** @return rollback segment for modifying temporary tables */ + trx_rseg_t* get_temp_rseg() + { + if (trx_rseg_t* rseg = rsegs.m_noredo.rseg) { + ut_ad(id != 0); + return(rseg); + } + + return(assign_temp_rseg()); + } + +private: + /** Assign a rollback segment for modifying temporary tables. + @return the assigned rollback segment */ + trx_rseg_t* assign_temp_rseg(); }; /** diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index ce9a265bd8c12..2a13203b74764 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -741,10 +741,11 @@ row_purge_upd_exist_or_extern_func( &is_insert, &rseg_id, &page_no, &offset); - rseg = trx_rseg_get_on_id(rseg_id); + rseg = trx_sys->rseg_array[rseg_id]; ut_a(rseg != NULL); - ut_a(rseg->id == rseg_id); + ut_ad(rseg->id == rseg_id); + ut_ad(rseg->is_persistent()); mtr_start(&mtr); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index b689cd012c6a6..a05bb5300a34b 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -139,10 +139,6 @@ my_bool srv_undo_log_truncate = FALSE; /** Maximum size of undo tablespace. */ unsigned long long srv_max_undo_log_size; -/** UNDO logs that are not redo logged. -These logs reside in the temp tablespace.*/ -const ulong srv_tmp_undo_logs = 32; - /** Default undo tablespace size in UNIV_PAGEs count (10MB). */ const ulint SRV_UNDO_TABLESPACE_SIZE_IN_PAGES = ((1024 * 1024) * 10) / UNIV_PAGE_SIZE_DEF; @@ -403,37 +399,38 @@ UNIV_INTERN ulong srv_n_spin_wait_rounds = 15; uint srv_spin_wait_delay; ibool srv_priority_boost = TRUE; -static ulint srv_n_rows_inserted_old = 0; -static ulint srv_n_rows_updated_old = 0; -static ulint srv_n_rows_deleted_old = 0; -static ulint srv_n_rows_read_old = 0; -static ulint srv_n_system_rows_inserted_old = 0; -static ulint srv_n_system_rows_updated_old = 0; -static ulint srv_n_system_rows_deleted_old = 0; -static ulint srv_n_system_rows_read_old = 0; - -ulint srv_truncated_status_writes = 0; -ulint srv_available_undo_logs = 0; - -UNIV_INTERN ib_uint64_t srv_page_compression_saved = 0; -UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect512 = 0; -UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect4096 = 0; -UNIV_INTERN ib_uint64_t srv_index_pages_written = 0; -UNIV_INTERN ib_uint64_t srv_non_index_pages_written = 0; -UNIV_INTERN ib_uint64_t srv_pages_page_compressed = 0; -UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op = 0; -UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op_saved = 0; -UNIV_INTERN ib_uint64_t srv_index_page_decompressed = 0; +static ulint srv_n_rows_inserted_old; +static ulint srv_n_rows_updated_old; +static ulint srv_n_rows_deleted_old; +static ulint srv_n_rows_read_old; +static ulint srv_n_system_rows_inserted_old; +static ulint srv_n_system_rows_updated_old; +static ulint srv_n_system_rows_deleted_old; +static ulint srv_n_system_rows_read_old; + +ulint srv_truncated_status_writes; +/** Number of initialized rollback segments for persistent undo log */ +ulong srv_available_undo_logs; + +UNIV_INTERN ib_uint64_t srv_page_compression_saved; +UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect512; +UNIV_INTERN ib_uint64_t srv_page_compression_trim_sect4096; +UNIV_INTERN ib_uint64_t srv_index_pages_written; +UNIV_INTERN ib_uint64_t srv_non_index_pages_written; +UNIV_INTERN ib_uint64_t srv_pages_page_compressed; +UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op; +UNIV_INTERN ib_uint64_t srv_page_compressed_trim_op_saved; +UNIV_INTERN ib_uint64_t srv_index_page_decompressed; /* Defragmentation */ -UNIV_INTERN my_bool srv_defragment = FALSE; +UNIV_INTERN my_bool srv_defragment; UNIV_INTERN uint srv_defragment_n_pages = 7; -UNIV_INTERN uint srv_defragment_stats_accuracy = 0; +UNIV_INTERN uint srv_defragment_stats_accuracy; UNIV_INTERN uint srv_defragment_fill_factor_n_recs = 20; UNIV_INTERN double srv_defragment_fill_factor = 0.9; UNIV_INTERN uint srv_defragment_frequency = SRV_DEFRAGMENT_FREQUENCY_DEFAULT; -UNIV_INTERN ulonglong srv_defragment_interval = 0; +UNIV_INTERN ulonglong srv_defragment_interval; /* Set the following to 0 if you want InnoDB to write messages on stderr on startup/shutdown. */ diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 7c16ce1e58f4f..bcb52fc5bfb57 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -804,20 +804,12 @@ srv_check_undo_redo_logs_exists() undo::undo_spaces_t undo::Truncate::s_fix_up_spaces; -/******************************************************************** -Opens the configured number of undo tablespaces. +/** Open the configured number of dedicated undo tablespaces. +@param[in] create_new_db whether the database is being initialized @return DB_SUCCESS or error code */ static dberr_t -srv_undo_tablespaces_init( -/*======================*/ - bool create_new_db, /*!< in: TRUE if new db being - created */ - const ulint n_conf_tablespaces, /*!< in: configured undo - tablespaces */ - ulint* n_opened) /*!< out: number of UNDO - tablespaces successfully - discovered and opened */ +srv_undo_tablespaces_init(bool create_new_db) { ulint i; dberr_t err = DB_SUCCESS; @@ -825,9 +817,9 @@ srv_undo_tablespaces_init( ulint n_undo_tablespaces; ulint undo_tablespace_ids[TRX_SYS_N_RSEGS + 1]; - *n_opened = 0; + srv_undo_tablespaces_open = 0; - ut_a(n_conf_tablespaces <= TRX_SYS_N_RSEGS); + ut_a(srv_undo_tablespaces <= TRX_SYS_N_RSEGS); memset(undo_tablespace_ids, 0x0, sizeof(undo_tablespace_ids)); @@ -839,7 +831,7 @@ srv_undo_tablespaces_init( the location of the undo tablespaces and their space ids this restriction will/should be lifted. */ - for (i = 0; create_new_db && i < n_conf_tablespaces; ++i) { + for (i = 0; create_new_db && i < srv_undo_tablespaces; ++i) { char name[OS_FILE_MAX_PATH]; ut_snprintf( @@ -902,7 +894,7 @@ srv_undo_tablespaces_init( } } } else { - n_undo_tablespaces = n_conf_tablespaces; + n_undo_tablespaces = srv_undo_tablespaces; for (i = 1; i <= n_undo_tablespaces; ++i) { undo_tablespace_ids[i - 1] = i; @@ -944,7 +936,7 @@ srv_undo_tablespaces_init( prev_space_id = undo_tablespace_ids[i]; - ++*n_opened; + ++srv_undo_tablespaces_open; } /* Open any extra unused undo tablespaces. These must be contiguous. @@ -968,19 +960,17 @@ srv_undo_tablespaces_init( ++n_undo_tablespaces; - ++*n_opened; + ++srv_undo_tablespaces_open; } /* If the user says that there are fewer than what we find we tolerate that discrepancy but not the inverse. Because there could be unused undo tablespaces for future use. */ - if (n_conf_tablespaces > n_undo_tablespaces) { - ib::error() << "Expected to open " << n_conf_tablespaces - << " undo tablespaces but was able to find only " - << n_undo_tablespaces << " undo tablespaces. Set the" - " innodb_undo_tablespaces parameter to the correct" - " value and retry. Suggested value is " + if (srv_undo_tablespaces > n_undo_tablespaces) { + ib::error() << "Expected to open innodb_undo_tablespaces=" + << srv_undo_tablespaces + << " but was able to find only " << n_undo_tablespaces; return(err != DB_SUCCESS ? err : DB_ERROR); @@ -988,15 +978,13 @@ srv_undo_tablespaces_init( } else if (n_undo_tablespaces > 0) { ib::info() << "Opened " << n_undo_tablespaces - << " undo tablespaces"; - - ib::info() << srv_undo_tablespaces_active << " undo tablespaces" - << " made active"; + << " undo tablespaces (" + << srv_undo_tablespaces_active + << " active)"; - if (n_conf_tablespaces == 0) { - ib::warn() << "Will use system tablespace for all newly" - << " created rollback-segment as" - << " innodb_undo_tablespaces=0"; + if (srv_undo_tablespaces == 0) { + ib::warn() << "innodb_undo_tablespaces=0 disables" + " dedicated undo log tablespaces"; } } @@ -2087,10 +2075,7 @@ innobase_start_or_create_for_mysql(void) fil_open_log_and_system_tablespace_files(); ut_d(fil_space_get(0)->recv_size = srv_sys_space_size_debug); - err = srv_undo_tablespaces_init( - create_new_db, - srv_undo_tablespaces, - &srv_undo_tablespaces_open); + err = srv_undo_tablespaces_init(create_new_db); /* If the force recovery is set very high then we carry on regardless of all errors. Basically this is fingers crossed mode. */ @@ -2512,22 +2497,7 @@ innobase_start_or_create_for_mysql(void) ut_a(srv_undo_logs > 0); ut_a(srv_undo_logs <= TRX_SYS_N_RSEGS); - /* The number of rsegs that exist in InnoDB is given by status - variable srv_available_undo_logs. The number of rsegs to use can - be set using the dynamic global variable srv_undo_logs. */ - - srv_available_undo_logs = trx_sys_create_rsegs( - srv_undo_tablespaces, srv_undo_logs, srv_tmp_undo_logs); - - if (srv_available_undo_logs == ULINT_UNDEFINED) { - /* Can only happen if server is read only. */ - ut_a(srv_read_only_mode); - srv_undo_logs = ULONG_UNDEFINED; - } else if (srv_available_undo_logs < srv_undo_logs - && !srv_force_recovery && !recv_needed_recovery) { - ib::error() << "System or UNDO tablespace is running of out" - << " of space"; - /* Should due to out of file space. */ + if (!trx_sys_create_rsegs()) { return(srv_init_abort(DB_ERROR)); } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 6ff4c882be8d9..f83d93778521b 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -327,17 +327,12 @@ trx_purge_remove_log_hdr( my_atomic_addlint(&trx_sys->rseg_history_len, -1); } -/** Frees an undo log segment which is in the history list. Removes the -undo log hdr from the history list. +/** Free an undo log segment, and remove the header from the history list. @param[in,out] rseg rollback segment -@param[in] hdr_addr file address of log_hdr -@param[in] noredo skip redo logging. */ +@param[in] hdr_addr file address of log_hdr */ static void -trx_purge_free_segment( - trx_rseg_t* rseg, - fil_addr_t hdr_addr, - bool noredo) +trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr) { mtr_t mtr; trx_rsegf_t* rseg_hdr; @@ -345,16 +340,12 @@ trx_purge_free_segment( trx_usegf_t* seg_hdr; ulint seg_size; ulint hist_size; - bool marked = noredo; + bool marked = false; for (;;) { page_t* undo_page; mtr_start(&mtr); - if (noredo) { - mtr.set_log_mode(MTR_LOG_NO_REDO); - } - ut_ad(noredo == trx_sys_is_noredo_rseg_slot(rseg->id)); mutex_enter(&rseg->mutex); @@ -428,14 +419,12 @@ trx_purge_free_segment( mtr_commit(&mtr); } -/********************************************************************//** -Removes unnecessary history data from a rollback segment. */ +/** Remove unnecessary history data from a rollback segment. +@param[in,out] rseg rollback segment +@param[in] limit truncate offset */ static void -trx_purge_truncate_rseg_history( -/*============================*/ - trx_rseg_t* rseg, /*!< in: rollback segment */ - const purge_iter_t* limit) /*!< in: truncate offset */ +trx_purge_truncate_rseg_history(trx_rseg_t* rseg, const purge_iter_t* limit) { fil_addr_t hdr_addr; fil_addr_t prev_hdr_addr; @@ -445,13 +434,9 @@ trx_purge_truncate_rseg_history( trx_usegf_t* seg_hdr; mtr_t mtr; trx_id_t undo_trx_no; - const bool noredo = trx_sys_is_noredo_rseg_slot( - rseg->id); mtr_start(&mtr); - if (noredo) { - mtr.set_log_mode(MTR_LOG_NO_REDO); - } + ut_ad(rseg->is_persistent()); mutex_enter(&(rseg->mutex)); rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); @@ -509,7 +494,7 @@ trx_purge_truncate_rseg_history( /* calls the trx_purge_remove_log_hdr() inside trx_purge_free_segment(). */ - trx_purge_free_segment(rseg, hdr_addr, noredo); + trx_purge_free_segment(rseg, hdr_addr); } else { /* Remove the log hdr from the rseg history. */ trx_purge_remove_log_hdr(rseg_hdr, log_hdr, &mtr); @@ -519,9 +504,6 @@ trx_purge_truncate_rseg_history( } mtr_start(&mtr); - if (noredo) { - mtr.set_log_mode(MTR_LOG_NO_REDO); - } mutex_enter(&(rseg->mutex)); rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); @@ -806,10 +788,9 @@ trx_purge_mark_undo_for_truncate( /* Step-2: Validation/Qualification checks a. At-least 2 UNDO tablespaces so even if one UNDO tablespace is being truncated server can continue to operate. - b. At-least 2 UNDO redo rseg/undo logs (besides the default rseg-0) + b. At-least 2 persistent UNDO logs (besides the default rseg-0) b. At-least 1 UNDO tablespace size > threshold. */ - if (srv_undo_tablespaces_active < 2 - || (srv_undo_logs < (1 + srv_tmp_undo_logs + 2))) { + if (srv_undo_tablespaces_active < 2 || srv_undo_logs < 3) { return; } @@ -846,11 +827,9 @@ trx_purge_mark_undo_for_truncate( /* Step-3: Iterate over all the rsegs of selected UNDO tablespace and mark them temporarily unavailable for allocation.*/ for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - trx_rseg_t* rseg = trx_sys->rseg_array[i]; - - if (rseg != NULL && !trx_sys_is_noredo_rseg_slot(rseg->id)) { - if (rseg->space - == undo_trunc->get_marked_space_id()) { + if (trx_rseg_t* rseg = trx_sys->rseg_array[i]) { + ut_ad(rseg->is_persistent()); + if (rseg->space == undo_trunc->get_marked_space_id()) { /* Once set this rseg will not be allocated to new booting transaction but we will wait diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 481e14d44dea6..47d24b631141b 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1893,13 +1893,7 @@ trx_undo_report_row_operation( if (is_temp) { mtr.set_log_mode(MTR_LOG_NO_REDO); - rseg = trx->rsegs.m_noredo.rseg; - - if (!rseg) { - trx_assign_rseg(trx); - rseg = trx->rsegs.m_noredo.rseg; - } - + rseg = trx->get_temp_rseg(); pundo = &trx->rsegs.m_noredo.undo; } else { ut_ad(!trx->read_only); @@ -2057,16 +2051,16 @@ trx_undo_report_row_operation( /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/ -/******************************************************************//** -Copies an undo record to heap. This function can be called if we know that -the undo log record exists. -@return own: copy of the record */ +/** Copy an undo record to heap. +@param[in] roll_ptr roll pointer to a record that exists +@param[in] is_temp whether this is a temporary table +@param[in,out] heap memory heap where copied */ static trx_undo_rec_t* trx_undo_get_undo_rec_low( -/*======================*/ - roll_ptr_t roll_ptr, /*!< in: roll pointer to record */ - mem_heap_t* heap) /*!< in: memory heap where copied */ + roll_ptr_t roll_ptr, + bool is_temp, + mem_heap_t* heap) { trx_undo_rec_t* undo_rec; ulint rseg_id; @@ -2079,7 +2073,10 @@ trx_undo_get_undo_rec_low( trx_undo_decode_roll_ptr(roll_ptr, &is_insert, &rseg_id, &page_no, &offset); - rseg = trx_rseg_get_on_id(rseg_id); + rseg = is_temp + ? trx_sys->temp_rsegs[rseg_id] + : trx_sys->rseg_array[rseg_id]; + ut_ad(is_temp == !rseg->is_persistent()); mtr_start(&mtr); @@ -2093,13 +2090,13 @@ trx_undo_get_undo_rec_low( return(undo_rec); } -/******************************************************************//** -Copies an undo record to heap. +/** Copy an undo record to heap. @param[in] roll_ptr roll pointer to record +@param[in] is_temp whether this is a temporary table +@param[in,out] heap memory heap where copied @param[in] trx_id id of the trx that generated the roll pointer: it points to an undo log of this transaction -@param[in] heap memory heap where copied @param[in] name table name @param[out] undo_rec own: copy of the record @retval true if the undo log has been @@ -2109,10 +2106,10 @@ NOTE: the caller must have latches on the clustered index page. */ static MY_ATTRIBUTE((warn_unused_result)) bool trx_undo_get_undo_rec( -/*==================*/ roll_ptr_t roll_ptr, - trx_id_t trx_id, + bool is_temp, mem_heap_t* heap, + trx_id_t trx_id, const table_name_t& name, trx_undo_rec_t** undo_rec) { @@ -2122,7 +2119,7 @@ trx_undo_get_undo_rec( missing_history = purge_sys->view.changes_visible(trx_id, name); if (!missing_history) { - *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap); + *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, is_temp, heap); } rw_lock_s_unlock(&purge_sys->latch); @@ -2203,13 +2200,17 @@ trx_undo_prev_version_build( return(true); } + const bool is_temp = dict_table_is_temporary(index->table); rec_trx_id = row_get_rec_trx_id(rec, index, offsets); if (trx_undo_get_undo_rec( - roll_ptr, rec_trx_id, heap, index->table->name, &undo_rec)) { + roll_ptr, is_temp, heap, rec_trx_id, index->table->name, + &undo_rec)) { if (v_status & TRX_UNDO_PREV_IN_PURGE) { /* We are fetching the record being purged */ - undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap); + ut_ad(!is_temp); + undo_rec = trx_undo_get_undo_rec_low( + roll_ptr, is_temp, heap); } else { /* The undo record may already have been purged, during purge or semi-consistent read. */ diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 883e2eb60b2b5..3393a0464a856 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -90,12 +90,7 @@ trx_rseg_header_create( trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr); } - if (!trx_sys_is_noredo_rseg_slot(rseg_slot_no)) { - /* Non-redo rseg are re-created on restart and so no need - to persist this information in sys-header. Anyway, on restart - this information is not valid too as there is no space with - persisted space-id on restart. */ - + if (space != SRV_TMP_SPACE_ID) { /* Add the rollback segment info to the free slot in the trx system header */ @@ -152,51 +147,48 @@ trx_rseg_mem_free(trx_rseg_t* rseg) ut_free(rseg); } -/** Creates and initializes a rollback segment object. -The values for the fields are read from the header. The object is inserted to -the rseg list of the trx system object and a pointer is inserted in the rseg -array in the trx system object. +/** Create a rollback segment object. @param[in] id rollback segment id @param[in] space space where the segment is placed -@param[in] page_no page number of the segment header -@param[in,out] mtr mini-transaction */ +@param[in] page_no page number of the segment header */ static -void -trx_rseg_mem_create( - ulint id, - ulint space, - ulint page_no, - mtr_t* mtr) +trx_rseg_t* +trx_rseg_mem_create(ulint id, ulint space, ulint page_no) { - ulint len; - trx_rseg_t* rseg; - fil_addr_t node_addr; - trx_rsegf_t* rseg_header; - trx_ulogf_t* undo_log_hdr; - ulint sum_of_undo_sizes; - - rseg = static_cast(ut_zalloc_nokey(sizeof(trx_rseg_t))); + trx_rseg_t* rseg = static_cast( + ut_zalloc_nokey(sizeof *rseg)); rseg->id = id; rseg->space = space; rseg->page_no = page_no; - rseg->trx_ref_count = 0; - rseg->skip_allocation = false; + rseg->last_page_no = FIL_NULL; - if (fsp_is_system_temporary(space)) { - mutex_create(LATCH_ID_NOREDO_RSEG, &rseg->mutex); - } else { - mutex_create(LATCH_ID_REDO_RSEG, &rseg->mutex); - } + mutex_create(rseg->is_persistent() + ? LATCH_ID_REDO_RSEG : LATCH_ID_NOREDO_RSEG, + &rseg->mutex); UT_LIST_INIT(rseg->update_undo_list, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->update_undo_cached, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list); UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list); - trx_sys->rseg_array[id] = rseg; + return(rseg); +} + +/** Restore the state of a persistent rollback segment. +@param[in,out] rseg persistent rollback segment +@param[in,out] mtr mini-transaction */ +static +void +trx_rseg_mem_restore(trx_rseg_t* rseg, mtr_t* mtr) +{ + ulint len; + fil_addr_t node_addr; + trx_rsegf_t* rseg_header; + trx_ulogf_t* undo_log_hdr; + ulint sum_of_undo_sizes; - rseg_header = trx_rsegf_get_new(space, page_no, mtr); + rseg_header = trx_rsegf_get_new(rseg->space, rseg->page_no, mtr); rseg->max_size = mtr_read_ulint( rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, mtr); @@ -240,8 +232,6 @@ trx_rseg_mem_create( purge_sys->purge_queue.push(elem); } - } else { - rseg->last_page_no = FIL_NULL; } } @@ -252,54 +242,45 @@ trx_rseg_array_init() mtr_t mtr; for (ulint i = 0; i < TRX_SYS_N_RSEGS; i++) { - ut_ad(!trx_rseg_get_on_id(i)); mtr.start(); trx_sysf_t* sys_header = trx_sysf_get(&mtr); ulint page_no = trx_sysf_rseg_get_page_no( sys_header, i, &mtr); if (page_no != FIL_NULL) { - trx_rseg_mem_create( + trx_rseg_t* rseg = trx_rseg_mem_create( i, trx_sysf_rseg_get_space(sys_header, i, &mtr), - page_no, &mtr); + page_no); + ut_ad(rseg->is_persistent()); + ut_ad(!trx_sys->rseg_array[rseg->id]); + trx_sys->rseg_array[rseg->id] = rseg; + trx_rseg_mem_restore(rseg, &mtr); } mtr.commit(); } } -/********************************************************************* -Creates a rollback segment. -@return pointer to new rollback segment if create successful */ +/** Create a persistent rollback segment. +@param[in] space_id system or undo tablespace id */ trx_rseg_t* -trx_rseg_create( -/*============*/ - ulint space_id, /*!< in: id of UNDO tablespace */ - ulint nth_free_slot) /*!< in: allocate nth free slot. - 0 means next free slots. */ +trx_rseg_create(ulint space_id) { - mtr_t mtr; + trx_rseg_t* rseg = NULL; + mtr_t mtr; mtr.start(); /* To obey the latching order, acquire the file space x-latch before the trx_sys->mutex. */ - const fil_space_t* space = mtr_x_lock_space(space_id, &mtr); +#ifdef UNIV_DEBUG + const fil_space_t* space = +#endif /* UNIV_DEBUG */ + mtr_x_lock_space(space_id, &mtr); + ut_ad(space->purpose == FIL_TYPE_TABLESPACE); - switch (space->purpose) { - case FIL_TYPE_LOG: - case FIL_TYPE_IMPORT: - ut_ad(0); - case FIL_TYPE_TEMPORARY: - mtr.set_log_mode(MTR_LOG_NO_REDO); - break; - case FIL_TYPE_TABLESPACE: - break; - } - - ulint slot_no = trx_sysf_rseg_find_free( - &mtr, space->purpose == FIL_TYPE_TEMPORARY, nth_free_slot); + ulint slot_no = trx_sysf_rseg_find_free(&mtr); ulint page_no = slot_no == ULINT_UNDEFINED ? FIL_NULL : trx_rseg_header_create(space_id, ULINT_MAX, slot_no, &mtr); @@ -309,14 +290,45 @@ trx_rseg_create( ulint id = trx_sysf_rseg_get_space( sys_header, slot_no, &mtr); - ut_a(id == space_id || trx_sys_is_noredo_rseg_slot(slot_no)); + ut_a(id == space_id); - trx_rseg_mem_create(slot_no, space_id, page_no, &mtr); + rseg = trx_rseg_mem_create(slot_no, space_id, page_no); + ut_ad(rseg->is_persistent()); + ut_ad(!trx_sys->rseg_array[rseg->id]); + trx_sys->rseg_array[rseg->id] = rseg; + trx_rseg_mem_restore(rseg, &mtr); } mtr.commit(); - return(page_no == FIL_NULL ? NULL : trx_sys->rseg_array[slot_no]); + return(rseg); +} + +/** Create the temporary rollback segments. */ +void +trx_temp_rseg_create() +{ + mtr_t mtr; + + for (ulong i = 0; i < TRX_SYS_N_RSEGS; i++) { + mtr.start(); + mtr.set_log_mode(MTR_LOG_NO_REDO); +#ifdef UNIV_DEBUG + const fil_space_t* space = +#endif /* UNIV_DEBUG */ + mtr_x_lock_space(SRV_TMP_SPACE_ID, &mtr); + ut_ad(space->purpose == FIL_TYPE_TEMPORARY); + + ulint page_no = trx_rseg_header_create( + SRV_TMP_SPACE_ID, ULINT_MAX, i, &mtr); + trx_rseg_t* rseg = trx_rseg_mem_create( + i, SRV_TMP_SPACE_ID, page_no); + ut_ad(!rseg->is_persistent()); + ut_ad(!trx_sys->temp_rsegs[i]); + trx_sys->temp_rsegs[i] = rseg; + trx_rseg_mem_restore(rseg, &mtr); + mtr.commit(); + } } /******************************************************************** diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index f08736ae1f128..24983dcc2a3bc 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -394,76 +394,41 @@ trx_sys_read_wsrep_checkpoint( #endif /* WITH_WSREP */ -/****************************************************************//** -Looks for a free slot for a rollback segment in the trx system file copy. -@return slot index or ULINT_UNDEFINED if not found */ +/** @return an unallocated rollback segment slot in the TRX_SYS header +@retval ULINT_UNDEFINED if not found */ ulint -trx_sysf_rseg_find_free( -/*====================*/ - mtr_t* mtr, /*!< in/out: mtr */ - bool include_tmp_slots, /*!< in: if true, report slots reserved - for temp-tablespace as free slots. */ - ulint nth_free_slots) /*!< in: allocate nth free slot. - 0 means next free slot. */ +trx_sysf_rseg_find_free(mtr_t* mtr) { - ulint i; - trx_sysf_t* sys_header; - - sys_header = trx_sysf_get(mtr); - - ulint found_free_slots = 0; - for (i = 0; i < TRX_SYS_N_RSEGS; i++) { - ulint page_no; - - if (!include_tmp_slots && trx_sys_is_noredo_rseg_slot(i)) { - continue; - } - - page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); + trx_sysf_t* sys_header = trx_sysf_get(mtr); - if (page_no == FIL_NULL - || (include_tmp_slots - && trx_sys_is_noredo_rseg_slot(i))) { - - if (found_free_slots++ >= nth_free_slots) { - return(i); - } + for (ulint i = 0; i < TRX_SYS_N_RSEGS; i++) { + if (trx_sysf_rseg_get_page_no(sys_header, i, mtr) + == FIL_NULL) { + return(i); } } return(ULINT_UNDEFINED); } -/****************************************************************//** -Looks for used slots for redo rollback segment. -@return number of used slots */ +/** Count the number of initialized persistent rollback segment slots. */ static -ulint -trx_sysf_used_slots_for_redo_rseg( -/*==============================*/ - mtr_t* mtr) /*!< in: mtr */ +void +trx_sysf_get_n_rseg_slots() { - trx_sysf_t* sys_header; - ulint n_used = 0; + mtr_t mtr; + mtr.start(); - sys_header = trx_sysf_get(mtr); + trx_sysf_t* sys_header = trx_sysf_get(&mtr); + srv_available_undo_logs = 0; for (ulint i = 0; i < TRX_SYS_N_RSEGS; i++) { - - if (trx_sys_is_noredo_rseg_slot(i)) { - continue; - } - - ulint page_no; - - page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); - - if (page_no != FIL_NULL) { - ++n_used; - } + srv_available_undo_logs + += trx_sysf_rseg_get_page_no(sys_header, i, &mtr) + != FIL_NULL; } - return(n_used); + mtr.commit(); } /*****************************************************************//** @@ -532,7 +497,7 @@ trx_sysf_create( + page - sys_header, mtr); /* Create the first rollback segment in the SYSTEM tablespace */ - slot_no = trx_sysf_rseg_find_free(mtr, false, 0); + slot_no = trx_sysf_rseg_find_free(mtr); page_no = trx_rseg_header_create(TRX_SYS_SPACE, ULINT_MAX, slot_no, mtr); @@ -904,118 +869,69 @@ trx_sys_file_format_close(void) mutex_free(&file_format_max.mutex); } -/********************************************************************* -Creates non-redo rollback segments. -@return number of non-redo rollback segments created. */ -static -ulint -trx_sys_create_noredo_rsegs( -/*========================*/ - ulint n_nonredo_rseg) /*!< number of non-redo rollback segment - to create. */ -{ - ulint n_created = 0; - - /* Create non-redo rollback segments residing in temp-tablespace. - non-redo rollback segments don't perform redo logging and so - are used for undo logging of objects/table that don't need to be - recover on crash. - (Non-Redo rollback segments are created on every server startup). - Slot-0: reserved for system-tablespace. - Slot-1....Slot-N: reserved for temp-tablespace. - Slot-N+1....Slot-127: reserved for system/undo-tablespace. */ - for (ulint i = 0; i < n_nonredo_rseg; i++) { - if (trx_rseg_create(SRV_TMP_SPACE_ID, i) == NULL) { - break; - } - ++n_created; - } - - return(n_created); -} - -/********************************************************************* -Creates the rollback segments. -@return number of rollback segments that are active. */ -ulint -trx_sys_create_rsegs( -/*=================*/ - ulint n_spaces, /*!< number of tablespaces for UNDO logs */ - ulint n_rsegs, /*!< number of rollback segments to create */ - ulint n_tmp_rsegs) /*!< number of rollback segments reserved for - temp-tables. */ +/** Create the rollback segments. +@return whether the creation succeeded */ +bool +trx_sys_create_rsegs() { - mtr_t mtr; - ulint n_used; - ulint n_noredo_created; + /* srv_available_undo_logs reflects the number of persistent + rollback segments that have been initialized in the + transaction system header page. - ut_a(n_spaces < TRX_SYS_N_RSEGS); - ut_a(n_rsegs <= TRX_SYS_N_RSEGS); - ut_a(n_tmp_rsegs > 0 && n_tmp_rsegs < TRX_SYS_N_RSEGS); + srv_undo_logs determines how many of the + srv_available_undo_logs rollback segments may be used for + logging new transactions. */ + ut_ad(srv_undo_tablespaces < TRX_SYS_N_RSEGS); + ut_ad(srv_undo_logs <= TRX_SYS_N_RSEGS); if (srv_read_only_mode) { - return(ULINT_UNDEFINED); + srv_undo_logs = srv_available_undo_logs = ULONG_UNDEFINED; + return(true); } - /* Create non-redo rollback segments. */ - n_noredo_created = trx_sys_create_noredo_rsegs(n_tmp_rsegs); + /* Create temporary rollback segments. */ + trx_temp_rseg_create(); /* This is executed in single-threaded mode therefore it is not necessary to use the same mtr in trx_rseg_create(). n_used cannot change while the function is executing. */ - mtr_start(&mtr); - n_used = trx_sysf_used_slots_for_redo_rseg(&mtr) + n_noredo_created; - mtr_commit(&mtr); + trx_sysf_get_n_rseg_slots(); - ut_ad(n_used <= TRX_SYS_N_RSEGS); + ut_ad(srv_available_undo_logs <= TRX_SYS_N_RSEGS); - /* By default 1 redo rseg is always active that is hosted in - system tablespace. */ - ulint n_redo_active; - if (n_rsegs <= n_tmp_rsegs) { - n_redo_active = 1; - } else if (n_rsegs > n_used) { - n_redo_active = n_used - n_tmp_rsegs; - } else { - n_redo_active = n_rsegs - n_tmp_rsegs; - } - - /* Do not create additional rollback segments if innodb_force_recovery - has been set and the database was not shutdown cleanly. */ - if (!srv_force_recovery && !recv_needed_recovery && n_used < n_rsegs) { - ulint i; - ulint new_rsegs = n_rsegs - n_used; - - for (i = 0; i < new_rsegs; ++i) { - ulint space; - - /* Tablespace 0 is the system tablespace. All UNDO - log tablespaces start from 1. */ + /* The first persistent rollback segment is always initialized + in the system tablespace. */ + ut_a(srv_available_undo_logs > 0); - if (n_spaces > 0) { - space = (i % n_spaces) + 1; - } else { - space = 0; /* System tablespace */ - } - - if (trx_rseg_create(space, 0) != NULL) { - ++n_used; - ++n_redo_active; - } else { - break; + if (srv_force_recovery) { + /* Do not create additional rollback segments if + innodb_force_recovery has been set. */ + if (srv_undo_logs > srv_available_undo_logs) { + srv_undo_logs = srv_available_undo_logs; + } + } else { + for (ulint i = 0; srv_available_undo_logs < srv_undo_logs; + i++, srv_available_undo_logs++) { + /* Tablespace 0 is the system tablespace. + Dedicated undo log tablespaces start from 1. */ + ulint space = srv_undo_tablespaces > 0 + ? (i % srv_undo_tablespaces) + 1 + : TRX_SYS_SPACE; + + if (!trx_rseg_create(space)) { + ib::error() << "Unable to allocate the" + " requested innodb_undo_logs"; + return(false); } } } - ib::info() << n_used - srv_tmp_undo_logs - << " redo rollback segment(s) found. " - << n_redo_active - << " redo rollback segment(s) are active."; + ut_ad(srv_undo_logs <= srv_available_undo_logs); - ib::info() << n_noredo_created << " non-redo rollback segment(s) are" - " active."; + ib::info() << srv_undo_logs << " out of " << srv_available_undo_logs + << " rollback segments are active."; - return(n_used); + return(true); } /********************************************************************* @@ -1027,9 +943,7 @@ trx_sys_close(void) ut_ad(trx_sys != NULL); ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS); - ulint size = trx_sys->mvcc->size(); - - if (size > 0) { + if (ulint size = trx_sys->mvcc->size()) { ib::error() << "All read views were not closed before" " shutdown: " << size << " read views open"; } @@ -1060,6 +974,10 @@ trx_sys_close(void) if (trx_rseg_t* rseg = trx_sys->rseg_array[i]) { trx_rseg_mem_free(rseg); } + + if (trx_rseg_t* rseg = trx_sys->temp_rsegs[i]) { + trx_rseg_mem_free(rseg); + } } UT_DELETE(trx_sys->mvcc); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index b687f8e899020..db09f7894a71e 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1090,42 +1090,33 @@ trx_lists_init_at_db_start() } } -/******************************************************************//** -Get next redo rollback segment. (Segment are assigned in round-robin fashion). -@return assigned rollback segment instance */ +/** Assign a persistent rollback segment in a round-robin fashion, +evenly distributed between 0 and innodb_undo_logs-1 +@return persistent rollback segment +@retval NULL if innodb_read_only */ static trx_rseg_t* -get_next_redo_rseg( -/*===============*/ - ulong max_undo_logs, /*!< in: maximum number of UNDO logs to use */ - ulint n_tablespaces) /*!< in: number of rollback tablespaces */ +trx_assign_rseg_low() { - trx_rseg_t* rseg; - static ulint redo_rseg_slot = 0; - ulint slot = 0; - - slot = redo_rseg_slot++; - slot = slot % max_undo_logs; - - /* Skip slots alloted to non-redo also ensure even distribution - in selecting next redo slots. - For example: If we don't do even distribution then for any value of - slot between 1 - 32 ... 33rd slots will be alloted creating - skewed distribution. */ - if (trx_sys_is_noredo_rseg_slot(slot)) { - - if (max_undo_logs > srv_tmp_undo_logs) { + if (srv_read_only_mode) { + ut_ad(srv_undo_logs == ULONG_UNDEFINED); + return(NULL); + } - slot %= (max_undo_logs - srv_tmp_undo_logs); + /* The first slot is always assigned to the system tablespace. */ + ut_ad(trx_sys->rseg_array[0]->space == TRX_SYS_SPACE); - if (trx_sys_is_noredo_rseg_slot(slot)) { - slot += srv_tmp_undo_logs; - } + /* Choose a rollback segment evenly distributed between 0 and + innodb_undo_logs-1 in a round-robin fashion, skipping those + undo tablespaces that are scheduled for truncation. - } else { - slot = 0; - } - } + Because rseg_slot is not protected by atomics or any mutex, race + conditions are possible, meaning that multiple transactions + that start modifications concurrently will write their undo + log to the same rollback segment. */ + static ulong rseg_slot; + ulint slot = rseg_slot++ % srv_undo_logs; + trx_rseg_t* rseg; #ifdef UNIV_DEBUG ulint start_scan_slot = slot; @@ -1134,8 +1125,7 @@ get_next_redo_rseg( bool allocated = false; - while (!allocated) { - + do { for (;;) { rseg = trx_sys->rseg_array[slot]; @@ -1148,37 +1138,31 @@ get_next_redo_rseg( look_for_rollover = true; #endif /* UNIV_DEBUG */ - slot = (slot + 1) % max_undo_logs; - - /* Skip slots allocated for noredo rsegs */ - while (trx_sys_is_noredo_rseg_slot(slot)) { - slot = (slot + 1) % max_undo_logs; - } + slot = (slot + 1) % srv_undo_logs; if (rseg == NULL) { continue; - } else if (rseg->space == srv_sys_space.space_id() - && n_tablespaces > 0 - && trx_sys->rseg_array[slot] != NULL - && trx_sys->rseg_array[slot]->space - != srv_sys_space.space_id()) { - /** If undo-tablespace is configured, skip - rseg from system-tablespace and try to use - undo-tablespace rseg unless it is not possible - due to lower limit of undo-logs. */ - continue; - } else if (rseg->skip_allocation) { - /** This rseg resides in the tablespace that - has been marked for truncate so avoid using this - rseg. Also, this is possible only if there are - at-least 2 UNDO tablespaces active and 2 redo - rsegs active (other than default system bound - rseg-0). */ - ut_ad(n_tablespaces > 1); - ut_ad(max_undo_logs - >= (1 + srv_tmp_undo_logs + 2)); - continue; } + + ut_ad(rseg->is_persistent()); + + if (rseg->space != TRX_SYS_SPACE) { + ut_ad(srv_undo_tablespaces > 1); + if (rseg->skip_allocation) { + continue; + } + } else if (trx_rseg_t* next + = trx_sys->rseg_array[slot]) { + if (next->space != TRX_SYS_SPACE + && srv_undo_tablespaces > 0) { + /** If dedicated + innodb_undo_tablespaces have + been configured, try to use them + instead of the system tablespace. */ + continue; + } + } + break; } @@ -1191,129 +1175,43 @@ get_next_redo_rseg( allocated = true; } mutex_exit(&rseg->mutex); - } + } while (!allocated); ut_ad(rseg->trx_ref_count > 0); - ut_ad(!trx_sys_is_noredo_rseg_slot(rseg->id)); - return(rseg); -} - -/******************************************************************//** -Get next noredo rollback segment. -@return assigned rollback segment instance */ -static -trx_rseg_t* -get_next_noredo_rseg( -/*=================*/ - ulong max_undo_logs) /*!< in: maximum number of UNDO logs to use */ -{ - trx_rseg_t* rseg; - static ulint noredo_rseg_slot = 1; - ulint slot = 0; - - slot = noredo_rseg_slot++; - slot = slot % max_undo_logs; - while (!trx_sys_is_noredo_rseg_slot(slot)) { - slot = (slot + 1) % max_undo_logs; - } - - for (;;) { - rseg = trx_sys->rseg_array[slot]; - - slot = (slot + 1) % max_undo_logs; - - while (!trx_sys_is_noredo_rseg_slot(slot)) { - slot = (slot + 1) % max_undo_logs; - } - - if (rseg != NULL) { - break; - } - } - - ut_ad(fsp_is_system_temporary(rseg->space)); - ut_ad(trx_sys_is_noredo_rseg_slot(rseg->id)); + ut_ad(rseg->is_persistent()); return(rseg); } -/******************************************************************//** -Assigns a rollback segment to a transaction in a round-robin fashion. -@return assigned rollback segment instance */ -static +/** Assign a rollback segment for modifying temporary tables. +@return the assigned rollback segment */ trx_rseg_t* -trx_assign_rseg_low( -/*================*/ - ulong max_undo_logs, /*!< in: maximum number of UNDO logs - to use */ - ulint n_tablespaces, /*!< in: number of rollback - tablespaces */ - trx_rseg_type_t rseg_type) /*!< in: type of rseg to assign. */ -{ - if (srv_read_only_mode) { - ut_a(max_undo_logs == ULONG_UNDEFINED); - return(NULL); - } - - /* This breaks true round robin but that should be OK. */ - ut_ad(max_undo_logs > 0 && max_undo_logs <= TRX_SYS_N_RSEGS); - - /* Note: The assumption here is that there can't be any gaps in - the array. Once we implement more flexible rollback segment - management this may not hold. The assertion checks for that case. */ - ut_ad(trx_sys->rseg_array[0] != NULL); - ut_ad(rseg_type == TRX_RSEG_TYPE_REDO - || trx_sys->rseg_array[1] != NULL); - - /* Slot-0 is always assigned to system-tablespace rseg. */ - ut_ad(trx_sys->rseg_array[0]->space == srv_sys_space.space_id()); - - /* Slot-1 is always assigned to temp-tablespace rseg. */ - ut_ad(rseg_type == TRX_RSEG_TYPE_REDO - || fsp_is_system_temporary(trx_sys->rseg_array[1]->space)); - - trx_rseg_t* rseg = 0; - - switch (rseg_type) { - case TRX_RSEG_TYPE_NONE: - ut_error; - - case TRX_RSEG_TYPE_REDO: - rseg = get_next_redo_rseg(max_undo_logs, n_tablespaces); - break; - - case TRX_RSEG_TYPE_NOREDO: - rseg = get_next_noredo_rseg(srv_tmp_undo_logs + 1); - break; - } - - return(rseg); -} - -/****************************************************************//** -Assign a transaction temp-tablespace bounded rollback-segment. */ -void -trx_assign_rseg( -/*============*/ - trx_t* trx) /*!< transaction that involves write - to temp-table. */ -{ - ut_a(trx->rsegs.m_noredo.rseg == 0); - ut_a(!trx_is_autocommit_non_locking(trx)); - - trx->rsegs.m_noredo.rseg = trx_assign_rseg_low( - srv_undo_logs, srv_undo_tablespaces, TRX_RSEG_TYPE_NOREDO); - - if (trx->id == 0) { +trx_t::assign_temp_rseg() +{ + ut_ad(!rsegs.m_noredo.rseg); + ut_ad(!trx_is_autocommit_non_locking(this)); + compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS)); + + /* Choose a temporary rollback segment between 0 and 127 + in a round-robin fashion. Because rseg_slot is not protected by + atomics or any mutex, race conditions are possible, meaning that + multiple transactions that start modifications concurrently + will write their undo log to the same rollback segment. */ + static ulong rseg_slot; + trx_rseg_t* rseg = trx_sys->temp_rsegs[ + rseg_slot++ & (TRX_SYS_N_RSEGS - 1)]; + ut_ad(!rseg->is_persistent()); + rsegs.m_noredo.rseg = rseg; + + if (id == 0) { mutex_enter(&trx_sys->mutex); - - trx->id = trx_sys_get_new_trx_id(); - - trx_sys->rw_trx_ids.push_back(trx->id); - - trx_sys->rw_trx_set.insert(TrxTrack(trx->id, trx)); - + id = trx_sys_get_new_trx_id(); + trx_sys->rw_trx_ids.push_back(id); + trx_sys->rw_trx_set.insert(TrxTrack(id, this)); mutex_exit(&trx_sys->mutex); } + + ut_ad(!rseg->is_persistent()); + return(rseg); } /****************************************************************//** @@ -1388,9 +1286,7 @@ trx_start_low( if (!trx->read_only && (trx->mysql_thd == 0 || read_write || trx->ddl)) { - trx->rsegs.m_redo.rseg = trx_assign_rseg_low( - srv_undo_logs, srv_undo_tablespaces, - TRX_RSEG_TYPE_REDO); + trx->rsegs.m_redo.rseg = trx_assign_rseg_low(); /* Temporary rseg is assigned only if the transaction updates a temporary table */ @@ -2969,8 +2865,6 @@ trx_start_if_not_started_xa_low( trx_sys_t::rw_trx_list. */ if (!trx->read_only) { trx_set_rw_mode(trx); - } else if (!srv_read_only_mode) { - trx_assign_rseg(trx); } } return; @@ -3116,8 +3010,7 @@ trx_set_rw_mode( that both threads are synced by acquring trx->mutex to avoid decision based on in-consistent view formed during promotion. */ - trx->rsegs.m_redo.rseg = trx_assign_rseg_low( - srv_undo_logs, srv_undo_tablespaces, TRX_RSEG_TYPE_REDO); + trx->rsegs.m_redo.rseg = trx_assign_rseg_low(); ut_ad(trx->rsegs.m_redo.rseg != 0); diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 92e18c1c37202..3eab3733f8fdf 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1027,7 +1027,7 @@ void trx_undo_truncate_end(trx_undo_t* undo, undo_no_t limit, bool is_temp) { ut_ad(mutex_own(&undo->rseg->mutex)); - ut_ad(is_temp == trx_sys_is_noredo_rseg_slot(undo->rseg->id)); + ut_ad(is_temp == !undo->rseg->is_persistent()); for (;;) { mtr_t mtr; @@ -1102,7 +1102,7 @@ trx_undo_truncate_start( loop: mtr_start(&mtr); - if (trx_sys_is_noredo_rseg_slot(rseg->id)) { + if (!rseg->is_persistent()) { mtr.set_log_mode(MTR_LOG_NO_REDO); } @@ -1856,7 +1856,7 @@ void trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp) { trx_rseg_t* rseg = undo->rseg; - ut_ad(is_temp == trx_sys_is_noredo_rseg_slot(rseg->id)); + ut_ad(is_temp == !rseg->is_persistent()); mutex_enter(&rseg->mutex);