diff options
author | istruewing@stella.local <> | 2007-12-11 21:38:08 +0100 |
---|---|---|
committer | istruewing@stella.local <> | 2007-12-11 21:38:08 +0100 |
commit | 65fda831ce0519430cdefd699ac067d583f09d9f (patch) | |
tree | 8557567e84288852d52c89547d9ed8bc26f3a58c /storage | |
parent | 03d99c595695fee897e66d7fb83a6b62603c934d (diff) | |
parent | 55aa6376f1faaa2a7925fd9538b976b74221df6d (diff) | |
download | mariadb-git-65fda831ce0519430cdefd699ac067d583f09d9f.tar.gz |
Merge stella.local:/home2/mydev/mysql-5.1-bug30273
into stella.local:/home2/mydev/mysql-5.1-axmrg
Diffstat (limited to 'storage')
-rw-r--r-- | storage/myisammrg/ha_myisammrg.cc | 31 | ||||
-rw-r--r-- | storage/myisammrg/myrg_close.c | 1 | ||||
-rw-r--r-- | storage/myisammrg/myrg_open.c | 17 |
3 files changed, 46 insertions, 3 deletions
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index f91b0dc7a92..4d3d8362a03 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -901,7 +901,14 @@ int ha_myisammrg::external_lock(THD *thd, int lock_type) uint ha_myisammrg::lock_count(void) const { - DBUG_ASSERT(this->file->children_attached); + /* + Return the real lock count even if the children are not attached. + This method is used for allocating memory. If we would return 0 + to another thread (e.g. doing FLUSH TABLE), and attach the children + before the other thread calls store_lock(), then we would return + more locks in store_lock() than we claimed by lock_count(). The + other tread would overrun its memory. + */ return file->tables; } @@ -911,7 +918,24 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd, enum thr_lock_type lock_type) { MYRG_TABLE *open_table; - DBUG_ASSERT(this->file->children_attached); + + /* + This method can be called while another thread is attaching the + children. If the processor reorders instructions or write to memory, + 'children_attached' could be set before 'open_tables' has all the + pointers to the children. Use of a mutex here and in + myrg_attach_children() forces consistent data. + */ + pthread_mutex_lock(&this->file->mutex); + + /* + When MERGE table is open, but not yet attached, other threads + could flush it, which means call mysql_lock_abort_for_thread() + on this threads TABLE. 'children_attached' is FALSE in this + situaton. Since the table is not locked, return no lock data. + */ + if (!this->file->children_attached) + goto end; /* purecov: tested */ for (open_table=file->open_tables ; open_table != file->end_table ; @@ -921,6 +945,9 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd, if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK) open_table->table->lock.type=lock_type; } + + end: + pthread_mutex_unlock(&this->file->mutex); return to; } diff --git a/storage/myisammrg/myrg_close.c b/storage/myisammrg/myrg_close.c index b402a35a253..97216ed47fe 100644 --- a/storage/myisammrg/myrg_close.c +++ b/storage/myisammrg/myrg_close.c @@ -58,6 +58,7 @@ int myrg_close(MYRG_INFO *info) pthread_mutex_lock(&THR_LOCK_open); myrg_open_list=list_delete(myrg_open_list,&info->open_list); pthread_mutex_unlock(&THR_LOCK_open); + VOID(pthread_mutex_destroy(&info->mutex)); my_free((uchar*) info,MYF(0)); if (error) { diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c index 6fb1888f84d..b5002116164 100644 --- a/storage/myisammrg/myrg_open.c +++ b/storage/myisammrg/myrg_open.c @@ -33,7 +33,7 @@ myrg_attach_children(). Please duplicate changes in these functions or make common sub-functions. */ -/* purecov: begin unused */ +/* purecov: begin deadcode */ /* not used in MySQL server */ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) { @@ -171,6 +171,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) VOID(my_close(fd,MYF(0))); end_io_cache(&file); + VOID(pthread_mutex_init(&m_info->mutex, MY_MUTEX_INIT_FAST)); m_info->open_list.data=(void*) m_info; pthread_mutex_lock(&THR_LOCK_open); myrg_open_list=list_add(myrg_open_list,&m_info->open_list); @@ -328,6 +329,7 @@ MYRG_INFO *myrg_parent_open(const char *parent_name, end_io_cache(&file_cache); VOID(my_close(fd, MYF(0))); + VOID(pthread_mutex_init(&m_info->mutex, MY_MUTEX_INIT_FAST)); m_info->open_list.data= (void*) m_info; pthread_mutex_lock(&THR_LOCK_open); @@ -393,6 +395,14 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, DBUG_ENTER("myrg_attach_children"); DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking)); + /* + This function can be called while another thread is trying to abort + locks of this MERGE table. If the processor reorders instructions or + write to memory, 'children_attached' could be set before + 'open_tables' has all the pointers to the children. Use of a mutex + here and in ha_myisammrg::store_lock() forces consistent data. + */ + pthread_mutex_lock(&m_info->mutex); rc= 1; errpos= 0; file_offset= 0; @@ -464,6 +474,7 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, m_info->keys= min_keys; m_info->last_used_table= m_info->open_tables; m_info->children_attached= TRUE; + pthread_mutex_unlock(&m_info->mutex); DBUG_RETURN(0); err: @@ -473,6 +484,7 @@ err: my_free((char*) m_info->rec_per_key_part, MYF(0)); m_info->rec_per_key_part= NULL; } + pthread_mutex_unlock(&m_info->mutex); my_errno= save_errno; DBUG_RETURN(1); } @@ -494,6 +506,8 @@ err: int myrg_detach_children(MYRG_INFO *m_info) { DBUG_ENTER("myrg_detach_children"); + /* For symmetry with myrg_attach_children() we use the mutex here. */ + pthread_mutex_lock(&m_info->mutex); if (m_info->tables) { /* Do not attach/detach an empty child list. */ @@ -504,6 +518,7 @@ int myrg_detach_children(MYRG_INFO *m_info) m_info->del= 0; m_info->data_file_length= 0; m_info->options= 0; + pthread_mutex_unlock(&m_info->mutex); DBUG_RETURN(0); } |