diff options
author | Sergei Golubchik <sergii@pisem.net> | 2010-11-25 18:17:28 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2010-11-25 18:17:28 +0100 |
commit | 65ca700def99289cc31a7040537f5aa6e12bf485 (patch) | |
tree | 97b3a07299b626c519da0e80c122b5b79b933914 /sql/lock.cc | |
parent | 2ab57de38d13d927ddff2d51aed4af34e13998f5 (diff) | |
parent | 6e5bcca7935d3c62f84bb640e5357664a210ee12 (diff) | |
download | mariadb-git-65ca700def99289cc31a7040537f5aa6e12bf485.tar.gz |
merge.
checkpoint.
does not compile.
Diffstat (limited to 'sql/lock.cc')
-rw-r--r-- | sql/lock.cc | 105 |
1 files changed, 74 insertions, 31 deletions
diff --git a/sql/lock.cc b/sql/lock.cc index 0181a544824..66b59fa5466 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -34,8 +34,8 @@ This is followed by a call to thr_multi_lock() for all tables. - When statement is done, we call mysql_unlock_tables(). - This will call thr_multi_unlock() followed by - table_handler->external_lock(thd, F_UNLCK) for each table. + table_handler->external_lock(thd, F_UNLCK) followed by + thr_multi_unlock() for each table. - Note that mysql_unlock_tables() may be called several times as MySQL in some cases can free some tables earlier than others. @@ -293,13 +293,13 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) if (lock_tables_check(thd, tables, count, flags)) DBUG_RETURN(NULL); - if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS))) + if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS)) || + ! sql_lock->table_count) DBUG_RETURN(NULL); thd_proc_info(thd, "System lock"); DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info)); - if (sql_lock->table_count && lock_external(thd, sql_lock->table, - sql_lock->table_count)) + if (lock_external(thd, sql_lock->table, sql_lock->table_count)) { /* Clear the lock type of all lock data to avoid reusage. */ reset_lock_data_and_free(&sql_lock); @@ -316,8 +316,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) &thd->lock_info, timeout)]; if (rc) { - if (sql_lock->table_count) - (void) unlock_external(thd, sql_lock->table, sql_lock->table_count); + (void) unlock_external(thd, sql_lock->table, sql_lock->table_count); reset_lock_data_and_free(&sql_lock); if (! thd->killed) my_error(rc, MYF(0)); @@ -383,7 +382,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) if (sql_lock->lock_count) thr_multi_unlock(sql_lock->locks,sql_lock->lock_count); if (sql_lock->table_count) - (void) unlock_external(thd,sql_lock->table,sql_lock->table_count); + unlock_external(thd,sql_lock->table,sql_lock->table_count); my_free(sql_lock); DBUG_VOID_RETURN; } @@ -411,25 +410,8 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) uint i,found; DBUG_ENTER("mysql_unlock_read_tables"); - /* Move all write locks first */ - THR_LOCK_DATA **lock=sql_lock->locks; - for (i=found=0 ; i < sql_lock->lock_count ; i++) - { - if (sql_lock->locks[i]->type > TL_WRITE_ALLOW_WRITE) - { - swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]); - lock++; - found++; - } - } - /* unlock the read locked tables */ - if (i != found) - { - thr_multi_unlock(lock,i-found); - sql_lock->lock_count= found; - } + /* Call external lock for all tables to be unlocked */ - /* Then do the same for the external locks */ /* Move all write locked tables first */ TABLE **table=sql_lock->table; for (i=found=0 ; i < sql_lock->table_count ; i++) @@ -448,6 +430,27 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) (void) unlock_external(thd,table,i-found); sql_lock->table_count=found; } + + /* Call thr_unlock() for all tables to be unlocked */ + + /* Move all write locks first */ + THR_LOCK_DATA **lock=sql_lock->locks; + for (i=found=0 ; i < sql_lock->lock_count ; i++) + { + if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_WRITE) + { + swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]); + lock++; + found++; + } + } + /* unlock the read locked tables */ + if (i != found) + { + thr_multi_unlock(lock, i-found, 0); + sql_lock->lock_count= found; + } + /* Fix the lock positions in TABLE */ table= sql_lock->table; found= 0; @@ -543,8 +546,21 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK))) { - for (uint i=0; i < locked->lock_count; i++) - thr_abort_locks(locked->locks[i]->lock, upgrade_lock); + if (table->children_attached) + { + /* + Don't abort locks for underlying tables just because merge table + is deleted. Doing would cause anyone accessing these tables to + spin in open_table/close_table forever until lock is released. + */ + thr_multi_unlock(locked->locks, locked->lock_count, + THR_UNLOCK_UPDATE_STATUS); + } + else + { + for (uint i=0; i < locked->lock_count; i++) + thr_abort_locks(locked->locks[i]->lock, upgrade_lock); + } my_free(locked); } DBUG_VOID_RETURN; @@ -583,21 +599,36 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) } +/** + Merge two thr_lock:s + mysql_lock_merge() + + @param a Original locks + @param b New locks + + @retval New lock structure that contains a and b + + @note + a and b are freed with my_free() +*/ + MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) { MYSQL_LOCK *sql_lock; TABLE **table, **end_table; DBUG_ENTER("mysql_lock_merge"); + DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u", + a->lock_count, b->lock_count)); if (!(sql_lock= (MYSQL_LOCK*) my_malloc(sizeof(*sql_lock)+ - sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+ + sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) + sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME)))) DBUG_RETURN(0); // Fatal error sql_lock->lock_count=a->lock_count+b->lock_count; sql_lock->table_count=a->table_count+b->table_count; sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1); - sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count); + sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2); memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks)); memcpy(sql_lock->locks+a->lock_count,b->locks, b->lock_count*sizeof(*b->locks)); @@ -618,6 +649,18 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) (*table)->lock_data_start+= a->lock_count; } + /* + Ensure that locks of the same tables share same data structures if we + reopen a table that is already open. This can happen for example with + MERGE tables. + */ + + /* Copy the lock data array. thr_merge_lock() reorders its content */ + memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, + sql_lock->lock_count * sizeof(*sql_lock->locks)); + thr_merge_locks(sql_lock->locks + sql_lock->lock_count, + a->lock_count, b->lock_count); + /* Delete old, not needed locks */ my_free(a); my_free(b); @@ -687,7 +730,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, /* Allocating twice the number of pointers for lock data for use in - thr_mulit_lock(). This function reorders the lock data, but cannot + thr_multi_lock(). This function reorders the lock data, but cannot update the table values. So the second part of the array is copied from the first part immediately before calling thr_multi_lock(). */ |