Merge 10.2 into 10.3

This commit is contained in:
Marko Mäkelä 2021-07-27 10:47:17 +03:00
commit f50eb0d398
35 changed files with 402 additions and 268 deletions

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. /* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2010, 2019, MariaDB Corporation. Copyright (c) 2010, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -283,7 +283,8 @@ extern int my_umask_dir,
extern my_bool my_use_symdir; extern my_bool my_use_symdir;
extern ulong my_default_record_cache_size; extern ulong my_default_record_cache_size;
extern my_bool my_disable_locking, my_disable_async_io, extern MYSQL_PLUGIN_IMPORT my_bool my_disable_locking;
extern my_bool my_disable_async_io,
my_disable_flush_key_blocks, my_disable_symlinks; my_disable_flush_key_blocks, my_disable_symlinks;
extern my_bool my_disable_sync, my_disable_copystat_in_redel; extern my_bool my_disable_sync, my_disable_copystat_in_redel;
extern char wild_many,wild_one,wild_prefix; extern char wild_many,wild_one,wild_prefix;

View File

@ -4565,6 +4565,28 @@ drop procedure sp1;
drop procedure sp2; drop procedure sp2;
drop table t1; drop table t1;
# #
# MDEV-26202: Recursive CTE used indirectly twice
# (fixed by the patch forMDEV-26025)
#
with recursive
rcte as ( SELECT 1 AS a
UNION ALL
SELECT cast(a + 1 as unsigned int) FROM rcte WHERE a < 3),
cte1 AS (SELECT a FROM rcte),
cte2 AS (SELECT a FROM cte1),
cte3 AS ( SELECT a FROM cte2)
SELECT * FROM cte2, cte3;
a a
1 1
2 1
3 1
1 2
2 2
3 2
1 3
2 3
3 3
#
# End of 10.2 tests # End of 10.2 tests
# #
# #

View File

@ -2919,6 +2919,20 @@ drop procedure sp2;
drop table t1; drop table t1;
--echo #
--echo # MDEV-26202: Recursive CTE used indirectly twice
--echo # (fixed by the patch forMDEV-26025)
--echo #
with recursive
rcte as ( SELECT 1 AS a
UNION ALL
SELECT cast(a + 1 as unsigned int) FROM rcte WHERE a < 3),
cte1 AS (SELECT a FROM rcte),
cte2 AS (SELECT a FROM cte1),
cte3 AS ( SELECT a FROM cte2)
SELECT * FROM cte2, cte3;
--echo # --echo #
--echo # End of 10.2 tests --echo # End of 10.2 tests
--echo # --echo #

View File

@ -2,6 +2,9 @@
# MySQL >= 5.0 # MySQL >= 5.0
# #
# The test can take hours with valgrind
--source include/not_valgrind.inc
# Save the initial number of concurrent sessions # Save the initial number of concurrent sessions
--source include/count_sessions.inc --source include/count_sessions.inc

View File

@ -4,6 +4,8 @@
# MySQL >= 5.0 # MySQL >= 5.0
# #
# The test can take hours with valgrind
--source include/not_valgrind.inc
# Save the initial number of concurrent sessions # Save the initial number of concurrent sessions
--source include/count_sessions.inc --source include/count_sessions.inc

View File

@ -18,6 +18,9 @@
# - with annotated events, default checksums and minimal binlog row image # - with annotated events, default checksums and minimal binlog row image
# #
# The test can take very long time with valgrind
--source include/not_valgrind.inc
--source include/have_partition.inc --source include/have_partition.inc
--source encryption_algorithms.inc --source encryption_algorithms.inc
--source include/have_innodb.inc --source include/have_innodb.inc

View File

@ -1,6 +1,9 @@
-- source include/have_innodb.inc -- source include/have_innodb.inc
-- source include/have_file_key_management_plugin.inc -- source include/have_file_key_management_plugin.inc
# The test can take very long time with valgrind
--source include/not_valgrind.inc
create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb; create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
show warnings; show warnings;
create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact encrypted=yes encryption_key_id=1; create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact encrypted=yes encryption_key_id=1;

View File

@ -48,12 +48,6 @@ while ($cnt)
{ {
real_sleep 1; real_sleep 1;
dec $cnt; dec $cnt;
if ($cnt == 200)
{
--disable_query_log
set global innodb_encrypt_tables = on;
--enable_query_log
}
} }
} }
if (!$success) if (!$success)
@ -84,12 +78,6 @@ while ($cnt)
{ {
real_sleep 1; real_sleep 1;
dec $cnt; dec $cnt;
if ($cnt == 200)
{
--disable_query_log
set global innodb_encrypt_tables = off;
--enable_query_log
}
} }
} }
if (!$success) if (!$success)
@ -119,12 +107,6 @@ while ($cnt)
{ {
real_sleep 1; real_sleep 1;
dec $cnt; dec $cnt;
if ($cnt == 200)
{
--disable_query_log
set global innodb_encrypt_tables=on;
--enable_query_log
}
} }
} }
if (!$success) if (!$success)

View File

@ -0,0 +1,52 @@
CREATE TABLE parent(parent_id int not null AUTO_INCREMENT PRIMARY KEY,
parent_name varchar(80)) ENGINE=InnoDB;
CREATE TABLE child(child_id int not null AUTO_INCREMENT PRIMARY KEY,
child_name varchar(80),
child_parent_id int not null,
CONSTRAINT `fk_child_parent`
FOREIGN KEY (child_parent_id) REFERENCES parent (parent_id)
ON DELETE CASCADE
ON UPDATE CASCADE) ENGINE=InnoDB;
INSERT INTO parent VALUES (1, 'first'),(2,'second'),(3,'foo'),(4,'tmp');
INSERT INTO child VALUES (NULL,'first_child',1);
INSERT INTO child VALUES (NULL,'second_child',1);
INSERT INTO child VALUES (NULL,'first_child2',2);
INSERT INTO child VALUES (NULL,'first_child3',2);
INSERT INTO child VALUES (NULL,'first_child4',3);
BEGIN;
UPDATE parent SET parent_name = 'bar' WHERE parent_id = 2;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
SET SESSION innodb_lock_wait_timeout=2;
UPDATE child SET child_parent_id = 5 where child_parent_id = 2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
connection node_1;
COMMIT;
SELECT * FROM parent;
parent_id parent_name
1 first
2 bar
3 foo
4 tmp
SELECT * FROM child;
child_id child_name child_parent_id
1 first_child 1
3 second_child 1
5 first_child2 2
7 first_child3 2
9 first_child4 3
connection node_2;
SELECT * FROM parent;
parent_id parent_name
1 first
2 bar
3 foo
4 tmp
SELECT * FROM child;
child_id child_name child_parent_id
1 first_child 1
3 second_child 1
5 first_child2 2
7 first_child3 2
9 first_child4 3
DROP TABLE child, parent;
disconnect node_1a;

View File

@ -0,0 +1,40 @@
--source include/galera_cluster.inc
CREATE TABLE parent(parent_id int not null AUTO_INCREMENT PRIMARY KEY,
parent_name varchar(80)) ENGINE=InnoDB;
CREATE TABLE child(child_id int not null AUTO_INCREMENT PRIMARY KEY,
child_name varchar(80),
child_parent_id int not null,
CONSTRAINT `fk_child_parent`
FOREIGN KEY (child_parent_id) REFERENCES parent (parent_id)
ON DELETE CASCADE
ON UPDATE CASCADE) ENGINE=InnoDB;
INSERT INTO parent VALUES (1, 'first'),(2,'second'),(3,'foo'),(4,'tmp');
INSERT INTO child VALUES (NULL,'first_child',1);
INSERT INTO child VALUES (NULL,'second_child',1);
INSERT INTO child VALUES (NULL,'first_child2',2);
INSERT INTO child VALUES (NULL,'first_child3',2);
INSERT INTO child VALUES (NULL,'first_child4',3);
BEGIN;
UPDATE parent SET parent_name = 'bar' WHERE parent_id = 2;
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
SET SESSION innodb_lock_wait_timeout=2;
--error ER_LOCK_WAIT_TIMEOUT
UPDATE child SET child_parent_id = 5 where child_parent_id = 2;
--connection node_1
COMMIT;
SELECT * FROM parent;
SELECT * FROM child;
--connection node_2
SELECT * FROM parent;
SELECT * FROM child;
DROP TABLE child, parent;
--disconnect node_1a

View File

@ -809,15 +809,18 @@ generated_email_id int as (email_id),
PRIMARY KEY (id), PRIMARY KEY (id),
KEY mautic_generated_sent_date_email_id (generated_email_id), KEY mautic_generated_sent_date_email_id (generated_email_id),
FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE SET NULL FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE SET NULL
ON UPDATE CASCADE
) ENGINE=InnoDB; ) ENGINE=InnoDB;
CREATE TABLE emails_metadata ( CREATE TABLE emails_metadata (
email_id int, email_id int,
PRIMARY KEY (email_id), PRIMARY KEY (email_id),
CONSTRAINT FK FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE CASCADE CONSTRAINT FK FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB; ) ENGINE=InnoDB;
INSERT INTO emails VALUES (1); INSERT INTO emails VALUES (1);
INSERT INTO email_stats (id, email_id, date_sent) VALUES (1,1,'Jan'); INSERT INTO email_stats (id, email_id, date_sent) VALUES (1,1,'Jan');
INSERT INTO emails_metadata VALUES (1); INSERT INTO emails_metadata VALUES (1);
UPDATE emails SET id=2;
DELETE FROM emails; DELETE FROM emails;
DROP TABLE email_stats; DROP TABLE email_stats;
DROP TABLE emails_metadata; DROP TABLE emails_metadata;

View File

@ -670,6 +670,7 @@ CREATE TABLE email_stats (
PRIMARY KEY (id), PRIMARY KEY (id),
KEY mautic_generated_sent_date_email_id (generated_email_id), KEY mautic_generated_sent_date_email_id (generated_email_id),
FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE SET NULL FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE SET NULL
ON UPDATE CASCADE
) ENGINE=InnoDB; ) ENGINE=InnoDB;
@ -677,6 +678,7 @@ CREATE TABLE emails_metadata (
email_id int, email_id int,
PRIMARY KEY (email_id), PRIMARY KEY (email_id),
CONSTRAINT FK FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE CASCADE CONSTRAINT FK FOREIGN KEY (email_id) REFERENCES emails (id) ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB; ) ENGINE=InnoDB;
@ -684,6 +686,7 @@ INSERT INTO emails VALUES (1);
INSERT INTO email_stats (id, email_id, date_sent) VALUES (1,1,'Jan'); INSERT INTO email_stats (id, email_id, date_sent) VALUES (1,1,'Jan');
INSERT INTO emails_metadata VALUES (1); INSERT INTO emails_metadata VALUES (1);
UPDATE emails SET id=2;
DELETE FROM emails; DELETE FROM emails;
DROP TABLE email_stats; DROP TABLE email_stats;

View File

@ -1,6 +1,8 @@
-- source include/have_innodb.inc -- source include/have_innodb.inc
-- source include/have_innodb_lz4.inc -- source include/have_innodb_lz4.inc
-- source include/not_embedded.inc -- source include/not_embedded.inc
# The test can take very long time with valgrind
--source include/not_valgrind.inc
# lz4 # lz4
set global innodb_compression_algorithm = 2; set global innodb_compression_algorithm = 2;

View File

@ -114,7 +114,7 @@ qsort_t my_qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp)
stack[0].low=stack[0].high=0; stack[0].low=stack[0].high=0;
#endif #endif
pivot = (char *) my_alloca((int) size); pivot = (char *) my_alloca((int) size);
ptr_cmp= size == sizeof(char*) && !((low - (char*) 0)& (sizeof(char*)-1)); ptr_cmp= size == sizeof(char*) && (intptr_t)low % sizeof(char*) == 0;
/* The following loop sorts elements between high and low */ /* The following loop sorts elements between high and low */
do do

