diff options
author | Michael Widenius <monty@askmonty.org> | 2010-11-04 16:53:10 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2010-11-04 16:53:10 +0200 |
commit | 3797ca41b39c862cf4733eadea8c91ed138ca1a4 (patch) | |
tree | ec51a2bcd2a7c071f89d3177ca7914dccd111c9f /mysys | |
parent | 5789f96c624d00aeef137602ab0c4828620748e8 (diff) | |
parent | 3bac9cf7fe12c1b1c644ac7963c701b79b3127f3 (diff) | |
download | mariadb-git-3797ca41b39c862cf4733eadea8c91ed138ca1a4.tar.gz |
Automatic merge with 5.1
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/my_getopt.c | 1 | ||||
-rw-r--r-- | mysys/my_symlink2.c | 4 | ||||
-rw-r--r-- | mysys/thr_lock.c | 208 |
3 files changed, 152 insertions, 61 deletions
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 21eea5517f1..db6ccd230f2 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -614,7 +614,6 @@ static int setval(const struct my_option *opts, void *value, char *argument, my_bool set_maximum_value) { int err= 0; - int pos; if (value && argument) { diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index 7c3ddbb911c..bc7ac751fad 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -34,8 +34,8 @@ File my_create_with_symlink(const char *linkname, const char *filename, char abs_linkname[FN_REFLEN]; DBUG_ENTER("my_create_with_symlink"); DBUG_PRINT("enter", ("linkname: %s filename: %s", - linkname ? linkname : "(null)", - filename ? filename : "(null)")); + linkname ? linkname : "(NULL)", + filename ? filename : "(NULL)")); if (my_disable_symlinks) { diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index b8aa9e5fcc0..341b2f0058e 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -63,6 +63,11 @@ update_status: A storage engine should also call update_status internally in the ::external_lock(F_UNLCK) method. In MyISAM and CSV this functions updates the length of the datafile. + MySQL does in some exceptional cases (when doing DLL statements on + open tables calls thr_unlock() followed by thr_lock() without calling + ::external_lock() in between. In this case thr_unlock() is called with + the THR_UNLOCK_UPDATE_STATUS flag and thr_unlock() will call + update_status for write locks. get_status: When one gets a lock this functions is called. In MyISAM this stores the number of rows and size of the datafile @@ -105,8 +110,30 @@ static inline pthread_cond_t *get_cond(void) return &my_thread_var->suspend; } + +/* + Priority for locks (decides in which order locks are locked) + We want all write locks to be first, followed by read locks. + Locks from MERGE tables has a little lower priority than other + locks, to allow one to release merge tables without having + to unlock and re-lock other locks. + The lower the number, the higher the priority for the lock. + Read locks should have 4, write locks should have 0. + UNLOCK is 8, to force these last in thr_merge_locks. + For MERGE tables we add 2 (THR_LOCK_MERGE_PRIV) to the lock priority. + THR_LOCK_LATE_PRIV (1) is used when one locks other tables to be merged + with existing locks. This way we prioritize the original locks over the + new locks. +*/ + +static uint lock_priority[(uint)TL_WRITE_ONLY+1] = +{ 8, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0}; + +#define LOCK_CMP(A,B) ((uchar*) ((A)->lock) + lock_priority[(uint) (A)->type] + (A)->priority < (uchar*) ((B)->lock) + lock_priority[(uint) (B)->type] + (B)->priority) + + /* -** For the future (now the thread specific cond is alloced by my_pthread.c) + For the future (now the thread specific cond is alloced by my_pthread.c) */ my_bool init_thr_lock() @@ -379,6 +406,7 @@ void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param) data->owner= 0; /* no owner yet */ data->status_param=param; data->cond=0; + data->priority= 0; } @@ -530,7 +558,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, } -enum enum_thr_lock_result +static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type) { @@ -544,6 +572,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, data->cond=0; /* safety */ data->type=lock_type; data->owner= owner; /* Must be reset ! */ + data->priority&= ~THR_LOCK_LATE_PRIV; VOID(pthread_mutex_lock(&lock->mutex)); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d", (long) data, data->owner->info->thread_id, @@ -808,7 +837,7 @@ static inline void free_all_read_locks(THR_LOCK *lock, /* Unlock lock and free next thread on same lock */ -void thr_unlock(THR_LOCK_DATA *data) +void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags) { THR_LOCK *lock=data->lock; enum thr_lock_type lock_type=data->type; @@ -832,6 +861,21 @@ void thr_unlock(THR_LOCK_DATA *data) } else lock->write.last=data->prev; + + if (unlock_flags & THR_UNLOCK_UPDATE_STATUS) + { + /* External lock was not called; Update or restore status */ + if (lock_type >= TL_WRITE_CONCURRENT_INSERT) + { + if (lock->update_status) + (*lock->update_status)(data->status_param); + } + else + { + if (lock->restore_status) + (*lock->restore_status)(data->status_param); + } + } if (lock_type == TL_READ_NO_INSERT) lock->read_no_write_count--; data->type=TL_UNLOCK; /* Mark unlocked */ @@ -967,14 +1011,12 @@ end: /* -** Get all locks in a specific order to avoid dead-locks -** Sort acording to lock position and put write_locks before read_locks if -** lock on same lock. + Get all locks in a specific order to avoid dead-locks + Sort acording to lock position and put write_locks before read_locks if + lock on same lock. Locks on MERGE tables has lower priority than other + locks of the same type. See comment for lock_priority. */ - -#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type)) - static void sort_locks(THR_LOCK_DATA **data,uint count) { THR_LOCK_DATA **pos,**end,**prev,*tmp; @@ -999,18 +1041,22 @@ static void sort_locks(THR_LOCK_DATA **data,uint count) enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) { - THR_LOCK_DATA **pos,**end; + THR_LOCK_DATA **pos, **end, **first_lock; DBUG_ENTER("thr_multi_lock"); DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count)); + if (count > 1) sort_locks(data,count); + else if (count == 0) + DBUG_RETURN(THR_LOCK_SUCCESS); + /* lock everything */ for (pos=data,end=data+count; pos < end ; pos++) { enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type); if (result != THR_LOCK_SUCCESS) { /* Aborted */ - thr_multi_unlock(data,(uint) (pos-data)); + thr_multi_unlock(data,(uint) (pos-data), 0); DBUG_RETURN(result); } #ifdef MAIN @@ -1018,63 +1064,103 @@ 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 + Call start_trans for all locks. If we lock the same table multiple times, we must use the same - status_param! + status_param; We ensure this by calling copy_status() for all + copies of the same tables. */ -#if !defined(DONT_USE_RW_LOCKS) - if (count > 1) + if ((*data)->lock->start_trans) + ((*data)->lock->start_trans)((*data)->status_param); + for (first_lock=data, pos= data+1 ; pos < end ; pos++) { - THR_LOCK_DATA *last_lock= end[-1]; - pos=end-1; - do + /* Get the current status (row count, checksum, trid etc) */ + if ((*pos)->lock->start_trans) + (*(*pos)->lock->start_trans)((*pos)->status_param); + /* + If same table as previous table use pointer to previous status + information to ensure that all read/write tables shares same + state. + */ + if (pos[0]->lock == pos[-1]->lock && pos[0]->lock->copy_status) + (pos[0]->lock->copy_status)((*pos)->status_param, + (*first_lock)->status_param); + else { - pos--; - if (last_lock->lock == (*pos)->lock && - last_lock->lock->copy_status) - { - if (last_lock->type <= TL_READ_NO_INSERT) - { - THR_LOCK_DATA **read_lock; - /* - If we are locking the same table with read locks we must ensure - that all tables share the status of the last write lock or - the same read lock. - */ - for (; - (*pos)->type <= TL_READ_NO_INSERT && - pos != data && - pos[-1]->lock == (*pos)->lock ; - pos--) ; - - read_lock = pos+1; - do - { - (last_lock->lock->copy_status)((*read_lock)->status_param, - (*pos)->status_param); - } while (*(read_lock++) != last_lock); - last_lock= (*pos); /* Point at last write lock */ - } - else - (*last_lock->lock->copy_status)((*pos)->status_param, - last_lock->status_param); - } - else - last_lock=(*pos); - } while (pos != data); + /* Different lock, use this as base for next lock */ + first_lock= pos; + } } -#endif DBUG_RETURN(THR_LOCK_SUCCESS); } - /* free all locks */ -void thr_multi_unlock(THR_LOCK_DATA **data,uint count) +/** + Merge two sets of locks. + + @param data All locks. First old locks, then new locks. + @param old_count Original number of locks. These are first in 'data'. + @param new_count How many new locks + + The merge is needed if the new locks contains same tables as the old + locks, in which case we have to ensure that same tables shares the + same status (as after a thr_multi_lock()). +*/ + +void thr_merge_locks(THR_LOCK_DATA **data, uint old_count, uint new_count) +{ + THR_LOCK_DATA **pos, **end, **first_lock= 0; + DBUG_ENTER("thr_merge_lock"); + + /* Remove marks on old locks to make them sort before new ones */ + for (pos=data, end= pos + old_count; pos < end ; pos++) + (*pos)->priority&= ~THR_LOCK_LATE_PRIV; + + /* Mark new locks with LATE_PRIV to make them sort after org ones */ + for (pos=data + old_count, end= pos + new_count; pos < end ; pos++) + (*pos)->priority|= THR_LOCK_LATE_PRIV; + + sort_locks(data, old_count + new_count); + + for (pos=data ; pos < end ; pos++) + { + /* Check if lock was unlocked before */ + if (pos[0]->type == TL_UNLOCK || ! pos[0]->lock->fix_status) + { + DBUG_PRINT("info", ("lock skipped. unlocked: %d fix_status: %d", + pos[0]->type == TL_UNLOCK, + pos[0]->lock->fix_status == 0)); + continue; + } + + /* + If same table as previous table use pointer to previous status + information to ensure that all read/write tables shares same + state. + */ + if (first_lock && pos[0]->lock == first_lock[0]->lock) + (pos[0]->lock->fix_status)((*first_lock)->status_param, + (*pos)->status_param); + else + { + /* Different lock, use this as base for next lock */ + first_lock= pos; + (pos[0]->lock->fix_status)((*first_lock)->status_param, 0); + } + } + DBUG_VOID_RETURN; +} + + +/* Unlock all locks */ + +void thr_multi_unlock(THR_LOCK_DATA **data,uint count, uint unlock_flags) { THR_LOCK_DATA **pos,**end; DBUG_ENTER("thr_multi_unlock"); - DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count)); + DBUG_PRINT("lock",("data: 0x%lx count: %d flags: %u", (long) data, count, + unlock_flags)); for (pos=data,end=data+count; pos < end ; pos++) { @@ -1084,7 +1170,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count) fflush(stdout); #endif if ((*pos)->type != TL_UNLOCK) - thr_unlock(*pos); + thr_unlock(*pos, unlock_flags); else { DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx", @@ -1400,6 +1486,7 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, enum thr_lock_type new_lock_type) { THR_LOCK *lock=data->lock; + enum enum_thr_lock_result res; DBUG_ENTER("thr_upgrade_write_delay_lock"); pthread_mutex_lock(&lock->mutex); @@ -1420,6 +1507,8 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, if (lock->get_status) (*lock->get_status)(data->status_param, 0); pthread_mutex_unlock(&lock->mutex); + if (lock->start_trans) + (*lock->start_trans)(data->status_param); DBUG_RETURN(0); } @@ -1440,7 +1529,10 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, { check_locks(lock,"waiting for lock",0); } - DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1)); + res= wait_for_lock(&lock->write_wait,data,1); + if (res == THR_LOCK_SUCCESS && lock->start_trans) + DBUG_RETURN((*lock->start_trans)(data->status_param)); + DBUG_RETURN(0); } @@ -1684,7 +1776,7 @@ static void *test_thread(void *arg) } } pthread_mutex_unlock(&LOCK_thread_count); - thr_multi_unlock(multi_locks,lock_counts[param]); + thr_multi_unlock(multi_locks,lock_counts[param], THR_UNLOCK_UPDATE_STATUS); } printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout); |