diff options
m--------- | libmariadb | 0 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/log_file.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/log_file.test | 6 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 2 | ||||
-rw-r--r-- | storage/innobase/include/srv0srv.h | 6 | ||||
-rw-r--r-- | storage/innobase/include/trx0rseg.h | 32 | ||||
-rw-r--r-- | storage/innobase/include/trx0sys.h | 49 | ||||
-rw-r--r-- | storage/innobase/include/trx0sys.ic | 12 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 30 | ||||
-rw-r--r-- | storage/innobase/row/row0purge.cc | 5 | ||||
-rw-r--r-- | storage/innobase/srv/srv0srv.cc | 53 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 72 | ||||
-rw-r--r-- | storage/innobase/trx/trx0purge.cc | 51 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rec.cc | 47 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rseg.cc | 144 | ||||
-rw-r--r-- | storage/innobase/trx/trx0sys.cc | 220 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 253 | ||||
-rw-r--r-- | storage/innobase/trx/trx0undo.cc | 6 |
18 files changed, 368 insertions, 624 deletions
diff --git a/libmariadb b/libmariadb -Subproject be34e12ba0f9a23074be5051259db954b3a302d +Subproject cae391f7bf47f17fb246cded8ddf0ef19dbfbde diff --git a/mysql-test/suite/innodb/r/log_file.result b/mysql-test/suite/innodb/r/log_file.result index 352e4b76cf1..918faec8ada 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 c50257a69be..e0f4b85c682 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/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3dc22fe58d8..6aacdd48ad8 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<unsigned long>(srv_available_undo_logs); + = srv_available_undo_logs; } /**************************************************************************** diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index e469cd90737..eb08c478965 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 e17d11b383e..95774cbf476 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 8ebb74e3d86..b867600653d 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 */ @@ -161,14 +154,6 @@ 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 mach_write_... */ @@ -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 f03535c53b3..1c805ead4b3 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -192,18 +192,6 @@ trx_write_trx_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 mach_read_... diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 7da3bfb5459..d0a67a7ed28 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 ce9a265bd8c..2a13203b747 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -741,10 +741,11 @@ skip_secondaries: &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 b689cd012c6..a05bb5300a3 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 7c16ce1e58f..bcb52fc5bfb 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 @@ files_checked: 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 @@ files_checked: 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 6ff4c882be8..f83d9377852 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 @@ loop: /* 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 @@ loop: } 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 481e14d44de..47d24b63114 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 @@ err_exit: /*============== 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 883e2eb60b2..3393a0464a8 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<trx_rseg_t*>(ut_zalloc_nokey(sizeof(trx_rseg_t))); + trx_rseg_t* rseg = static_cast<trx_rseg_t*>( + 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 f08736ae1f1..24983dcc2a3 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 b687f8e8990..db09f7894a7 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 92e18c1c372..3eab3733f8f 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); |