List:Internals« Previous MessageNext Message »
From:mikael Date:July 19 2005 12:29am
Subject:bk commit into 4.0 tree (mronstrom:1.2123) BUG#10600
View as plain text  
Below is the list of changes that have just been committed into a local
4.0 repository of mikron. When mikron does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2123 05/07/19 00:29:19 mronstrom@stripped +6 -0
  Bug #10600
  remove_table_from_cache fails to signal other thread and gets
  blocked when other thread also gets blocked

  sql/sql_table.cc
    1.197 05/07/19 00:29:11 mronstrom@stripped +15 -23
    Use new interface of remove_table_from_cache

  sql/sql_base.cc
    1.189 05/07/19 00:29:11 mronstrom@stripped +92 -46
    Use new interface of remove_table_cache
    Rewrote remove_table_from_cache to fix bug

  sql/mysql_priv.h
    1.234 05/07/19 00:29:11 mronstrom@stripped +5 -2
    New interface for remove_table_from_cache
    + mysql_lock_abort_for_thread

  sql/lock.cc
    1.52 05/07/19 00:29:11 mronstrom@stripped +18 -6
    Report if any threads was signalled
    Use new interface for remove_table_from_cache

  mysys/thr_lock.c
    1.38 05/07/19 00:29:11 mronstrom@stripped +5 -2
    Report if any threads was signalled

  include/thr_lock.h
    1.13 05/07/19 00:29:10 mronstrom@stripped +1 -1
    Report if any threads was signalled

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	mronstrom
# Host:	c-1e0ae253.1238-1-64736c10.cust.bredbandsbolaget.se
# Root:	/Users/mikron/clean-mysql-4.0

--- 1.12/include/thr_lock.h	2003-03-04 11:22:33 +01:00
+++ 1.13/include/thr_lock.h	2005-07-19 00:29:10 +02:00
@@ -107,7 +107,7 @@
 int thr_multi_lock(THR_LOCK_DATA **data,uint count);
 void thr_multi_unlock(THR_LOCK_DATA **data,uint count);
 void thr_abort_locks(THR_LOCK *lock);
-void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread);
+bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread);
 void thr_print_locks(void);		/* For debugging */
 my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data);
 my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data);

--- 1.37/mysys/thr_lock.c	2004-10-20 15:04:26 +02:00
+++ 1.38/mysys/thr_lock.c	2005-07-19 00:29:11 +02:00
@@ -966,9 +966,10 @@
   This is used to abort all locks for a specific thread
 */
 
-void thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
+bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
 {
   THR_LOCK_DATA *data;
+  bool found= FALSE;
   DBUG_ENTER("thr_abort_locks_for_thread");
 
   pthread_mutex_lock(&lock->mutex);
@@ -978,6 +979,7 @@
     {
       DBUG_PRINT("info",("Aborting read-wait lock"));
       data->type= TL_UNLOCK;			/* Mark killed */
+      found= TRUE;
       pthread_cond_signal(data->cond);
       data->cond= 0;				/* Removed from list */
 
@@ -993,6 +995,7 @@
     {
       DBUG_PRINT("info",("Aborting write-wait lock"));
       data->type= TL_UNLOCK;
+      found= TRUE;
       pthread_cond_signal(data->cond);
       data->cond= 0;
 
@@ -1003,7 +1006,7 @@
     }
   }
   pthread_mutex_unlock(&lock->mutex);
-  DBUG_VOID_RETURN;
+  DBUG_RETURN(found);
 }
 
 

--- 1.51/sql/lock.cc	2005-05-31 11:08:12 +02:00
+++ 1.52/sql/lock.cc	2005-07-19 00:29:11 +02:00
@@ -333,20 +333,25 @@
 
 /* Abort one thread / table combination */
 
