1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge 10.2 into bb-10.2-mariarocks

This commit is contained in:
Sergei Petrunia
2017-04-03 13:48:05 +03:00
32 changed files with 443 additions and 644 deletions

View File

@@ -140,3 +140,7 @@ create table t1 (a int, b int, check(a>0));
alter table t1 drop column a;
ERROR 42S22: Unknown column 'a' in 'CHECK'
drop table t1;
create table t1 (a int check (@b in (select user from mysql.user)));
ERROR HY000: Function or expression 'select ...' cannot be used in the CHECK clause of `a`
create table t1 (a int check (a > @b));
ERROR HY000: Function or expression '@b' cannot be used in the CHECK clause of `a`

View File

@@ -121,3 +121,12 @@ a
2
#cleanup
DROP TABLE t1, pid_table;
#
# MDEV-12416 OOM in create_virtual_tmp_table() makes the server crash
#
CREATE FUNCTION f1(a INT) RETURNS INT RETURN a;
SET SESSION debug_dbug="+d,simulate_create_virtual_tmp_table_out_of_memory";
SELECT f1(1);
Got one of the listed errors
DROP FUNCTION f1;
SET SESSION debug_dbug=DEFAULT;

View File

@@ -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 1 /Expected to open 3 undo tablespaces but was able to find only 1 undo tablespaces/ in mysqld.1.err
FOUND 1 /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 1 /Expected to open 3 undo tablespaces but was able to find only 0 undo tablespaces/ in mysqld.1.err
FOUND 1 /InnoDB: Unable to open undo tablespace.*undo001/ in mysqld.1.err
bak_ib_logfile0
bak_ib_logfile1
bak_ib_logfile2

View File

@@ -40,7 +40,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;
@@ -171,7 +171,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
@@ -183,7 +183,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

View File

@@ -1 +1 @@
cmp_per_index: MDEV-11629

View File

@@ -39,13 +39,13 @@ BEGIN;
COMMIT;
ALTER TABLE t DROP INDEX c;
GRANT USAGE ON *.* TO 'tuser01'@'localhost' IDENTIFIED BY 'cDJvI9s_Uq';
Warnings:
Level Warning
Code 1287
Message Using GRANT for creating new user is deprecated and will be removed in future release. Create new user with CREATE USER statement.
FLUSH PRIVILEGES;
connect con1,localhost,tuser01,cDJvI9s_Uq,;
connection con1;
SELECT * FROM information_schema.innodb_cmp_per_index;
ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation
connection default;
disconnect con1;
DROP USER 'tuser01'@'localhost';
SELECT
database_name,
@@ -70,7 +70,6 @@ index_name PRIMARY
compress_ops 65
compress_ops_ok 65
uncompress_ops 0
# restart
SET GLOBAL innodb_cmp_per_index_enabled=ON;
SELECT COUNT(*) FROM t;
COUNT(*) 128
@@ -86,9 +85,15 @@ FROM information_schema.innodb_cmp_per_index
ORDER BY 1, 2, 3;
database_name test
table_name t
index_name b
compress_ops 0
compress_ops_ok 0
uncompress_ops 6
database_name test
table_name t
index_name PRIMARY
compress_ops 0
compress_ops_ok 0
uncompress_ops 9
uncompress_ops 5
DROP TABLE t;
SET GLOBAL innodb_cmp_per_index_enabled=default;

View File

@@ -0,0 +1,2 @@
--innodb_log_compressed_pages=on
--innodb_cmp_per_index_reset

View File

