00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #include <config.h>
00056 #include <drizzled/internal/my_sys.h>
00057 #include <drizzled/internal/thread_var.h>
00058 #include <drizzled/statistics_variables.h>
00059 #include <drizzled/pthread_globals.h>
00060
00061 #include <drizzled/session.h>
00062
00063 #include "thr_lock.h"
00064 #include <drizzled/internal/m_string.h>
00065 #include <errno.h>
00066 #include <list>
00067
00068 #if TIME_WITH_SYS_TIME
00069 # include <sys/time.h>
00070 # include <time.h>
00071 #else
00072 # if HAVE_SYS_TIME_H
00073 # include <sys/time.h>
00074 # else
00075 # include <time.h>
00076 # endif
00077 #endif
00078
00079 #include <drizzled/util/test.h>
00080
00081 #include <boost/interprocess/sync/lock_options.hpp>
00082
00083 using namespace std;
00084
00085 namespace drizzled {
00086
00087 uint64_t table_lock_wait_timeout;
00088 static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
00089
00090
00091 uint64_t max_write_lock_count= UINT64_MAX;
00092
00093
00094
00095
00096
00097 static inline bool
00098 thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
00099 {
00100 return rhs == lhs;
00101 }
00102
00103
00104
00105
00106 void thr_lock_init(THR_LOCK *lock)
00107 {
00108 lock->read.last= &lock->read.data;
00109 lock->read_wait.last= &lock->read_wait.data;
00110 lock->write_wait.last= &lock->write_wait.data;
00111 lock->write.last= &lock->write.data;
00112 }
00113
00114
00115 void THR_LOCK_INFO::init()
00116 {
00117 thread_id= internal::my_thread_var2()->id;
00118 n_cursors= 0;
00119 }
00120
00121
00122
00123 void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
00124 {
00125 lock= lock_arg;
00126 type= TL_UNLOCK;
00127 owner= NULL;
00128 status_param= param_arg;
00129 cond= NULL;
00130 }
00131
00132
00133 static inline bool
00134 have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
00135 {
00136 for ( ; data ; data=data->next)
00137 {
00138 if (thr_lock_owner_equal(data->owner, owner))
00139 return true;
00140 }
00141 return false;
00142 }
00143
00144 static void wake_up_waiters(THR_LOCK *lock);
00145
00146
00147 static enum enum_thr_lock_result wait_for_lock(Session &session, struct st_lock_list *wait, THR_LOCK_DATA *data)
00148 {
00149 boost::condition_variable_any *cond= &session.getThreadVar()->suspend;
00150 enum enum_thr_lock_result result= THR_LOCK_ABORTED;
00151 bool can_deadlock= test(data->owner->info->n_cursors);
00152
00153 {
00154 (*wait->last)=data;
00155 data->prev= wait->last;
00156 wait->last= &data->next;
00157 }
00158
00159 current_global_counters.locks_waited++;
00160
00161
00162 session.getThreadVar()->current_mutex= data->lock->native_handle();
00163 session.getThreadVar()->current_cond= &session.getThreadVar()->suspend;
00164 data->cond= &session.getThreadVar()->suspend;;
00165
00166 while (not session.getThreadVar()->abort)
00167 {
00168 boost::mutex::scoped_lock scoped(*data->lock->native_handle(), boost::adopt_lock_t());
00169
00170 if (can_deadlock)
00171 {
00172 boost::xtime xt;
00173 xtime_get(&xt, boost::TIME_UTC);
00174 xt.sec += table_lock_wait_timeout;
00175 if (not cond->timed_wait(scoped, xt))
00176 {
00177 result= THR_LOCK_WAIT_TIMEOUT;
00178 scoped.release();
00179 break;
00180 }
00181 }
00182 else
00183 {
00184 cond->wait(scoped);
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 if (data->cond == NULL)
00200 {
00201 scoped.release();
00202 break;
00203 }
00204 scoped.release();
00205 }
00206 if (data->cond || data->type == TL_UNLOCK)
00207 {
00208 if (data->cond)
00209 {
00210 if (((*data->prev)=data->next))
00211 {
00212 data->next->prev= data->prev;
00213 }
00214 else
00215 {
00216 wait->last=data->prev;
00217 }
00218 data->type= TL_UNLOCK;
00219 wake_up_waiters(data->lock);
00220 }
00221 }
00222 else
00223 {
00224 result= THR_LOCK_SUCCESS;
00225 }
00226 data->lock->unlock();
00227
00228
00229 boost::mutex::scoped_lock scopedLock(session.getThreadVar()->mutex);
00230 session.getThreadVar()->current_mutex= NULL;
00231 session.getThreadVar()->current_cond= NULL;
00232
00233 return(result);
00234 }
00235
00236
00237 static enum enum_thr_lock_result thr_lock(Session &session, THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
00238 {
00239 THR_LOCK *lock= data->lock;
00240 enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
00241 struct st_lock_list *wait_queue;
00242 THR_LOCK_DATA *lock_owner;
00243
00244 data->next=0;
00245 data->cond=0;
00246 data->type=lock_type;
00247 data->owner= owner;
00248 lock->lock();
00249 if ((int) lock_type <= (int) TL_READ_NO_INSERT)
00250 {
00251
00252 if (lock->write.data)
00253 {
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
00264 (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
00265 (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
00266 (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
00267 lock->write.data->type != TL_WRITE_ALLOW_READ))))
00268 {
00269 (*lock->read.last)=data;
00270 data->prev=lock->read.last;
00271 lock->read.last= &data->next;
00272 if (lock_type == TL_READ_NO_INSERT)
00273 lock->read_no_write_count++;
00274 current_global_counters.locks_immediate++;
00275 goto end;
00276 }
00277 if (lock->write.data->type == TL_WRITE_ONLY)
00278 {
00279
00280 data->type=TL_UNLOCK;
00281 result= THR_LOCK_ABORTED;
00282 goto end;
00283 }
00284 }
00285 else if (!lock->write_wait.data ||
00286 lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
00287 have_old_read_lock(lock->read.data, data->owner))
00288 {
00289 (*lock->read.last)=data;
00290 data->prev=lock->read.last;
00291 lock->read.last= &data->next;
00292 if (lock_type == TL_READ_NO_INSERT)
00293 lock->read_no_write_count++;
00294 current_global_counters.locks_immediate++;
00295 goto end;
00296 }
00297
00298
00299
00300
00301
00302 wait_queue= &lock->read_wait;
00303 }
00304 else
00305 {
00306 if (lock_type == TL_WRITE_CONCURRENT_INSERT)
00307 data->type=lock_type= thr_upgraded_concurrent_insert_lock;
00308
00309 if (lock->write.data)
00310 {
00311 if (lock->write.data->type == TL_WRITE_ONLY)
00312 {
00313
00314 if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
00315 {
00316
00317 data->type=TL_UNLOCK;
00318 result= THR_LOCK_ABORTED;
00319 goto end;
00320 }
00321 }
00322
00323
00324
00325
00326
00327
00328 if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
00329 (lock_type == TL_WRITE_ALLOW_WRITE &&
00330 !lock->write_wait.data &&
00331 lock->write.data->type == TL_WRITE_ALLOW_WRITE))
00332 {
00333
00334
00335
00336
00337
00338 (*lock->write.last)=data;
00339 data->prev=lock->write.last;
00340 lock->write.last= &data->next;
00341 current_global_counters.locks_immediate++;
00342 goto end;
00343 }
00344 }
00345 else
00346 {
00347 if (!lock->write_wait.data)
00348 {
00349 if (!lock->read.data ||
00350 (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
00351 ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
00352 lock_type != TL_WRITE_ALLOW_WRITE) ||
00353 !lock->read_no_write_count)))
00354 {
00355 (*lock->write.last)=data;
00356 data->prev=lock->write.last;
00357 lock->write.last= &data->next;
00358 current_global_counters.locks_immediate++;
00359 goto end;
00360 }
00361 }
00362 }
00363 wait_queue= &lock->write_wait;
00364 }
00365
00366
00367
00368
00369
00370
00371 lock_owner= lock->read.data ? lock->read.data : lock->write.data;
00372 if (lock_owner && lock_owner->owner->info == owner->info)
00373 {
00374 result= THR_LOCK_DEADLOCK;
00375 goto end;
00376 }
00377
00378
00379 return(wait_for_lock(session, wait_queue, data));
00380
00381 end:
00382 lock->unlock();
00383
00384 return(result);
00385 }
00386
00387
00388 static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
00389 {
00390 THR_LOCK_DATA *data= lock->read_wait.data;
00391
00392
00393 (*lock->read.last)=data;
00394 data->prev=lock->read.last;
00395 lock->read.last=lock->read_wait.last;
00396
00397
00398 lock->read_wait.last= &lock->read_wait.data;
00399
00400 do
00401 {
00402 boost::condition_variable_any *cond= data->cond;
00403 if ((int) data->type == (int) TL_READ_NO_INSERT)
00404 {
00405 if (using_concurrent_insert)
00406 {
00407
00408
00409
00410
00411 if (((*data->prev)=data->next))
00412 data->next->prev=data->prev;
00413 else
00414 lock->read.last=data->prev;
00415 *lock->read_wait.last= data;
00416 data->prev= lock->read_wait.last;
00417 lock->read_wait.last= &data->next;
00418 continue;
00419 }
00420 lock->read_no_write_count++;
00421 }
00422 data->cond= NULL;
00423 cond->notify_one();
00424 } while ((data=data->next));
00425 *lock->read_wait.last=0;
00426 if (!lock->read_wait.data)
00427 lock->write_lock_count=0;
00428 }
00429
00430
00431
00432 static void thr_unlock(THR_LOCK_DATA *data)
00433 {
00434 THR_LOCK *lock=data->lock;
00435 enum thr_lock_type lock_type=data->type;
00436 lock->lock();
00437
00438 if (((*data->prev)=data->next))
00439 data->next->prev= data->prev;
00440 else if (lock_type <= TL_READ_NO_INSERT)
00441 lock->read.last=data->prev;
00442 else
00443 lock->write.last=data->prev;
00444 if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
00445 { }
00446 else
00447 { }
00448 if (lock_type == TL_READ_NO_INSERT)
00449 lock->read_no_write_count--;
00450 data->type=TL_UNLOCK;
00451 wake_up_waiters(lock);
00452 lock->unlock();
00453 }
00454
00455
00464 static void wake_up_waiters(THR_LOCK *lock)
00465 {
00466 THR_LOCK_DATA *data;
00467 enum thr_lock_type lock_type;
00468
00469 if (!lock->write.data)
00470 {
00471 data=lock->write_wait.data;
00472 if (!lock->read.data)
00473 {
00474
00475 if (data &&
00476 (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
00477 {
00478 if (lock->write_lock_count++ > max_write_lock_count)
00479 {
00480
00481 lock->write_lock_count=0;
00482 if (lock->read_wait.data)
00483 {
00484 free_all_read_locks(lock,0);
00485 goto end;
00486 }
00487 }
00488 for (;;)
00489 {
00490 if (((*data->prev)=data->next))
00491 data->next->prev= data->prev;
00492 else
00493 lock->write_wait.last=data->prev;
00494 (*lock->write.last)=data;
00495 data->prev=lock->write.last;
00496 data->next=0;
00497 lock->write.last= &data->next;
00498
00499 {
00500 boost::condition_variable_any *cond= data->cond;
00501 data->cond= NULL;
00502 cond->notify_one();
00503 }
00504 if (data->type != TL_WRITE_ALLOW_WRITE ||
00505 !lock->write_wait.data ||
00506 lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
00507 break;
00508 data=lock->write_wait.data;
00509 }
00510 if (data->type >= TL_WRITE)
00511 goto end;
00512
00513 }
00514 if (lock->read_wait.data)
00515 free_all_read_locks(lock,
00516 data &&
00517 (data->type == TL_WRITE_CONCURRENT_INSERT ||
00518 data->type == TL_WRITE_ALLOW_WRITE));
00519 }
00520 else if (data &&
00521 (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
00522 ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
00523 lock_type != TL_WRITE_ALLOW_WRITE) ||
00524 !lock->read_no_write_count))
00525 {
00526 do {
00527 boost::condition_variable_any *cond= data->cond;
00528 if (((*data->prev)=data->next))
00529 data->next->prev= data->prev;
00530 else
00531 lock->write_wait.last=data->prev;
00532 (*lock->write.last)=data;
00533 data->prev=lock->write.last;
00534 lock->write.last= &data->next;
00535 data->next=0;
00536 data->cond= NULL;
00537 cond->notify_one();
00538 } while (lock_type == TL_WRITE_ALLOW_WRITE &&
00539 (data=lock->write_wait.data) &&
00540 data->type == TL_WRITE_ALLOW_WRITE);
00541 if (lock->read_wait.data)
00542 free_all_read_locks(lock,
00543 (lock_type == TL_WRITE_CONCURRENT_INSERT ||
00544 lock_type == TL_WRITE_ALLOW_WRITE));
00545 }
00546 else if (!data && lock->read_wait.data)
00547 {
00548 free_all_read_locks(lock,0);
00549 }
00550 }
00551 end:
00552 return;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 #define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint32_t) ((A)->type) < (unsigned char*) (B->lock)- (uint32_t) ((B)->type))
00564
00565 static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
00566 {
00567 THR_LOCK_DATA **pos,**end,**prev,*tmp;
00568
00569
00570
00571 for (pos=data+1,end=data+count; pos < end ; pos++)
00572 {
00573 tmp= *pos;
00574 if (LOCK_CMP(tmp,pos[-1]))
00575 {
00576 prev=pos;
00577 do {
00578 prev[0]=prev[-1];
00579 } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
00580 prev[0]=tmp;
00581 }
00582 }
00583 }
00584
00585
00586 enum enum_thr_lock_result
00587 thr_multi_lock(Session &session, THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
00588 {
00589 THR_LOCK_DATA **pos,**end;
00590 if (count > 1)
00591 sort_locks(data,count);
00592
00593 for (pos=data,end=data+count; pos < end ; pos++)
00594 {
00595 enum enum_thr_lock_result result= thr_lock(session, *pos, owner, (*pos)->type);
00596 if (result != THR_LOCK_SUCCESS)
00597 {
00598 thr_multi_unlock(data,(uint32_t) (pos-data));
00599 return(result);
00600 }
00601 }
00602 return(THR_LOCK_SUCCESS);
00603 }
00604
00605
00606
00607 void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
00608 {
00609 THR_LOCK_DATA **pos,**end;
00610
00611 for (pos=data,end=data+count; pos < end ; pos++)
00612 {
00613 if ((*pos)->type != TL_UNLOCK)
00614 thr_unlock(*pos);
00615 }
00616 }
00617
00618 void DrizzleLock::unlock(uint32_t count)
00619 {
00620 THR_LOCK_DATA **pos,**end;
00621
00622 for (pos= getLocks(),end= getLocks()+count; pos < end ; pos++)
00623 {
00624 if ((*pos)->type != TL_UNLOCK)
00625 thr_unlock(*pos);
00626 }
00627 }
00628
00629
00630
00631
00632
00633
00634 void THR_LOCK::abort_locks()
00635 {
00636 boost::mutex::scoped_lock scopedLock(mutex);
00637
00638 for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
00639 {
00640 local_data->type= TL_UNLOCK;
00641
00642 local_data->cond->notify_one();
00643 local_data->cond= NULL;
00644 }
00645 for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
00646 {
00647 local_data->type= TL_UNLOCK;
00648 local_data->cond->notify_one();
00649 local_data->cond= NULL;
00650 }
00651 read_wait.last= &read_wait.data;
00652 write_wait.last= &write_wait.data;
00653 read_wait.data= write_wait.data=0;
00654 if (write.data)
00655 write.data->type=TL_WRITE_ONLY;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665 bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
00666 {
00667 bool found= false;
00668
00669 boost::mutex::scoped_lock scopedLock(mutex);
00670 for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
00671 {
00672 if (local_data->owner->info->thread_id == thread_id_arg)
00673 {
00674 local_data->type= TL_UNLOCK;
00675
00676 found= true;
00677 local_data->cond->notify_one();
00678 local_data->cond= 0;
00679
00680 if (((*local_data->prev)= local_data->next))
00681 local_data->next->prev= local_data->prev;
00682 else
00683 read_wait.last= local_data->prev;
00684 }
00685 }
00686 for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
00687 {
00688 if (local_data->owner->info->thread_id == thread_id_arg)
00689 {
00690 local_data->type= TL_UNLOCK;
00691 found= true;
00692 local_data->cond->notify_one();
00693 local_data->cond= NULL;
00694
00695 if (((*local_data->prev)= local_data->next))
00696 local_data->next->prev= local_data->prev;
00697 else
00698 write_wait.last= local_data->prev;
00699 }
00700 }
00701 wake_up_waiters(this);
00702
00703 return found;
00704 }
00705
00706 }