-void mysql_lock_abort_for_thread(THD *thd, TABLE *table)
+bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
 {
   MYSQL_LOCK *locked;
   TABLE *write_lock_used;
+  bool result= FALSE;
   DBUG_ENTER("mysql_lock_abort_for_thread");
 
   if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
   {
     for (uint i=0; i < locked->lock_count; i++)
-      thr_abort_locks_for_thread(locked->locks[i]->lock,
-				 table->in_use->real_id);
+    {
+      bool found;
+      found= thr_abort_locks_for_thread(locked->locks[i]->lock,
+	         			 table->in_use->real_id);
+      result|= found;
+    }
     my_free((gptr) locked,MYF(0));
   }
-  DBUG_VOID_RETURN;
+  DBUG_RETURN(result);
 }
 
 
@@ -542,8 +547,15 @@
     my_free((gptr) table,MYF(0));
     DBUG_RETURN(-1);
   }
-  if (remove_table_from_cache(thd, db, table_list->real_name))
-    DBUG_RETURN(1);					// Table is in use
+  
+  {
+    uint flags= 0;
+    if (remove_table_from_cache(thd, db,
+                                table_list->real_name, flags))
+    {
+      DBUG_RETURN(1);				// Table is in use
+    }
+  }
   DBUG_RETURN(0);
 }
 

--- 1.233/sql/mysql_priv.h	2005-05-31 11:08:12 +02:00
+++ 1.234/sql/mysql_priv.h	2005-07-19 00:29:11 +02:00
@@ -606,8 +606,11 @@
 			    const char *table_name);
 void remove_db_from_cache(const my_string db);
 void flush_tables();
+#define OWNED_BY_THD_FLAG 1
+#define WAIT_OTHER_THREAD_FLAG 2
+#define CHECK_KILLED_FLAG 4
 bool remove_table_from_cache(THD *thd, const char *db, const char *table,
-			     bool return_if_owned_by_thd=0);
+                             uint flags);
 bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables);
 void copy_field_from_tmp_record(Field *field,int offset);
 int fill_record(List<Item> &fields,List<Item> &values, bool
ignore_errors);
@@ -776,7 +779,7 @@
 void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
 void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
 void mysql_lock_abort(THD *thd, TABLE *table);
-void mysql_lock_abort_for_thread(THD *thd, TABLE *table);
+bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
 MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
 bool lock_global_read_lock(THD *thd);
 void unlock_global_read_lock(THD *thd);

--- 1.188/sql/sql_base.cc	2005-05-31 11:08:12 +02:00
+++ 1.189/sql/sql_base.cc	2005-07-19 00:29:11 +02:00
@@ -370,7 +370,9 @@
     bool found=0;
     for (TABLE_LIST *table=tables ; table ; table=table->next)
     {
-      if (remove_table_from_cache(thd, table->db, table->real_name, 1))
+      uint flags= OWNED_BY_THD_FLAG;
+      if (remove_table_from_cache(thd, table->db, table->real_name,
+                                  flags))
 	found=1;
     }
     if (!found)
@@ -2407,62 +2409,106 @@
 */
 
 bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