@@ -40,12 +40,6 @@ connection default;
select * from t1;
a b c d e
2010-10-10 10:10:10 1 0 0 NULL
Warnings:
Warning 1292 Incorrect datetime value: '1'
Warning 1292 Incorrect datetime value: '2'
Warning 1292 Incorrect datetime value: '1'
Warning 1292 Incorrect datetime value: '1'
Warning 1292 Incorrect datetime value: '2'
drop table t1;
connect con1, localhost, root;
create table t1 (a datetime,

View File

@@ -16,11 +16,15 @@ create table t1 (a datetime,
);
show create table t1;
connect con1, localhost, root;
disable_warnings;
insert t1 (a) values ('2010-10-10 10:10:10');
enable_warnings;
select * from t1;
disconnect con1;
connection default;
disable_warnings;
select * from t1;
enable_warnings;
drop table t1;
connect con1, localhost, root;

View File

@@ -86,3 +86,11 @@ create table t1 (a int, b int, check(a>0));
--error ER_BAD_FIELD_ERROR
alter table t1 drop column a;
drop table t1;
#
# MDEV-12421 Check constraint with query crashes server and renders DB unusable
#
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t1 (a int check (@b in (select user from mysql.user)));
--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
create table t1 (a int check (a > @b));

View File

@@ -148,3 +148,17 @@ SELECT a FROM t1 ORDER BY rand(1);
--echo #cleanup
DROP TABLE t1, pid_table;
--echo #
--echo # MDEV-12416 OOM in create_virtual_tmp_table() makes the server crash
--echo #
CREATE FUNCTION f1(a INT) RETURNS INT RETURN a;
SET SESSION debug_dbug="+d,simulate_create_virtual_tmp_table_out_of_memory";
# May fail with either ER_OUT_OF_RESOURCES or EE_OUTOFMEMORY
--error ER_OUT_OF_RESOURCES, 5
SELECT f1(1);
DROP FUNCTION f1;
SET SESSION debug_dbug=DEFAULT;

View File

@@ -1,5 +1,5 @@
--source include/not_valgrind.inc
--disable_ps_protocol
--source include/no_protocol.inc
SET GLOBAL net_write_timeout = 900;

View File

@@ -137,8 +137,8 @@ ELSE()
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/aws_sdk_cpp/include)
ENDIF()
MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc
COMPONENT aws-key-management)
ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}")
TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS})
MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc
LINK_LIBRARIES ${AWS_SDK_LIBS}
COMPONENT aws-key-management)

View File

@@ -1993,7 +1993,7 @@ class Virtual_tmp_table: public TABLE
This is needed to avoid memory leaks, as some fields can be BLOB
variants and thus can have String onboard. Strings must be destructed
as they store data not the heap (not on MEM_ROOT).
as they store data on the heap (not on MEM_ROOT).
*/
void destruct_fields()
{
@@ -2025,6 +2025,7 @@ public:
@param thd - Current thread.
*/
static void *operator new(size_t size, THD *thd) throw();
static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
Virtual_tmp_table(THD *thd)
{
@@ -2035,7 +2036,8 @@ public:
~Virtual_tmp_table()
{
destruct_fields();
if (s)
destruct_fields();
}
/**
@@ -2120,6 +2122,17 @@ create_virtual_tmp_table(THD *thd, List<Column_definition> &field_list)
Virtual_tmp_table *table;
if (!(table= new(thd) Virtual_tmp_table(thd)))
return NULL;
/*
If "simulate_create_virtual_tmp_table_out_of_memory" debug option
is enabled, we now enable "simulate_out_of_memory". This effectively
makes table->init() fail on OOM inside multi_alloc_root().
This is done to test that ~Virtual_tmp_table() called from the "delete"
below correcly handles OOM.
*/
DBUG_EXECUTE_IF("simulate_create_virtual_tmp_table_out_of_memory",
DBUG_SET("+d,simulate_out_of_memory"););
if (table->init(field_list.elements) ||
table->add(field_list) ||
table->open())

View File

@@ -4667,7 +4667,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE *table,
table_list.view= (LEX*) share->is_view;
res= schema_table->process_table(thd, &table_list, table,
res, db_name, table_name);
free_root(&tbl.mem_root, MYF(0));
closefrm(&tbl);
}

View File

@@ -6013,8 +6013,8 @@ field_list_item:
;
column_def:
field_spec opt_check_constraint
{ $$= $1; $$->check_constraint= $2; }
field_spec
{ $$= $1; }
| field_spec references
{ $$= $1; }
;
@@ -6152,11 +6152,13 @@ field_spec:
lex->init_last_field(f, $1.str, NULL);
$<create_field>$= f;
}
field_type_or_serial
field_type_or_serial opt_check_constraint
{
LEX *lex=Lex;
$$= $<create_field>2;
$$->check_constraint= $4;
if ($$->check(thd))
MYSQL_YYABORT;

View File

@@ -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;
}
/****************************************************************************

View File

@@ -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;

View File

@@ -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 */

