1
0
mirror of https://github.com/MariaDB/server.git synced 2025-12-24 11:21:21 +03:00

WL#3984 (Revise locking of mysql.general_log and mysql.slow_log)

Bug#25422 (Hang with log tables)
Bug 17876 (Truncating mysql.slow_log in a SP after using cursor locks the
          thread)
Bug 23044 (Warnings on flush of a log table)
Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
           a deadlock)

Prior to this fix, the server would hang when performing concurrent
ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES,
which are mysql.general_log and mysql.slow_log.

The root cause traces to the following code:
in sql_base.cc, open_table()
  if (table->in_use != thd)
  {
    /* wait_for_condition will unlock LOCK_open for us */
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
  }
The problem with this code is that the current implementation of the
LOGGER creates 'fake' THD objects, like
- Log_to_csv_event_handler::general_log_thd
- Log_to_csv_event_handler::slow_log_thd
which are not associated to a real thread running in the server,
so that waiting for these non-existing threads to release table locks
cause the dead lock.

In general, the design of Log_to_csv_event_handler does not fit into the
general architecture of the server, so that the concept of general_log_thd
and slow_log_thd has to be abandoned:
- this implementation does not work with table locking
- it will not work with commands like SHOW PROCESSLIST
- having the log tables always opened does not integrate well with DDL
operations / FLUSH TABLES / SET GLOBAL READ_ONLY

With this patch, the fundamental design of the LOGGER has been changed to:
- always open and close a log table when writing a log
- remove totally the usage of fake THD objects
- clarify how locking of log tables is implemented in general.

See WL#3984 for details related to the new locking design.

Additional changes (misc bugs exposed and fixed):

1)

mysqldump which would ignore some tables in dump_all_tables_in_db(),
 but forget to ignore the same in dump_all_views_in_db().

2)

mysqldump would also issue an empty "LOCK TABLE" command when all the tables
to lock are to be ignored (numrows == 0), instead of not issuing the query.

3)

Internal errors handlers could intercept errors but not warnings
(see sql_error.cc).

4)

Implementing a nested call to open tables, for the performance schema tables,
exposed an existing bug in remove_table_from_cache(), which would perform:
  in_use->some_tables_deleted=1;
against another thread, without any consideration about thread locking.
This call inside remove_table_from_cache() was not required anyway,
since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads
that might hold a lock on a table.
This line (in_use->some_tables_deleted=1) has been removed.
This commit is contained in:
malff/marcsql@weblab.(none)
2007-07-27 00:31:06 -06:00
parent cbd6e56ffa
commit c7bbd8917c
39 changed files with 1490 additions and 993 deletions

View File

@@ -1035,44 +1035,6 @@ public:
{
cached_table_flags= table_flags();
}
/*
Check whether a handler allows to lock the table.
SYNOPSIS
check_if_locking_is_allowed()
thd Handler of the thread, trying to lock the table
table Table handler to check
count Total number of tables to be locked
current Index of the current table in the list of the tables
to be locked.
system_count Pointer to the counter of system tables seen thus
far.
called_by_privileged_thread TRUE if called from a logger THD
(general_log_thd or slow_log_thd)
or by a privileged thread, which
has the right to lock log tables.
DESCRIPTION
Check whether a handler allows to lock the table. For instance,
MyISAM does not allow to lock mysql.proc along with other tables.
This limitation stems from the fact that MyISAM does not support
row-level locking and we have to add this limitation to avoid
deadlocks.
RETURN
TRUE Locking is allowed
FALSE Locking is not allowed. The error was thrown.
*/
virtual bool check_if_locking_is_allowed(uint sql_command,
ulong type, TABLE *table,
uint count, uint current,
uint *system_count,
bool called_by_privileged_thread)
{
return TRUE;
}
bool check_if_log_table_locking_is_allowed(uint sql_command,
ulong type, TABLE *table);
int ha_open(TABLE *table, const char *name, int mode, int test_if_locked);
void adjust_next_insert_id_after_explicit_value(ulonglong nr);
int update_auto_increment();
@@ -1196,6 +1158,7 @@ public:
*/
int ha_external_lock(THD *thd, int lock_type);
int ha_write_row(uchar * buf);
int ha_write_row_no_binlog(uchar * buf);
int ha_update_row(const uchar * old_data, uchar * new_data);
int ha_delete_row(const uchar * buf);