• Dmitry Lenev's avatar
    Pre-requisite patch for bug #51263 "Deadlock between · bee0f214
    Dmitry Lenev authored
    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.
    bee0f214
lock.cc 46.3 KB