View File

@ -1,5 +1,5 @@
// Copyright (c) 2014, Google Inc. // Copyright (c) 2014, Google Inc.
// Copyright (c) 2017, MariaDB Corporation. // Copyright (c) 2017, 2021, MariaDB Corporation.
/**************************************************//** /**************************************************//**
@file btr/btr0scrub.cc @file btr/btr0scrub.cc
@ -830,20 +830,12 @@ btr_scrub_page(
/**************************************************************//** /**************************************************************//**
Start iterating a space */ Start iterating a space */
UNIV_INTERN bool btr_scrub_start_space(const fil_space_t &space, btr_scrub_t *scrub_data)
bool
btr_scrub_start_space(
/*===================*/
ulint space, /*!< in: space */
btr_scrub_t* scrub_data) /*!< in/out: scrub data */
{ {
bool found; scrub_data->space = space.id;
scrub_data->space = space;
scrub_data->current_table = NULL; scrub_data->current_table = NULL;
scrub_data->current_index = NULL; scrub_data->current_index = NULL;
const page_size_t page_size = fil_space_get_page_size(space, &found); scrub_data->compressed = FSP_FLAGS_GET_ZIP_SSIZE(space.flags) != 0;
scrub_data->compressed = page_size.is_compressed();
scrub_data->scrubbing = check_scrub_setting(scrub_data); scrub_data->scrubbing = check_scrub_setting(scrub_data);
return scrub_data->scrubbing; return scrub_data->scrubbing;
} }

View File

