Below is the list of changes that have just been committed into a local
5.0 repository of davi. When davi 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@stripped, 2007-08-30 23:00:33-03:00, davi@stripped +1 -0
Bug#28870 check that table locks are released/reset
The problem is that some mysql_lock_tables error paths are not resetting the
tables lock type back to TL_UNLOCK. If the lock types are not reset properly,
a table might be returned to the table cache with wrong lock_type.
The proposed fix is to ensure that the tables lock type is always properly
reset when mysql_lock_tables fails.
sql/lock.cc@stripped, 2007-08-30 23:00:29-03:00, davi@stripped +30 -24
Move mysql_lock_tables cleanup sequence to a separate function and take
steps to ensure it is always called for each error exit path.
diff -Nrup a/sql/lock.cc b/sql/lock.cc
--- a/sql/lock.cc 2007-08-27 10:13:52 -03:00
+++ b/sql/lock.cc 2007-08-30 23:00:29 -03:00
@@ -83,6 +83,22 @@ static int unlock_external(THD *thd, TAB
static void print_lock_error(int error, const char *);
/*
+ Helper function for mysql_lock_tables error path cleanup
+
+ @param thd The current thread.
+ @param sql_lock Lock structures to reset.
+*/
+static inline void mysql_lock_reset_and_free(THD *thd, MYSQL_LOCK *&sql_lock)
+{
+ if (thd->locked && sql_lock->table_count)
+ VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
+ /* Clear the lock type of all lock data to avoid reusage. */
+ reset_lock_data(sql_lock);
+ my_free((gptr) sql_lock,MYF(0));
+ sql_lock=0;
+}
+
+/*
Lock tables.
SYNOPSIS
@@ -135,17 +151,12 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,
*/
if (wait_if_global_read_lock(thd, 1, 1))
{
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
- sql_lock=0;
+ mysql_lock_reset_and_free(thd, sql_lock);
break;
}
if (thd->version != refresh_version)
{
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
+ mysql_lock_reset_and_free(thd, sql_lock);
goto retry;
}
}
@@ -154,10 +165,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
sql_lock->table_count))
{
- /* Clear the lock type of all lock data to avoid reusage. */
- reset_lock_data(sql_lock);
- my_free((gptr) sql_lock,MYF(0));
- sql_lock=0;
+ mysql_lock_reset_and_free(thd, sql_lock);
break;
}
thd->proc_info="Table lock";
@@ -172,22 +180,12 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,
thd->lock_id)];
if (rc > 1) /* a timeout or a deadlock */
{
- if (sql_lock->table_count)
- VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
+ mysql_lock_reset_and_free(thd, sql_lock);
my_error(rc, MYF(0));
- my_free((gptr) sql_lock,MYF(0));
- sql_lock= 0;
break;
}
else if (rc == 1) /* aborted */
{
- /*
- reset_lock_data is required here. If thr_multi_lock fails it
- resets lock type for tables, which were locked before (and
- including) one that caused error. Lock type for other tables
- preserved.
- */
- reset_lock_data(sql_lock);
thd->some_tables_deleted=1; // Try again
sql_lock->lock_count= 0; // Locks are already freed
}
@@ -205,9 +203,17 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,
}
thd->proc_info=0;
+ if (sql_lock->lock_count)
+ thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
+
+ /*
+ If thr_multi_lock fails it resets lock type for tables, which
+ were locked before (and including) one that caused error. Lock
+ type for other tables preserved.
+ */
+ mysql_lock_reset_and_free(thd, sql_lock);
+
/* some table was altered or deleted. reopen tables marked deleted */
- mysql_unlock_tables(thd,sql_lock);
- thd->locked=0;
retry:
sql_lock=0;
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)