View File

@@ -75,17 +75,10 @@ Creates and initializes the transaction system at the database creation. */
void
trx_sys_create_sys_pages(void);
/*==========================*/
/****************************************************************//**
Looks for a free slot for a rollback segment in the trx system file copy.
@return slot index or ULINT_UNDEFINED if not found */
/** @return an unallocated rollback segment slot in the TRX_SYS header
@retval ULINT_UNDEFINED if not found */
ulint
trx_sysf_rseg_find_free(
/*====================*/
mtr_t* mtr, /*!< in/out: mtr */
bool include_tmp_slots, /*!< in: if true, report slots reserved
for temp-tablespace as free slots. */
ulint nth_free_slots); /*!< in: allocate nth free slot.
0 means next free slot. */
trx_sysf_rseg_find_free(mtr_t* mtr);
/**********************************************************************//**
Gets a pointer to the transaction system file copy and x-locks its page.
@return pointer to system file copy, page x-locked */
@@ -160,14 +153,6 @@ trx_sys_get_max_trx_id(void);
extern uint trx_rseg_n_slots_debug;
#endif
/*****************************************************************//**
Check if slot-id is reserved slot-id for noredo rsegs. */
UNIV_INLINE
bool
trx_sys_is_noredo_rseg_slot(
/*========================*/
ulint slot_id); /*!< in: slot_id to check */
/*****************************************************************//**
Writes a trx id to an index page. In case that the id size changes in
some future version, this function should be used instead of
@@ -319,16 +304,10 @@ trx_sys_file_format_max_set(
ulint format_id, /*!< in: file format id */
const char** name); /*!< out: max file format name or
NULL if not needed. */
/*********************************************************************
Creates the rollback segments
@return number of rollback segments that are active. */
ulint
trx_sys_create_rsegs(
/*=================*/
ulint n_spaces, /*!< number of tablespaces for UNDO logs */
ulint n_rsegs, /*!< number of rollback segments to create */
ulint n_tmp_rsegs); /*!< number of rollback segments reserved for
temp-tables. */
/** Create the rollback segments.
@return whether the creation succeeded */
bool
trx_sys_create_rsegs();
/*****************************************************************//**
Get the number of transaction in the system, independent of their state.
@return count of transactions in trx_sys_t::trx_list */
@@ -556,13 +535,15 @@ struct trx_sys_t {
transactions which exist or existed */
#endif /* UNIV_DEBUG */
char pad1[64]; /*!< To avoid false sharing */
/** Avoid false sharing */
const char pad1[CACHE_LINE_SIZE];
trx_ut_list_t rw_trx_list; /*!< List of active and committed in
memory read-write transactions, sorted
on trx id, biggest first. Recovered
transactions are always on this list. */
char pad2[64]; /*!< To avoid false sharing */
/** Avoid false sharing */
const char pad2[CACHE_LINE_SIZE];
trx_ut_list_t mysql_trx_list; /*!< List of transactions created
for MySQL. All user transactions are
on mysql_trx_list. The rw_trx_list
@@ -582,7 +563,13 @@ struct trx_sys_t {
to ensure right order of removal and
consistent snapshot. */
char pad3[64]; /*!< To avoid false sharing */
/** Avoid false sharing */
const char pad3[CACHE_LINE_SIZE];
/** Temporary rollback segments */
trx_rseg_t* temp_rsegs[TRX_SYS_N_RSEGS];
/** Avoid false sharing */
const char pad4[CACHE_LINE_SIZE];
trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS];
/*!< Pointer array to rollback
segments; NULL if slot not in use;

View File

@@ -191,18 +191,6 @@ trx_write_trx_id(
mach_write_to_6(ptr, id);
}
/*****************************************************************//**
Check if slot-id is reserved slot-id for noredo rsegs. */
UNIV_INLINE
bool
trx_sys_is_noredo_rseg_slot(
/*========================*/
ulint slot_id) /*!< in: slot_id to check */
{
/* Slots allocated from temp-tablespace are no-redo slots. */
return(slot_id > 0 && slot_id < (srv_tmp_undo_logs + 1));
}
/*****************************************************************//**
Reads a trx id from an index page. In case that the id size changes in
some future version, this function should be used instead of

View File

@@ -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();
};
/**

View File

@@ -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);

View File

@@ -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;
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 = 0;
ulint srv_available_undo_logs = 0;
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 = 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;
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. */

