diff options
-rw-r--r-- | include/intrusive_list.h | 190 | ||||
-rw-r--r-- | mysql-test/main/group_by.result | 6 | ||||
-rw-r--r-- | mysql-test/main/group_by.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result | 26 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test | 10 | ||||
-rw-r--r-- | mysql-test/suite/wsrep/r/variables.result | 9 | ||||
-rw-r--r-- | mysql-test/suite/wsrep/t/variables.test | 4 | ||||
-rw-r--r-- | storage/innobase/fil/fil0crypt.cc | 2 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 131 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 45 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 15 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 29 | ||||
-rw-r--r-- | storage/innobase/include/dyn0buf.h | 99 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 29 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 9 |
15 files changed, 412 insertions, 194 deletions
diff --git a/include/intrusive_list.h b/include/intrusive_list.h new file mode 100644 index 00000000000..d745c6c6c62 --- /dev/null +++ b/include/intrusive_list.h @@ -0,0 +1,190 @@ +/* + Copyright (c) 2019, 2020, MariaDB + + 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 Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +*/ + +#pragma once + +#include <cstddef> +#include <iterator> + +namespace intrusive +{ + +// Derive your class from this struct to insert to a linked list. +template <class Tag= void> struct list_node +{ + list_node(list_node *next= NULL, list_node *prev= NULL) + : next(next), prev(prev) + { + } + + list_node *next; + list_node *prev; +}; + +// Modelled after std::list<T> +template <class T, class Tag= void> class list +{ +public: + typedef list_node<Tag> ListNode; + class Iterator; + + // All containers in C++ should define these types to implement generic + // container interface. + typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef T *pointer; + typedef const T *const_pointer; + typedef Iterator iterator; + typedef Iterator const_iterator; /* FIXME */ + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const iterator> const_reverse_iterator; + + class Iterator + { + public: + // All iterators in C++ should define these types to implement generic + // iterator interface. + typedef std::bidirectional_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T *pointer; + typedef T &reference; + + Iterator(ListNode *node) : node_(node) {} + + Iterator &operator++() + { + node_= node_->next; + return *this; + } + Iterator operator++(int) + { + Iterator tmp(*this); + operator++(); + return tmp; + } + + Iterator &operator--() + { + node_= node_->prev; + return *this; + } + Iterator operator--(int) + { + Iterator tmp(*this); + operator--(); + return tmp; + } + + reference operator*() { return *static_cast<pointer>(node_); } + pointer operator->() { return static_cast<pointer>(node_); } + + bool operator==(const Iterator &rhs) { return node_ == rhs.node_; } + bool operator!=(const Iterator &rhs) { return !(*this == rhs); } + + private: + ListNode *node_; + + friend class list; + }; + + list() : sentinel_(&sentinel_, &sentinel_), size_(0) {} + + reference front() { return *begin(); } + reference back() { return *--end(); } + const_reference front() const { return *begin(); } + const_reference back() const { return *--end(); } + + iterator begin() { return iterator(sentinel_.next); } + const_iterator begin() const + { + return iterator(const_cast<ListNode *>(sentinel_.next)); + } + iterator end() { return iterator(&sentinel_); } + const_iterator end() const + { + return iterator(const_cast<ListNode *>(&sentinel_)); + } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return reverse_iterator(begin()); } + + bool empty() const { return size_ == 0; } + size_type size() const { return size_; } + + void clear() + { + sentinel_.next= &sentinel_; + sentinel_.prev= &sentinel_; + size_= 0; + } + + iterator insert(iterator pos, reference value) + { + ListNode *curr= pos.node_; + ListNode *prev= pos.node_->prev; + + prev->next= &value; + curr->prev= &value; + + static_cast<ListNode &>(value).prev= prev; + static_cast<ListNode &>(value).next= curr; + + ++size_; + return iterator(&value); + } + + iterator erase(iterator pos) + { + ListNode *prev= pos.node_->prev; + ListNode *next= pos.node_->next; + + prev->next= next; + next->prev= prev; + + // This is not required for list functioning. But maybe it'll prevent bugs + // and ease debugging. + ListNode *curr= pos.node_; + curr->prev= NULL; + curr->next= NULL; + + --size_; + return next; + } + + void push_back(reference value) { insert(end(), value); } + void pop_back() { erase(end()); } + + void push_front(reference value) { insert(begin(), value); } + void pop_front() { erase(begin()); } + + // STL version is O(n) but this is O(1) because an element can't be inserted + // several times in the same intrusive list. + void remove(reference value) { erase(iterator(&value)); } + +private: + ListNode sentinel_; + size_type size_; +}; + +} // namespace intrusive diff --git a/mysql-test/main/group_by.result b/mysql-test/main/group_by.result index d72836141ee..d5d987b9d6d 100644 --- a/mysql-test/main/group_by.result +++ b/mysql-test/main/group_by.result @@ -2838,16 +2838,16 @@ drop table t1; # MDEV-20922: Adding an order by changes the query results # CREATE TABLE t1(a int, b int); -INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200); +INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200), (5, 200); create view v1 as select a, b+1 as x from t1; SELECT x, COUNT(DISTINCT a) AS y FROM v1 GROUP BY x ORDER BY y; x y 101 2 -201 2 +201 3 SELECT b+1 AS x, COUNT(DISTINCT a) AS y FROM t1 GROUP BY x ORDER BY y; x y 101 2 -201 2 +201 3 drop view v1; drop table t1; # diff --git a/mysql-test/main/group_by.test b/mysql-test/main/group_by.test index 091a7de26fe..fdebe058043 100644 --- a/mysql-test/main/group_by.test +++ b/mysql-test/main/group_by.test @@ -1952,7 +1952,7 @@ drop table t1; --echo # CREATE TABLE t1(a int, b int); -INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200); +INSERT INTO t1 values (1, 100), (2, 200), (3, 100), (4, 200), (5, 200); create view v1 as select a, b+1 as x from t1; diff --git a/mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result b/mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result index c175f8ee915..fba209dd2b5 100644 --- a/mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result +++ b/mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result @@ -16,6 +16,30 @@ col_1 TEXT ) ENGINE=INNODB ROW_FORMAT=COMPACT; Warnings: Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +TRUNCATE TABLE t1; +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +ALTER TABLE t1 FORCE; +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +SET innodb_strict_mode = ON; +TRUNCATE TABLE t1; +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. +ALTER TABLE t1 FORCE; +Warnings: +Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. DROP TABLE t1; SET @@global.log_warnings = 2; -SET innodb_strict_mode = 1; diff --git a/mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test b/mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test index 35b86cc4c46..af6c15e0e6b 100644 --- a/mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test +++ b/mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test @@ -18,7 +18,15 @@ CREATE TABLE t1 ( ,col_10 TEXT ,col_11 TEXT ) ENGINE=INNODB ROW_FORMAT=COMPACT; +--enable_warnings +TRUNCATE TABLE t1; +OPTIMIZE TABLE t1; +ALTER TABLE t1 FORCE; +SET innodb_strict_mode = ON; +TRUNCATE TABLE t1; +OPTIMIZE TABLE t1; +ALTER TABLE t1 FORCE; DROP TABLE t1; +--disable_warnings SET @@global.log_warnings = 2; -SET innodb_strict_mode = 1; diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 4cd8595177f..db5ce3d2a77 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -170,6 +170,9 @@ SELECT @@global.wsrep_slave_threads; SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address +SELECT @@global.wsrep_on; +@@global.wsrep_on +1 SHOW STATUS LIKE 'threads_connected'; Variable_name Value Threads_connected 1 @@ -183,6 +186,9 @@ SELECT @@global.wsrep_provider; SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address +SELECT @@global.wsrep_on; +@@global.wsrep_on +1 SHOW STATUS LIKE 'threads_connected'; Variable_name Value Threads_connected 1 @@ -210,6 +216,9 @@ SELECT @@global.wsrep_provider; SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address gcomm:// +SELECT @@global.wsrep_on; +@@global.wsrep_on +1 SHOW STATUS LIKE 'threads_connected'; Variable_name Value Threads_connected 1 diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 9209079871c..cf5280fa688 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -79,6 +79,7 @@ eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; SELECT @@global.wsrep_provider; SELECT @@global.wsrep_slave_threads; SELECT @@global.wsrep_cluster_address; +SELECT @@global.wsrep_on; SHOW STATUS LIKE 'threads_connected'; SHOW STATUS LIKE 'wsrep_thread_count'; --echo @@ -90,6 +91,7 @@ eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; SELECT @@global.wsrep_cluster_address; +SELECT @@global.wsrep_on; SHOW STATUS LIKE 'threads_connected'; SHOW STATUS LIKE 'wsrep_thread_count'; --echo @@ -112,6 +114,7 @@ SELECT VARIABLE_VALUE AS EXPECT_2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VA --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; SELECT @@global.wsrep_cluster_address; +SELECT @@global.wsrep_on; SHOW STATUS LIKE 'threads_connected'; SHOW STATUS LIKE 'wsrep_thread_count'; --echo @@ -134,6 +137,7 @@ SHOW STATUS LIKE 'threads_connected'; # set wsrep_on=0; set wsrep_on=1; +--source include/wait_until_connected_again.inc create user test@localhost; connect con1,localhost,test; set auto_increment_increment=10; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 7833abca9c5..2e5f56b87dc 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -2556,7 +2556,7 @@ static void fil_crypt_rotation_list_fill() } } - UT_LIST_ADD_LAST(fil_system.rotation_list, space); + fil_system.rotation_list.push_back(*space); } } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 7d6edeb8752..457f677df50 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2020, MariaDB Corporation. 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 @@ -760,9 +760,7 @@ skip_flush: if (space->is_in_unflushed_spaces() && fil_space_is_flushed(space)) { - UT_LIST_REMOVE( - fil_system.unflushed_spaces, - space); + fil_system.unflushed_spaces.remove(*space); } } @@ -1056,7 +1054,7 @@ fil_node_close_to_free( } else if (space->is_in_unflushed_spaces() && fil_space_is_flushed(space)) { - UT_LIST_REMOVE(fil_system.unflushed_spaces, space); + fil_system.unflushed_spaces.remove(*space); } node->close(); @@ -1079,13 +1077,11 @@ fil_space_detach( if (space->is_in_unflushed_spaces()) { ut_ad(!fil_buffering_disabled(space)); - - UT_LIST_REMOVE(fil_system.unflushed_spaces, space); + fil_system.unflushed_spaces.remove(*space); } if (space->is_in_rotation_list()) { - - UT_LIST_REMOVE(fil_system.rotation_list, space); + fil_system.rotation_list.remove(*space); } UT_LIST_REMOVE(fil_system.space_list, space); @@ -1300,7 +1296,7 @@ fil_space_create( || srv_encrypt_tables)) { /* Key rotation is not enabled, need to inform background encryption threads. */ - UT_LIST_ADD_LAST(fil_system.rotation_list, space); + fil_system.rotation_list.push_back(*space); mutex_exit(&fil_system.mutex); os_event_set(fil_crypt_threads_event); } else { @@ -1636,7 +1632,7 @@ void fil_system_t::close() { ut_ad(this == &fil_system); ut_a(!UT_LIST_GET_LEN(LRU)); - ut_a(!UT_LIST_GET_LEN(unflushed_spaces)); + ut_a(unflushed_spaces.empty()); ut_a(!UT_LIST_GET_LEN(space_list)); ut_ad(!sys_space); ut_ad(!temp_space); @@ -4037,8 +4033,8 @@ fil_node_complete_io(fil_node_t* node, const IORequest& type) node->needs_flush = true; if (!node->space->is_in_unflushed_spaces()) { - UT_LIST_ADD_FIRST(fil_system.unflushed_spaces, - node->space); + fil_system.unflushed_spaces.push_front( + *node->space); } } } @@ -4491,7 +4487,6 @@ void fil_flush_file_spaces( fil_type_t purpose) { - fil_space_t* space; ulint* space_ids; ulint n_space_ids; @@ -4499,30 +4494,25 @@ fil_flush_file_spaces( mutex_enter(&fil_system.mutex); - n_space_ids = UT_LIST_GET_LEN(fil_system.unflushed_spaces); + n_space_ids = fil_system.unflushed_spaces.size(); if (n_space_ids == 0) { mutex_exit(&fil_system.mutex); return; } - /* Assemble a list of space ids to flush. Previously, we - traversed fil_system.unflushed_spaces and called UT_LIST_GET_NEXT() - on a space that was just removed from the list by fil_flush(). - Thus, the space could be dropped and the memory overwritten. */ space_ids = static_cast<ulint*>( ut_malloc_nokey(n_space_ids * sizeof(*space_ids))); n_space_ids = 0; - for (space = UT_LIST_GET_FIRST(fil_system.unflushed_spaces); - space; - space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { + for (intrusive::list<fil_space_t, unflushed_spaces_tag_t>::iterator it + = fil_system.unflushed_spaces.begin(), + end = fil_system.unflushed_spaces.end(); + it != end; ++it) { - if (space->purpose == purpose - && !space->is_stopping()) { - - space_ids[n_space_ids++] = space->id; + if (it->purpose == purpose && !it->is_stopping()) { + space_ids[n_space_ids++] = it->id; } } @@ -5030,8 +5020,8 @@ fil_space_remove_from_keyrotation(fil_space_t* space) ut_ad(space); if (!space->referenced() && space->is_in_rotation_list()) { - ut_a(UT_LIST_GET_LEN(fil_system.rotation_list) > 0); - UT_LIST_REMOVE(fil_system.rotation_list, space); + ut_a(!fil_system.rotation_list.empty()); + fil_system.rotation_list.remove(*space); } } @@ -5047,53 +5037,45 @@ If NULL, use the first fil_space_t on fil_system.space_list. @param[in] key_version key version of the key state thread @return pointer to the next fil_space_t. @retval NULL if this was the last */ -fil_space_t* -fil_system_t::keyrotate_next( - fil_space_t* prev_space, - bool recheck, - uint key_version) +fil_space_t *fil_system_t::keyrotate_next(fil_space_t *prev_space, + bool recheck, uint key_version) { - mutex_enter(&fil_system.mutex); + mutex_enter(&fil_system.mutex); - /* If one of the encryption threads already started the encryption - of the table then don't remove the unencrypted spaces from - rotation list + /* If one of the encryption threads already started the encryption + of the table then don't remove the unencrypted spaces from rotation list - If there is a change in innodb_encrypt_tables variables value then - don't remove the last processed tablespace from the rotation list. */ - const bool remove = ((!recheck || prev_space->crypt_data) - && (!key_version == !srv_encrypt_tables)); + If there is a change in innodb_encrypt_tables variables value then + don't remove the last processed tablespace from the rotation list. */ + const bool remove= (!recheck || prev_space->crypt_data) && + !key_version == !srv_encrypt_tables; + intrusive::list<fil_space_t, rotation_list_tag_t>::iterator it= + prev_space == NULL ? fil_system.rotation_list.end() : prev_space; - fil_space_t* space = prev_space; + if (it == fil_system.rotation_list.end()) + it= fil_system.rotation_list.begin(); + else + { + /* Move on to the next fil_space_t */ + prev_space->release(); - if (prev_space == NULL) { - space = UT_LIST_GET_FIRST(fil_system.rotation_list); + ++it; - /* We can trust that space is not NULL because we - checked list length above */ - } else { - /* Move on to the next fil_space_t */ - space->release(); + while (it != fil_system.rotation_list.end() && + (UT_LIST_GET_LEN(it->chain) == 0 || it->is_stopping())) + ++it; - space = UT_LIST_GET_NEXT(rotation_list, space); + if (remove) + fil_space_remove_from_keyrotation(prev_space); + } - while (space != NULL - && (UT_LIST_GET_LEN(space->chain) == 0 - || space->is_stopping())) { - space = UT_LIST_GET_NEXT(rotation_list, space); - } + fil_space_t *space= it == fil_system.rotation_list.end() ? NULL : &*it; - if (remove) { - fil_space_remove_from_keyrotation(prev_space); - } - } - - if (space != NULL) { - space->acquire(); - } + if (space) + space->acquire(); - mutex_exit(&fil_system.mutex); - return(space); + mutex_exit(&fil_system.mutex); + return space; } /** Determine the block size of the data file. @@ -5148,18 +5130,21 @@ fil_space_found_by_id( /** Checks that this tablespace in a list of unflushed tablespaces. @return true if in a list */ -bool fil_space_t::is_in_unflushed_spaces() const { - ut_ad(mutex_own(&fil_system.mutex)); +bool fil_space_t::is_in_unflushed_spaces() const +{ + ut_ad(mutex_own(&fil_system.mutex)); - return fil_system.unflushed_spaces.start == this - || unflushed_spaces.next || unflushed_spaces.prev; + return static_cast<const intrusive::list_node<unflushed_spaces_tag_t> *>( + this) + ->next; } /** Checks that this tablespace needs key rotation. @return true if in a rotation list */ -bool fil_space_t::is_in_rotation_list() const { - ut_ad(mutex_own(&fil_system.mutex)); +bool fil_space_t::is_in_rotation_list() const +{ + ut_ad(mutex_own(&fil_system.mutex)); - return fil_system.rotation_list.start == this || rotation_list.next - || rotation_list.prev; + return static_cast<const intrusive::list_node<rotation_list_tag_t> *>(this) + ->next; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8c139a6facb..0c60348a9ed 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4,7 +4,7 @@ Copyright (c) 2000, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3415,17 +3415,6 @@ trx_is_interrupted( return(trx && trx->mysql_thd && thd_kill_level(trx->mysql_thd)); } -/**********************************************************************//** -Determines if the currently running transaction is in strict mode. -@return TRUE if strict */ -ibool -trx_is_strict( -/*==========*/ - trx_t* trx) /*!< in: transaction */ -{ - return(trx && trx->mysql_thd && THDVAR(trx->mysql_thd, strict_mode)); -} - /**************************************************************//** Resets some fields of a m_prebuilt struct. The template is used in fast retrieval of just those column values MySQL needs in its processing. */ @@ -11800,6 +11789,12 @@ create_table_info_t::parse_table_name( DBUG_RETURN(0); } +/** @return whether innodb_strict_mode is active */ +bool ha_innobase::is_innodb_strict_mode(THD *thd) +{ + return THDVAR(thd, strict_mode); +} + /** Determine InnoDB table flags. If strict_mode=OFF, this will adjust the flags to what should be assumed. @retval true on success @@ -12515,7 +12510,9 @@ int create_table_info_t::create_table(bool create_fk) } } - if (!row_size_is_acceptable(*m_table)) { + /* In TRUNCATE TABLE, we will merely warn about the maximum + row size being too large. */ + if (!row_size_is_acceptable(*m_table, create_fk)) { DBUG_RETURN(convert_error_code_to_mysql( DB_TOO_BIG_RECORD, m_flags, NULL)); } @@ -12524,18 +12521,12 @@ int create_table_info_t::create_table(bool create_fk) } bool create_table_info_t::row_size_is_acceptable( - const dict_table_t &table) const + const dict_table_t &table, bool strict) const { for (dict_index_t *index= dict_table_get_first_index(&table); index; index= dict_table_get_next_index(index)) - { - - if (!row_size_is_acceptable(*index)) - { + if (!row_size_is_acceptable(*index, strict)) return false; - } - } - return true; } @@ -12713,7 +12704,7 @@ static void ib_warn_row_too_big(THD *thd, const dict_table_t *table) } bool create_table_info_t::row_size_is_acceptable( - const dict_index_t &index) const + const dict_index_t &index, bool strict) const { if ((index.type & DICT_FTS) || index.table->is_system_db) { @@ -12722,7 +12713,7 @@ bool create_table_info_t::row_size_is_acceptable( return true; } - const bool strict= THDVAR(m_thd, strict_mode); + const bool innodb_strict_mode= THDVAR(m_thd, strict_mode); dict_index_t::record_size_info_t info= index.record_size_info(); if (info.row_is_too_big()) @@ -12734,9 +12725,9 @@ bool create_table_info_t::row_size_is_acceptable( const dict_field_t *field= dict_index_get_nth_field(&index, idx); ut_ad((!field->name) == field->col->is_dropped()); - if (strict || global_system_variables.log_warnings > 2) + if (innodb_strict_mode || global_system_variables.log_warnings > 2) { - ib::error_or_warn eow(strict); + ib::error_or_warn eow(strict && innodb_strict_mode); if (field->name) eow << "Cannot add field " << field->name << " in table "; else @@ -12747,10 +12738,8 @@ bool create_table_info_t::row_size_is_acceptable( << info.max_leaf_size << " bytes) for a record on index leaf page."; } - if (strict) - { + if (strict && innodb_strict_mode) return false; - } ib_warn_row_too_big(m_thd, index.table); } diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index e00003c30a6..79e3bdb3d13 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -439,6 +439,13 @@ public: can_convert_blob(const Field_blob* field, const Column_definition& new_field) const override; + /** @return whether innodb_strict_mode is active */ + static bool is_innodb_strict_mode(THD* thd); + + /** @return whether innodb_strict_mode is active */ + bool is_innodb_strict_mode() + { return is_innodb_strict_mode(m_user_thd); } + protected: dberr_t innobase_get_autoinc(ulonglong* value); dberr_t innobase_lock_autoinc(); @@ -679,9 +686,11 @@ public: void allocate_trx(); /** Checks that every index have sane size. Depends on strict mode */ - bool row_size_is_acceptable(const dict_table_t& table) const; + bool row_size_is_acceptable(const dict_table_t& table, + bool strict) const; /** Checks that given index have sane size. Depends on strict mode */ - bool row_size_is_acceptable(const dict_index_t& index) const; + bool row_size_is_acceptable(const dict_index_t& index, + bool strict) const; /** Determines InnoDB table flags. If strict_mode=OFF, this will adjust the flags to what should be assumed. diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 6da14429f0d..741a94ae42b 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -124,6 +124,15 @@ static const alter_table_operations INNOBASE_ALTER_NOCREATE = ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX | ALTER_DROP_UNIQUE_INDEX; +/** Operations that InnoDB cares about and can perform without validation */ +static const alter_table_operations INNOBASE_ALTER_NOVALIDATE + = INNOBASE_ALTER_NOCREATE + | ALTER_VIRTUAL_COLUMN_ORDER + | ALTER_COLUMN_NAME + | INNOBASE_FOREIGN_OPERATIONS + | ALTER_COLUMN_UNVERSIONED + | ALTER_DROP_VIRTUAL_COLUMN; + /** Operations that InnoDB cares about and can perform without rebuild */ static const alter_table_operations INNOBASE_ALTER_NOREBUILD = INNOBASE_ONLINE_CREATE @@ -2330,7 +2339,7 @@ next_column: const bool supports_instant = instant_alter_column_possible( *m_prebuilt->table, ha_alter_info, table, altered_table, - trx_is_strict(m_prebuilt->trx)); + is_innodb_strict_mode()); if (add_drop_v_cols) { ulonglong flags = ha_alter_info->handler_flags; @@ -6526,7 +6535,7 @@ new_clustered_failed: if (ctx->need_rebuild() && instant_alter_column_possible( *user_table, ha_alter_info, old_table, altered_table, - trx_is_strict(ctx->trx))) { + ha_innobase::is_innodb_strict_mode(ctx->trx->mysql_thd))) { for (uint a = 0; a < ctx->num_to_add_index; a++) { ctx->add_index[a]->table = ctx->new_table; error = dict_index_add_to_cache( @@ -6759,7 +6768,15 @@ error_handling_drop_uncached_1: } ctx->add_index[a] = index; - if (!info.row_size_is_acceptable(*index)) { + /* For ALTER TABLE...FORCE or OPTIMIZE TABLE, + we may only issue warnings, because there will + be no schema change from the user perspective. */ + if (!info.row_size_is_acceptable( + *index, + !!(ha_alter_info->handler_flags + & ~(INNOBASE_INPLACE_IGNORE + | INNOBASE_ALTER_NOVALIDATE + | ALTER_RECREATE_TABLE)))) { error = DB_TOO_BIG_RECORD; goto error_handling_drop_uncached_1; } @@ -6860,7 +6877,7 @@ error_handling_drop_uncached: DBUG_ASSERT(index != ctx->add_index[a]); } ctx->add_index[a]= index; - if (!info.row_size_is_acceptable(*index)) { + if (!info.row_size_is_acceptable(*index, true)) { error = DB_TOO_BIG_RECORD; goto error_handling_drop_uncached; } @@ -6913,7 +6930,7 @@ error_handling_drop_uncached: } } } else if (ctx->is_instant() - && !info.row_size_is_acceptable(*user_table)) { + && !info.row_size_is_acceptable(*user_table, true)) { error = DB_TOO_BIG_RECORD; goto error_handling; } diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h index db809c908ae..b5da367bae1 100644 --- a/storage/innobase/include/dyn0buf.h +++ b/storage/innobase/include/dyn0buf.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -29,7 +29,8 @@ Created 2013-03-16 Sunny Bains #include "mem0mem.h" #include "dyn0types.h" -#include "ut0lst.h" +#include "intrusive_list.h" + /** Class that manages dynamic buffers. It uses a UT_LIST of mtr_buf_t::block_t instances. We don't use STL containers in @@ -40,17 +41,11 @@ backend for the custom allocator because we would like the data in the blocks to be contiguous. */ class mtr_buf_t { public: - - class block_t; - - typedef UT_LIST_NODE_T(block_t) block_node_t; - typedef UT_LIST_BASE_NODE_T(block_t) block_list_t; - /** SIZE - sizeof(m_node) + sizeof(m_used) */ enum { MAX_DATA_SIZE = DYN_ARRAY_DATA_SIZE - - sizeof(block_node_t) + sizeof(ib_uint32_t) }; + - sizeof(intrusive::list_node<>) + sizeof(uint32_t) }; - class block_t { + class block_t : public intrusive::list_node<> { public: block_t() @@ -158,9 +153,6 @@ public: /** Storage */ byte m_data[MAX_DATA_SIZE]; - /** Doubly linked list node. */ - block_node_t m_node; - /** number of data bytes used in this block; DYN_BLOCK_FULL_FLAG is set when the block becomes full */ uint32_t m_used; @@ -168,13 +160,14 @@ public: friend class mtr_buf_t; }; + typedef intrusive::list<block_t> list_t; + /** Default constructor */ mtr_buf_t() : m_heap(), m_size() { - UT_LIST_INIT(m_list, &block_t::m_node); push_back(&m_first_block); } @@ -192,11 +185,11 @@ public: m_heap = NULL; /* Initialise the list and add the first block. */ - UT_LIST_INIT(m_list, &block_t::m_node); - push_back(&m_first_block); + m_list.clear(); + m_list.push_back(m_first_block); } else { m_first_block.init(); - ut_ad(UT_LIST_GET_LEN(m_list) == 1); + ut_ad(m_list.size() == 1); } m_size = 0; @@ -228,7 +221,7 @@ public: @param ptr end of used space */ void close(const byte* ptr) { - ut_ad(UT_LIST_GET_LEN(m_list) > 0); + ut_ad(!m_list.empty()); block_t* block = back(); m_size -= block->used(); @@ -310,11 +303,10 @@ public: #ifdef UNIV_DEBUG ulint total_size = 0; - for (const block_t* block = UT_LIST_GET_FIRST(m_list); - block != NULL; - block = UT_LIST_GET_NEXT(m_node, block)) { - - total_size += block->used(); + for (typename list_t::iterator it = m_list.begin(), + end = m_list.end(); + it != end; ++it) { + total_size += it->used(); } ut_ad(total_size == m_size); @@ -328,12 +320,12 @@ public: template <typename Functor> bool for_each_block(Functor& functor) const { - for (const block_t* block = UT_LIST_GET_FIRST(m_list); - block != NULL; - block = UT_LIST_GET_NEXT(m_node, block)) { + for (typename list_t::iterator it = m_list.begin(), + end = m_list.end(); + it != end; ++it) { - if (!functor(block)) { - return(false); + if (!functor(&*it)) { + return false; } } @@ -346,12 +338,12 @@ public: template <typename Functor> bool for_each_block_in_reverse(Functor& functor) const { - for (block_t* block = UT_LIST_GET_LAST(m_list); - block != NULL; - block = UT_LIST_GET_PREV(m_node, block)) { + for (typename list_t::reverse_iterator it = m_list.rbegin(), + end = m_list.rend(); + it != end; ++it) { - if (!functor(block)) { - return(false); + if (!functor(&*it)) { + return false; } } @@ -364,12 +356,12 @@ public: template <typename Functor> bool for_each_block_in_reverse(const Functor& functor) const { - for (block_t* block = UT_LIST_GET_LAST(m_list); - block != NULL; - block = UT_LIST_GET_PREV(m_node, block)) { + for (typename list_t::reverse_iterator it = m_list.rbegin(), + end = m_list.rend(); + it != end; ++it) { - if (!functor(block)) { - return(false); + if (!functor(&*it)) { + return false; } } @@ -381,8 +373,7 @@ public: block_t* front() MY_ATTRIBUTE((warn_unused_result)) { - ut_ad(UT_LIST_GET_LEN(m_list) > 0); - return(UT_LIST_GET_FIRST(m_list)); + return &m_list.front(); } /** @@ -403,14 +394,13 @@ private: void push_back(block_t* block) { block->init(); - - UT_LIST_ADD_LAST(m_list, block); + m_list.push_back(*block); } /** @return the last block in the list */ block_t* back() const { - return(UT_LIST_GET_LAST(m_list)); + return &const_cast<block_t&>(m_list.back()); } /* @@ -433,25 +423,22 @@ private: @return the block containing the pos. */ block_t* find(ulint& pos) { - block_t* block; + ut_ad(!m_list.empty()); - ut_ad(UT_LIST_GET_LEN(m_list) > 0); + for (typename list_t::iterator it = m_list.begin(), + end = m_list.end(); + it != end; ++it) { - for (block = UT_LIST_GET_FIRST(m_list); - block != NULL; - block = UT_LIST_GET_NEXT(m_node, block)) { + if (pos < it->used()) { + ut_ad(it->used() >= pos); - if (pos < block->used()) { - break; + return &*it; } - pos -= block->used(); + pos -= it->used(); } - ut_ad(block != NULL); - ut_ad(block->used() >= pos); - - return(block); + return NULL; } /** @@ -477,7 +464,7 @@ private: mem_heap_t* m_heap; /** Allocated blocks */ - block_list_t m_list; + list_t m_list; /** Total size used by all blocks */ ulint m_size; diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index afb8debd853..efbd85584e0 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -33,10 +33,14 @@ Created 10/25/1995 Heikki Tuuri #include "log0recv.h" #include "dict0types.h" +#include "intrusive_list.h" #ifdef UNIV_LINUX # include <set> #endif +struct unflushed_spaces_tag_t; +struct rotation_list_tag_t; + // Forward declaration extern my_bool srv_use_doublewrite_buf; extern struct buf_dblwr_t* buf_dblwr; @@ -77,7 +81,13 @@ struct fil_node_t; #endif /** Tablespace or log data space */ -struct fil_space_t { +#ifndef UNIV_INNOCHECKSUM +struct fil_space_t : intrusive::list_node<unflushed_spaces_tag_t>, + intrusive::list_node<rotation_list_tag_t> +#else +struct fil_space_t +#endif +{ #ifndef UNIV_INNOCHECKSUM ulint id; /*!< space id */ hash_node_t hash; /*!< hash chain node */ @@ -147,9 +157,6 @@ struct fil_space_t { std::atomic<ulint> n_pending_ios; rw_lock_t latch; /*!< latch protecting the file space storage allocation */ - UT_LIST_NODE_T(fil_space_t) unflushed_spaces; - /*!< list of spaces with at least one unflushed - file we have written to */ UT_LIST_NODE_T(fil_space_t) named_spaces; /*!< list of spaces for which MLOG_FILE_NAME records have been issued */ @@ -158,8 +165,6 @@ struct fil_space_t { bool is_in_unflushed_spaces() const; UT_LIST_NODE_T(fil_space_t) space_list; /*!< list of all spaces */ - /** other tablespaces needing key rotation */ - UT_LIST_NODE_T(fil_space_t) rotation_list; /** Checks that this tablespace needs key rotation. @return true if in a rotation list */ bool is_in_rotation_list() const; @@ -267,7 +272,7 @@ struct fil_space_t { void release_for_io() { ut_ad(pending_io()); n_pending_ios--; } /** @return whether I/O is pending */ bool pending_io() const { return n_pending_ios; } -#endif +#endif /* !UNIV_INNOCHECKSUM */ /** FSP_SPACE_FLAGS and FSP_FLAGS_MEM_ flags; check fsp0types.h to more info about flags. */ ulint flags; @@ -877,8 +882,6 @@ struct fil_system_t { { UT_LIST_INIT(LRU, &fil_node_t::LRU); UT_LIST_INIT(space_list, &fil_space_t::space_list); - UT_LIST_INIT(rotation_list, &fil_space_t::rotation_list); - UT_LIST_INIT(unflushed_spaces, &fil_space_t::unflushed_spaces); UT_LIST_INIT(named_spaces, &fil_space_t::named_spaces); } @@ -930,8 +933,8 @@ public: not put to this list: they are opened after the startup, and kept open until shutdown */ - UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces; - /*!< base node for the list of those + intrusive::list<fil_space_t, unflushed_spaces_tag_t> unflushed_spaces; + /*!< list of those tablespaces whose files contain unflushed writes; those spaces have at least one file node where @@ -951,7 +954,7 @@ public: record has been written since the latest redo log checkpoint. Protected only by log_sys.mutex. */ - UT_LIST_BASE_NODE_T(fil_space_t) rotation_list; + intrusive::list<fil_space_t, rotation_list_tag_t> rotation_list; /*!< list of all file spaces needing key rotation.*/ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 350615eee64..738f725c60d 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. 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 @@ -342,13 +342,6 @@ bool trx_is_interrupted( /*===============*/ const trx_t* trx); /*!< in: transaction */ -/**********************************************************************//** -Determines if the currently running transaction is in strict mode. -@return TRUE if strict */ -ibool -trx_is_strict( -/*==========*/ - trx_t* trx); /*!< in: transaction */ /*******************************************************************//** Calculates the "weight" of a transaction. The weight of one transaction |