summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------libmariadb0
-rw-r--r--mysql-test/suite/innodb/r/log_file.result4
-rw-r--r--mysql-test/suite/innodb/t/log_file.test6
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/innobase/include/srv0srv.h6
-rw-r--r--storage/innobase/include/trx0rseg.h32
-rw-r--r--storage/innobase/include/trx0sys.h49
-rw-r--r--storage/innobase/include/trx0sys.ic12
-rw-r--r--storage/innobase/include/trx0trx.h30
-rw-r--r--storage/innobase/row/row0purge.cc5
-rw-r--r--storage/innobase/srv/srv0srv.cc53
-rw-r--r--storage/innobase/srv/srv0start.cc72
-rw-r--r--storage/innobase/trx/trx0purge.cc51
-rw-r--r--storage/innobase/trx/trx0rec.cc47
-rw-r--r--storage/innobase/trx/trx0rseg.cc144
-rw-r--r--storage/innobase/trx/trx0sys.cc220
-rw-r--r--storage/innobase/trx/trx0trx.cc253
-rw-r--r--storage/innobase/trx/trx0undo.cc6
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);