List:Commits« Previous MessageNext Message »
From:ingo Date:January 6 2006 3:37pm
Subject:bk commit into 4.0 tree (ingo:1.2168) BUG#5390
View as plain text  
Below is the list of changes that have just been committed into a local
4.0 repository of mydev. When mydev 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.2168 06/01/06 16:37:22 ingo@stripped +2 -0
  BUG#5390 - problems with merge tables
  Optimizations suggested by Monty.
  We assume that mysql_lock_have_duplicate() is called
  when all tables are locked. Then we have no need to
  call get_lock_data() again. We just work on the existing lock.

  sql/sql_class.h
    1.192 06/01/06 16:37:21 ingo@stripped +1 -0
    BUG#5390 - problems with merge tables
    Optimizations suggested by Monty.
    We do now store where the THR_LOCK_DATA for each table start.

  sql/lock.cc
    1.56 06/01/06 16:37:21 ingo@stripped +91 -64
    BUG#5390 - problems with merge tables
    Optimizations suggested by Monty.
    We assume that mysql_lock_have_duplicate() is called
    when all tables are locked. Then we have no need to
    call get_lock_data() again. We just work on the existing lock.

# 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:	ingo
# Host:	chilla.local
# Root:	/home/mydev/mysql-4.0-bug5390

--- 1.55/sql/lock.cc	2005-11-29 19:17:37 +01:00
+++ 1.56/sql/lock.cc	2006-01-06 16:37:21 +01:00
@@ -303,6 +303,9 @@
 	bmove((char*) (locked->table+i),
 	      (char*) (locked->table+i+1),
 	      (locked->table_count-i)* sizeof(TABLE*));
+	bmove((char*) (locked->table_lock_starts + i),
+	      (char*) (locked->table_lock_starts + i + 1),
+	      (locked->table_count - i) * sizeof(uint));
 	break;
       }
     }
