diff options
author | unknown <ingo@mysql.com> | 2006-02-06 15:15:44 +0100 |
---|---|---|
committer | unknown <ingo@mysql.com> | 2006-02-06 15:15:44 +0100 |
commit | 0e88bff6cb73f1e95ad6683d45626fadef41f35d (patch) | |
tree | 86ac1cb5e291d1c456e125e1954b4cdb41d5bb49 | |
parent | b948741b6beebb024ae4df23107f9e1f016cb14f (diff) | |
parent | cfbb86034d284c8c24a63725735f17cf00304b3b (diff) | |
download | mariadb-git-0e88bff6cb73f1e95ad6683d45626fadef41f35d.tar.gz |
Merge mysql.com:/home/mydev/mysql-4.1-bug5390
into mysql.com:/home/mydev/mysql-5.0-bug5390
mysql-test/r/lock.result:
Auto merged
mysql-test/t/lock.test:
Auto merged
sql/lock.cc:
BUG#5390 - problems with merge tables
Manual merge
sql/table.h:
BUG#5390 - problems with merge tables
Manual merge
-rw-r--r-- | mysql-test/r/lock.result | 11 | ||||
-rw-r--r-- | mysql-test/t/lock.test | 18 | ||||
-rw-r--r-- | sql/lock.cc | 144 | ||||
-rw-r--r-- | sql/table.h | 8 |
4 files changed, 150 insertions, 31 deletions
diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index a1efb1a8e69..079b0253ff6 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -47,6 +47,17 @@ unlock tables; lock tables t1 write, t1 as t1_alias read; insert into t1 select index1,nr from t1 as t1_alias; drop table t1,t2; +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write; +drop table t2, t3, t1; +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write, t1 as t4 read; +alter table t2 add column c2 int; +drop table t1, t2, t3; create table t1 ( a int(11) not null auto_increment, primary key(a)); create table t2 ( a int(11) not null auto_increment, primary key(a)); lock tables t1 write, t2 read; diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 4815c1a30b7..8300219b3d4 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -61,6 +61,24 @@ insert into t1 select index1,nr from t1 as t1_alias; drop table t1,t2; # +# BUG#5390 - problems with merge tables +# Supplement test for the after-fix optimization +# Check that a dropped table is correctly removed from a lock. +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write; +# This removes one table after the other from the lock. +drop table t2, t3, t1; +# +# Check that a lock merge works. +create table t1 (c1 int); +create table t2 (c1 int); +create table t3 (c1 int); +lock tables t1 write, t2 write, t3 write, t1 as t4 read; +alter table t2 add column c2 int; +drop table t1, t2, t3; + # Bug7241 - Invalid response when DELETE .. USING and LOCK TABLES used. # create table t1 ( a int(11) not null auto_increment, primary key(a)); diff --git a/sql/lock.cc b/sql/lock.cc index d0bfcfd7272..6f206f017e4 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -68,20 +68,20 @@ TODO: #include "mysql_priv.h" #include <hash.h> -#include "ha_myisammrg.h" -#ifndef MASTER -#include "../srclib/myisammrg/myrg_def.h" -#else -#include "../myisammrg/myrg_def.h" -#endif +#include <assert.h> + +extern HASH open_cache; + +/* flags for get_lock_data */ +#define GET_LOCK_UNLOCK 1 +#define GET_LOCK_STORE_LOCKS 2 static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count, - bool unlock, TABLE **write_locked); + uint flags, TABLE **write_locked); 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, const char *); - /* Lock tables. @@ -122,7 +122,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, for (;;) { - if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) + if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, + &write_lock_used))) break; if (global_read_lock && write_lock_used && @@ -267,7 +268,8 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; - if ((sql_lock = get_lock_data(thd, table, count, 1, &write_lock_used))) + if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK, + &write_lock_used))) mysql_unlock_tables(thd, sql_lock); } @@ -304,6 +306,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) TABLE **table=sql_lock->table; for (i=found=0 ; i < sql_lock->table_count ; i++) { + DBUG_ASSERT(sql_lock->table[i]->lock_position == i); if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ) { swap_variables(TABLE *, *table, sql_lock->table[i]); @@ -317,6 +320,17 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) VOID(unlock_external(thd,table,i-found)); sql_lock->table_count=found; } + /* Fix the lock positions in TABLE */ + table= sql_lock->table; + found= 0; + for (i= 0; i < sql_lock->table_count; i++) + { + TABLE *tbl= *table; + tbl->lock_position= table - sql_lock->table; + tbl->lock_data_start= found; + found+= tbl->lock_count; + table++; + } DBUG_VOID_RETURN; } @@ -332,20 +346,51 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) { if (locked->table[i] == table) { - locked->table_count--; + uint j, removed_locks, old_tables; + TABLE *tbl; + uint lock_data_end; + + DBUG_ASSERT(table->lock_position == i); + + /* Decrement table_count in advance, making below expressions easier */ + old_tables= --locked->table_count; + + /* The table has 'removed_locks' lock data elements in locked->locks */ + removed_locks= table->lock_count; + + /* Move down all table pointers above 'i'. */ bmove((char*) (locked->table+i), (char*) (locked->table+i+1), - (locked->table_count-i)* sizeof(TABLE*)); + (old_tables - i) * sizeof(TABLE*)); + + lock_data_end= table->lock_data_start + table->lock_count; + /* Move down all lock data pointers above 'table->lock_data_end-1' */ + bmove((char*) (locked->locks + table->lock_data_start), + (char*) (locked->locks + lock_data_end), + (locked->lock_count - lock_data_end) * + sizeof(THR_LOCK_DATA*)); + + /* + Fix moved table elements. + lock_position is the index in the 'locked->table' array, + it must be fixed by one. + table->lock_data_start is pointer to the lock data for this table + in the 'locked->locks' array, they must be fixed by 'removed_locks', + the lock data count of the removed table. + */ + for (j= i ; j < old_tables; j++) + { + tbl= locked->table[j]; + tbl->lock_position--; + DBUG_ASSERT(tbl->lock_position == j); + tbl->lock_data_start-= removed_locks; + } + + /* Finally adjust lock_count. */ + locked->lock_count-= removed_locks; break; } } - THR_LOCK_DATA **prev=locked->locks; - for (i=0 ; i < locked->lock_count ; i++) - { - if (locked->locks[i]->type != TL_UNLOCK) - *prev++ = locked->locks[i]; - } - locked->lock_count=(uint) (prev - locked->locks); } } @@ -355,7 +400,8 @@ void mysql_lock_abort(THD *thd, TABLE *table) { MYSQL_LOCK *locked; TABLE *write_lock_used; - if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used))) + if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, + &write_lock_used))) { for (uint i=0; i < locked->lock_count; i++) thr_abort_locks(locked->locks[i]->lock); @@ -384,7 +430,8 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) bool result= FALSE; DBUG_ENTER("mysql_lock_abort_for_thread"); - if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used))) + if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, + &write_lock_used))) { for (uint i=0; i < locked->lock_count; i++) { @@ -401,7 +448,9 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) { MYSQL_LOCK *sql_lock; + TABLE **table, **end_table; DBUG_ENTER("mysql_lock_merge"); + if (!(sql_lock= (MYSQL_LOCK*) my_malloc(sizeof(*sql_lock)+ sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+ @@ -417,6 +466,21 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table)); memcpy(sql_lock->table+a->table_count,b->table, b->table_count*sizeof(*b->table)); + + /* + Now adjust lock_position and lock_data_start for all objects that was + moved in 'b' (as there is now all objects in 'a' before these). + */ + for (table= sql_lock->table + a->table_count, + end_table= table + b->table_count; + table < end_table; + table++) + { + (*table)->lock_position+= a->table_count; + (*table)->lock_data_start+= a->lock_count; + } + + /* Delete old, not needed locks */ my_free((gptr) a,MYF(0)); my_free((gptr) b,MYF(0)); DBUG_RETURN(sql_lock); @@ -570,17 +634,27 @@ static int unlock_external(THD *thd, TABLE **table,uint count) /* -** Get lock structures from table structs and initialize locks + Get lock structures from table structs and initialize locks + + SYNOPSIS + get_lock_data() + thd Thread handler + table_ptr Pointer to tables that should be locks + flags One of: + GET_LOCK_UNLOCK: If we should send TL_IGNORE to + store lock + GET_LOCK_STORE_LOCKS: Store lock info in TABLE + write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE */ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, - bool get_old_locks, TABLE **write_lock_used) + uint flags, TABLE **write_lock_used) { uint i,tables,lock_count; MYSQL_LOCK *sql_lock; - THR_LOCK_DATA **locks; - TABLE **to; + THR_LOCK_DATA **locks, **locks_buf, **locks_start; + TABLE **to, **table_buf; DBUG_ENTER("get_lock_data"); *write_lock_used=0; @@ -611,8 +685,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count, MYF(0)))) DBUG_RETURN(0); - locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); - to=sql_lock->table=(TABLE**) (locks+tables); + locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1); + to= table_buf= sql_lock->table= (TABLE**) (locks + tables); sql_lock->table_count=lock_count; sql_lock->lock_count=tables; @@ -621,8 +695,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, TABLE *table; if ((table=table_ptr[i])->s->tmp_table == TMP_TABLE) continue; - *to++=table; - enum thr_lock_type lock_type= table->reginfo.lock_type; + lock_type= table->reginfo.lock_type; if (lock_type >= TL_WRITE_ALLOW_WRITE) { *write_lock_used=table; @@ -634,8 +707,17 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, } } THR_LOCK_DATA **org_locks = locks; - locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE : - lock_type); + locks_start= locks; + locks= table->file->store_lock(thd, locks, + (flags & GET_LOCK_UNLOCK) ? TL_IGNORE : + lock_type); + if (flags & GET_LOCK_STORE_LOCKS) + { + table->lock_position= (uint) (to - table_buf); + table->lock_data_start= (uint) (locks_start - locks_buf); + table->lock_count= (uint) (locks - locks_start); + } + *to++= table; if (locks) for ( ; org_locks != locks ; org_locks++) (*org_locks)->debug_print_param= (void *) table; diff --git a/sql/table.h b/sql/table.h index 78a942ef301..62990a966cc 100644 --- a/sql/table.h +++ b/sql/table.h @@ -235,6 +235,14 @@ struct st_table { timestamp_auto_set_type timestamp_field_type; table_map map; /* ID bit of table (1,2,4,8,16...) */ + uint next_number_index; + uint blob_ptr_size; /* 4 or 8 */ + uint next_number_key_offset; + uint lock_position; /* Position in MYSQL_LOCK.table */ + uint lock_data_start; /* Start pos. in MYSQL_LOCK.locks */ + uint lock_count; /* Number of locks */ + int current_lock; /* Type of lock on table */ + enum tmp_table_type tmp_table; uint tablenr,used_fields; uint temp_pool_slot; /* Used by intern temp tables */ uint status; /* What's in record[0] */ |