From: Date: January 6 2006 4:37pm Subject: bk commit into 4.0 tree (ingo:1.2168) BUG#5390 List-Archive: http://lists.mysql.com/commits/704 X-Bug: 5390 Message-Id: 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;