@@ -391,6 +394,40 @@
 
 
 /*
+  Get the range of lock data for a table in a lock.
+
+  SYNOPSIS
+    mysql_lock_data_range()
+      mylock                        The lock.
+      table                         The table.
+      start_p               OUT     Start of range.
+      end_p                 OUT     End of range.
+
+  RETURN
+    void
+*/
+
+void mysql_lock_data_range(MYSQL_LOCK *mylock, TABLE *table,
+                           uint *start_p, uint *end_p)
+{
+  uint                  idx;
+
+  /* Find table in lock. */
+  for (idx= 0; idx < mylock->table_count; idx++)
+  {
+    if (mylock->table[idx] == table)
+        break;
+  }
+  DBUG_ASSERT(idx < mylock->table_count);
+
+  /* Compute the lock data range for table. */
+  *start_p= mylock->table_lock_starts[idx++];   /* Note:  idx ++  here */
+  *end_p=   ((idx < mylock->table_count) ?
+             mylock->table_lock_starts[idx] : mylock->table_count);
+}
+
+
+/*
   Find duplicate lock in tables.
 
   SYNOPSIS
@@ -402,73 +439,58 @@
   NOTE
     This is mainly meant for MERGE tables in INSERT ... SELECT
     situations. The 'real', underlying tables can be found only after
-    the table is opened. The easier way is to check this after the
-    tables are locked.
+    the table is opened. This function assumes that the tables are
+    already locked.
 
   RETURN
     1           A table from 'tables' matches a lock on 'table'.
-    0           No duplicate lock is present.
-    -1          Error.
+    0           No duplicate lock found.
 */
 
 int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables)
 {
-  uint                  count;
-  MYSQL_LOCK            *sql_lock1;
-  MYSQL_LOCK            *sql_lock2;
-  TABLE                 **tables1= &table;
-  TABLE                 **tables2;
-  TABLE                 **table_ptr;
-  TABLE_LIST            *tablist2;
-  TABLE                 *write_lock_used;
-  THR_LOCK_DATA         **lock_data1;
-  THR_LOCK_DATA         **end_data1;
-  THR_LOCK_DATA         **lock_data2;
-  THR_LOCK_DATA         **end_data2;
+  uint                  idx1;
+  uint                  beg1;
+  uint                  end1;
+  uint                  idx2;
+  uint                  beg2;
+  uint                  end2;
+  MYSQL_LOCK            *mylock;
+  TABLE_LIST            *tablist;
   THR_LOCK              *lock1;
   DBUG_ENTER("mysql_lock_have_duplicate");
 
-  if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
-    goto err0;
+  /* Get command lock or LOCK TABLES lock. */
+  mylock= thd->lock ? thd->lock : thd->locked_tables;
+  DBUG_ASSERT(mylock);
+
+  /* If we have less than one table, we cannot have duplicates. */
+  if (mylock->table_count < 2)
+    DBUG_RETURN(0);
+
+  /* Get the lock data range for table. */
+  mysql_lock_data_range(mylock, table, &beg1, &end1);
 
-  count=0;
-  for (tablist2 = tables; tablist2; tablist2= tablist2->next)
-    count++;
-  if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
-    goto err1;
-  table_ptr= tables2;
-  for (tablist2 = tables; tablist2; tablist2= tablist2->next)
-    *(table_ptr++)= tablist2->table;
-  if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
-    goto err1;
-
-  count= 1;
-  for (lock_data1= sql_lock1->locks,
-         end_data1= lock_data1 + sql_lock1->lock_count;
-       lock_data1 < end_data1;
-       lock_data1++)
-  {
-    lock1= (*lock_data1)->lock;
-    for (lock_data2= sql_lock2->locks,
-           end_data2= lock_data2 + sql_lock2->lock_count;
-         lock_data2 < end_data2;
-         lock_data2++)
+  /* Compare all tables locks against this range. */
+  for (tablist = tables; tablist; tablist= tablist->next)
+  {
+    /* Get the lock data range for the current table in the list. */
+    mysql_lock_data_range(mylock, tablist->table, &beg2, &end2);
+
+    /* Compare all locks in the lock data range for table ... */
+    for (idx1= beg1; idx1 < end1; idx1++)
     {
-      if ((*lock_data2)->lock == lock1)
-        goto end;
+      lock1= mylock->locks[idx1]->lock;
+
+      /* ... against all locks in the lock data range for the listed table. */
+      for (idx2= beg2; idx2 < end2; idx2++)
+      {
+        if (mylock->locks[idx2]->lock == lock1)
+          DBUG_RETURN(1);
+      }
     }
   }
-  count= 0;
-
- end:
-  my_free((gptr) sql_lock2, MYF(0));
-  my_free((gptr) sql_lock1, MYF(0));
-  DBUG_RETURN(count);
-
- err1:
-  my_free((gptr) sql_lock1, MYF(0));
- err0:
-  DBUG_RETURN(-1);
+  DBUG_RETURN(0);
 }
 
 
@@ -504,31 +526,35 @@
 static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
 				 bool get_old_locks, TABLE **write_lock_used)
 {
-  uint i,tables,lock_count;
+  uint i, table_count, lock_count;
+  uint *start;
   MYSQL_LOCK *sql_lock;
   THR_LOCK_DATA **locks;
   TABLE **to;
   DBUG_ENTER("get_lock_data");
 
   *write_lock_used=0;
-  for (i=tables=lock_count=0 ; i < count ; i++)
+  for (i= table_count= lock_count= 0 ; i < count ; i++)
   {
     if (table_ptr[i]->tmp_table != TMP_TABLE)
     {
-      tables+=table_ptr[i]->file->lock_count();
-      lock_count++;
+      lock_count+= table_ptr[i]->file->lock_count();
+      table_count++;
     }
   }
 
   if (!(sql_lock= (MYSQL_LOCK*)
-	my_malloc(sizeof(*sql_lock)+
-		  sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
-		  MYF(0))))
+	my_malloc(sizeof(*sql_lock) +
+		  sizeof(THR_LOCK_DATA*) * lock_count +
+                  (sizeof(table_ptr) + sizeof(uint)) * table_count, MYF(0))))
     DBUG_RETURN(0);
-  locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
-  to=sql_lock->table=(TABLE**) (locks+tables);
-  sql_lock->table_count=lock_count;
-  sql_lock->lock_count=tables;
+
+  locks= sql_lock->locks=             (THR_LOCK_DATA**) (sql_lock + 1);
+  to=    sql_lock->table=             (TABLE**)         (locks + lock_count);
+  start= sql_lock->table_lock_starts= (uint*)           (to + table_count);
+
+  sql_lock->table_count= table_count;
+  sql_lock->lock_count=  lock_count;
 
   for (i=0 ; i < count ; i++)
   {
@@ -536,6 +562,7 @@
     if ((table=table_ptr[i])->tmp_table == TMP_TABLE)
       continue;
     *to++=table;
+    *(start++)= locks - sql_lock->locks;
     enum thr_lock_type lock_type= table->reginfo.lock_type;
     if (lock_type >= TL_WRITE_ALLOW_WRITE)
     {

--- 1.191/sql/sql_class.h	2004-12-03 00:02:39 +01:00
+++ 1.192/sql/sql_class.h	2006-01-06 16:37:21 +01:00
@@ -254,6 +254,7 @@
 typedef struct st_mysql_lock
 {
   TABLE **table;
+  uint *table_lock_starts;
   uint table_count,lock_count;
   THR_LOCK_DATA **locks;
 } MYSQL_LOCK;
Thread
bk commit into 4.0 tree (ingo:1.2168) BUG#5390ingo6 Jan