@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
Copyright (c) 2014, 2020, MariaDB Corporation. Copyright (c) 2014, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -1091,6 +1091,33 @@ struct rotate_thread_t {
} }
}; };
/** Avoid the removal of the tablespace from
default_encrypt_list only when
1) Another active encryption thread working on tablespace
2) Eligible for tablespace key rotation
3) Tablespace is in flushing phase
@return true if tablespace should be removed from
default encrypt */
static bool fil_crypt_must_remove(const fil_space_t &space)
{
ut_ad(space.purpose == FIL_TYPE_TABLESPACE);
fil_space_crypt_t *crypt_data = space.crypt_data;
ut_ad(mutex_own(&fil_system.mutex));
const ulong encrypt_tables= srv_encrypt_tables;
if (!crypt_data)
return !encrypt_tables;
if (!crypt_data->is_key_found())
return true;
mutex_enter(&crypt_data->mutex);
const bool remove= (space.is_stopping() || crypt_data->not_encrypted()) &&
(!crypt_data->rotate_state.flushing &&
!encrypt_tables == !!crypt_data->min_key_version &&
!crypt_data->rotate_state.active_threads);
mutex_exit(&crypt_data->mutex);
return remove;
}
/*********************************************************************** /***********************************************************************
Check if space needs rotation given a key_state Check if space needs rotation given a key_state
@param[in,out] state Key rotation state @param[in,out] state Key rotation state
@ -1172,7 +1199,7 @@ fil_crypt_space_needs_rotation(
key_state->rotate_key_age); key_state->rotate_key_age);
crypt_data->rotate_state.scrubbing.is_active = crypt_data->rotate_state.scrubbing.is_active =
btr_scrub_start_space(space->id, &state->scrub_data); btr_scrub_start_space(*space, &state->scrub_data);
time_t diff = time(0) - crypt_data->rotate_state.scrubbing. time_t diff = time(0) - crypt_data->rotate_state.scrubbing.
last_scrub_completed; last_scrub_completed;
@ -1428,8 +1455,7 @@ inline fil_space_t *fil_system_t::default_encrypt_next(
If there is a change in innodb_encrypt_tables variables If there is a change in innodb_encrypt_tables variables
value then don't remove the last processed tablespace value then don't remove the last processed tablespace
from the default encrypt list. */ from the default encrypt list. */
if (released && (!recheck || space->crypt_data) && if (released && !recheck && fil_crypt_must_remove(*space))
!encrypt == !srv_encrypt_tables)
{ {
ut_a(!default_encrypt_tables.empty()); ut_a(!default_encrypt_tables.empty());
default_encrypt_tables.remove(*space); default_encrypt_tables.remove(*space);

View File

@ -4441,7 +4441,7 @@ innobase_commit_low(
if (trx_is_started(trx)) { if (trx_is_started(trx)) {
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
} else { } else {
trx->will_lock = 0; trx->will_lock = false;
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
@ -4795,7 +4795,7 @@ innobase_rollback_trx(
lock_unlock_table_autoinc(trx); lock_unlock_table_autoinc(trx);
if (!trx->has_logged()) { if (!trx->has_logged()) {
trx->will_lock = 0; trx->will_lock = false;
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
#endif #endif
@ -8066,7 +8066,7 @@ ha_innobase::write_row(
ut_a(m_prebuilt->trx == trx); ut_a(m_prebuilt->trx == trx);
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
#ifdef WITH_WSREP #ifdef WITH_WSREP
@ -8842,7 +8842,7 @@ ha_innobase::update_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY); DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) { } else if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
if (m_upd_buf == NULL) { if (m_upd_buf == NULL) {
@ -9021,7 +9021,7 @@ ha_innobase::delete_row(
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY); DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) { } else if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
if (!m_prebuilt->upd_node) { if (!m_prebuilt->upd_node) {
@ -9899,7 +9899,7 @@ ha_innobase::ft_init()
them as regular read only transactions for now. */ them as regular read only transactions for now. */
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(rnd_init(false)); DBUG_RETURN(rnd_init(false));
@ -9965,7 +9965,7 @@ ha_innobase::ft_init_ext(
them as regular read only transactions for now. */ them as regular read only transactions for now. */
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
dict_table_t* ft_table = m_prebuilt->table; dict_table_t* ft_table = m_prebuilt->table;
@ -12893,7 +12893,7 @@ create_table_info_t::allocate_trx()
{ {
m_trx = innobase_trx_allocate(m_thd); m_trx = innobase_trx_allocate(m_thd);
m_trx->will_lock++; m_trx->will_lock = true;
m_trx->ddl = true; m_trx->ddl = true;
} }
@ -13207,13 +13207,7 @@ inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
ut_a(name_len < 1000); ut_a(name_len < 1000);
/* Either the transaction is already flagged as a locking transaction trx->will_lock = true;
or it hasn't been started yet. */
ut_a(!trx_is_started(trx) || trx->will_lock > 0);
/* We are doing a DDL operation. */
++trx->will_lock;
/* Drop the table in InnoDB */ /* Drop the table in InnoDB */
@ -13390,14 +13384,7 @@ innobase_drop_database(
#endif /* _WIN32 */ #endif /* _WIN32 */
trx_t* trx = innobase_trx_allocate(thd); trx_t* trx = innobase_trx_allocate(thd);
trx->will_lock = true;
/* Either the transaction is already flagged as a locking transaction
or it hasn't been started yet. */
ut_a(!trx_is_started(trx) || trx->will_lock > 0);
/* We are doing a DDL operation. */
++trx->will_lock;
ulint dummy; ulint dummy;
@ -13441,7 +13428,7 @@ inline dberr_t innobase_rename_table(trx_t *trx, const char *from,
DEBUG_SYNC_C("innodb_rename_table_ready"); DEBUG_SYNC_C("innodb_rename_table_ready");
trx_start_if_not_started(trx, true); trx_start_if_not_started(trx, true);
ut_ad(trx->will_lock > 0); ut_ad(trx->will_lock);
if (commit) { if (commit) {
/* Serialize data dictionary operations with dictionary mutex: /* Serialize data dictionary operations with dictionary mutex:
@ -13590,8 +13577,7 @@ int ha_innobase::truncate()
heap, ib_table->name.m_name, ib_table->id); heap, ib_table->name.m_name, ib_table->id);
const char* name = mem_heap_strdup(heap, ib_table->name.m_name); const char* name = mem_heap_strdup(heap, ib_table->name.m_name);
trx_t* trx = innobase_trx_allocate(m_user_thd); trx_t* trx = innobase_trx_allocate(m_user_thd);
trx->will_lock = true;
++trx->will_lock;
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dict_stats_wait_bg_to_stop_using_table(ib_table, trx); dict_stats_wait_bg_to_stop_using_table(ib_table, trx);
@ -13676,9 +13662,7 @@ ha_innobase::rename_table(
} }
trx_t* trx = innobase_trx_allocate(thd); trx_t* trx = innobase_trx_allocate(thd);
trx->will_lock = true;
/* We are doing a DDL operation. */
++trx->will_lock;
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
dberr_t error = innobase_rename_table(trx, from, to, true); dberr_t error = innobase_rename_table(trx, from, to, true);
@ -15673,7 +15657,7 @@ ha_innobase::start_stmt(
innobase_register_trx(ht, thd, trx); innobase_register_trx(ht, thd, trx);
if (!trx_is_started(trx)) { if (!trx_is_started(trx)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
@ -15900,7 +15884,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
@ -15941,7 +15925,7 @@ ha_innobase::external_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
DBUG_RETURN(0); DBUG_RETURN(0);
@ -16623,7 +16607,7 @@ ha_innobase::store_lock(
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) { || m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
++trx->will_lock; trx->will_lock = true;
} }
return(to); return(to);

View File

@ -1369,7 +1369,7 @@ ha_innobase::check_if_supported_inplace_alter(
} }
} }
m_prebuilt->trx->will_lock++; m_prebuilt->trx->will_lock = true;
/* When changing a NULL column to NOT NULL and specifying a /* When changing a NULL column to NOT NULL and specifying a
DEFAULT value, ensure that the DEFAULT expression is a constant. DEFAULT value, ensure that the DEFAULT expression is a constant.
@ -10131,7 +10131,6 @@ foreign_fail:
m_prebuilt = ctx->prebuilt; m_prebuilt = ctx->prebuilt;
} }
trx_start_if_not_started(user_trx, true); trx_start_if_not_started(user_trx, true);
user_trx->will_lock++;
m_prebuilt->trx = user_trx; m_prebuilt->trx = user_trx;
} }
DBUG_INJECT_CRASH("ib_commit_inplace_crash", DBUG_INJECT_CRASH("ib_commit_inplace_crash",

View File

@ -141,12 +141,7 @@ btr_scrub_skip_page(
/**************************************************************** /****************************************************************
Start iterating a space Start iterating a space
* @return true if scrubbing is turned on */ * @return true if scrubbing is turned on */
UNIV_INTERN bool btr_scrub_start_space(const fil_space_t &space, btr_scrub_t *scrub_data);
bool
btr_scrub_start_space(
/*===================*/
ulint space, /*!< in: space */
btr_scrub_t* scrub_data); /*!< in/out: scrub data */
/** Complete iterating a space. /** Complete iterating a space.
@param[in,out] scrub_data scrub data */ @param[in,out] scrub_data scrub data */

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -164,8 +164,8 @@ struct i_s_trx_row_t {
/*!< detailed_error in trx_t */ /*!< detailed_error in trx_t */
ulint trx_is_read_only; ulint trx_is_read_only;
/*!< trx_t::read_only */ /*!< trx_t::read_only */
ulint trx_is_autocommit_non_locking; bool trx_is_autocommit_non_locking;
/*!< trx_is_autocommit_non_locking(trx) /*!< trx:t::is_autocommit_non_locking()
*/ */
}; };

View File

@ -512,7 +512,7 @@ class rw_trx_hash_t
static void validate_element(trx_t *trx) static void validate_element(trx_t *trx)
{ {
ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg); ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg);
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
/* trx->state can be anything except TRX_STATE_NOT_STARTED */ /* trx->state can be anything except TRX_STATE_NOT_STARTED */
mutex_enter(&trx->mutex); mutex_enter(&trx->mutex);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||

View File

@ -406,81 +406,6 @@ from innodb_lock_wait_timeout via trx_t::mysql_thd.
? thd_lock_wait_timeout((t)->mysql_thd) \ ? thd_lock_wait_timeout((t)->mysql_thd) \
: 0) : 0)
/**
Determine if the transaction is a non-locking autocommit select
(implied read-only).
@param t transaction
@return true if non-locking autocommit select transaction. */
#define trx_is_autocommit_non_locking(t) \
((t)->auto_commit && (t)->will_lock == 0)
/**
Determine if the transaction is a non-locking autocommit select
with an explicit check for the read-only status.
@param t transaction
@return true if non-locking autocommit read-only transaction. */
#define trx_is_ac_nl_ro(t) \
((t)->read_only && trx_is_autocommit_non_locking((t)))
/**
Check transaction state */
#define check_trx_state(t) do { \
ut_ad(!trx_is_autocommit_non_locking((t))); \
switch ((t)->state) { \
case TRX_STATE_PREPARED: \
case TRX_STATE_PREPARED_RECOVERED: \
case TRX_STATE_ACTIVE: \
case TRX_STATE_COMMITTED_IN_MEMORY: \
continue; \
case TRX_STATE_NOT_STARTED: \
break; \
} \
ut_error; \
} while (0)
/** Check if transaction is free so that it can be re-initialized.
@param t transaction handle */
#define assert_trx_is_free(t) do { \
ut_ad(trx_state_eq((t), TRX_STATE_NOT_STARTED)); \
ut_ad(!(t)->id); \
ut_ad(!(t)->has_logged()); \
ut_ad(!(t)->is_referenced()); \
ut_ad(!(t)->is_wsrep()); \
ut_ad(!(t)->read_view.is_open()); \
ut_ad((t)->lock.wait_thr == NULL); \
ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \
ut_ad((t)->lock.table_locks.empty()); \
ut_ad(!(t)->autoinc_locks \
|| ib_vector_is_empty((t)->autoinc_locks)); \
ut_ad((t)->dict_operation == TRX_DICT_OP_NONE); \
} while(0)
#ifdef UNIV_DEBUG
/*******************************************************************//**
Assert that an autocommit non-locking select cannot be in the
rw_trx_hash and that it is a read-only transaction.
The transaction must have mysql_thd assigned. */
# define assert_trx_nonlocking_or_in_list(t) \
do { \
if (trx_is_autocommit_non_locking(t)) { \
trx_state_t t_state = (t)->state; \
ut_ad((t)->read_only); \
ut_ad(!(t)->is_recovered); \
ut_ad((t)->mysql_thd); \
ut_ad(t_state == TRX_STATE_NOT_STARTED \
|| t_state == TRX_STATE_ACTIVE); \
} else { \
check_trx_state(t); \
} \
} while (0)
#else /* UNIV_DEBUG */
/*******************************************************************//**
Assert that an autocommit non-locking slect cannot be in the
rw_trx_hash and that it is a read-only transaction.
The transaction must have mysql_thd assigned. */
# define assert_trx_nonlocking_or_in_list(trx) ((void)0)
#endif /* UNIV_DEBUG */
typedef std::vector<ib_lock_t*, ut_allocator<ib_lock_t*> > lock_list; typedef std::vector<ib_lock_t*, ut_allocator<ib_lock_t*> > lock_list;
/*******************************************************************//** /*******************************************************************//**
@ -985,16 +910,15 @@ public:
/*------------------------------*/ /*------------------------------*/
bool read_only; /*!< true if transaction is flagged bool read_only; /*!< true if transaction is flagged
as a READ-ONLY transaction. as a READ-ONLY transaction.
if auto_commit && will_lock == 0 if auto_commit && !will_lock
then it will be handled as a then it will be handled as a
AC-NL-RO-SELECT (Auto Commit Non-Locking AC-NL-RO-SELECT (Auto Commit Non-Locking
Read Only Select). A read only Read Only Select). A read only
transaction will not be assigned an transaction will not be assigned an
UNDO log. */ UNDO log. */
bool auto_commit; /*!< true if it is an autocommit */ bool auto_commit; /*!< true if it is an autocommit */
ib_uint32_t will_lock; /*!< Will acquire some locks. Increment bool will_lock; /*!< set to inform trx_start_low() that
each time we determine that a lock will the transaction may acquire locks */
be acquired by the MySQL layer. */
/*------------------------------*/ /*------------------------------*/
fts_trx_t* fts_trx; /*!< FTS information, or NULL if fts_trx_t* fts_trx; /*!< FTS information, or NULL if
transaction hasn't modified tables transaction hasn't modified tables
@ -1116,10 +1040,28 @@ public:
void free(); void free();
void assert_freed() const
{
ut_ad(state == TRX_STATE_NOT_STARTED);
ut_ad(!id);
ut_ad(!has_logged());
ut_ad(!const_cast<trx_t*>(this)->is_referenced());
ut_ad(!is_wsrep());
ut_ad(!read_view.is_open());
ut_ad(!lock.wait_thr);
ut_ad(UT_LIST_GET_LEN(lock.trx_locks) == 0);
ut_ad(lock.table_locks.empty());
ut_ad(!autoinc_locks || ib_vector_is_empty(autoinc_locks));
ut_ad(dict_operation == TRX_DICT_OP_NONE);
}
/** @return whether this is a non-locking autocommit transaction */
bool is_autocommit_non_locking() const { return auto_commit && !will_lock; }
private: private:
/** Assign a rollback segment for modifying temporary tables. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
trx_rseg_t* assign_temp_rseg(); trx_rseg_t *assign_temp_rseg();
}; };
/** /**

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2019, MariaDB Corporation. Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -49,11 +49,15 @@ trx_state_eq(
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_PREPARED_RECOVERED:
case TRX_STATE_COMMITTED_IN_MEMORY: case TRX_STATE_COMMITTED_IN_MEMORY:
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
return(trx->state == state); return(trx->state == state);
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
assert_trx_nonlocking_or_in_list(trx); if (trx->is_autocommit_non_locking()) {
ut_ad(!trx->is_recovered);
ut_ad(trx->read_only);
ut_ad(trx->mysql_thd);
}
return(state == trx->state); return(state == trx->state);
case TRX_STATE_NOT_STARTED: case TRX_STATE_NOT_STARTED:

View File

@ -1309,6 +1309,19 @@ wsrep_print_wait_locks(
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
#ifdef UNIV_DEBUG
/** Check transaction state */
static void check_trx_state(const trx_t *trx)
{
ut_ad(!trx->auto_commit || trx->will_lock);
const trx_state_t state= trx->state;
ut_ad(state == TRX_STATE_ACTIVE ||
state == TRX_STATE_PREPARED_RECOVERED ||
state == TRX_STATE_PREPARED ||
state == TRX_STATE_COMMITTED_IN_MEMORY);
}
#endif
/** Create a new record lock and inserts it to the lock queue, /** Create a new record lock and inserts it to the lock queue,
without checking for deadlocks or conflicts. without checking for deadlocks or conflicts.
@param[in] type_mode lock mode and wait flag; type will be replaced @param[in] type_mode lock mode and wait flag; type will be replaced
@ -3449,8 +3462,8 @@ lock_table_create(
ut_ad(table && trx); ut_ad(table && trx);
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx)); ut_ad(trx_mutex_own(trx));
ut_ad(trx->is_recovered || trx->state == TRX_STATE_ACTIVE);
check_trx_state(trx); ut_ad(!trx->auto_commit || trx->will_lock);
if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) { if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) {
++table->n_waiting_or_granted_auto_inc_locks; ++table->n_waiting_or_granted_auto_inc_locks;
@ -4841,7 +4854,8 @@ lock_rec_queue_validate(
ut_ad(!index || lock->index == index); ut_ad(!index || lock->index == index);
trx_mutex_enter(lock->trx); trx_mutex_enter(lock->trx);
ut_ad(!trx_is_ac_nl_ro(lock->trx)); ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
ut_ad(trx_state_eq(lock->trx, ut_ad(trx_state_eq(lock->trx,
TRX_STATE_COMMITTED_IN_MEMORY) TRX_STATE_COMMITTED_IN_MEMORY)
|| !lock_get_wait(lock) || !lock_get_wait(lock)
@ -4927,8 +4941,8 @@ func_exit:
for (lock = lock_rec_get_first(lock_sys.rec_hash, block, heap_no); for (lock = lock_rec_get_first(lock_sys.rec_hash, block, heap_no);
lock != NULL; lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) { lock = lock_rec_get_next_const(heap_no, lock)) {
ut_ad(!lock->trx->read_only
ut_ad(!trx_is_ac_nl_ro(lock->trx)); || !lock->trx->is_autocommit_non_locking());
ut_ad(!page_rec_is_metadata(rec)); ut_ad(!page_rec_is_metadata(rec));
if (index) { if (index) {
@ -5018,7 +5032,8 @@ loop:
} }
} }
ut_ad(!trx_is_ac_nl_ro(lock->trx)); ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
/* Only validate the record queues when this thread is not /* Only validate the record queues when this thread is not
holding a space->latch. */ holding a space->latch. */
@ -5085,7 +5100,8 @@ lock_rec_validate(
ib_uint64_t current; ib_uint64_t current;
ut_ad(!trx_is_ac_nl_ro(lock->trx)); ut_ad(!lock->trx->read_only
|| !lock->trx->is_autocommit_non_locking());
ut_ad(lock_get_type(lock) == LOCK_REC); ut_ad(lock_get_type(lock) == LOCK_REC);
current = ut_ull_create( current = ut_ull_create(
@ -6775,7 +6791,8 @@ DeadlockChecker::search()
ut_ad(m_start != NULL); ut_ad(m_start != NULL);
ut_ad(m_wait_lock != NULL); ut_ad(m_wait_lock != NULL);
check_trx_state(m_wait_lock->trx); ut_ad(!m_wait_lock->trx->auto_commit || m_wait_lock->trx->will_lock);
ut_d(check_trx_state(m_wait_lock->trx));
ut_ad(m_mark_start <= s_lock_mark_counter); ut_ad(m_mark_start <= s_lock_mark_counter);
/* Look at the locks ahead of wait_lock in the lock queue. */ /* Look at the locks ahead of wait_lock in the lock queue. */
@ -6935,7 +6952,8 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx)
{ {
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx)); ut_ad(trx_mutex_own(trx));
check_trx_state(trx); ut_ad(trx->state == TRX_STATE_ACTIVE);
ut_ad(!trx->auto_commit || trx->will_lock);
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
if (!innobase_deadlock_detect) { if (!innobase_deadlock_detect) {

View File

@ -1112,6 +1112,10 @@ os_file_lock(
int fd, int fd,
const char* name) const char* name)
{ {
if (my_disable_locking) {
return 0;
}
struct flock lk; struct flock lk;
lk.l_type = F_WRLCK; lk.l_type = F_WRLCK;

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2019, MariaDB Corporation. Copyright (c) 2018, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -235,7 +235,7 @@ void ReadView::open(trx_t *trx)
may get started, committed and purged meanwhile. It is acceptable as may get started, committed and purged meanwhile. It is acceptable as
well, since this view doesn't see it. well, since this view doesn't see it.
*/ */
if (trx_is_autocommit_non_locking(trx) && m_ids.empty() && if (trx->is_autocommit_non_locking() && m_ids.empty() &&
m_low_limit_id == trx_sys.get_max_trx_id()) m_low_limit_id == trx_sys.get_max_trx_id())
goto reopen; goto reopen;

View File

@ -935,8 +935,8 @@ row_ins_foreign_fill_virtual(
upd_field = update->fields + n_diff; upd_field = update->fields + n_diff;
upd_field->old_v_val = static_cast<dfield_t*>( upd_field->old_v_val = static_cast<dfield_t*>(
mem_heap_alloc(cascade->heap, mem_heap_alloc(update->heap,
sizeof *upd_field->old_v_val)); sizeof *upd_field->old_v_val));
dfield_copy(upd_field->old_v_val, vfield); dfield_copy(upd_field->old_v_val, vfield);

View File

@ -52,6 +52,11 @@ Created 12/27/1996 Heikki Tuuri
#include <algorithm> #include <algorithm>
#include <mysql/plugin.h> #include <mysql/plugin.h>
#include <mysql/service_wsrep.h> #include <mysql/service_wsrep.h>
#ifdef WITH_WSREP
#include "log.h"
#include "wsrep.h"
#endif /* WITH_WSREP */
/* What kind of latch and lock can we assume when the control comes to /* What kind of latch and lock can we assume when the control comes to
------------------------------------------------------------------- -------------------------------------------------------------------
@ -2466,34 +2471,30 @@ row_upd_sec_index_entry(
err = DB_SUCCESS; err = DB_SUCCESS;
break; break;
case DB_LOCK_WAIT: case DB_LOCK_WAIT:
if (UNIV_UNLIKELY(wsrep_debug)) {
ib::warn() << "WSREP: sec index FK lock wait"
<< " index " << index->name
<< " table " << index->table->name
<< " query " << wsrep_thd_query(trx->mysql_thd);
}
break;
case DB_DEADLOCK: case DB_DEADLOCK:
if (UNIV_UNLIKELY(wsrep_debug)) { case DB_LOCK_WAIT_TIMEOUT:
ib::warn() << "WSREP: sec index FK check fail for deadlock" WSREP_DEBUG("Foreign key check fail: "
<< " index " << index->name "%s on table %s index %s query %s",
<< " table " << index->table->name ut_strerr(err), index->name, index->table->name,
<< " query " << wsrep_thd_query(trx->mysql_thd); wsrep_thd_query(trx->mysql_thd));
}
break; break;
default: default:
ib::error() << "WSREP: referenced FK check fail: " << err WSREP_ERROR("Foreign key check fail: "
<< " index " << index->name "%s on table %s index %s query %s",
<< " table " << index->table->name ut_strerr(err), index->name, index->table->name,
<< " query " << wsrep_thd_query(trx->mysql_thd); wsrep_thd_query(trx->mysql_thd));
break; break;
} }
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
} }
#ifdef WITH_WSREP
ut_ad(err == DB_SUCCESS || err == DB_LOCK_WAIT
|| err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT);
#else
ut_ad(err == DB_SUCCESS); ut_ad(err == DB_SUCCESS);
#endif
if (referenced) { if (referenced) {
rec_offs* offsets = rec_get_offsets( rec_offs* offsets = rec_get_offsets(
@ -2804,17 +2805,21 @@ check_fk:
case DB_NO_REFERENCED_ROW: case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS; err = DB_SUCCESS;
break; break;
case DB_LOCK_WAIT:
case DB_DEADLOCK: case DB_DEADLOCK:
if (UNIV_UNLIKELY(wsrep_debug)) { case DB_LOCK_WAIT_TIMEOUT:
ib::warn() << "WSREP: sec index FK check fail for deadlock" WSREP_DEBUG("Foreign key check fail: "
<< " index " << index->name "%s on table %s index %s query %s",
<< " table " << index->table->name; ut_strerr(err), index->name, index->table->name,
} wsrep_thd_query(trx->mysql_thd));
goto err_exit; goto err_exit;
default: default:
ib::error() << "WSREP: referenced FK check fail: " << err WSREP_ERROR("Foreign key check fail: "
<< " index " << index->name "%s on table %s index %s query %s",
<< " table " << index->table->name; ut_strerr(err), index->name, index->table->name,
wsrep_thd_query(trx->mysql_thd));
goto err_exit; goto err_exit;
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
@ -3031,18 +3036,19 @@ row_upd_del_mark_clust_rec(
case DB_NO_REFERENCED_ROW: case DB_NO_REFERENCED_ROW:
err = DB_SUCCESS; err = DB_SUCCESS;
break; break;
case DB_LOCK_WAIT:
case DB_DEADLOCK: case DB_DEADLOCK:
if (UNIV_UNLIKELY(wsrep_debug)) { case DB_LOCK_WAIT_TIMEOUT:
ib::warn() << "WSREP: sec index FK check fail for deadlock" WSREP_DEBUG("Foreign key check fail: "
<< " index " << index->name "%d on table %s index %s query %s",
<< " table " << index->table->name; err, index->name, index->table->name,
} wsrep_thd_query(trx->mysql_thd));
break; break;
default: default:
ib::error() << "WSREP: referenced FK check fail: " << err WSREP_ERROR("Foreign key check fail: "
<< " index " << index->name "%d on table %s index %s query %s",
<< " table " << index->table->name; err, index->name, index->table->name,
wsrep_thd_query(trx->mysql_thd));
break; break;
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */

View File

@ -578,7 +578,7 @@ thd_done:
row->trx_is_read_only = trx->read_only; row->trx_is_read_only = trx->read_only;
row->trx_is_autocommit_non_locking = trx_is_autocommit_non_locking(trx); row->trx_is_autocommit_non_locking = trx->is_autocommit_non_locking();
return(TRUE); return(TRUE);
} }
@ -1233,7 +1233,24 @@ static void fetch_data_into_cache_low(trx_i_s_cache_t *cache, const trx_t *trx)
{ {
i_s_locks_row_t *requested_lock_row; i_s_locks_row_t *requested_lock_row;
assert_trx_nonlocking_or_in_list(trx); #ifdef UNIV_DEBUG
{
const trx_state_t state= trx->state;
if (trx->is_autocommit_non_locking())
{
ut_ad(trx->read_only);
ut_ad(!trx->is_recovered);
ut_ad(trx->mysql_thd);
ut_ad(state == TRX_STATE_NOT_STARTED || state == TRX_STATE_ACTIVE);
}
else
ut_ad(state == TRX_STATE_ACTIVE ||
state == TRX_STATE_PREPARED ||
state == TRX_STATE_PREPARED_RECOVERED ||
state == TRX_STATE_COMMITTED_IN_MEMORY);
}
#endif /* UNIV_DEBUG */
if (add_trx_relevant_locks_to_cache(cache, trx, &requested_lock_row)) if (add_trx_relevant_locks_to_cache(cache, trx, &requested_lock_row))
{ {

View File

@ -108,12 +108,18 @@ trx_rollback_to_savepoint_low(
heap = mem_heap_create(512); heap = mem_heap_create(512);
roll_node = roll_node_create(heap); roll_node = roll_node_create(heap);
ut_ad(!trx->in_rollback);
if (savept != NULL) { if (savept != NULL) {
roll_node->savept = savept; roll_node->savept = savept;
check_trx_state(trx); ut_ad(trx->mysql_thd);
ut_ad(!trx->is_recovered);
ut_ad(trx->state == TRX_STATE_ACTIVE);
} else { } else {
assert_trx_nonlocking_or_in_list(trx); ut_d(trx_state_t state = trx->state);
ut_ad(state == TRX_STATE_ACTIVE
|| state == TRX_STATE_PREPARED
|| state == TRX_STATE_PREPARED_RECOVERED);
} }
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
@ -219,7 +225,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
switch (trx->state) { switch (trx->state) {
case TRX_STATE_NOT_STARTED: case TRX_STATE_NOT_STARTED:
trx->will_lock = 0; trx->will_lock = false;
ut_ad(trx->mysql_thd); ut_ad(trx->mysql_thd);
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep = false; trx->wsrep = false;
@ -228,13 +234,14 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
ut_ad(trx->mysql_thd); ut_ad(trx->mysql_thd);
assert_trx_nonlocking_or_in_list(trx); ut_ad(!trx->is_recovered);
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
return(trx_rollback_for_mysql_low(trx)); return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_PREPARED: case TRX_STATE_PREPARED:
case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_PREPARED_RECOVERED:
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
if (trx->rsegs.m_redo.undo) { if (trx->has_logged_persistent()) {
/* The XA ROLLBACK of a XA PREPARE transaction /* The XA ROLLBACK of a XA PREPARE transaction
will consist of multiple mini-transactions. will consist of multiple mini-transactions.
@ -272,7 +279,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
return(trx_rollback_for_mysql_low(trx)); return(trx_rollback_for_mysql_low(trx));
case TRX_STATE_COMMITTED_IN_MEMORY: case TRX_STATE_COMMITTED_IN_MEMORY:
check_trx_state(trx); ut_ad(!trx->is_autocommit_non_locking());
break; break;
} }
@ -301,7 +308,9 @@ trx_rollback_last_sql_stat_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
case TRX_STATE_ACTIVE: case TRX_STATE_ACTIVE:
assert_trx_nonlocking_or_in_list(trx); ut_ad(trx->mysql_thd);
ut_ad(!trx->is_recovered);
ut_ad(!trx->is_autocommit_non_locking() || trx->read_only);
trx->op_info = "rollback of SQL statement"; trx->op_info = "rollback of SQL statement";

View File

@ -140,7 +140,7 @@ trx_init(
trx->auto_commit = false; trx->auto_commit = false;
trx->will_lock = 0; trx->will_lock = false;
trx->ddl = false; trx->ddl = false;
@ -345,13 +345,13 @@ trx_t *trx_create()
MEM_MAKE_DEFINED(trx, sizeof *trx); MEM_MAKE_DEFINED(trx, sizeof *trx);
#endif #endif
assert_trx_is_free(trx); trx->assert_freed();
mem_heap_t* heap; mem_heap_t* heap;
ib_alloc_t* alloc; ib_alloc_t* alloc;
/* We just got trx from pool, it should be non locking */ /* We just got trx from pool, it should be non locking */
ut_ad(trx->will_lock == 0); ut_ad(!trx->will_lock);
ut_ad(trx->state == TRX_STATE_NOT_STARTED); ut_ad(trx->state == TRX_STATE_NOT_STARTED);
ut_ad(!trx->rw_trx_hash_pins); ut_ad(!trx->rw_trx_hash_pins);
@ -395,7 +395,7 @@ void trx_t::free()
dict_operation= TRX_DICT_OP_NONE; dict_operation= TRX_DICT_OP_NONE;
trx_sys.deregister_trx(this); trx_sys.deregister_trx(this);
assert_trx_is_free(this); assert_freed();
trx_sys.rw_trx_hash.put_pins(this); trx_sys.rw_trx_hash.put_pins(this);
mysql_thd= NULL; mysql_thd= NULL;
@ -567,7 +567,7 @@ void trx_disconnect_prepared(trx_t *trx)
trx->is_recovered= true; trx->is_recovered= true;
trx->mysql_thd= NULL; trx->mysql_thd= NULL;
/* todo/fixme: suggest to do it at innodb prepare */ /* todo/fixme: suggest to do it at innodb prepare */
trx->will_lock= 0; trx->will_lock= false;
} }
/****************************************************************//** /****************************************************************//**
@ -917,11 +917,10 @@ void trx_t::remove_flush_observer()
/** Assign a rollback segment for modifying temporary tables. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
trx_rseg_t* trx_rseg_t *trx_t::assign_temp_rseg()
trx_t::assign_temp_rseg()
{ {
ut_ad(!rsegs.m_noredo.rseg); ut_ad(!rsegs.m_noredo.rseg);
ut_ad(!trx_is_autocommit_non_locking(this)); ut_ad(!is_autocommit_non_locking());
compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS)); compile_time_assert(ut_is_2pow(TRX_SYS_N_RSEGS));
/* Choose a temporary rollback segment between 0 and 127 /* Choose a temporary rollback segment between 0 and 127
@ -971,8 +970,8 @@ trx_start_low(
&& thd_trx_is_read_only(trx->mysql_thd)); && thd_trx_is_read_only(trx->mysql_thd));
if (!trx->auto_commit) { if (!trx->auto_commit) {
++trx->will_lock; trx->will_lock = true;
} else if (trx->will_lock == 0) { } else if (!trx->will_lock) {
trx->read_only = true; trx->read_only = true;
} }
@ -1015,7 +1014,7 @@ trx_start_low(
trx_sys.register_rw(trx); trx_sys.register_rw(trx);
} else { } else {
if (!trx_is_autocommit_non_locking(trx)) { if (!trx->is_autocommit_non_locking()) {
/* If this is a read-only transaction that is writing /* If this is a read-only transaction that is writing
to a temporary table then it needs a transaction id to a temporary table then it needs a transaction id
@ -1285,11 +1284,14 @@ trx_commit_in_memory(
trx->must_flush_log_later = false; trx->must_flush_log_later = false;
trx->read_view.close(); trx->read_view.close();
if (trx_is_autocommit_non_locking(trx)) { if (trx->is_autocommit_non_locking()) {
ut_ad(trx->id == 0); ut_ad(trx->id == 0);
ut_ad(trx->read_only); ut_ad(trx->read_only);
ut_ad(!trx->will_lock);
ut_a(!trx->is_recovered); ut_a(!trx->is_recovered);
ut_ad(trx->rsegs.m_redo.rseg == NULL); ut_ad(trx->rsegs.m_redo.rseg == NULL);
ut_ad(trx->mysql_thd);
ut_ad(trx->state == TRX_STATE_ACTIVE);
/* Note: We are asserting without holding the lock mutex. But /* Note: We are asserting without holding the lock mutex. But
that is OK because this transaction is not waiting and cannot that is OK because this transaction is not waiting and cannot
@ -1305,8 +1307,6 @@ trx_commit_in_memory(
and it cannot be removed from the trx_list and freed and it cannot be removed from the trx_list and freed
without first acquiring the trx_sys_t::mutex. */ without first acquiring the trx_sys_t::mutex. */
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT); MONITOR_INC(MONITOR_TRX_NL_RO_COMMIT);
DBUG_LOG("trx", "Autocommit in memory: " << trx); DBUG_LOG("trx", "Autocommit in memory: " << trx);
@ -1437,7 +1437,7 @@ trx_commit_in_memory(
trx->wsrep = false; trx->wsrep = false;
#endif #endif
assert_trx_is_free(trx); trx->assert_freed();
trx_init(trx); trx_init(trx);
@ -1452,8 +1452,6 @@ trx_commit_in_memory(
@param[in,out] mtr mini-transaction (NULL if no modifications) */ @param[in,out] mtr mini-transaction (NULL if no modifications) */
void trx_commit_low(trx_t* trx, mtr_t* mtr) void trx_commit_low(trx_t* trx, mtr_t* mtr)
{ {
assert_trx_nonlocking_or_in_list(trx);
ut_ad(!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
ut_ad(!mtr || mtr->is_active()); ut_ad(!mtr || mtr->is_active());
ut_d(bool aborted = trx->in_rollback ut_d(bool aborted = trx->in_rollback
&& trx->error_state == DB_DEADLOCK); && trx->error_state == DB_DEADLOCK);
@ -1462,23 +1460,15 @@ void trx_commit_low(trx_t* trx, mtr_t* mtr)
/* undo_no is non-zero if we're doing the final commit. */ /* undo_no is non-zero if we're doing the final commit. */
if (trx->fts_trx != NULL && trx->undo_no != 0) { if (trx->fts_trx != NULL && trx->undo_no != 0) {
dberr_t error; ut_a(!trx->is_autocommit_non_locking());
ut_a(!trx_is_autocommit_non_locking(trx));
error = fts_commit(trx);
/* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY /* FTS-FIXME: Temporarily tolerate DB_DUPLICATE_KEY
instead of dying. This is a possible scenario if there instead of dying. This is a possible scenario if there
is a crash between insert to DELETED table committing is a crash between insert to DELETED table committing
and transaction committing. The fix would be able to and transaction committing. The fix would be able to
return error from this function */ return error from this function */
if (error != DB_SUCCESS && error != DB_DUPLICATE_KEY) { if (dberr_t error = fts_commit(trx)) {
/* FTS-FIXME: once we can return values from this ut_a(error == DB_DUPLICATE_KEY);
function, we should do so and signal an error
instead of just dying. */
ut_error;
} }
} }
@ -1770,7 +1760,6 @@ trx_print_low(
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */ /*!< in: mem_heap_get_size(trx->lock.lock_heap) */
{ {
ibool newline; ibool newline;
const char* op_info;
fprintf(f, "TRANSACTION " TRX_ID_FMT, trx_get_id_for_print(trx)); fprintf(f, "TRANSACTION " TRX_ID_FMT, trx_get_id_for_print(trx));
@ -1797,9 +1786,7 @@ trx_print_low(
fprintf(f, ", state %lu", (ulong) trx->state); fprintf(f, ", state %lu", (ulong) trx->state);
ut_ad(0); ut_ad(0);
state_ok: state_ok:
const char* op_info = trx->op_info;
/* prevent a race condition */
op_info = trx->op_info;
if (*op_info) { if (*op_info) {
putc(' ', f); putc(' ', f);
@ -2270,7 +2257,7 @@ trx_start_internal_low(
/* Ensure it is not flagged as an auto-commit-non-locking /* Ensure it is not flagged as an auto-commit-non-locking
transaction. */ transaction. */
trx->will_lock = 1; trx->will_lock = true;
trx->internal = true; trx->internal = true;
@ -2286,7 +2273,7 @@ trx_start_internal_read_only_low(
/* Ensure it is not flagged as an auto-commit-non-locking /* Ensure it is not flagged as an auto-commit-non-locking
transaction. */ transaction. */
trx->will_lock = 1; trx->will_lock = true;
trx->internal = true; trx->internal = true;
@ -2307,13 +2294,7 @@ trx_start_for_ddl_low(
the data dictionary will be locked in crash recovery. */ the data dictionary will be locked in crash recovery. */
trx_set_dict_operation(trx, op); trx_set_dict_operation(trx, op);
/* Ensure it is not flagged as an auto-commit-non-locking
transation. */
trx->will_lock = 1;
trx->ddl= true; trx->ddl= true;
trx_start_internal_low(trx); trx_start_internal_low(trx);
return; return;
@ -2340,7 +2321,7 @@ trx_set_rw_mode(
trx_t* trx) /*!< in/out: transaction that is RW */ trx_t* trx) /*!< in/out: transaction that is RW */
{ {
ut_ad(trx->rsegs.m_redo.rseg == 0); ut_ad(trx->rsegs.m_redo.rseg == 0);
ut_ad(!trx_is_autocommit_non_locking(trx)); ut_ad(!trx->is_autocommit_non_locking());
ut_ad(!trx->read_only); ut_ad(!trx->read_only);
ut_ad(trx->id == 0); ut_ad(trx->id == 0);

View File

@ -1,3 +1,6 @@
# The test can take very long time with valgrind
--source include/not_valgrind.inc
--disable_warnings --disable_warnings
DROP TABLE IF EXISTS rsb, rsb_graph; DROP TABLE IF EXISTS rsb, rsb_graph;
--enable_warnings --enable_warnings

View File

@ -7266,7 +7266,7 @@ int ha_tokudb::create(
// in the database directory, so automatic filename-based // in the database directory, so automatic filename-based
// discover_table_names() doesn't work either. So, it must force .frm // discover_table_names() doesn't work either. So, it must force .frm
// file to disk. // file to disk.
form->s->write_frm_image(); error= form->s->write_frm_image();
#endif #endif
#if defined(TOKU_INCLUDE_OPTION_STRUCTS) && TOKU_INCLUDE_OPTION_STRUCTS #if defined(TOKU_INCLUDE_OPTION_STRUCTS) && TOKU_INCLUDE_OPTION_STRUCTS
@ -7298,8 +7298,8 @@ int ha_tokudb::create(
#endif // defined(TOKU_INCLUDE_OPTION_STRUCTS) && TOKU_INCLUDE_OPTION_STRUCTS #endif // defined(TOKU_INCLUDE_OPTION_STRUCTS) && TOKU_INCLUDE_OPTION_STRUCTS
const toku_compression_method compression_method = const toku_compression_method compression_method =
row_format_to_toku_compression_method(row_format); row_format_to_toku_compression_method(row_format);
bool create_from_engine = (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE); bool create_from_engine = (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
if (error) { goto cleanup; }
if (create_from_engine) { if (create_from_engine) {
// table already exists, nothing to do // table already exists, nothing to do
error = 0; error = 0;

View File

@ -0,0 +1,10 @@
#
# 10.2 Test
#
# MDEV-23786: Assertion `!is_set() || (m_status == DA_OK_BULK &&
# is_bulk_op())'failed for TokuDB engine CREATE TABLE
#
set default_storage_engine='tokudb';
CREATE TABLE _uppercase.t (a INT) ENGINE=TokuDB;
ERROR 42000: Unknown database '_uppercase'
# End of 10.2 Test

View File

@ -0,0 +1,14 @@
source include/have_tokudb.inc;
--echo #
--echo # 10.2 Test
--echo #
--echo # MDEV-23786: Assertion `!is_set() || (m_status == DA_OK_BULK &&
--echo # is_bulk_op())'failed for TokuDB engine CREATE TABLE
--echo #
set default_storage_engine='tokudb';
--error ER_BAD_DB_ERROR
CREATE TABLE _uppercase.t (a INT) ENGINE=TokuDB;
--echo # End of 10.2 Test