summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-08-25 15:17:20 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-08-25 15:17:20 +0300
commit851058a3e6f40cd2714762916235ebe93fc594b5 (patch)
tree8a2c796543e3b89c5d8958bd8e641dd71ce17065
parente404315258bb20378eef6a70857c1d16d1da9638 (diff)
parentd1a80c42ee5b9c845ca72288d3bc58b47f5632a3 (diff)
downloadmariadb-git-851058a3e6f40cd2714762916235ebe93fc594b5.tar.gz
Merge 10.3 into 10.4
-rw-r--r--mysql-test/include/mtr_warnings.sql2
-rw-r--r--mysql-test/suite/rpl/r/rpl_filter_set_var_missing_data.result55
-rw-r--r--mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test83
-rw-r--r--sql/sql_acl.cc94
-rw-r--r--storage/innobase/btr/btr0sea.cc5
-rw-r--r--storage/innobase/buf/buf0buf.cc41
-rw-r--r--storage/innobase/dict/dict0crea.cc2
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
8 files changed, 223 insertions, 61 deletions
diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql
index fa1ea95e5e1..9ce81703450 100644
--- a/mysql-test/include/mtr_warnings.sql
+++ b/mysql-test/include/mtr_warnings.sql
@@ -174,7 +174,7 @@ INSERT INTO global_suppressions VALUES
/* Added 2009-08-XX after fixing Bug #42408 */
- ("Although a path was specified for the .* option, log tables are used"),
+ ("Although a .* file was specified, log tables are used. To enable logging to files "),
("Backup: Operation aborted"),
("Restore: Operation aborted"),
("Restore: The grant .* was skipped because the user does not exist"),
diff --git a/mysql-test/suite/rpl/r/rpl_filter_set_var_missing_data.result b/mysql-test/suite/rpl/r/rpl_filter_set_var_missing_data.result
new file mode 100644
index 00000000000..e232edae1ed
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_filter_set_var_missing_data.result
@@ -0,0 +1,55 @@
+include/master-slave.inc
+[connection master]
+#
+# Set replica to ignore system mysql tables
+connection slave;
+include/stop_slave.inc
+SET @@GLOBAL.replicate_wild_ignore_table="mysql.%";
+include/start_slave.inc
+#
+# Execute grant-based commands on primary which modify mysql system
+# tables
+connection master;
+CREATE ROLE journalist;
+CREATE USER testuser@localhost IDENTIFIED by '';
+GRANT journalist to testuser@localhost;
+#
+# Execute SET commands which use the previous user/role data
+SET DEFAULT ROLE journalist for testuser@localhost;
+SET PASSWORD for testuser@localhost= PASSWORD('123');
+include/save_master_gtid.inc
+#
+# Verify primary's grant tables have the correct user/role data
+select count(*)=1 from mysql.user where User='testuser';
+count(*)=1
+1
+select count(*)=1 from mysql.roles_mapping where User='testuser';
+count(*)=1
+1
+#
+# Ensure that the replica receives all of the primary's events without
+# error
+connection slave;
+include/sync_with_master_gtid.inc
+Last_SQL_Error =
+Last_SQL_Errno = 0
+#
+# Verify that the replica did not execute the master's commands
+select count(*)=0 from mysql.user where User='testuser';
+count(*)=0
+1
+select count(*)=0 from mysql.roles_mapping where User='testuser';
+count(*)=0
+1
+#
+# Clean up
+connection master;
+DROP ROLE journalist;
+DROP USER testuser@localhost;
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+SET @@GLOBAL.replicate_wild_ignore_table="";
+include/start_slave.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test b/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test
new file mode 100644
index 00000000000..25efb6ed662
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test
@@ -0,0 +1,83 @@
+#
+# Purpose:
+# This test ensures that the SET DEFAULT ROLE and SET PASSWORD commands can
+# be ignored by replica filter rules. MDEV-28294 exposed a bug in which
+# SET DEFAULT ROLE would check for the existence of the given roles/user even
+# when the targeted tables are ignored, resulting in errors if the targeted
+# data does not exist. More specifically, when previously issued
+# CREATE USER/ROLE commands are ignored by the replica because of the
+# replication filtering rules, SET DEFAULT ROLE would result in an error
+# because the targeted data does not exist.
+#
+# Methodology:
+# Using a replica configured with replicate_wild_ignore_table="mysql.%",
+# execute SET DEFAULT ROLE and SET PASSWORD on the primary and ensure that the
+# replica neither errors nor executes the commands which the primary sends.
+#
+# References:
+# MDEV-28294: set default role bypasses Replicate_Wild_Ignore_Table: mysql.%
+#
+
+source include/master-slave.inc;
+source include/have_binlog_format_mixed.inc;
+
+--echo #
+--echo # Set replica to ignore system mysql tables
+connection slave;
+let $old_filter= query_get_value(SHOW SLAVE STATUS, Replicate_Wild_Ignore_Table, 1);
+source include/stop_slave.inc;
+SET @@GLOBAL.replicate_wild_ignore_table="mysql.%";
+source include/start_slave.inc;
+
+--echo #
+--echo # Execute grant-based commands on primary which modify mysql system
+--echo # tables
+connection master;
+CREATE ROLE journalist;
+CREATE USER testuser@localhost IDENTIFIED by '';
+GRANT journalist to testuser@localhost;
+
+--echo #
+--echo # Execute SET commands which use the previous user/role data
+SET DEFAULT ROLE journalist for testuser@localhost;
+SET PASSWORD for testuser@localhost= PASSWORD('123');
+--source include/save_master_gtid.inc
+
+--echo #
+--echo # Verify primary's grant tables have the correct user/role data
+select count(*)=1 from mysql.user where User='testuser';
+select count(*)=1 from mysql.roles_mapping where User='testuser';
+
+--echo #
+--echo # Ensure that the replica receives all of the primary's events without
+--echo # error
+connection slave;
+--source include/sync_with_master_gtid.inc
+let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+--echo Last_SQL_Error = $error
+let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+--echo Last_SQL_Errno = $errno
+
+--echo #
+--echo # Verify that the replica did not execute the master's commands
+select count(*)=0 from mysql.user where User='testuser';
+select count(*)=0 from mysql.roles_mapping where User='testuser';
+
+--echo #
+--echo # Clean up
+
+# The master has to drop the role/user combination while the slave still has
+# its filters active; otherwise, the slave would try to drop users/roles that
+# were never replicated.
+--connection master
+DROP ROLE journalist;
+DROP USER testuser@localhost;
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/sync_with_master_gtid.inc
+source include/stop_slave.inc;
+--eval SET @@GLOBAL.replicate_wild_ignore_table="$old_filter"
+source include/start_slave.inc;
+
+--source include/rpl_end.inc
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 8c52318c498..7584c35c8d7 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2020, MariaDB
+ Copyright (c) 2009, 2022, 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
@@ -1814,10 +1814,17 @@ class Grant_tables
public:
Grant_tables() : p_user_table(&m_user_table_json) { }
- int open_and_lock(THD *thd, int which_tables, enum thr_lock_type lock_type)
+ /**
+ An auxiliary to build a list of involved tables.
+
+ @retval 0 Success
+ @retval -1 A my_error reported error
+ */
+ int build_table_list(THD *thd, TABLE_LIST** ptr_first,
+ int which_tables, enum thr_lock_type lock_type,
+ TABLE_LIST *tables)
{
- DBUG_ENTER("Grant_tables::open_and_lock");
- TABLE_LIST tables[USER_TABLE+1], *first= NULL;
+ DBUG_ENTER("Grant_tables::build_table_list");
DBUG_ASSERT(which_tables); /* At least one table must be opened. */
/*
@@ -1842,12 +1849,23 @@ class Grant_tables
tl->updating= lock_type >= TL_WRITE_ALLOW_WRITE;
if (i >= FIRST_OPTIONAL_TABLE)
tl->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
- tl->next_global= tl->next_local= first;
- first= tl;
+ tl->next_global= tl->next_local= *ptr_first;
+ *ptr_first= tl;
}
else
tl->table= NULL;
}
+ DBUG_RETURN(0);
+ }
+
+ int open_and_lock(THD *thd, int which_tables, enum thr_lock_type lock_type)
+ {
+ DBUG_ENTER("Grant_tables::open_and_lock");
+
+ TABLE_LIST tables[USER_TABLE+1], *first= NULL;
+
+ if (build_table_list(thd, &first, which_tables, lock_type, tables))
+ DBUG_RETURN(-1);
uint counter;
int res= really_open(thd, first, &counter);
@@ -1916,6 +1934,48 @@ class Grant_tables
inline const Roles_mapping_table& roles_mapping_table() const
{ return m_roles_mapping_table; }
+#ifdef HAVE_REPLICATION
+ /**
+ Checks if the tables targeted by a grant command should be ignored because
+ of the configured replication filters
+
+ @retval 1 Tables are excluded for replication
+ @retval 0 tables are included for replication
+ */
+ int rpl_ignore_tables(THD *thd, TABLE_LIST* tables, int which_tables= 0,
+ enum thr_lock_type lock_type= TL_IGNORE)
+ {
+ DBUG_ENTER("Grant_tables::rpl_ignore_tables");
+
+ if (!(thd->slave_thread && !thd->spcont))
+ DBUG_RETURN(0);
+
+ TABLE_LIST all_tables[USER_TABLE+1];
+
+ if (!tables)
+ {
+ int rc __attribute__((unused))=
+ build_table_list(thd, &tables, which_tables, lock_type, all_tables);
+
+ DBUG_ASSERT(!rc); // Grant_tables must be already initialized
+ DBUG_ASSERT(tables);
+ }
+
+ if (tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ /*
+ GRANT and REVOKE are applied the slave in/exclusion rules as they are
+ some kind of updates to the mysql.% tables.
+ */
+ Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
+
+ if (rpl_filter->is_on() && !rpl_filter->tables_ok(0, tables))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+#endif
+
private:
/* Before any operation is possible on grant tables, they must be opened.
@@ -1929,16 +1989,9 @@ class Grant_tables
{
DBUG_ENTER("Grant_tables::really_open:");
#ifdef HAVE_REPLICATION
- if (tables->lock_type >= TL_WRITE_ALLOW_WRITE &&
- thd->slave_thread && !thd->spcont)
+ if (rpl_ignore_tables(thd, tables))
{
- /*
- GRANT and REVOKE are applied the slave in/exclusion rules as they are
- some kind of updates to the mysql.% tables.
- */
- Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
- if (rpl_filter->is_on() && !rpl_filter->tables_ok(0, tables))
- DBUG_RETURN(1);
+ DBUG_RETURN(1);
}
#endif
if (open_tables(thd, &tables, counter, MYSQL_LOCK_IGNORE_TIMEOUT))
@@ -3940,6 +3993,17 @@ int acl_check_set_default_role(THD *thd, const char *host, const char *user,
const char *role)
{
DBUG_ENTER("acl_check_set_default_role");
+#ifdef HAVE_REPLICATION
+ /*
+ If the roles_mapping table is excluded by the replication filter, we return
+ successful without validating the user/role data because the command will
+ be ignored in a later call to `acl_set_default_role()` for a graceful exit.
+ */
+ Grant_tables tables;
+ TABLE_LIST* first= NULL;
+ if (tables.rpl_ignore_tables(thd, first, Table_roles_mapping, TL_WRITE))
+ DBUG_RETURN(0);
+#endif
DBUG_RETURN(check_alter_user(thd, host, user) ||
check_user_can_set_role(thd, user, host, NULL, role, NULL));
}
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 2e86d27cc0e..131f8c13c27 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2017, 2021, MariaDB Corporation.
+Copyright (c) 2017, 2022, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -1116,9 +1116,6 @@ void btr_search_drop_page_hash_index(buf_block_t* block,
rw_lock_t* latch;
retry:
- /* This debug check uses a dirty read that could theoretically cause
- false positives while buf_pool_clear_hash_index() is executing. */
- assert_block_ahi_valid(block);
ut_ad(!btr_search_own_any(RW_LOCK_S));
ut_ad(!btr_search_own_any(RW_LOCK_X));
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 060b5da362f..f688cf4f719 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -3897,42 +3897,6 @@ buf_wait_for_read(
}
}
-#ifdef BTR_CUR_HASH_ADAPT
-/** If a stale adaptive hash index exists on the block, drop it.
-Multiple executions of btr_search_drop_page_hash_index() on the
-same block must be prevented by exclusive page latch. */
-ATTRIBUTE_COLD
-static void buf_defer_drop_ahi(buf_block_t *block, mtr_memo_type_t fix_type)
-{
- switch (fix_type) {
- case MTR_MEMO_BUF_FIX:
- /* We do not drop the adaptive hash index, because safely doing
- so would require acquiring block->lock, and that is not safe
- to acquire in some RW_NO_LATCH access paths. Those code paths
- should have no business accessing the adaptive hash index anyway. */
- break;
- case MTR_MEMO_PAGE_S_FIX:
- /* Temporarily release our S-latch. */
- rw_lock_s_unlock(&block->lock);
- rw_lock_x_lock(&block->lock);
- btr_search_drop_page_hash_index(block, true);
- rw_lock_x_unlock(&block->lock);
- rw_lock_s_lock(&block->lock);
- break;
- case MTR_MEMO_PAGE_SX_FIX:
- rw_lock_sx_unlock(&block->lock);
- rw_lock_x_lock(&block->lock);
- btr_search_drop_page_hash_index(block, true);
- rw_lock_x_unlock(&block->lock);
- rw_lock_sx_lock(&block->lock);
- break;
- default:
- ut_ad(fix_type == MTR_MEMO_PAGE_X_FIX);
- btr_search_drop_page_hash_index(block);
- }
-}
-#endif /* BTR_CUR_HASH_ADAPT */
-
/** Lock the page with the given latch type.
@param[in,out] block block to be locked
@param[in] rw_latch RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH
@@ -3968,10 +3932,7 @@ static buf_block_t* buf_page_mtr_lock(buf_block_t *block,
}
#ifdef BTR_CUR_HASH_ADAPT
- {
- if (block->index)
- buf_defer_drop_ahi(block, fix_type);
- }
+ btr_search_drop_page_hash_index(block, true);
#endif /* BTR_CUR_HASH_ADAPT */
done:
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index be0e0cd7adb..fbcacf9d6ff 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -1159,7 +1159,7 @@ dict_create_table_step(
if (node->state == TABLE_ADD_TO_CACHE) {
DBUG_EXECUTE_IF("ib_ddl_crash_during_create", DBUG_SUICIDE(););
- node->table->can_be_evicted = true;
+ node->table->can_be_evicted = !node->table->fts;
node->table->add_to_cache();
err = DB_SUCCESS;
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index d24eb4e0ac5..b8a80d02350 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -14397,9 +14397,11 @@ ha_innobase::info_low(
stats.index_file_length
= ulonglong(stat_sum_of_other_index_sizes)
* size;
+ rw_lock_s_lock(&space->latch);
stats.delete_length = 1024
* fsp_get_available_space_in_free_extents(
*space);
+ rw_lock_s_unlock(&space->latch);
}
stats.check_time = 0;
stats.mrr_length_per_rec= (uint)ref_length + 8; // 8 = max(sizeof(void *));