List:Commits« Previous MessageNext Message »
From:Sergey Vojtovich Date:April 19 2006 5:54pm
Subject:bk commit into 4.1 tree (svoj:1.2464) BUG#18544
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of svoj. When svoj 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.2464 06/04/19 22:54:25 svoj@april.(none) +1 -0
  Bug#18544 - LOCK TABLES timeout causes MyISAM table corruption
  
  After a locking error the open table(s) were not fully
  cleaned up for reuse. But they were put into the open table
  cache even before the lock was tried. The next statement
  reused the table(s) with a wrong lock type set up. This
  tricked MyISAM into believing that it don't need to update
  the table statistics. Hence CHECK TABLE reported a mismatch
  of record count and table size.
  
  Fortunately nothing worse has been detected yet. The effect
  of the test case was that the insert worked on a read locked
  table. (!)
  
  I added a new function that clears the lock type from all
  tables that were prepared for a lock. I call this function
  when a lock failes.
  
  No test case. One test would add 50 seconds to the
  test suite. Another test requires file mode modifications.
  I added a test script to the bug report. It contains three
  cases for failing locks. All could reproduce a table
  corruption. All are fixed by this patch.
  
  This bug was not lock timeout specific.

  sql/lock.cc
    1.67 06/04/19 22:54:22 svoj@april.(none) +53 -1
    Bug#18544 - LOCK TABLES timeout causes MyISAM table corruption
    Resetting the lock type in the open table(s) lock data
    after a locking error.

# 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:	svoj
# Host:	april.(none)
# Root:	/home/svoj/devel/mysql/BUG18544/mysql-4.1

--- 1.66/sql/lock.cc	2006-02-20 15:28:52 +04:00
+++ 1.67/sql/lock.cc	2006-04-19 22:54:22 +05:00
@@ -78,6 +78,7 @@
 
 static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
 				 uint flags, TABLE **write_locked);
+static void reset_lock_data(MYSQL_LOCK *sql_lock);
 static int lock_external(THD *thd, TABLE **table,uint count);
 static int unlock_external(THD *thd, TABLE **table,uint count);
 static void print_lock_error(int error);
@@ -120,12 +121,16 @@
       */
       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;
 	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));
 	goto retry;
       }
@@ -134,6 +139,8 @@
     thd->proc_info="System lock";
     if (lock_external(thd, tables, 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;
       thd->proc_info=0;
@@ -639,6 +646,9 @@
       if (table->db_stat & HA_READ_ONLY)
       {
 	my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name);
+        /* Clear the lock type of the lock data that are stored already. */
+        sql_lock->lock_count= locks - sql_lock->locks;
+        reset_lock_data(sql_lock);
 	my_free((gptr) sql_lock,MYF(0));
 	DBUG_RETURN(0);
       }
@@ -660,6 +670,48 @@
 	(*org_locks)->debug_print_param= (void *) table;
   }
   DBUG_RETURN(sql_lock);
+}
+
+
+/*
+  Reset lock type in lock data.
+
+  SYNOPSIS
+    reset_lock_data()
+      sql_lock                  The MySQL lock.
+
+  DESCRIPTION
+
+    After a locking error we want to quit the locking of the table(s).
+    The test case in the bug report for Bug #18544 has the following
+    cases: 1. Locking error in lock_external() due to InnoDB timeout.
+    2. Locking error in get_lock_data() due to missing write permission.
+    3. Locking error in wait_if_global_read_lock() due to lock conflict.
+
+    In all these cases we have already set the lock type into the lock
+    data of the open table(s). If the table(s) are in the open table
+    cache, they could be reused with the non-zero lock type set. This
+    could lead to ignoring a different lock type with the next lock.
+
+    Clear the lock type of all lock data. This ensures that the next
+    lock request will set its lock type properly.
+
+  RETURN
+    void
+*/
+
+static void reset_lock_data(MYSQL_LOCK *sql_lock)
+{
+  THR_LOCK_DATA **ldata;
+  THR_LOCK_DATA **ldata_end;
+
+  for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
+       ldata < ldata_end;
+       ldata++)
+  {
+    /* Reset lock type. */
+    (*ldata)->type= TL_UNLOCK;
+  }
 }
 
 
Thread
bk commit into 4.1 tree (svoj:1.2464) BUG#18544Sergey Vojtovich19 Apr