View File

@@ -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";
<< " undo tablespaces ("
<< srv_undo_tablespaces_active
<< " active)";
ib::info() << srv_undo_tablespaces_active << " undo tablespaces"
<< " made 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));
}

View File

@@ -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

View File

@@ -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. */

View File

@@ -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);
}
rseg_header = trx_rsegf_get_new(space, page_no, mtr);
/** 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(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();
}
}
/********************************************************************

View File

@@ -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;
trx_sysf_t* sys_header = trx_sysf_get(mtr);
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);
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. */
/** Create the rollback segments.
@return whether the creation succeeded */
bool
trx_sys_create_rsegs()
{
ulint n_created = 0;
/* srv_available_undo_logs reflects the number of persistent
rollback segments that have been initialized in the
transaction system header page.
/* 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. */
{
mtr_t mtr;
ulint n_used;
ulint n_noredo_created;
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;
/* The first persistent rollback segment is always initialized
in the system tablespace. */
ut_a(srv_available_undo_logs > 0);
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 {
n_redo_active = n_rsegs - n_tmp_rsegs;
}
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;
/* 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. */
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 (!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);

View File

@@ -1090,43 +1090,34 @@ 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) {
slot %= (max_undo_logs - srv_tmp_undo_logs);
if (trx_sys_is_noredo_rseg_slot(slot)) {
slot += srv_tmp_undo_logs;
}
} else {
slot = 0;
}
if (srv_read_only_mode) {
ut_ad(srv_undo_logs == ULONG_UNDEFINED);
return(NULL);
}
/* The first slot is always assigned to the system tablespace. */
ut_ad(trx_sys->rseg_array[0]->space == TRX_SYS_SPACE);
/* 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.
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;
bool look_for_rollover = false;
@@ -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));
ut_ad(rseg->is_persistent());
return(rseg);
}
/******************************************************************//**
Get next noredo rollback segment.
@return assigned rollback segment instance */
static
/** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */
trx_rseg_t*
get_next_noredo_rseg(
/*=================*/
ulong max_undo_logs) /*!< in: maximum number of UNDO logs to use */
trx_t::assign_temp_rseg()
{
trx_rseg_t* rseg;
static ulint noredo_rseg_slot = 1;
ulint slot = 0;
ut_ad(!rsegs.m_noredo.rseg);
ut_ad(!trx_is_autocommit_non_locking(this));
compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS));
slot = noredo_rseg_slot++;
slot = slot % max_undo_logs;
while (!trx_sys_is_noredo_rseg_slot(slot)) {
slot = (slot + 1) % max_undo_logs;
}
/* 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;
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));
return(rseg);
}
/******************************************************************//**
Assigns a rollback segment to a transaction in a round-robin fashion.
@return assigned rollback segment instance */
static
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) {
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);

View File

@@ -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);