diff options
author | Konstantin Osipov <kostja@sun.com> | 2010-02-27 20:05:14 +0300 |
---|---|---|
committer | Konstantin Osipov <kostja@sun.com> | 2010-02-27 20:05:14 +0300 |
commit | e5f595601422ead2ddff450dc77e7062a7959911 (patch) | |
tree | 471fa62f6c3a91f1be012911d4f2ba03f73e9d5f /sql | |
parent | 2e9d7d78f9501b7adde3b3c945a3cdc054e7fe97 (diff) | |
download | mariadb-git-e5f595601422ead2ddff450dc77e7062a7959911.tar.gz |
WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK.
Extend and implement the grammar that allows to FLUSH WITH READ LOCK
a list of tables, rather than all of them.
Incompatible grammar change:
Previously one could perform FLUSH TABLES, HOSTS, PRIVILEGES in a single
statement.
After this change, FLUSH TABLES must always be alone on the list.
Judging by the test suite, however, the old extended syntax
was never or very rarely used.
The new statement requires RELOAD ACL global privilege and
LOCK_TABLES_ACL | SELECT_ACL on individual tables.
In other words, it's an atomic combination of LOCK TALBES <list> READ
and FLUSH TABLES <list>, and requires respective privileges.
For additional information about the semantics, please
see WL#5000 and the comment for flush_tables_with_read_lock()
function in sql_parse.cc
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_parse.cc | 116 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 29 |
2 files changed, 136 insertions, 9 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e66f2756c54..7a13c46e4f6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1588,6 +1588,113 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, /** + Implementation of FLUSH TABLES <table_list> WITH READ LOCK. + + In brief: take exclusive locks, expel tables from the table + cache, reopen the tables, enter the 'LOCKED TABLES' mode, + downgrade the locks. + + Required privileges + ------------------- + Since the statement implicitly enters LOCK TABLES mode, + it requires LOCK TABLES privilege on every table. + But since the rest of FLUSH commands require + the global RELOAD_ACL, it also requires RELOAD_ACL. + + Compatibility with the global read lock + --------------------------------------- + We don't wait for the GRL, since neither the + 5.1 combination that this new statement is intended to + replace (LOCK TABLE <list> WRITE; FLUSH TABLES;), + nor FLUSH TABLES WITH READ LOCK do. + @todo: this is not implemented, Dmitry disagrees. + Currently we wait for GRL in another connection, + but are compatible with a GRL in our own connection. + + Behaviour under LOCK TABLES + --------------------------- + Bail out: i.e. don't perform an implicit UNLOCK TABLES. + This is not consistent with LOCK TABLES statement, but is + in line with behaviour of FLUSH TABLES WITH READ LOCK, and we + try to not introduce any new statements with implicit + semantics. + + Compatibility with parallel updates + ----------------------------------- + As a result, we will wait for all open transactions + against the tables to complete. After the lock downgrade, + new transactions will be able to read the tables, but not + write to them. + + Differences from FLUSH TABLES <list> + ------------------------------------- + - you can't flush WITH READ LOCK a non-existent table + - you can't flush WITH READ LOCK under LOCK TABLES + - currently incompatible with the GRL (@todo: fix) +*/ + +static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) +{ + Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + TABLE_LIST *table_list; + + /* + This is called from SQLCOM_FLUSH, the transaction has + been committed implicitly. + */ + + /* RELOAD_ACL is checked by the caller. Check table-level privileges. */ + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, + FALSE, UINT_MAX, FALSE)) + goto error; + + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + goto error; + } + + /* + @todo: Since lock_table_names() acquires a global IX + lock, this actually waits for a GRL in another connection. + We are thus introducing an incompatibility. + Do nothing for now, since not taking a global IX violates + current internal MDL asserts, fix after discussing with + Dmitry. + */ + if (lock_table_names(thd, all_tables)) + goto error; + + if (open_and_lock_tables(thd, all_tables, FALSE, + MYSQL_OPEN_HAS_MDL_LOCK, + &lock_tables_prelocking_strategy) || + thd->locked_tables_list.init_locked_tables(thd)) + { + close_thread_tables(thd); + goto error; + } + + /* + Downgrade the exclusive locks. + Use MDL_SHARED_NO_WRITE as the intended + post effect of this call is identical + to LOCK TABLES <...> READ, and we didn't use + thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES + hacks to enter the LTM. + @todo: release the global IX lock here!!! + */ + for (table_list= all_tables; table_list; + table_list= table_list->next_global) + table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE); + + return FALSE; + +error: + return TRUE; +} + + +/** Read query from packet and store in thd->query. Used in COM_QUERY and COM_STMT_PREPARE. @@ -3728,9 +3835,18 @@ end_with_restore_list: case SQLCOM_FLUSH: { bool write_to_binlog; + if (check_global_access(thd,RELOAD_ACL)) goto error; + if (first_table && lex->type & REFRESH_READ_LOCK) + { + if (flush_tables_with_read_lock(thd, all_tables)) + goto error; + my_ok(thd); + break; + } + /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f03694cb359..5648e3cbdb5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -767,10 +767,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 169 shift/reduce conflicts. + Currently there are 168 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 169 +%expect 168 /* Comments for TOKENS. @@ -1554,6 +1554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list clear_privileges flush_options flush_option + opt_with_read_lock flush_options_list equal optional_braces opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as @@ -11095,17 +11096,27 @@ flush: ; flush_options: - flush_options ',' flush_option + table_or_tables + { Lex->type|= REFRESH_TABLES; } + opt_table_list {} + opt_with_read_lock {} + | flush_options_list + ; + +opt_with_read_lock: + /* empty */ {} + | WITH READ_SYM LOCK_SYM + { Lex->type|= REFRESH_READ_LOCK; } + ; + +flush_options_list: + flush_options_list ',' flush_option | flush_option + {} ; flush_option: - table_or_tables - { Lex->type|= REFRESH_TABLES; } - opt_table_list {} - | TABLES WITH READ_SYM LOCK_SYM - { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; } - | ERROR_SYM LOGS_SYM + ERROR_SYM LOGS_SYM { Lex->type|= REFRESH_ERROR_LOG; } | ENGINE_SYM LOGS_SYM { Lex->type|= REFRESH_ENGINE_LOG; } |