diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-25 15:17:20 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-08-25 15:17:20 +0300 |
commit | 851058a3e6f40cd2714762916235ebe93fc594b5 (patch) | |
tree | 8a2c796543e3b89c5d8958bd8e641dd71ce17065 | |
parent | e404315258bb20378eef6a70857c1d16d1da9638 (diff) | |
parent | d1a80c42ee5b9c845ca72288d3bc58b47f5632a3 (diff) | |
download | mariadb-git-851058a3e6f40cd2714762916235ebe93fc594b5.tar.gz |
Merge 10.3 into 10.4
-rw-r--r-- | mysql-test/include/mtr_warnings.sql | 2 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_filter_set_var_missing_data.result | 55 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_filter_set_var_missing_data.test | 83 | ||||
-rw-r--r-- | sql/sql_acl.cc | 94 | ||||
-rw-r--r-- | storage/innobase/btr/btr0sea.cc | 5 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 41 | ||||
-rw-r--r-- | storage/innobase/dict/dict0crea.cc | 2 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 2 |
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 *)); |