List:Commits« Previous MessageNext Message »
From:Chuck Bell Date:December 14 2009 10:38pm
Subject:bzr commit into mysql-5.6-next-mr branch (charles.bell:3005) Bug#32702
View as plain text  
#At file:///home/cbell/source/bzr/backport/ based on revid:charles.bell@stripped

 3005 Chuck Bell	2009-12-14
      BUG#32702 - Backup: DDL blocker does not block all it should
        
      After this patch, the DDL blocker will be renamed to 
      Backup Metadata Lock and will block all the statements 
      listed in WL#4644. Test backup_ddl_blocker will be 
      renamed to backup_bml and extended to test all these 
      statements.
        
      This patch implements desing described in WL#4644. It 
      marks all statements which need to be blocked by BML with 
      special CF_BLOCKED_BY_BML flag. Then registering 
      and unregistering marked statements with BML is done 
      globally in mysql_execute_command(). 
       
      This makes changes in the parser code minimal, makes it 
      easy to trace the list of statements which ale blocked 
      and easily ensures that each bml_enter() call is matched 
      with bml_leave().
      
      original changeset: 2599.121.10
     @ libmysqld/CMakeLists.txt
         Rename ddl_blocker.{h,cc} -> bml.{h,cc}.
     @ libmysqld/Makefile.am
         Rename ddl_blocker.{h,cc} -> bml.{h,cc}.
     @ sql/CMakeLists.txt
         Rename ddl_blocker.{h,cc} -> bml.{h,cc}.
     @ sql/Makefile.am
         Rename ddl_blocker.{h,cc} -> bml.{h,cc}.
     @ sql/bml.cc
        Rename "DDL blocker" -> "Backup Metadata Lock":
            - change class and member names.
            - update documentation.
     @ sql/bml.h
        Rename "DDL blocker" -> "Backup Metadata Lock":
            - change class and member names.
            - update documentation.

    renamed:
      sql/ddl_blocker.cc => sql/bml.cc
      sql/ddl_blocker.h => sql/bml.h
    modified:
      libmysqld/CMakeLists.txt
      libmysqld/Makefile.am
      sql/CMakeLists.txt
      sql/Makefile.am
      sql/bml.cc
      sql/bml.h
=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt	2009-12-03 18:37:38 +0000
+++ b/libmysqld/CMakeLists.txt	2009-12-14 22:38:28 +0000
@@ -132,6 +132,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
            ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc
            ../sql/partition_info.cc ../sql/sql_connect.cc 
            ../sql/scheduler.cc ../sql/event_parse_data.cc
+           ../sql/bml.cc ../sql/si_objects.cc
            ../sql/sql_signal.cc ../sql/rpl_handler.cc
            ../sql/mdl.cc ../sql/transaction.cc
            ${GEN_SOURCES}

=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am	2009-12-14 21:45:06 +0000
+++ b/libmysqld/Makefile.am	2009-12-14 22:38:28 +0000
@@ -77,7 +77,7 @@ sqlsources = derror.cc field.cc field_co
 	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
 	debug_sync.cc sql_tablespace.cc transaction.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
-	sql_servers.cc si_objects.cc
+	sql_servers.cc bml.cc si_objects.cc
 	rpl_handler.cc mdl.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2009-12-14 21:58:37 +0000
