summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/intrusive_list.h190
-rw-r--r--mysql-test/main/group_by.result6
-rw-r--r--mysql-test/main/group_by.test2
-rw-r--r--mysql-test/suite/innodb/r/row_size_error_log_warnings_3.result26
-rw-r--r--mysql-test/suite/innodb/t/row_size_error_log_warnings_3.test10
-rw-r--r--mysql-test/suite/wsrep/r/variables.result9
-rw-r--r--mysql-test/suite/wsrep/t/variables.test4
-rw-r--r--storage/innobase/fil/fil0crypt.cc2
-rw-r--r--storage/innobase/fil/fil0fil.cc131
-rw-r--r--storage/innobase/handler/ha_innodb.cc45
-rw-r--r--storage/innobase/handler/ha_innodb.h15
-rw-r--r--storage/innobase/handler/handler0alter.cc29
-rw-r--r--storage/innobase/include/dyn0buf.h99
-rw-r--r--storage/innobase/include/fil0fil.h29
-rw-r--r--storage/innobase/include/trx0trx.h9
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