-			     bool return_if_owned_by_thd)
+                             uint flags)
 {
   char key[MAX_DBKEY_LENGTH];
   uint key_length;
   TABLE *table;
-  bool result=0;
+  bool result=0, signalled= 0;
+  bool return_if_owned_by_thd= flags & OWNED_BY_THD_FLAG;
+  bool wait_for_other_thread= flags & WAIT_OTHER_THREAD_FLAG;
+  bool check_killed_flag= flags & CHECK_KILLED_FLAG;
   DBUG_ENTER("remove_table_from_cache");
 
   key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
-  for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
-       table;
-       table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+  do
   {
-    THD *in_use;
-    table->version=0L;			/* Free when thread is ready */
-    if (!(in_use=table->in_use))
-    {
-      DBUG_PRINT("info",("Table was not in use"));
-      relink_unused(table);
-    }
-    else if (in_use != thd)
-    {
-      in_use->some_tables_deleted=1;
-      if (table->db_stat)
-	result=1;
-      /* Kill delayed insert threads */
-      if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
-          ! in_use->killed)
-      {
-	in_use->killed=1;
-	pthread_mutex_lock(&in_use->mysys_var->mutex);
-	if (in_use->mysys_var->current_cond)
-	{
-	  pthread_mutex_lock(in_use->mysys_var->current_mutex);
-	  pthread_cond_broadcast(in_use->mysys_var->current_cond);
-	  pthread_mutex_unlock(in_use->mysys_var->current_mutex);
-	}
-	pthread_mutex_unlock(&in_use->mysys_var->mutex);
+    result= signalled= 0;
+
+    for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
+         table;
+         table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
+    {
+      THD *in_use;
+      table->version=0L;		/* Free when thread is ready */
+      if (!(in_use=table->in_use))
+      {
+        DBUG_PRINT("info",("Table was not in use"));
+        relink_unused(table);
+      }
+      else if (in_use != thd)
+      {
+        in_use->some_tables_deleted=1;
+        if (table->db_stat)
+  	  result=1;
+        /* Kill delayed insert threads */
+        if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
+            ! in_use->killed)
+        {
+  	  in_use->killed=1;
+	  pthread_mutex_lock(&in_use->mysys_var->mutex);
+	  if (in_use->mysys_var->current_cond)
+	  {
+	    pthread_mutex_lock(in_use->mysys_var->current_mutex);
+            signalled= 1;
+	    pthread_cond_broadcast(in_use->mysys_var->current_cond);
+	    pthread_mutex_unlock(in_use->mysys_var->current_mutex);
+	  }
+	  pthread_mutex_unlock(&in_use->mysys_var->mutex);
+        }
+        /*
+	  Now we must abort all tables locks used by this thread
+	  as the thread may be waiting to get a lock for another table
+        */
+        for (TABLE *thd_table= in_use->open_tables;
+	     thd_table ;
+	     thd_table= thd_table->next)
+        {
+	  if (thd_table->db_stat)		// If table is open
+          {
+            bool found;
+	    found= mysql_lock_abort_for_thread(thd, thd_table);
+            signalled|= found;
+          }
+        }
       }
-      /*
-	Now we must abort all tables locks used by this thread
-	as the thread may be waiting to get a lock for another table
-      */
-      for (TABLE *thd_table= in_use->open_tables;
-	   thd_table ;
-	   thd_table= thd_table->next)
-      {
-	if (thd_table->db_stat)			// If table is open
-	  mysql_lock_abort_for_thread(thd, thd_table);
+      else
+        result= result || return_if_owned_by_thd;
+    }
+    while (unused_tables && !unused_tables->version)
+      VOID(hash_delete(&open_cache,(byte*) unused_tables));
+    if (result && wait_for_other_thread)
+    {
+      if (!check_killed_flag || !thd->killed)
+      {
+        if (likely(signalled))
+        {
+          dropping_tables++;
+          (void) pthread_cond_wait(&COND_refresh, &LOCK_open);
+          dropping_tables--;
+          continue;
+        }
+        else
+        {
+          /*
+            It can happen that another thread has opened the
+            table but has not yet locked any table at all. Since
+            it can be locked waiting for a table that our thread
+            has done LOCK TABLE x WRITE on previously, we need to
+            ensure that the thread actually hears our signal
+            before we go to sleep. Thus we wait for a short time
+            and then we retry another loop in the
+            remove_table_from_cache routine.
+          */
+          pthread_mutex_unlock(&LOCK_open);
+          my_sleep(10);
+          pthread_mutex_lock(&LOCK_open);
+          continue;
+        }
       }
     }
-    else
-      result= result || return_if_owned_by_thd;
-  }
-  while (unused_tables && !unused_tables->version)
-    VOID(hash_delete(&open_cache,(byte*) unused_tables));
+    break;
+  } while (1);
   DBUG_RETURN(result);
 }
 