+++ b/sql/CMakeLists.txt	2009-12-14 22:38:28 +0000
@@ -75,7 +75,7 @@ SET (SQL_SOURCE
                partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
                rpl_rli.cc rpl_mi.cc sql_servers.cc
                sql_connect.cc scheduler.cc 
-               ddl_blocker.cc si_objects.cc
+               bml.cc si_objects.cc
                sql_signal.cc rpl_handler.cc mdl.cc
                transaction.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2009-12-14 21:58:37 +0000
+++ b/sql/Makefile.am	2009-12-14 22:38:28 +0000
@@ -112,7 +112,7 @@ noinst_HEADERS =	item.h item_func.h item
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
 			contributors.h sql_servers.h sql_signal.h records.h \
-			ddl_blocker.h si_objects.cc \
+			bml.h si_objects.cc \
 			sql_plist.h transaction.h 
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
@@ -158,7 +158,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
                         event_queue.cc event_db_repository.cc events.cc \
 			sql_plugin.cc sql_binlog.cc \
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
-			sql_servers.cc ddl_blocker.cc si_objects.cc
+			sql_servers.cc bml.cc si_objects.cc
 
 nodist_mysqld_SOURCES =	mini_client_errors.c pack.c client.c my_time.c my_user.c 
 

=== renamed file 'sql/ddl_blocker.cc' => 'sql/bml.cc'
--- a/sql/ddl_blocker.cc	2009-12-14 21:58:37 +0000
+++ b/sql/bml.cc	2009-12-14 22:38:28 +0000
@@ -17,129 +17,236 @@
 /**
    @file
 
-   @brief Contains methods to implement a basic DDL blocker.
+   @brief Contains methods to implement the Backup Metadata Lock (BML) service.
 
-   This file contains methods that allow DDL statements to register and 
-   another process (such as backup) to check to see if there are any DDL
-   statements running and block or exit if so. 
+   This file contains methods that allow SQL statements to register with the
+   BML service. In case the lock is taken, these statements will be blocked.
+   It also contains methods for taking and releasing the lock.
 
-   It also allows a process (such as backup) to register itself to block
-   all DDL methods until the process is complete.
-  */
+   The list of statements which should obey BML is as follows:
+
+    DROP   DATABASE/TABLE/VIEW/FUNCTION/PROCEDURE/EVENT/TRIGGER/INDEX
+    DROP   USER/TABLESPACE
+    CREATE DATABASE/TABLE/VIEW/FUNCTION/PROCEDURE/EVENT/TRIGGER/INDEX
+    ALTER  DATABASE/TABLE/VIEW/FUNCTION/PROCEDURE/EVENT/TABLESPACE
+    RENAME TABLE/USER
+    GRANT/REVOKE
+    TRUNCATE/OPTIMIZE/REPAIR TABLE
+
+   The parser (mysql_execute_command() in sql_parse.cc) arranges for calls to
+   bml_enter() and bml_leave() for these statements.
+*/
+
+#include "bml.h"
+#include "debug_sync.h"
+
+BML_class *BML_class::m_instance= NULL;
+
+BML_class *BML_class::get_BML_class_instance()
+{
+  if (m_instance == NULL)
+    m_instance = new BML_class();
+  return m_instance;
+}
 
-#include "ddl_blocker.h"
+void BML_class::destroy_BML_class_instance()
+{
+  delete m_instance;
+  m_instance= NULL;
+}
+
+BML_class::BML_class()
+{
+  pthread_mutex_init(&THR_LOCK_BML, MY_MUTEX_INIT_FAST);
+  pthread_mutex_init(&THR_LOCK_BML_active, MY_MUTEX_INIT_FAST);
+  pthread_mutex_init(&THR_LOCK_BML_get, MY_MUTEX_INIT_FAST);
+  pthread_cond_init(&COND_BML, NULL);
+  pthread_cond_init(&COND_BML_registered, NULL);
+  pthread_cond_init(&COND_BML_release, NULL);
+  BML_active= FALSE;
+  BML_registered= 0;
+}
 
-my_bool DDL_blocked= FALSE;   ///< Assume DDL is not blocked.
-int DDL_blocks= 0;            ///< Number of DDL operations in progress.
+BML_class::~BML_class()
+{
+  pthread_mutex_destroy(&THR_LOCK_BML);
+  pthread_mutex_destroy(&THR_LOCK_BML_active);
+  pthread_mutex_destroy(&THR_LOCK_BML_get);
+  pthread_cond_destroy(&COND_BML);
+  pthread_cond_destroy(&COND_BML_registered);
+  pthread_cond_destroy(&COND_BML_release);
+}
 
 /**
-   start_DDL()
+   do_enter()
 
-   Increments the DDL_blocks counter to indicate a DDL is in progress.
-  */
-void start_DDL()
+   Registers operation which obeys BML by increasing BML_registered counter.
+*/
+void BML_class::do_enter()
 {
-  DBUG_ENTER("start_DDL()");
-  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
-  DDL_blocks++;
-  pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
+  DBUG_ENTER("BML_class::do_enter()");
+  pthread_mutex_lock(&THR_LOCK_BML);
+  BML_registered++;
+  pthread_mutex_unlock(&THR_LOCK_BML);
   DBUG_VOID_RETURN;
 }
 
 /**
-   end_DDL()
+   bml_leave()
 
-   Decrements the DDL_blocks counter to indicate a DDL is done.
-   Signals blocked process if counter == 0.
-  */
-void end_DDL()
+   Unregister operation which checked for BML with bml_enter(). 
+   Decrements the BML_registered counter to indicate the operation 
+   is done. Signals COND_BML_registered if counter == 0.
+*/
+void BML_class::bml_leave()
 {
-  DBUG_ENTER("end_DDL()");
-  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
-  if (DDL_blocks > 0)
-    DDL_blocks--;
-  if (DDL_blocks == 0)
-    pthread_cond_broadcast(&COND_process_blocked);
-  pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
+  DBUG_ENTER("BML_class::bml_leave()");
+  pthread_mutex_lock(&THR_LOCK_BML);
+  if (BML_registered > 0)
+    BML_registered--;
+  if (BML_registered == 0)
+    pthread_cond_broadcast(&COND_BML_registered);
+  pthread_mutex_unlock(&THR_LOCK_BML);
   DBUG_VOID_RETURN;
 }
 
 /**
-    check_ddl_blocker
+   bml_enter
 
-    Check to see if we are blocked from continuing. If so,
-    wait until the blocked process signals the condition.
+   Check to see if BML is active. If so, wait until it is deactivated.
+   When BML is not active, register the operation with BML.
 
-    @param thd The THD object from the caller.
-    @returns TRUE
-  */
-my_bool check_DDL_blocker(THD *thd)
+   If a timeout specified by backup_wait_timeout variable occurs, this
+   method returns FALSE. The operation is not registered in that case.
+    
+   @param[in] thd        The THD object from the caller.
+
+   @note: A successful call to bml_enter() must be matched by bml_leave().
+
+   @return Operation status
+     @retval TRUE if the BML was not set
+     @retval FALSE if timeout occurred while waiting for BML to be released
+*/
+my_bool BML_class::bml_enter(THD *thd)
 {
-  DBUG_ENTER("check_DDL_blocker()");
-  BACKUP_BREAKPOINT("DDL_not_blocked");
+  int ret = 0;
+  struct timespec ddl_timeout;
+  DBUG_ENTER("BML_class::bml_enter()");
+
+  set_timespec(ddl_timeout, thd->backup_wait_timeout);
 
   /*
-    Check the ddl blocker condition. Rest until ddl blocker is released.
+    Check whether BML is active. If yes, wait for deactivation which is 
+    signalled with COND_BML.
   */
-  pthread_mutex_lock(&THR_LOCK_DDL_is_blocked);
-  thd->enter_cond(&COND_DDL_blocker, &THR_LOCK_DDL_is_blocked,
-                  "DDL blocker: DDL is blocked");
-  while (DDL_blocked && !thd->DDL_exception)
-    pthread_cond_wait(&COND_DDL_blocker, &THR_LOCK_DDL_is_blocked);
-  start_DDL();
-  thd->exit_cond("DDL blocker: Ok to run DDL");
-  BACKUP_BREAKPOINT("DDL_in_progress");
-  DBUG_RETURN(TRUE);
+  pthread_mutex_lock(&THR_LOCK_BML_active);
+  thd->enter_cond(&COND_BML, &THR_LOCK_BML_active,
+                  "BML: waiting until released");
+  DEBUG_SYNC(thd, "bml_enter_check");
+  while (BML_active && !thd->killed && !thd->BML_exception && (ret == 0))
+  {
+    if (thd->backup_wait_timeout == 0)
+      ret = -1;
+    else
+      ret= pthread_cond_timedwait(&COND_BML, &THR_LOCK_BML_active,
+                                  &ddl_timeout);
+  }
+  if (thd->killed)
+  {
+    /* Releases THR_LOCK_BML_active */
+    thd->exit_cond("BML: Thread was killed");
+    DBUG_RETURN(FALSE);
+  }
+
+  thd->exit_cond("BML: entered");
+  if (ret == 0)
+    do_enter();
+  else
+    my_error(ER_DDL_TIMEOUT, MYF(0), thd->query());
+
+  DBUG_RETURN(ret == 0);
 }
 
 /**
-   block_DDL
-
-   This method is used to block all DDL commands. It checks the counter
-   DDL_blocks and if > 0 it blocks the process until all DDL operations are
-   complete and the condition variable has been signaled. 
+   bml_get
 
-   The method also sets the boolean DDL_blocked to TRUE to tell the DDL
-   operations that they must block until the blocking operation is complete.
+  This method is used to activate BML. It waits for any operations which
+  registered with bml_enter() to unregister using bml_leave().
+  The method also prevents any other thread from activating the lock until
+  bml_release() is called.
+
+  It checks the counter BML_registered and if > 0 it blocks the process until 
+  all registerd operations are complete and the condition variable has been 
+  signaled. The fact that BML is in force is indicated by setting the boolean 
+  BML_active to TRUE.
 
    @params thd THD object.
-   @returns TRUE
+   @return TRUE if the lock was set successfully, FALSE otherwise
   */
-my_bool block_DDL(THD *thd)
+my_bool BML_class::bml_get(THD *thd)
 {
-  DBUG_ENTER("block_DDL()");
+  DBUG_ENTER("BML_class::bml_get()");
 
-  BACKUP_BREAKPOINT("DDL_in_progress");
   /*
-    Only 1 DDL blocking operation can run at a time.
+    Only 1 thread can hold the BML. If BML_active is TRUE, wait for
+    bml_release() which signals COND_BML_release condition.
   */
-  if (DDL_blocked)
+  pthread_mutex_lock(&THR_LOCK_BML_get);
+  thd->enter_cond(&COND_BML_release, &THR_LOCK_BML_get,
+                  "BML: waiting for release before activating");
+  DEBUG_SYNC(thd, "bml_get_check1");
+  while (BML_active && !thd->killed)
+    pthread_cond_wait(&COND_BML_release, &THR_LOCK_BML_get);
+
+  if (thd->killed)
+  {
+    thd->exit_cond("BML: Thread was killed");
     DBUG_RETURN(FALSE);
+  }
+
+  BML_active= TRUE;
+  thd->exit_cond("BML: activating");
+
   /*
-    Check the ddl blocker condition. Rest until ddl blocker is released.
+    Wait for all registered statements to complete, i.e., until BML_registered
+    is zero in which case COND_BML_registered is signalled.
   */
-  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
-  thd->enter_cond(&COND_process_blocked, &THR_LOCK_DDL_blocker,
-                  "DDL blocker: Checking block on DDL changes");
-  while (DDL_blocks != 0)
-    pthread_cond_wait(&COND_process_blocked, &THR_LOCK_DDL_blocker);
-  DDL_blocked= TRUE;
-  thd->exit_cond("DDL blocker: Ok to run operation - no DDL in progress");
-  BACKUP_BREAKPOINT("DDL_blocked");
+  pthread_mutex_lock(&THR_LOCK_BML);
+  thd->enter_cond(&COND_BML_registered, &THR_LOCK_BML,
+                  "BML: waiting for all statements to leave");
+  DEBUG_SYNC(thd, "bml_get_check2");
+  while (BML_registered != 0 && !thd->killed)
+    pthread_cond_wait(&COND_BML_registered, &THR_LOCK_BML);
+
+  if (thd->killed)
+  {
+    /* Releases THR_LOCK_BML */
+    thd->exit_cond("BML: Thread was killed");
+    /* This thread still has BML_active set - release it */
+    bml_release();
+    DBUG_RETURN(FALSE);
+  }
+
+  thd->exit_cond("BML: activated");
+
+  DEBUG_SYNC(thd, "after_bml_activated");
   DBUG_RETURN(TRUE);
 }
 
 /**
-   unblock_DDL
+   bml_release
 
-   This method is used to unblock all DDL commands. It sets the boolean
-   DDL_blocked to FALSE to tell the DDL operations that they can proceed.
-  */
-void unblock_DDL()
+   This method is used to deactivate BML. All operations which are waiting
+   in bml_enter() call (if any) will be allowed to continue.
+
+   The BML_active flag is set to FALSE to indicate that BML is not active and
+   conditions COND_BML and COND_BML_release are signalled.
+*/
+void BML_class::bml_release()
 {
-  pthread_mutex_lock(&THR_LOCK_DDL_blocker);
-  DDL_blocked= FALSE;
-  pthread_cond_broadcast(&COND_DDL_blocker);
-  pthread_mutex_unlock(&THR_LOCK_DDL_blocker);
+  pthread_mutex_lock(&THR_LOCK_BML);
+  BML_active= FALSE;
+  pthread_cond_broadcast(&COND_BML);
+  pthread_cond_signal(&COND_BML_release);
+  pthread_mutex_unlock(&THR_LOCK_BML);
 }
-

=== renamed file 'sql/ddl_blocker.h' => 'sql/bml.h'
--- a/sql/ddl_blocker.h	2009-12-14 21:58:37 +0000
+++ b/sql/bml.h	2009-12-14 22:38:28 +0000
@@ -1,49 +1,127 @@
+#ifndef BML_INCLUDED
+#define BML_INCLUDED
+
 /**
   @file
 
-  Header file for DDL blocker code.
+  Header file for Backup Metadata Lock.
  */
+
 #include "mysql_priv.h"
-#include "debug.h"
 
-/*
-  Mutexes and condition variables -- see mysqld.cc.
-*/
-extern pthread_mutex_t THR_LOCK_DDL_blocker; 
-extern pthread_mutex_t THR_LOCK_DDL_is_blocked; 
-extern pthread_cond_t COND_DDL_blocker;
-extern pthread_cond_t COND_process_blocked;
-
-/*
-  Increments the backup's counter to indicate a DDL is in progress.
-*/
-void start_DDL();
-
-/*
-  Decrements the backup's counter to indicate a DDL is done.
-  Signals backup process if counter == 0.
-*/
-void end_DDL();
-
-/*
-  Check to see if we are blocked from continuing. If so,
-  wait until the backup process signals the condition.
-*/
-my_bool check_DDL_blocker(THD *thd);
-
-/*
-  This method is used to block all DDL commands. It checks the counter
-  DDL_blocks and if > 0 it blocks the backup until all DDL operations are
-  complete and the condition variable has been signaled. 
-
-  The method also sets the boolean DDL_blocked to TRUE to tell the DDL
-  operations that they must block until the backup operation is complete.
-*/
-my_bool block_DDL(THD *thd);
-
-/*
-  This method is used to unblock all DDL commands. It sets the boolean
-  DDL_blocked to FALSE to tell the DDL operations that they can proceed.
-*/
-void unblock_DDL();
+/**
+   @class BML_class
+ 
+   @brief Implements a simple Backup Metadata Lock (BML) mechanism.
+ 
+   The BML_class is a singleton class designed to allow blocking statements 
+   changing metadata which should be constant during backup/restore operation.
+   Only one thread can hold the lock but there is no restriction on number
+   of blocked statements which can run in parallel. 
+
+   If a thread has acquired BML and another thread attempts to activate it,
+   the second thread will wait until the first one is complete.
+ 
+   Checking for Block
+   Any statement that needs to be blocked by BML should call @c bml_enter() at
+   the beginning of its execution. This method will return when BML is not active
+   or wait until it becomes inactive. Once the method returns, the statement
+   which called the method is registered and while it is running, it will be not
+   possible to activate BML. When the statement is complete, you must unregister
+   it by calling bml_leave(). All this is done inside the parser
+   (@c mysql_execute_command()).
+
+   Blocking Statements
+   To prevent metadata changes, call bml_get(). This activates the lock and
+   prevents any statements which use bml_enter() from executing. To remove the
+   lock bml_release().
+
+   Singleton Methods
+   The creation of the singleton is accomplished using 
+   get_BML_class_instance(). This method is called from mysqld.cc
+   and creates and initializes all of the private mutex, condition, and
+   controlling variables. The method destroy_BML_class_instance()
+   destroys the mutex and condition variables. 
+
+   Calling the Singleton
+   To call the singleton class, you must declare an external variable
+   to the global variable BML_instance as shown below.
+
+   @c extern BML_class *BML_instance;
+
+   Calling methods on the singleton is accomplished using the BML_instance
+   variable such as: @c BML_instance->bml_get().
+
+   @note: This class is currently only used in MySQL backup. If you would
+          like to use it elsewhere and have questions, please contact
+          Chuck Bell (cbell@stripped) for more details and how to setup
+          a test case to test the BML mechanism for your use.
+  */
+class BML_class
+{
+  public:
+
+    /*
+      Singleton class
+    */
+    static BML_class *get_BML_class_instance();
+    static void destroy_BML_class_instance();
+
+    /*
+      Check to see if BML is active. If so, wait until it is deactivated.
+      When BML is not active, register the operation with BML.
+    */
+    my_bool bml_enter(THD *thd);
+
+    /*
+      Unregister operation which checked for BML with bml_enter(). 
+    */
+    void bml_leave();
+
+    /*
+      This method is used to activate BML. It waits for any operations which
+      registered with bml_enter() to unregister using bml_leave().
+      The method also prevents any other thread from activating the lock until
+      bml_release() is called.
+    */
+    my_bool bml_get(THD *thd);
+
+    /*
+      This method is used to deactivate BML. All operations which are waiting
+      in bml_enter() call (if any) will be allowed to continue.
+    */
+    void bml_release();
+
+  private:
+
+    BML_class();
+    ~BML_class();
+
+    /*
+      Registers operation which obeys BML.
+    */
+    void do_enter();
+
+    /*
+      These variables are used to implement the Backup Metadata Lock.
+    */
+
+    /// Mutex for protecting BML_registered counter.
+    pthread_mutex_t THR_LOCK_BML;
+    /// Mutex for proteting BML_active falg.
+    pthread_mutex_t THR_LOCK_BML_active;
+    /// Mutex for serializing BML usage. 
+    pthread_mutex_t THR_LOCK_BML_get;
+    /// Signals deactivation of BML for statements waiting in bml_enter(). 
+    pthread_cond_t COND_BML;
+    /// Signals deactivation of BML for threads waiting in bml_get().
+    pthread_cond_t COND_BML_release;
+    /// Signals that BML_reagistered count dropped to 0.
+    pthread_cond_t COND_BML_registered;
+
+    my_bool BML_active;           ///< Is BML activated.
+    int BML_registered;           ///< Number of statements registered with BML.
+    static BML_class *m_instance; ///< instance var for singleton 
+};
 
+#endif /* BML_INCLUDED */


Attachment: [text/bzr-bundle] bzr/charles.bell@sun.com-20091214223828-9np5xejpkvoypfxy.bundle
Thread
bzr commit into mysql-5.6-next-mr branch (charles.bell:3005) Bug#32702Chuck Bell14 Dec