strict aliasing violations.
One somewhat major source of strict-aliasing violations and
related warnings is the SQL_LIST structure. For example,
consider its member function `link_in_list` which takes
a pointer to pointer of type T (any type) as a pointer to
pointer to unsigned char. Dereferencing this pointer, which
is done to reset the next field, violates strict-aliasing
rules and might cause problems for surrounding code that
uses the next field of the object being added to the list.
The solution is to use templates to parametrize the SQL_LIST
structure in order to deference the pointers with compatible
types. As a side bonus, it becomes possible to remove quite
a few casts related to acessing data members of SQL_LIST.
sql/handler.h:
Use the appropriate template type argument.
sql/item.cc:
Remove now-unnecessary cast.
sql/item_subselect.cc:
Remove now-unnecessary casts.
sql/item_sum.cc:
Use the appropriate template type argument.
Remove now-unnecessary cast.
sql/mysql_priv.h:
Move SQL_LIST structure to sql_list.h
Use the appropriate template type argument.
sql/sp.cc:
Remove now-unnecessary casts.
sql/sql_delete.cc:
Use the appropriate template type argument.
Remove now-unnecessary casts.
sql/sql_derived.cc:
Remove now-unnecessary casts.
sql/sql_lex.cc:
Remove now-unnecessary casts.
sql/sql_lex.h:
SQL_LIST now takes a template type argument which must
match the type of the elements of the list. Use forward
declaration when the type is not available, it is used
in pointers anyway.
sql/sql_list.h:
Rename SQL_LIST to SQL_I_List. The template parameter is
the type of object that is stored in the list.
sql/sql_olap.cc:
Remove now-unnecessary casts.
sql/sql_parse.cc:
Remove now-unnecessary casts.
sql/sql_prepare.cc:
Remove now-unnecessary casts.
sql/sql_select.cc:
Remove now-unnecessary casts.
sql/sql_show.cc:
Remove now-unnecessary casts.
sql/sql_table.cc:
Remove now-unnecessary casts.
sql/sql_trigger.cc:
Remove now-unnecessary casts.
sql/sql_union.cc:
Remove now-unnecessary casts.
sql/sql_update.cc:
Remove now-unnecessary casts.
sql/sql_view.cc:
Remove now-unnecessary casts.
sql/sql_yacc.yy:
Remove now-unnecessary casts.
storage/myisammrg/ha_myisammrg.cc:
Remove now-unnecessary casts.
The problem was that TRUNCATE TABLE didn't take a exclusive
lock on a table if it resorted to truncating via delete of
all rows in the table. Specifically for InnoDB tables, this
could break proper isolation as InnoDB ends up aborting some
granted locks when truncating a table.
The solution is to take a exclusive metadata lock before
TRUNCATE TABLE can proceed. This guarantees that no other
transaction is using the table.
Incompatible change: Truncate via delete no longer fails
if sql_safe_updates is activated (this was a undocumented
side effect).
libmysqld/CMakeLists.txt:
Add new files to the build list.
libmysqld/Makefile.am:
Add new files to the build list.
mysql-test/extra/binlog_tests/binlog_truncate.test:
Add test case for Bug#42643
mysql-test/include/mix1.inc:
Update test case as TRUNCATE TABLE now grabs a exclusive lock.
Ensure that TRUNCATE waits for granted locks on the table.
mysql-test/suite/binlog/t/binlog_truncate_innodb.test:
As with other data modifying statements, TRUNCATE is still not
possible in a transaction with isolation level READ COMMITTED
or READ UNCOMMITED. It would be possible to implement so, but
it is not worth the effort.
mysql-test/suite/binlog/t/binlog_truncate_myisam.test:
Test under different binlog formats.
mysql-test/suite/binlog/t/disabled.def:
Re-enable test case.
mysql-test/t/innodb_bug38231.test:
Truncate no longer works with row-level locks.
mysql-test/t/mdl_sync.test:
Ensure that a acquired lock is not given up due to a conflict.
mysql-test/t/partition_innodb_semi_consistent.test:
End transaction as to release metadata locks.
mysql-test/t/truncate.test:
A metadata lock is now taken before the object is verified.
sql/CMakeLists.txt:
Add new files to the build list.
sql/Makefile.am:
Add new files to the build list.
sql/datadict.cc:
Introduce a new file specific for data dictionary operations.
sql/datadict.h:
Add header file.
sql/sql_base.cc:
Rename data dictionary function.
sql/sql_bitmap.h:
Include dependency.
sql/sql_delete.cc:
Move away from relying on mysql_delete() to delete all rows of
a table. Thus, move any bits related to truncate to sql_truncate.cc
sql/sql_delete.h:
Remove parameter.
sql/sql_parse.cc:
Add protection against the global read lock -- a intention
exclusive lock can be acquired in the truncate path.
sql/sql_show.cc:
Add sync point for testing scenarios where a pending flush
is ignored.
sql/sql_truncate.cc:
Acquire a shared metadata lock before accessing table metadata.
Upgrade the lock to a exclusive one if the table can be re-created.
Rework binlog rules to better reflect the requirements.
sql/sql_yacc.yy:
Set appropriate lock types for table to be truncated.
sql/table.h:
Move to data dictionary header.
transactional SELECT and ALTER TABLE ... REBUILD PARTITION".
The goal of this patch is to decouple type of metadata
lock acquired for table by open_tables() from type of
table-level lock to be acquired on it.
To achieve this we change approach to how we determine what
type of metadata lock should be acquired on table to be open.
Now instead of inferring it at open_tables() time from flags
and type of table-level lock we rely on that type of metadata
lock is properly set at parsing time and is not changed
further.
sql/ha_ndbcluster.cc:
Now one needs to properly initialize table list element's
MDL_request object before calling mysql_rm_table_part2().
sql/lock.cc:
lock_table_names() no longer initializes table list elements'
MDL_request objects. Now proper initialization of these
requests is a responsibility of the caller.
sql/lock.h:
Removed MYSQL_OPEN_TAKE_UPGRADABLE_MDL flag which became
unnecessary. Thanks to the fact that we don't reset type of
requests for metadata locks between re-executions we now can
figure out that upgradable locks are requested by simply
looking at their type which were set in the parser. As result
this flag became redundant.
sql/mdl.h:
Added version of new operator which simplifies allocation of
MDL_request objects on a MEM_ROOT.
sql/sp_head.cc:
Added comment explaining why it is OK to infer type of
metadata lock to request from type of table-level lock
for prelocking.
Added enum_mdl_type argument to sp_add_to_query_tables()
to simplify its usage in trigger implementation.
sql/sp_head.h:
Added enum_mdl_type argument to sp_add_to_query_tables()
to simplify its usage in trigger implementation.
sql/sql_base.cc:
- open_table_get_mdl_lock():
Preserve type of MDL_request for table list element which
was set in the parser by creating MDL_request objects on
memory root if MYSQL_OPEN_FORCE_SHARED_MDL or
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL flag were specified.
Thanks to this and to the fact that we no longer reset
type of requests for metadata locks between re-executions
we no longer need to acquire exclusive metadata lock on
table to be created in a special way. This lock is acquired
by code handling acquiring of upgradable locks.
Also changed signature/calling convention for this function
to simplify its usage.
- Accordingly special lock strategy for table list elements
which was used for such locks became unnecessary and was
removed. Other strategies were renamed.
- Since we no longer have guarantee that MDL_request object
which were not satisfied due to lock conflict belongs to
table list element Open_table_context class and its methods
were extended to remember pointer to MDL_request which has
caused problem at request_backoff_action() time and use it
in recover_from_failed_open(). Similar approach is used
for cases when problem from which we need to recover is
not related to MDL but to the table itself. In this case
we store pointer to the element of table list.
- Changed open_tables()/open_tables_check_upgradable_mdl()/
open_tables_acquire_upgradable_mdl() not to rely on
MYSQL_OPEN_TAKE_UPGRADABLE_MDL flag to understand when
upgradable metadata locks should be acquired and not to
infer type of MDL lock from type of table-level lock.
Instead we assume that type of MDL to be acquired was set
in the parser (we can do this as type of MDL_request is
no longer reset between re-executions).
sql/sql_class.h:
Since we no longer have guarantee that MDL_request object
which were not satisfied due to lock conflict belongs to
table list element Open_table_context class and its methods
were extended to remember pointer to MDL_request which has
caused problem at request_backoff_action() time and use it
in recover_from_failed_open(). Similar approach is used
for cases when problem from which we need to recover is
not related to MDL but to the table itself. In this case
we store pointer to the element of table list.
sql/sql_db.cc:
Now one needs to properly initialize table list element's
MDL_request object before calling mysql_rm_table_part2()
or mysql_rename_tables().
sql/sql_lex.cc:
st_select_lex/st_select_lex_node::add_table_to_list() method
now has argument which allows specify type of metadata lock
to be requested for table list element being added.
sql/sql_lex.h:
- st_select_lex/st_select_lex_node::add_table_to_list()
method now has argument which specifies type of metadata
lock to be requested for table list element being added.
This allows to explicitly set type of MDL lock to be
acquired for a DDL statement in parser. It is also more
future-proof than inferring type of MDL request from type
of table-level lock.
- Added Yacc_state::m_mdl_type member which specifies which
type of metadata lock should be requested for tables to be
added to table list by a grammar rule in cases when the same
rule is used in several statements requiring different kinds
of metadata locks.
sql/sql_parse.cc:
- st_select_lex::add_table_to_list() method now has argument
which specifies type of metadata lock to be requested for
table list element being added. This allows to explicitly
set type of MDL lock to be acquired for a DDL statement in
parser. It is also more future-proof than inferring type of
MDL request from type of table-level lock.
- EXCLUSIVE_DOWNGRADABLE_MDL lock strategy has a new name -
OTLS_DOWNGRADE_IF_EXISTS.
- Adjusted LOCK TABLES implementation to the fact that we no
longer infer type of metadata lock to be acquired from table
level lock and that type of MDL request is set at parsing.
And thus MYSQL_OPEN_TAKE_UPGRADABLE_MDL flag became
unnecessary.
sql/sql_prepare.cc:
TABLE_LIST's lock strategy SHARED_MDL was renamed to OTLS_NONE
as now it means that metadata lock should not be changed during
call to open_table() (if it has been already acquired) and is
also used for exclusive metadata lock.
sql/sql_show.cc:
st_select_lex::add_table_to_list() method now has argument
which specifies type of metadata lock to be requested for
table list element being added.
sql/sql_table.cc:
- Adjusted mysql_admin_table()'s code to the fact that
open_tables() no longer determines what kind of metadata
lock should be obtained basing on type of table-level
lock and flags. Instead type of metadata lock for table
to be open should be set before calling open_tables().
- Changed mysql_alter_table() code to the facts:
a) that now it is responsibility of caller to properly
initalize MDL_request in table list elements before calling
lock_table_names()
b) and that MYSQL_OPEN_TAKE_UPGRADABLE_MDL is no longer
necessary since type of metadata lock to be obtained
at open_tables() time is set during parsing.
- Changed code of mysql_recreate_table() to properly set
type of metadata and table-level lock to be obtained
by mysql_alter_table() which it calls.
sql/sql_trigger.cc:
Instead of relying on MYSQL_OPEN_TAKE_UPGRADABLE_MDL flag to
force open_tables() to take an upgradable lock we now specify
exact type of lock to be taken when constructing table list
element for table to be open for CREATE/DROP TRIGGER.
sql/sql_view.cc:
We no longer use TABLE_LIST::EXCLUSIVE_MDL strategy to force
open_tables() to take an exclusive metadata lock on view to
be created. Instead we rely on parser setting proper type of
metadata lock to request and open_tables() acquiring it.
This became possible thanks to the fact that we no longer
reset type of MDL_request between statement re-executions.
sql/sql_yacc.yy:
Instead of inferring type of MDL_request for table to be
open from type of table-level lock and flags passed to
open_tables() we now explicitly specify them at parsing.
This became possible thanks to the fact that we no longer
reset type of MDL_request between statement re-executions.
In future this should allow to decouple type of metadata
lock from type of table-level lock.
The only exception to this approach is statements implemented
through mysql_admin_table() which re-uses same table list
element several times with different types of table-level
and metadata locks.
We now also properly initialize MDL_request objects for table
list elements which are later passed to lock_table_names()
function.
sql/table.cc:
Do not reset type of MDL_request between statement
re-executions. This became unnecessesary as we no longer
change type of MDL_request residing in table list element.
In its turn this change allows to set type of MDL_request
only once - at parsing time.
sql/table.h:
Got rid of TABLE_LIST::EXCLUSIVE_MDL lock strategy.
Now we can specify that we need to acquire exclusive lock
on table to be processed by open_tables() through setting
an appropriate type of MDL_request at parsing time (this
became possible thanks to the fact that we no longer reset
types of MDL_request's belonging to table list elements
between statement re-execution).
Strategy SHARED_MDL was renamed to OTLS_NONE as now it
means that metadata lock should not be changed during call
to open_table() (if it has been already acquired) and is
also used for exclusive metadata lock.
Strategy EXCLUSIVE_DOWNGRADABLE_MDL was renamed to
OTLS_DOWNGRADE_IF_EXISTS.
Item_hex_string::Item_hex_string
The status of memory allocation in the Lex_input_stream (called
from the Parser_state constructor) was not checked which led to
a parser crash in case of the out-of-memory error.
The solution is to introduce new init() member function in
Parser_state and Lex_input_stream so that status of memory
allocation can be returned to the caller.
mysql-test/r/error_simulation.result:
Added a test case for bug #42064.
mysql-test/t/error_simulation.test:
Added a test case for bug #42064.
mysys/my_alloc.c:
Added error injection code for the regression test.
mysys/my_malloc.c:
Added error injection code for the regression test.
mysys/safemalloc.c:
Added error injection code for the regression test.
sql/event_data_objects.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/mysqld.cc:
Added error injection code for the regression test.
sql/sp.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/sql_lex.cc:
Moved memory allocation from constructor to the separate init()
member function.
Added error injection code for the regression test.
sql/sql_lex.h:
Moved memory allocation from constructor to the separate init()
member function.
sql/sql_parse.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/sql_partition.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/sql_prepare.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/sql_trigger.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures.
sql/sql_view.cc:
Use the new init() member function of Parser_state and check
its return value to handle memory allocation failures..
sql/thr_malloc.cc:
Added error injection code for the regression test.
Adding my_global.h first in all files using
NO_EMBEDDED_ACCESS_CHECKS.
Correcting a merge problem resulting from a changed definition
of check_some_access compared to the original patches.
This patch:
- Moves all definitions from the mysql_priv.h file into
header files for the component where the variable is
defined
- Creates header files if the component lacks one
- Eliminates all include directives from mysql_priv.h
- Eliminates all circular include cycles
- Rename time.cc to sql_time.cc
- Rename mysql_priv.h to sql_priv.h
Conflicts:
Text conflict in client/mysqlbinlog.cc
Text conflict in mysql-test/Makefile.am
Text conflict in mysql-test/collections/default.daily
Text conflict in mysql-test/r/mysqlbinlog_row_innodb.result
Text conflict in mysql-test/suite/rpl/r/rpl_typeconv_innodb.result
Text conflict in mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test
Text conflict in mysql-test/suite/rpl/t/rpl_row_create_table.test
Text conflict in mysql-test/suite/rpl/t/rpl_slave_skip.test
Text conflict in mysql-test/suite/rpl/t/rpl_typeconv_innodb.test
Text conflict in mysys/charset.c
Text conflict in sql/field.cc
Text conflict in sql/field.h
Text conflict in sql/item.h
Text conflict in sql/item_func.cc
Text conflict in sql/log.cc
Text conflict in sql/log_event.cc
Text conflict in sql/log_event_old.cc
Text conflict in sql/mysqld.cc
Text conflict in sql/rpl_utility.cc
Text conflict in sql/rpl_utility.h
Text conflict in sql/set_var.cc
Text conflict in sql/share/Makefile.am
Text conflict in sql/sql_delete.cc
Text conflict in sql/sql_plugin.cc
Text conflict in sql/sql_select.cc
Text conflict in sql/sql_table.cc
Text conflict in storage/example/ha_example.h
Text conflict in storage/federated/ha_federated.cc
Text conflict in storage/myisammrg/ha_myisammrg.cc
Text conflict in storage/myisammrg/myrg_open.c
Conflicts:
Text conflict in client/mysqlbinlog.cc
Text conflict in mysql-test/r/explain.result
Text conflict in mysql-test/r/subselect.result
Text conflict in mysql-test/r/subselect3.result
Text conflict in mysql-test/r/type_datetime.result
Text conflict in sql/share/Makefile.am
The problem is that not all column names retrieved from a SELECT
statement can be used as view column names due to length and format
restrictions. The server failed to properly check the conformity
of those automatically generated column names before storing the
final view definition on disk.
Since columns retrieved from a SELECT statement can be anything
ranging from functions to constants values of any format and length,
the solution is to rewrite to a pre-defined format any names that
are not acceptable as a view column name.
The name is rewritten to "Name_exp_%u" where %u translates to the
position of the column. To avoid this conversion scheme, define
explict names for the view columns via the column_list clause.
Also, aliases are now only generated for top level statements.
mysql-test/include/view_alias.inc:
Add test case for Bug#40277
mysql-test/r/compare.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/group_by.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/ps.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/subselect.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/subselect3.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/type_datetime.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/union.result:
Bug#40277: SHOW CREATE VIEW returns invalid SQL
mysql-test/r/view.result:
Add test case result for Bug#40277
mysql-test/r/view_alias.result:
Add test case result for Bug#40277
mysql-test/t/view_alias.test:
Add test case for Bug#40277
sql/sql_view.cc:
Check if auto generated column names are conforming. Also, the
make_unique_view_field_name function is not used as it uses the
original name to construct a new one, which does not work if the
name is invalid.
This patch prevents system threads and system table accesses from
using user-specified values for "lock_wait_timeout". Instead all
such accesses are done using the default value (1 year).
This prevents background tasks (such as replication, events,
accessing stored function definitions, logging, reading time-zone
information, etc.) from failing in cases where the global value
of "lock_wait_timeout" is set very low.
The patch also simplifies the open tables API. Rather than adding
another convenience function for opening and locking system tables,
this patch removes most of the existing convenience functions for
open_and_lock_tables_derived(). Before, open_and_lock_tables() was
a convenience function that enforced derived tables handling, while
open_and_lock_tables_derived() was the main function where derived
tables handling was optional. Now, this convencience function is
gone and the main function is renamed to open_and_lock_tables().
No test case added as it would have required the use of --sleep to
check that system threads and system tables have a different timeout
value from the user-specified "lock_wait_timeout" system variable.
This bug is just one facet of stored routines not being able to
detect changes in meta-data (WL#4179). This particular problem
can be triggered within a single session due to the improper
management of the pre-locking list if the view is expanded after
the pre-locking list is calculated.
Since the overall solution for the meta-data detection issue is
planned for a later release, for now a workaround is used to
fix this particular aspect that only involves a single session.
The workaround is to flush the thread-local stored routine cache
every time a view is created or modified, causing locally cached
routines to be re-evaluated upon invocation.
mysql-test/r/sp-bugs.result:
Add test case result for Bug#50624.
mysql-test/t/sp-bugs.test:
Add test case for Bug#50624.
sql/sp_cache.cc:
Update function description.
sql/sql_view.cc:
Invalidate the SP cache if a view is being created or modified.
and MDL".
Concurrent execution of a multi-DELETE statement and ALTER
TABLE statement which affected one of the tables used in
the multi-DELETE sometimes led to deadlock.
Similar deadlocks might have occured when one performed
INSERT/UPDATE/DELETE on a view and concurrently executed
ALTER TABLE for the view's underlying table, or when one
concurrently executed TRUNCATE TABLE for InnoDB table and
ALTER TABLE for the same table.
These deadlocks were caused by a discrepancy between types of
metadata and thr_lock.cc locks acquired by those statements.
What happened was that multi-DELETE/TRUNCATE/DML-through-the-
view statement in the first connection acquired SR lock on a
table, then ALTER TABLE would come in in the second connection
and acquire SNW metadata lock and TL_WRITE_ALLOW_READ
thr_lock.c lock and then would start waiting for the first
connection during lock upgrade. After that the statement in
the first connection would try to acquire TL_WRITE lock on
table and would start waiting for the second connection,
creating a deadlock.
This patch solves this problem by ensuring that we acquire
SW metadata lock in all cases in which we acquiring write
thr_lock.c lock. This guarantees that deadlocks like the
one described above won't occur since all lock conflicts
in such situation are resolved within MDL subsystem.
This patch also adds assert which should guarantee that
such situations won't arise in future.
mysql-test/r/lock_multi.result:
Added main test for bug #50913 "Deadlock between
open_and_lock_tables_derived and MDL".
mysql-test/r/mdl_sync.result:
Added additional coverage for bug #50913 "Deadlock
between open_and_lock_tables_derived and MDL".
mysql-test/t/lock_multi.test:
Added main test for bug #50913 "Deadlock between
open_and_lock_tables_derived and MDL".
mysql-test/t/mdl_sync.test:
Added additional coverage for bug #50913 "Deadlock
between open_and_lock_tables_derived and MDL".
sql/lock.cc:
Added assert that enforces that when we are locking
a non-temporary table we have an appropriate type of
metadata lock on this table.
sql/mysql_priv.h:
Added separate flag for open_tables() to be able specify that
SH metadata locks on table to be open should be acquired.
We can no longer use MYSQL_LOCK_IGNORE_FLUSH flag for this
as in addition to use in I_S implementation it is also used
for opening system tables. Since in the latter case we also
acquire thr_lock.c locks using SH metadata lock in it instead
of SR or SW locks may lead to deadlock.
sql/sql_base.cc:
When opening tables don't interpret MYSQL_LOCK_IGNORE_FLUSH
flag as request to acquire SH metadata locks. This flag is
also used for opening system tables for which we also take
thr_lock.c locks and thus proper metadata lock to take in
this case is SR or SW lock (otherwise deadlocks can occur).
In cases when SH lock is really required (e.g. when tables
are open by I_S implementation) we rely on that newly
introduced MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL flag is
used.
sql/sql_delete.cc:
mysql_truncate_by_delete():
Adjust type of metadata lock to be requested after changing
type of thr_lock.c lock for table list element from one
which was set in parser to TL_WRITE.
This removes discrepancy between types of these locks which
allowed deadlocks to creep in.
sql/sql_handler.cc:
When closing table which was open by HANDLER statement clear
TABLE::open_by_handler flag. This allows to use this flag as
a reliable indication that TABLE instance was open by HANDLER
statement in assert which was added to mysql_lock_tables().
sql/sql_parse.cc:
multi_delete_set_locks_and_link_aux_tables():
Adjust type of metadata lock to be requested after changing
type of thr_lock.c lock for table list element from one
which was set in parser to TL_WRITE.
This removes discrepancy between types of these locks which
allowed deadlocks to creep in.
sql/sql_show.cc:
Use newly introduced MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL
flag in order to acquire SH metadata locks when opening tables
in I_S implementation.
sql/sql_update.cc:
Added comment explaining why in multi-update after deciding
that we need weaker thr_lock.c lock on a table we don't
downgrade metadata lock on it.
sql/sql_view.cc:
When merging view into main statement adjust type of metadata
lock to be requested after changing type of thr_lock.c lock
for table. This removes discrepancy between types of these
locks which allowed deadlocks to creep in.
Cherry-pick a fix Bug#37148 from next-mr, to preserve
file ids of the added files, and ensure that all the necessary
changes have been pulled.
Since initially Bug#37148 was null-merged into 6.0,
the changeset that is now being cherry-picked was likewise
null merged into next-4284.
Now that Bug#37148 has been reapplied to 6.0, try to make
it work with next-4284. This is also necessary to be able
to pull other changes from 5.1-rep into next-4284.
To resolve the merge issues use this changeset applied
to 6.0:
revid:jperkin@sun.com-20091216103628-ylhqf7s6yegui2t9
revno: 3776.1.1
committer: He Zhenxing <zhenxing.he@sun.com>
branch nick: 6.0-codebase-bugfixing
timestamp: Thu 2009-12-17 17:02:50 +0800
message:
Fix merge problem with Bug#37148
Add a wait-for graph based deadlock detector to the
MDL subsystem.
Fixes bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock" and
bug #37346 "innodb does not detect deadlock between update and
alter table".
The first bug manifested itself as an unwarranted abort of a
transaction with ER_LOCK_DEADLOCK error by a concurrent ALTER
statement, when this transaction tried to repeat use of a
table, which it has already used in a similar fashion before
ALTER started.
The second bug showed up as a deadlock between table-level
locks and InnoDB row locks, which was "detected" only after
innodb_lock_wait_timeout timeout.
A transaction would start using the table and modify a few
rows.
Then ALTER TABLE would come in, and start copying rows
into a temporary table. Eventually it would stumble on
the modified records and get blocked on a row lock.
The first transaction would try to do more updates, and get
blocked on thr_lock.c lock.
This situation of circular wait would only get resolved
by a timeout.
Both these bugs stemmed from inadequate solutions to the
problem of deadlocks occurring between different
locking subsystems.
In the first case we tried to avoid deadlocks between metadata
locking and table-level locking subsystems, when upgrading shared
metadata lock to exclusive one.
Transactions holding the shared lock on the table and waiting for
some table-level lock used to be aborted too aggressively.
We also allowed ALTER TABLE to start in presence of transactions
that modify the subject table. ALTER TABLE acquires
TL_WRITE_ALLOW_READ lock at start, and that block all writes
against the table (naturally, we don't want any writes to be lost
when switching the old and the new table). TL_WRITE_ALLOW_READ
lock, in turn, would block the started transaction on thr_lock.c
lock, should they do more updates. This, again, lead to the need
to abort such transactions.
The second bug occurred simply because we didn't have any
mechanism to detect deadlocks between the table-level locks
in thr_lock.c and row-level locks in InnoDB, other than
innodb_lock_wait_timeout.
This patch solves both these problems by moving lock conflicts
which are causing these deadlocks into the metadata locking
subsystem, thus making it possible to avoid or detect such
deadlocks inside MDL.
To do this we introduce new type-of-operation-aware metadata
locks, which allow MDL subsystem to know not only the fact that
transaction has used or is going to use some object but also what
kind of operation it has carried out or going to carry out on the
object.
This, along with the addition of a special kind of upgradable
metadata lock, allows ALTER TABLE to wait until all
transactions which has updated the table to go away.
This solves the second issue.
Another special type of upgradable metadata lock is acquired
by LOCK TABLE WRITE. This second lock type allows to solve the
first issue, since abortion of table-level locks in event of
DDL under LOCK TABLES becomes also unnecessary.
Below follows the list of incompatible changes introduced by
this patch:
- From now on, ALTER TABLE and CREATE/DROP TRIGGER SQL (i.e. those
statements that acquire TL_WRITE_ALLOW_READ lock)
wait for all transactions which has *updated* the table to
complete.
- From now on, LOCK TABLES ... WRITE, REPAIR/OPTIMIZE TABLE
(i.e. all statements which acquire TL_WRITE table-level lock) wait
for all transaction which *updated or read* from the table
to complete.
As a consequence, innodb_table_locks=0 option no longer applies
to LOCK TABLES ... WRITE.
- DROP DATABASE, DROP TABLE, RENAME TABLE no longer abort
statements or transactions which use tables being dropped or
renamed, and instead wait for these transactions to complete.
- Since LOCK TABLES WRITE now takes a special metadata lock,
not compatible with with reads or writes against the subject table
and transaction-wide, thr_lock.c deadlock avoidance algorithm
that used to ensure absence of deadlocks between LOCK TABLES
WRITE and other statements is no longer sufficient, even for
MyISAM. The wait-for graph based deadlock detector of MDL
subsystem may sometimes be necessary and is involved. This may
lead to ER_LOCK_DEADLOCK error produced for multi-statement
transactions even if these only use MyISAM:
session 1: session 2:
begin;
update t1 ... lock table t2 write, t1 write;
-- gets a lock on t2, blocks on t1
update t2 ...
(ER_LOCK_DEADLOCK)
- Finally, support of LOW_PRIORITY option for LOCK TABLES ... WRITE
was abandoned.
LOCK TABLE ... LOW_PRIORITY WRITE from now on has the same
priority as the usual LOCK TABLE ... WRITE.
SELECT HIGH PRIORITY no longer trumps LOCK TABLE ... WRITE in
the wait queue.
- We do not take upgradable metadata locks on implicitly
locked tables. So if one has, say, a view v1 that uses
table t1, and issues:
LOCK TABLE v1 WRITE;
FLUSH TABLE t1; -- (or just 'FLUSH TABLES'),
an error is produced.
In order to be able to perform DDL on a table under LOCK TABLES,
the table must be locked explicitly in the LOCK TABLES list.
mysql-test/include/handler.inc:
Adjusted test case to trigger an execution path on which bug 41110
"crash with handler command when used concurrently with alter
table" and bug 41112 "crash in mysql_ha_close_table/get_lock_data
with alter table" were originally discovered. Left old test case
which no longer triggers this execution path for the sake of
coverage.
Added test coverage for HANDLER SQL statements and type-aware
metadata locks.
Added a test for the global shared lock and HANDLER SQL.
Updated tests to take into account that the old simple deadlock
detection heuristics was replaced with a graph-based deadlock
detector.
mysql-test/r/debug_sync.result:
Updated results (see debug_sync.test).
mysql-test/r/handler_innodb.result:
Updated results (see handler.inc test).
mysql-test/r/handler_myisam.result:
Updated results (see handler.inc test).
mysql-test/r/innodb-lock.result:
Updated results (see innodb-lock.test).
mysql-test/r/innodb_mysql_lock.result:
Updated results (see innodb_mysql_lock.test).
mysql-test/r/lock.result:
Updated results (see lock.test).
mysql-test/r/lock_multi.result:
Updated results (see lock_multi.test).
mysql-test/r/lock_sync.result:
Updated results (see lock_sync.test).
mysql-test/r/mdl_sync.result:
Updated results (see mdl_sync.test).
mysql-test/r/sp-threads.result:
SHOW PROCESSLIST output has changed due to the fact that waiting
for LOCK TABLES WRITE now happens within metadata locking
subsystem.
mysql-test/r/truncate_coverage.result:
Updated results (see truncate_coverage.test).
mysql-test/suite/funcs_1/datadict/processlist_val.inc:
SELECT FROM I_S.PROCESSLIST output has changed due to fact that
waiting for LOCK TABLES WRITE now happens within metadata locking
subsystem.
mysql-test/suite/funcs_1/r/processlist_val_no_prot.result:
SELECT FROM I_S.PROCESSLIST output has changed due to fact that
waiting for LOCK TABLES WRITE now happens within metadata locking
subsystem.
mysql-test/suite/rpl/t/rpl_sp.test:
Updated to a new SHOW PROCESSLIST state name.
mysql-test/t/debug_sync.test:
Use LOCK TABLES READ instead of LOCK TABLES WRITE as the latter
no longer allows to trigger execution path involving waiting on
thr_lock.c lock and therefore reaching debug sync-point covered
by this test.
mysql-test/t/innodb-lock.test:
Adjusted test case to the fact that innodb_table_locks=0 option is
no longer supported, since LOCK TABLES WRITE handles all its
conflicts within MDL subsystem.
mysql-test/t/innodb_mysql_lock.test:
Added test for bug #37346 "innodb does not detect deadlock between
update and alter table".
mysql-test/t/lock.test:
Added test coverage which checks the fact that we no longer support
DDL under LOCK TABLES on tables which were locked implicitly.
Adjusted existing test cases accordingly.
mysql-test/t/lock_multi.test:
Added test for bug #46272 "MySQL 5.4.4, new MDL: unnecessary
deadlock". Adjusted other test cases to take into account the
fact that waiting for LOCK TABLES ... WRITE now happens within MDL
subsystem.
mysql-test/t/lock_sync.test:
Since LOCK TABLES ... WRITE now takes SNRW metadata lock for
tables locked explicitly we have to implicitly lock InnoDB tables
(through view) to trigger the table-level lock conflict between
TL_WRITE and TL_WRITE_ALLOW_WRITE.
mysql-test/t/mdl_sync.test:
Added basic test coverage for type-of-operation-aware metadata
locks. Also covered with tests some use cases involving HANDLER
statements in which a deadlock could arise.
Adjusted existing tests to take type-of-operation-aware MDL into
account.
mysql-test/t/multi_update.test:
Update to a new SHOW PROCESSLIST state name.
mysql-test/t/truncate_coverage.test:
Adjusted test case after making LOCK TABLES WRITE to wait until
transactions that use the table to be locked are completed.
Updated to the changed name of DEBUG_SYNC point.
sql/handler.cc:
Global read lock functionality has been
moved into a class.
sql/lock.cc:
Global read lock functionality has been
moved into a class.
Updated code to use the new MDL API.
sql/mdl.cc:
Introduced new type-of-operation aware metadata locks.
To do this:
- Changed MDL_lock to use one list for waiting requests and one
list for granted requests. For each list, added a bitmap
that holds information what lock types a list contains.
Added a helper class MDL_lock::List to manipulate with granted
and waited lists while keeping the bitmaps in sync
with list contents.
- Changed lock-compatibility functions to use bitmaps that
define compatibility.
- Introduced a graph based deadlock detector inspired by
waiting_threads.c from Maria implementation.
- Now that we have a deadlock detector, and no longer have
a global lock to protect individual lock objects, but rather
use an rw lock per object, removed redundant code for upgrade,
and the global read lock. Changed the MDL API to
no longer require the caller to acquire the global
intention exclusive lock by means of a separate method.
Removed a few more methods that became redundant.
- Removed deadlock detection heuristic, it has been made
obsolete by the deadlock detector.
- With operation-type-aware metadata locks, MDL subsystem has
become aware of potential conflicts between DDL and open
transactions. This made it possible to remove calls to
mysql_abort_transactions_with_shared_lock() from acquisition
paths for exclusive lock and lock upgrade. Now we can simply
wait for these transactions to complete without fear of
deadlock. Function mysql_lock_abort() has also become
unnecessary for all conflicting cases except when a DDL
conflicts with a connection that has an open HANDLER.
sql/mdl.h:
Introduced new type-of-operation aware metadata locks.
Introduced a graph based deadlock detector and supporting
methods.
Added comments.
God rid of redundant API calls.
Renamed m_lt_or_ha_sentinel to m_trans_sentinel,
since now it guards the global read lock as well as
LOCK TABLES and HANDLER locks.
sql/mysql_priv.h:
Moved the global read lock functionality into a
class.
Added MYSQL_OPEN_FORCE_SHARED_MDL flag which forces
open_tables() to take MDL_SHARED on tables instead of
metadata locks specified in the parser. We use this to
allow PREPARE run concurrently in presence of
LOCK TABLES ... WRITE.
Added signature for find_table_for_mdl_ugprade().
sql/set_var.cc:
Global read lock functionality has been
moved into a class.
sql/sp_head.cc:
When creating TABLE_LIST elements for prelocking or
system tables set the type of request for metadata
lock according to the operation that will be performed
on the table.
sql/sql_base.cc:
- Updated code to use the new MDL API.
- In order to avoid locks starvation we take upgradable
locks all at once. As result implicitly locked tables no
longer get an upgradable lock. Consequently DDL and FLUSH
TABLES for such tables is prohibited.
find_write_locked_table() was replaced by
find_table_for_mdl_upgrade() function.
open_table() was adjusted to return TABLE instance with
upgradable ticket when necessary.
- We no longer wait for all locks on OT_WAIT back off
action -- only on the lock that caused the wait
conflict. Moreover, now we distinguish cases when we
have to wait due to conflict in MDL and old version
of table in TDC.
- Upate mysql_notify_threads_having_share_locks()
to only abort thr_lock.c waits of threads that
have open HANDLERs, since lock conflicts with only
these threads now can lead to deadlocks not detectable
by the MDL deadlock detector.
- Remove mysql_abort_transactions_with_shared_locks()
which is no longer needed.
sql/sql_class.cc:
Global read lock functionality has been moved into a class.
Re-arranged code in THD::cleanup() to simplify assert.
sql/sql_class.h:
Introduced class to incapsulate global read lock
functionality.
Now sentinel in MDL subsystem guards the global read lock
as well as LOCK TABLES and HANDLER locks. Adjusted code
accordingly.
sql/sql_db.cc:
Global read lock functionality has been moved into a class.
sql/sql_delete.cc:
We no longer acquire upgradable metadata locks on tables
which are locked by LOCK TABLES implicitly. As result
TRUNCATE TABLE is no longer allowed for such tables.
Updated code to use the new MDL API.
sql/sql_handler.cc:
Inform MDL_context about presence of open HANDLERs.
Since HANLDERs break MDL protocol by acquiring table-level
lock while holding only S metadata lock on a table MDL
subsystem should take special care about such contexts (Now
this is the only case when mysql_lock_abort() is used).
sql/sql_parse.cc:
Global read lock functionality has been moved into a class.
Do not take upgradable metadata locks when opening tables
for CREATE TABLE SELECT as it is not necessary and limits
concurrency.
When initializing TABLE_LIST objects before adding them
to the table list set the type of request for metadata lock
according to the operation that will be performed on the
table.
We no longer acquire upgradable metadata locks on tables
which are locked by LOCK TABLES implicitly. As result FLUSH
TABLES is no longer allowed for such tables.
sql/sql_prepare.cc:
Use MYSQL_OPEN_FORCE_SHARED_MDL flag when opening
tables during PREPARE. This allows PREPARE to run
concurrently in presence of LOCK TABLES ... WRITE.
sql/sql_rename.cc:
Global read lock functionality has been moved into a class.
sql/sql_show.cc:
Updated code to use the new MDL API.
sql/sql_table.cc:
Global read lock functionality has been moved into a class.
We no longer acquire upgradable metadata locks on tables
which are locked by LOCK TABLES implicitly. As result DROP
TABLE is no longer allowed for such tables.
Updated code to use the new MDL API.
sql/sql_trigger.cc:
Global read lock functionality has been moved into a class.
We no longer acquire upgradable metadata locks on tables
which are locked by LOCK TABLES implicitly. As result
CREATE/DROP TRIGGER is no longer allowed for such tables.
Updated code to use the new MDL API.
sql/sql_view.cc:
Global read lock functionality has been moved into a class.
Fixed results of wrong merge that led to misuse of GLR API.
CREATE VIEW statement is not a commit statement.
sql/table.cc:
When resetting TABLE_LIST objects for PS or SP re-execution
set the type of request for metadata lock according to the
operation that will be performed on the table. Do the same
in auxiliary function initializing metadata lock requests
in a table list.
sql/table.h:
When initializing TABLE_LIST objects set the type of request
for metadata lock according to the operation that will be
performed on the table.
sql/transaction.cc:
Global read lock functionality has been moved into a class.
Conflicts:
Text conflict in .bzr-mysql/default.conf
Text conflict in mysql-test/extra/rpl_tests/rpl_loaddata.test
Text conflict in mysql-test/r/mysqlbinlog2.result
Text conflict in mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
Text conflict in mysql-test/suite/binlog/r/binlog_unsafe.result
Text conflict in mysql-test/suite/rpl/r/rpl_insert_id.result
Text conflict in mysql-test/suite/rpl/r/rpl_loaddata.result
Text conflict in mysql-test/suite/rpl/r/rpl_stm_auto_increment_bug33029.result
Text conflict in mysql-test/suite/rpl/r/rpl_udf.result
Text conflict in mysql-test/suite/rpl/t/rpl_slow_query_log.test
Text conflict in sql/field.h
Text conflict in sql/log.cc
Text conflict in sql/log_event.cc
Text conflict in sql/log_event_old.cc
Text conflict in sql/mysql_priv.h
Text conflict in sql/share/errmsg.txt
Text conflict in sql/sp.cc
Text conflict in sql/sql_acl.cc
Text conflict in sql/sql_base.cc
Text conflict in sql/sql_class.h
Text conflict in sql/sql_db.cc
Text conflict in sql/sql_delete.cc
Text conflict in sql/sql_insert.cc
Text conflict in sql/sql_lex.cc
Text conflict in sql/sql_lex.h
Text conflict in sql/sql_load.cc
Text conflict in sql/sql_table.cc
Text conflict in sql/sql_update.cc
Text conflict in sql/sql_view.cc
Conflict adding files to storage/innobase. Created directory.
Conflict because storage/innobase is not versioned, but has versioned children. Versioned directory.
Conflict adding file storage/innobase. Moved existing file to storage/innobase.moved.
Conflict adding files to storage/innobase/handler. Created directory.
Conflict because storage/innobase/handler is not versioned, but has versioned children. Versioned directory.
Contents conflict in storage/innobase/handler/ha_innodb.cc
Bug#16565 mysqld --help --verbose does not order variablesBug#20413 sql_slave_skip_counter is not shown in show variables
Bug#20415 Output of mysqld --help --verbose is incomplete
Bug#25430 variable not found in SELECT @@global.ft_max_word_len;
Bug#32902 plugin variables don't know their names
Bug#34599 MySQLD Option and Variable Reference need to be consistent in formatting!
Bug#34829 No default value for variable and setting default does not raise error
Bug#34834 ? Is accepted as a valid sql mode
Bug#34878 Few variables have default value according to documentation but error occurs
Bug#34883 ft_boolean_syntax cant be assigned from user variable to global var.
Bug#37187 `INFORMATION_SCHEMA`.`GLOBAL_VARIABLES`: inconsistent status
Bug#40988 log_output_basic.test succeeded though syntactically false.
Bug#41010 enum-style command-line options are not honoured (maria.maria-recover fails)
Bug#42103 Setting key_buffer_size to a negative value may lead to very large allocations
Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled
Bug#44797 plugins w/o command-line options have no disabling option in --help
Bug#46314 string system variables don't support expressions
Bug#46470 sys_vars.max_binlog_cache_size_basic_32 is broken
Bug#46586 When using the plugin interface the type "set" for options caused a crash.
Bug#47212 Crash in DBUG_PRINT in mysqltest.cc when trying to print octal number
Bug#48758 mysqltest crashes on sys_vars.collation_server_basic in gcov builds
Bug#49417 some complaints about mysqld --help --verbose output
Bug#49540 DEFAULT value of binlog_format isn't the default value
Bug#49640 ambiguous option '--skip-skip-myisam' (double skip prefix)
Bug#49644 init_connect and \0
Bug#49645 init_slave and multi-byte characters
Bug#49646 mysql --show-warnings crashes when server dies
CMakeLists.txt:
Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled
client/mysql.cc:
don't crash with --show-warnings when mysqld dies
config/ac-macros/plugins.m4:
Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled
include/my_getopt.h:
comments
include/my_pthread.h:
fix double #define
mysql-test/mysql-test-run.pl:
run sys_vars suite by default
properly recognize envirinment variables (e.g. MTR_MAX_SAVE_CORE) set to 0
escape gdb command line arguments
mysql-test/suite/sys_vars/r/rpl_init_slave_func.result:
init_slave+utf8 bug
mysql-test/suite/sys_vars/t/rpl_init_slave_func.test:
init_slave+utf8 bug
mysys/my_getopt.c:
Bug#34599 MySQLD Option and Variable Reference need to be consistent in formatting!
Bug#46586 When using the plugin interface the type "set" for options caused a crash.
Bug#49640 ambiguous option '--skip-skip-myisam' (double skip prefix)
mysys/typelib.c:
support for flagset
sql/ha_ndbcluster.cc:
backport from telco tree
sql/item_func.cc:
Bug#49644 init_connect and \0
Bug#49645 init_slave and multi-byte characters
sql/sql_builtin.cc.in:
Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled
sql/sql_plugin.cc:
Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled
Bug#32902 plugin variables don't know their names
Bug#44797 plugins w/o command-line options have no disabling option in --help
sql/sys_vars.cc:
all server variables are defined here
storage/myisam/ft_parser.c:
remove unnecessary updates of param->quot
storage/myisam/ha_myisam.cc:
myisam_* variables belong here
strings/my_vsnprintf.c:
%o and %llx
unittest/mysys/my_vsnprintf-t.c:
%o and %llx tests
vio/viosocket.c:
bugfix: fix @@wait_timeout to work with socket timeouts (vs. alarm thread)
check_key_in_view() had one code branch which returned with "return TRUE"
rather than "DBUG_RETURN(TRUE)". Only affected debug builds.
No test case added.
Bug #47313 assert in check_key_in_view during CALL procedure
View definitions are inlined in a stored procedure when the procedure
is fist called. This means that if a temporary table is later added
with the same name as the view, the stored procedure will still
use the view. This happens even if temporary tables normally shadow
base tables/views.
The reason for the assert was that even if the stored procedure
referenced the view, open_table() still tried to open the
temporary table. This "half view/half temporary table" state
caused the assert.
The bug was not present in 5.1 as open_table() is not called
for the view there. This code was changed with the introduction
of MDL in order to properly lock the view and any objects it
refers to.
This patch fixes the problem by instructing open_table()
to open base tables/views (using OT_BASE_ONLY) when reopening
tables/views used by stored procedures. This also means that
a prepared statement is no longer invalidated if a temporary
table is created with the same name as a view used in the
prepared statement.
Test case added to sp.test. The test case also demonstrates
the effect of sp cache invalidation between CALLs.
mysql-test/t/ps_ddl.test:
Extended the VIEW->TEMPORARY TABLE transition test to cover not only
merged views, but now also materialized views and views containing
a reference to an information schema table.
Test also updated to reflect the change to prepared statement
invalidatation.
Bug #47335 assert in get_table_share
The assert would happen if ALTER VIEW was used to alter a view (existing
or non-existing) and a temporary table with the same name already existed.
The assert is triggered if the current statement does not have a MDL lock on
the view to be altered. This would happen because open_table() would open
the temporary table instead and MDL locks are not taken for temporary
tables (since they are local to one connection).
The patch changes open_type for CREATE/ALTER VIEW to OT_BASE_ONLY. This prevents
open_table() from trying to open a temporary table with the same name should
one exist. Now the view will be altered if it exists or ER_NO_SUCH_TABLE will
be reported if it does not.
Test case added to view.test
Bug#42546 Backup: RESTORE fails, thinking it finds an existing table
The problem occured when a MDL locking conflict happened for a non-existent
table between a CREATE and a INSERT statement. The code for CREATE
interpreted this lock conflict to mean that the table existed,
which meant that the statement failed when it should not have.
The problem could occur for CREATE TABLE, CREATE TABLE LIKE and
ALTER TABLE RENAME.
This patch fixes the problem for CREATE TABLE and CREATE TABLE LIKE.
It is based on code backported from the mysql-6.1-fk tree written
by Dmitry Lenev. CREATE now uses normal open_and_lock_tables() code
to acquire exclusive locks. This means that for the test case in the bug
description, CREATE will wait until INSERT completes so that it can
get the exclusive lock. This resolves the reported bug.
The patch also prohibits CREATE TABLE and CREATE TABLE LIKE under
LOCK TABLES. Note that this is an incompatible change and must
be reflected in the documentation. Affected test cases have been
updated.
mdl_sync.test contains tests for CREATE TABLE and CREATE TABLE LIKE.
Fixing the issue for ALTER TABLE RENAME is beyond the scope of this
patch. ALTER TABLE cannot be prohibited from working under LOCK TABLES
as this could seriously impact customers and a proper fix would require
a significant rewrite.
2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1
- initial changeset that introduced the fix for
Bug#989 and follow up fixes for all test suite failures
introduced in the initial changeset.
------------------------------------------------------------
revno: 2617.31.1
committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
branch nick: 4284-6.0
timestamp: Fri 2009-03-06 19:17:00 -0300
message:
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking
Currently the MySQL server does not keep metadata locks on
schema objects for the duration of a transaction, thus failing
to guarantee the integrity of the schema objects being used
during the transaction and to protect then from concurrent
DDL operations. This also poses a problem for replication as
a DDL operation might be replicated even thought there are
active transactions using the object being modified.
The solution is to defer the release of metadata locks until
a active transaction is either committed or rolled back. This
prevents other statements from modifying the table for the
entire duration of the transaction. This provides commitment
ordering for guaranteeing serializability across multiple
transactions.
- Incompatible change:
If MySQL's metadata locking system encounters a lock conflict,
the usual schema is to use the try and back-off technique to
avoid deadlocks -- this schema consists in releasing all locks
and trying to acquire them all in one go.
But in a transactional context this algorithm can't be utilized
as its not possible to release locks acquired during the course
of the transaction without breaking the transaction commitments.
To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
returned if a lock conflict is encountered during a transaction.
Let's consider an example:
A transaction has two statements that modify table t1, then table
t2, and then commits. The first statement of the transaction will
acquire a shared metadata lock on table t1, and it will be kept
utill COMMIT to ensure serializability.
At the moment when the second statement attempts to acquire a
shared metadata lock on t2, a concurrent ALTER or DROP statement
might have locked t2 exclusively. The prescription of the current
locking protocol is that the acquirer of the shared lock backs off
-- gives up all his current locks and retries. This implies that
the entire multi-statement transaction has to be rolled back.
- Incompatible change:
FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
LOCK won't cause locked tables to be implicitly unlocked anymore.
mysql-test/extra/binlog_tests/drop_table.test:
Add test case for Bug#989.
mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
mysql-test/include/mix1.inc:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
mysql-test/include/mix2.inc:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
mysql-test/r/flush_block_commit.result:
Update test case result (WL#4284).
mysql-test/r/flush_block_commit_notembedded.result:
Update test case result (WL#4284).
mysql-test/r/innodb.result:
Update test case result (WL#4284).
mysql-test/r/innodb_mysql.result:
Update test case result (WL#4284).
mysql-test/r/lock.result:
Add test case result for an effect of WL#4284/Bug#989
(all locks should be released when a connection terminates).
mysql-test/r/mix2_myisam.result:
Update test case result (effects of WL#4284/Bug#989).
mysql-test/r/not_embedded_server.result:
Update test case result (effects of WL#4284/Bug#989).
Add a test case for interaction of WL#4284 and FLUSH PRIVILEGES.
mysql-test/r/partition_innodb_semi_consistent.result:
Update test case result (effects of WL#4284/Bug#989).
mysql-test/r/partition_sync.result:
Temporarily disable the test case for Bug#43867,
which will be fixed by a subsequent backport.
mysql-test/r/ps.result:
Add a test case for effect of PREPARE on transactional
locks: we take a savepoint at beginning of PREAPRE
and release it at the end. Thus PREPARE does not
accumulate metadata locks (Bug#989/WL#4284).
mysql-test/r/read_only_innodb.result:
Update test case result (effects of WL#4284/Bug#989).
mysql-test/suite/binlog/r/binlog_row_drop_tbl.result:
Add a test case result (WL#4284/Bug#989).
mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result:
Update test case result (effects of WL#4284/Bug#989).
mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result:
Add a test case result (WL#4284/Bug#989).
mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result:
Update test case result (effects of WL#4284/Bug#989).
mysql-test/suite/binlog/r/binlog_unsafe.result:
A side effect of Bug#989 -- slightly different table map ids.
mysql-test/suite/binlog/t/binlog_row_drop_tbl.test:
Add a test case for WL#4284/Bug#989.
mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test:
Add a test case for WL#4284/Bug#989.
mysql-test/suite/binlog/t/binlog_stm_row.test:
Update to the new state name. This
is actually a follow up to another patch for WL#4284,
that changes Locked thread state to Table lock.
mysql-test/suite/ndb/r/ndb_index_ordered.result:
Remove result for disabled part of the test case.
mysql-test/suite/ndb/t/disabled.def:
Temporarily disable a test case (Bug#45621).
mysql-test/suite/ndb/t/ndb_index_ordered.test:
Disable a part of a test case (needs update to
reflect semantics of Bug#989).
mysql-test/suite/rpl/t/disabled.def:
Disable tests made meaningless by transactional metadata
locking.
mysql-test/suite/sys_vars/r/autocommit_func.result:
Add a commit (Bug#989).
mysql-test/suite/sys_vars/t/autocommit_func.test:
Add a commit (Bug#989).
mysql-test/t/flush_block_commit.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
mysql-test/t/flush_block_commit_notembedded.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
Add a test case for transaction-scope locks and the global
read lock (Bug#989/WL#4284).
mysql-test/t/innodb.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction
(effects of Bug#989/WL#4284).
mysql-test/t/lock.test:
Add a test case for Bug#989/WL#4284.
mysql-test/t/not_embedded_server.test:
Add a test case for Bug#989/WL#4284.
mysql-test/t/partition_innodb_semi_consistent.test:
Replace TRUNCATE with DELETE, to not issue
an implicit commit of a transaction, and not depend
on metadata locks.
mysql-test/t/partition_sync.test:
Temporarily disable the test case for Bug#43867,
which needs a fix to be backported from 6.0.
mysql-test/t/ps.test:
Add a test case for semantics of PREPARE and transaction-scope
locks: metadata locks on tables used in PREPARE are enclosed into a
temporary savepoint, taken at the beginning of PREPARE,
and released at the end. Thus PREPARE does not effect
what locks a transaction owns.
mysql-test/t/read_only_innodb.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction
(Bug#989/WL#4284).
Wait for the read_only statement to actually flush tables before
sending other concurrent statements that depend on its state.
mysql-test/t/xa.test:
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction
(Bug#989/WL#4284).
sql/ha_ndbcluster_binlog.cc:
Backport bits of changes of ha_ndbcluster_binlog.cc
from 6.0, to fix the failing binlog test suite with
WL#4284. WL#4284 implementation does not work
with 5.1 implementation of ndbcluster binlog index.
sql/log_event.cc:
Release metadata locks after issuing a commit.
sql/mdl.cc:
Style changes (WL#4284).
sql/mysql_priv.h:
Rename parameter to match the name used in the definition (WL#4284).
sql/rpl_injector.cc:
Release metadata locks on commit (WL#4284).
sql/rpl_rli.cc:
Remove assert made meaningless, metadata locks are released
at the end of the transaction.
sql/set_var.cc:
Close tables and release locks if autocommit mode is set.
sql/slave.cc:
Release metadata locks after a rollback.
sql/sql_acl.cc:
Don't implicitly unlock locked tables. Issue a implicit commit
at the end and unlock tables.
sql/sql_base.cc:
Defer the release of metadata locks when closing tables
if not required to.
Issue a deadlock error if the locking protocol requires
that a transaction re-acquire its locks.
Release metadata locks when closing tables for reopen.
sql/sql_class.cc:
Release metadata locks if the thread is killed.
sql/sql_parse.cc:
Release metadata locks after implicitly committing a active
transaction, or after explicit commits or rollbacks.
sql/sql_plugin.cc:
Allocate MDL request on the stack as the use of the table
is contained within the function. It will be removed from
the context once close_thread_tables is called at the end
of the function.
sql/sql_prepare.cc:
The problem is that the prepare phase of the CREATE TABLE
statement takes a exclusive metadata lock lock and this can
cause a self-deadlock the thread already holds a shared lock
on the table being that should be created.
The solution is to make the prepare phase take a shared
metadata lock when preparing a CREATE TABLE statement. The
execution of the statement will still acquire a exclusive
lock, but won't cause any problem as it issues a implicit
commit.
After some discussions with stakeholders it has been decided that
metadata locks acquired during a PREPARE statement must be released
once the statement is prepared even if it is prepared within a multi
statement transaction.
sql/sql_servers.cc:
Don't implicitly unlock locked tables. Issue a implicit commit
at the end and unlock tables.
sql/sql_table.cc:
Close table and release metadata locks after a admin operation.
sql/table.h:
The problem is that the prepare phase of the CREATE TABLE
statement takes a exclusive metadata lock lock and this can
cause a self-deadlock the thread already holds a shared lock
on the table being that should be created.
The solution is to make the prepare phase take a shared
metadata lock when preparing a CREATE TABLE statement. The
execution of the statement will still acquire a exclusive
lock, but won't cause any problem as it issues a implicit
commit.
sql/transaction.cc:
Release metadata locks after the implicitly committed due
to a new transaction being started. Also, release metadata
locks acquired after a savepoint if the transaction is rolled
back to the save point.
The problem is that in some cases transaction-long metadata locks
could be released before the transaction was committed. This could
happen when a active transaction was ended by a "START TRANSACTION"
or "BEGIN" statement, in which case the metadata locks would be
released before the actual commit of the active transaction.
The solution is to defer the release of metadata locks to after the
transaction has been implicitly committed. No test case is provided
as the effort to provide one is too disproportional to the size of
the fix.