diff options
-rw-r--r-- | include/thr_lock.h | 2 | ||||
-rw-r--r-- | mysql-test/r/lock.result | 18 | ||||
-rw-r--r-- | mysql-test/t/lock.test | 18 | ||||
-rw-r--r-- | mysys/thr_lock.c | 42 | ||||
-rw-r--r-- | sql/lock.cc | 2 |
5 files changed, 76 insertions, 6 deletions
diff --git a/include/thr_lock.h b/include/thr_lock.h index fb70c57c0e7..d5a7cd57ea7 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -160,6 +160,8 @@ void thr_unlock(THR_LOCK_DATA *data); enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner); void thr_multi_unlock(THR_LOCK_DATA **data,uint count); +void +thr_lock_merge_status(THR_LOCK_DATA **data, uint count); void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock); my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread); void thr_print_locks(void); /* For debugging */ diff --git a/mysql-test/r/lock.result b/mysql-test/r/lock.result index 676a8c41bb6..092c376b34a 100644 --- a/mysql-test/r/lock.result +++ b/mysql-test/r/lock.result @@ -244,5 +244,23 @@ a unlock tables; drop table t1, t2; # +# Ensure that mi_copy_status is called for two instances +# of the same table when it is reopened after a flush. +# +drop table if exists t1; +drop view if exists v1; +create table t1 (c1 int); +create view v1 as select * from t1; +lock tables t1 write, v1 write; +flush table t1; +insert into t1 values (33); +flush table t1; +select * from t1; +c1 +33 +unlock tables; +drop table t1; +drop view v1; +# # End of 6.0 tests. # diff --git a/mysql-test/t/lock.test b/mysql-test/t/lock.test index 7effaaeb20d..51900be4df8 100644 --- a/mysql-test/t/lock.test +++ b/mysql-test/t/lock.test @@ -291,6 +291,24 @@ select * from t1; unlock tables; drop table t1, t2; +--echo # +--echo # Ensure that mi_copy_status is called for two instances +--echo # of the same table when it is reopened after a flush. +--echo # +--disable_warnings +drop table if exists t1; +drop view if exists v1; +--enable_warnings +create table t1 (c1 int); +create view v1 as select * from t1; +lock tables t1 write, v1 write; +flush table t1; +insert into t1 values (33); +flush table t1; +select * from t1; +unlock tables; +drop table t1; +drop view v1; --echo # --echo # End of 6.0 tests. diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 1d724de641c..1288dc36a90 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -1026,12 +1026,43 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) (long) pos[0]->lock, pos[0]->type); fflush(stdout); #endif } - /* - Ensure that all get_locks() have the same status - If we lock the same table multiple times, we must use the same - status_param! - */ + thr_lock_merge_status(data, count); + DBUG_RETURN(THR_LOCK_SUCCESS); +} + + +/** + Ensure that all locks for a given table have the same + status_param. + + This is a MyISAM and possibly Maria specific crutch. MyISAM + engine stores data file length, record count and other table + properties in status_param member of handler. When a table is + locked, connection-local copy is made from a global copy + (myisam_share) by mi_get_status(). When a table is unlocked, + the changed status is transferred back to the global share by + mi_update_status(). + + One thing MyISAM doesn't do is to ensure that when the same + table is opened twice in a connection all instances share the + same status_param. This is necessary, however: for one, to keep + all instances of a connection "on the same page" with regard to + the current state of the table. For other, unless this is done, + myisam_share will always get updated from the last unlocked + instance (in mi_update_status()), and when this instance was not + the one that was used to update data, records may be lost. + + For each table, this function looks up the last lock_data in the + list of acquired locks, and makes sure that all other instances + share status_param with it. +*/ + +void +thr_lock_merge_status(THR_LOCK_DATA **data, uint count) +{ #if !defined(DONT_USE_RW_LOCKS) + THR_LOCK_DATA **pos= data; + THR_LOCK_DATA **end= data + count; if (count > 1) { THR_LOCK_DATA *last_lock= end[-1]; @@ -1073,7 +1104,6 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) } while (pos != data); } #endif - DBUG_RETURN(THR_LOCK_SUCCESS); } /* free all locks */ diff --git a/sql/lock.cc b/sql/lock.cc index 199ab354c22..d19f4b46821 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -687,6 +687,8 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) /* Delete old, not needed locks */ my_free((uchar*) a,MYF(0)); my_free((uchar*) b,MYF(0)); + + thr_lock_merge_status(sql_lock->locks, sql_lock->lock_count); DBUG_RETURN(sql_lock); } |