--- 1.196/sql/sql_table.cc	2005-05-31 11:08:12 +02:00
+++ 1.197/sql/sql_table.cc	2005-07-19 00:29:11 +02:00
@@ -178,6 +178,7 @@
   for (table=tables ; table ; table=table->next)
   {
     char *db=table->db;
+    uint flags;
     mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL);
     if (!close_temporary_table(thd, db, table->real_name))
     {
@@ -186,12 +187,8 @@
     }
 
     abort_locked_tables(thd,db,table->real_name);
-    while (remove_table_from_cache(thd,db,table->real_name) &&
!thd->killed)
-    {
-      dropping_tables++;
-      (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
-      dropping_tables--;
-    }
+    flags= WAIT_OTHER_THREAD_FLAG | CHECK_KILLED_FLAG;
+    remove_table_from_cache(thd,db,table->real_name,flags);
     drop_locked_tables(thd,db,table->real_name);
     if (thd->killed)
       DBUG_RETURN(-1);
@@ -979,6 +976,7 @@
 static void wait_while_table_is_used(THD *thd,TABLE *table,
 				     enum ha_extra_function function)
 {
+  uint flags;
   DBUG_PRINT("enter",("table: %s", table->real_name));
   DBUG_ENTER("wait_while_table_is_used");
   safe_mutex_assert_owner(&LOCK_open);
@@ -988,13 +986,9 @@
   mysql_lock_abort(thd, table);			// end threads waiting on lock
 
   /* Wait until all there are no other threads that has this table open */
-  while (remove_table_from_cache(thd,table->table_cache_key,
-				 table->real_name))
-  {
-    dropping_tables++;
-    (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
-    dropping_tables--;
-  }
+  flags= WAIT_OTHER_THREAD_FLAG;
+  remove_table_from_cache(thd,table->table_cache_key,
+                          table->real_name,flags);
   DBUG_VOID_RETURN;
 }
 
@@ -1306,18 +1300,14 @@
     /* Close all instances of the table to allow repair to rename files */
     if (lock_type == TL_WRITE && table->table->version)
     {
+      uint flags;
       pthread_mutex_lock(&LOCK_open);
       const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
 					      "Waiting to get writelock");
       mysql_lock_abort(thd,table->table);
-      while (remove_table_from_cache(thd, table->table->table_cache_key,
-				     table->table->real_name) &&
-	     ! thd->killed)
-      {
-	dropping_tables++;
-	(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
-	dropping_tables--;
-      }
+      flags= WAIT_OTHER_THREAD_FLAG | CHECK_KILLED_FLAG;
+      remove_table_from_cache(thd, table->table->table_cache_key,
+                              table->table->real_name, flags);
       thd->exit_cond(old_message);
       if (thd->killed)
 	goto err;
@@ -1382,9 +1372,10 @@
       table->table->version=0;			// Force close of table
     else if (open_for_modify)
     {
+      uint flags= 0;
       pthread_mutex_lock(&LOCK_open);
       remove_table_from_cache(thd, table->table->table_cache_key,
-			      table->table->real_name);
+			      table->table->real_name, flags);
       pthread_mutex_unlock(&LOCK_open);
       /* May be something modified consequently we have to invalidate cache */
       query_cache_invalidate3(thd, table->table, 0);
@@ -2108,8 +2099,9 @@
     */
     if (table)
     {
+      uint flags= 0;
       VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
-      remove_table_from_cache(thd,db,table_name); // Mark all in-use copies old
+      remove_table_from_cache(thd,db,table_name,flags);// Mark in-use copies old
       mysql_lock_abort(thd,table);		 // end threads waiting on lock
     }
     VOID(quick_rm_table(old_db_type,db,old_name));
Thread
bk commit into 4.0 tree (mronstrom:1.2123) BUG#10600mikael21 Jul