46
50
should put a pointer to the following functions in the lock structure:
47
51
(If the pointer is zero (default), the function is not called)
54
Before giving a lock of type TL_WRITE_CONCURRENT_INSERT,
55
we check if this function exists and returns 0.
56
If not, then the lock is upgraded to TL_WRITE_LOCK
57
In MyISAM this is a simple check if the insert can be done
58
at the end of the datafile.
60
Before a write lock is released, this function is called.
61
In MyISAM this functions updates the count and length of the datafile
63
When one gets a lock this functions is called.
64
In MyISAM this stores the number of rows and size of the datafile
50
67
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
51
TL_WRITE_CONCURRENT_INSERT lock at the same time as multiple read locks.
68
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
56
#include "drizzled/internal/my_sys.h"
57
#include "drizzled/internal/thread_var.h"
58
#include "drizzled/statistics_variables.h"
59
#include "drizzled/pthread_globals.h"
61
#include "drizzled/session.h"
73
#include "mysys_priv.h"
63
75
#include "thr_lock.h"
64
#include "drizzled/internal/m_string.h"
76
#include <mystrings/m_string.h>
109
129
void thr_lock_init(THR_LOCK *lock)
131
memset(lock, 0, sizeof(*lock));
132
pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST);
112
133
lock->read.last= &lock->read.data;
113
134
lock->read_wait.last= &lock->read_wait.data;
114
135
lock->write_wait.last= &lock->write_wait.data;
115
136
lock->write.last= &lock->write.data;
119
void THR_LOCK_INFO::init()
121
internal::st_my_thread_var *tmp= my_thread_var;
138
pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */
139
thr_lock_thread_list.push_front(lock);
140
pthread_mutex_unlock(&THR_LOCK_lock);
145
void thr_lock_delete(THR_LOCK *lock)
147
pthread_mutex_destroy(&lock->mutex);
148
pthread_mutex_lock(&THR_LOCK_lock);
149
thr_lock_thread_list.remove(lock);
150
pthread_mutex_unlock(&THR_LOCK_lock);
155
void thr_lock_info_init(THR_LOCK_INFO *info)
157
struct st_my_thread_var *tmp= my_thread_var;
158
info->thread= tmp->pthread_self;
159
info->thread_id= tmp->id;
126
163
/* Initialize a lock instance */
128
void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
165
void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
132
owner= NULL; /* no owner yet */
133
status_param= param_arg;
168
data->type=TL_UNLOCK;
169
data->owner= 0; /* no owner yet */
170
data->status_param=param;
141
178
for ( ; data ; data=data->next)
143
180
if (thr_lock_owner_equal(data->owner, owner))
144
return true; /* Already locked by thread */
181
return 1; /* Already locked by thread */
186
static inline bool have_specific_lock(THR_LOCK_DATA *data,
187
enum thr_lock_type type)
189
for ( ; data ; data=data->next)
191
if (data->type == type)
149
198
static void wake_up_waiters(THR_LOCK *lock);
152
static enum enum_thr_lock_result wait_for_lock(Session &session, struct st_lock_list *wait, THR_LOCK_DATA *data)
201
static enum enum_thr_lock_result
202
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
154
internal::st_my_thread_var *thread_var= session.getThreadVar();
156
boost::condition_variable_any *cond= &thread_var->suspend;
205
struct st_my_thread_var *thread_var= my_thread_var;
206
pthread_cond_t *cond= &thread_var->suspend;
207
struct timespec wait_timeout;
157
208
enum enum_thr_lock_result result= THR_LOCK_ABORTED;
158
209
bool can_deadlock= test(data->owner->info->n_cursors);
161
213
(*wait->last)=data; /* Wait for lock */
162
214
data->prev= wait->last;
163
215
wait->last= &data->next;
166
current_global_counters.locks_waited++;
218
statistic_increment(locks_waited, &THR_LOCK_lock);
168
220
/* Set up control struct to allow others to abort locks */
169
thread_var->current_mutex= data->lock->native_handle();
170
thread_var->current_cond= &thread_var->suspend;
171
data->cond= &thread_var->suspend;;
221
thread_var->current_mutex= &data->lock->mutex;
222
thread_var->current_cond= cond;
173
while (not thread_var->abort)
226
set_timespec(wait_timeout, table_lock_wait_timeout);
227
while (!thread_var->abort || in_wait_list)
175
boost_unique_lock_t scoped(*data->lock->native_handle(), boost::adopt_lock_t());
180
xtime_get(&xt, boost::TIME_UTC);
181
xt.sec += table_lock_wait_timeout;
182
if (not cond->timed_wait(scoped, xt))
184
result= THR_LOCK_WAIT_TIMEOUT;
229
int rc= (can_deadlock ?
230
pthread_cond_timedwait(cond, &data->lock->mutex,
232
pthread_cond_wait(cond, &data->lock->mutex));
194
234
We must break the wait if one of the following occurs:
195
235
- the connection has been aborted (!thread_var->abort), but
227
272
result= THR_LOCK_SUCCESS;
273
if (data->lock->get_status)
274
(*data->lock->get_status)(data->status_param, 0);
229
data->lock->unlock();
276
pthread_mutex_unlock(&data->lock->mutex);
231
278
/* The following must be done after unlock of lock->mutex */
232
boost_unique_lock_t scopedLock(thread_var->mutex);
233
thread_var->current_mutex= NULL;
234
thread_var->current_cond= NULL;
279
pthread_mutex_lock(&thread_var->mutex);
280
thread_var->current_mutex= 0;
281
thread_var->current_cond= 0;
282
pthread_mutex_unlock(&thread_var->mutex);
239
static enum enum_thr_lock_result thr_lock(Session &session, THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
287
enum enum_thr_lock_result
288
thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
289
enum thr_lock_type lock_type)
241
THR_LOCK *lock= data->lock;
291
THR_LOCK *lock=data->lock;
242
292
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
243
293
struct st_lock_list *wait_queue;
244
294
THR_LOCK_DATA *lock_owner;
306
361
else /* Request for WRITE lock */
308
if (lock_type == TL_WRITE_CONCURRENT_INSERT)
363
if (lock_type == TL_WRITE_DELAYED)
365
if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
367
data->type=TL_UNLOCK;
368
result= THR_LOCK_ABORTED; /* Can't wait for this one */
372
if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
373
(TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
375
if ((!lock->write.data ||
376
lock->write.data->type != TL_WRITE_ALLOW_READ) &&
377
!have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
378
(lock->write.data || lock->read.data))
380
/* Add delayed write lock to write_wait queue, and return at once */
381
(*lock->write_wait.last)=data;
382
data->prev=lock->write_wait.last;
383
lock->write_wait.last= &data->next;
384
data->cond=get_cond();
386
We don't have to do get_status here as we will do it when we change
387
the delayed lock to a real write lock
389
statistic_increment(locks_immediate,&THR_LOCK_lock);
393
else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
309
394
data->type=lock_type= thr_upgraded_concurrent_insert_lock;
311
396
if (lock->write.data) /* If there is a write lock */
427
520
lock->read_no_write_count++;
429
data->cond= NULL; /* Mark thread free */
522
data->cond=0; /* Mark thread free */
523
pthread_cond_signal(cond);
431
524
} while ((data=data->next));
432
525
*lock->read_wait.last=0;
433
526
if (!lock->read_wait.data)
434
527
lock->write_lock_count=0;
437
/* Unlock lock and free next thread on same lock */
530
/* Unlock lock and free next thread on same lock */
439
static void thr_unlock(THR_LOCK_DATA *data)
532
void thr_unlock(THR_LOCK_DATA *data)
441
534
THR_LOCK *lock=data->lock;
442
535
enum thr_lock_type lock_type=data->type;
536
pthread_mutex_lock(&lock->mutex);
445
538
if (((*data->prev)=data->next)) /* remove from lock-list */
446
539
data->next->prev= data->prev;
447
540
else if (lock_type <= TL_READ_NO_INSERT)
448
541
lock->read.last=data->prev;
542
else if (lock_type == TL_WRITE_DELAYED && data->cond)
545
This only happens in extreme circumstances when a
546
write delayed lock that is waiting for a lock
548
lock->write_wait.last=data->prev; /* Put it on wait queue */
450
551
lock->write.last=data->prev;
451
552
if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
554
if (lock->update_status)
555
(*lock->update_status)(data->status_param);
559
if (lock->restore_status)
560
(*lock->restore_status)(data->status_param);
455
562
if (lock_type == TL_READ_NO_INSERT)
456
563
lock->read_no_write_count--;
457
564
data->type=TL_UNLOCK; /* Mark unlocked */
458
565
wake_up_waiters(lock);
566
pthread_mutex_unlock(&lock->mutex);
643
void DrizzleLock::unlock(uint32_t count)
645
THR_LOCK_DATA **pos,**end;
647
for (pos= getLocks(),end= getLocks()+count; pos < end ; pos++)
649
if ((*pos)->type != TL_UNLOCK)
655
795
Abort all threads waiting for a lock. The lock will be upgraded to
656
796
TL_WRITE_ONLY to abort any new accesses to the lock
659
void THR_LOCK::abort_locks()
799
void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
661
boost_unique_lock_t scopedLock(mutex);
802
pthread_mutex_lock(&lock->mutex);
663
for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
804
for (data=lock->read_wait.data; data ; data=data->next)
665
local_data->type= TL_UNLOCK; /* Mark killed */
806
data->type=TL_UNLOCK; /* Mark killed */
666
807
/* It's safe to signal the cond first: we're still holding the mutex. */
667
local_data->cond->notify_one();
668
local_data->cond= NULL; /* Removed from list */
808
pthread_cond_signal(data->cond);
809
data->cond=0; /* Removed from list */
670
for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
811
for (data=lock->write_wait.data; data ; data=data->next)
672
local_data->type= TL_UNLOCK;
673
local_data->cond->notify_one();
674
local_data->cond= NULL;
813
data->type=TL_UNLOCK;
814
pthread_cond_signal(data->cond);
676
read_wait.last= &read_wait.data;
677
write_wait.last= &write_wait.data;
678
read_wait.data= write_wait.data=0;
680
write.data->type=TL_WRITE_ONLY;
817
lock->read_wait.last= &lock->read_wait.data;
818
lock->write_wait.last= &lock->write_wait.data;
819
lock->read_wait.data=lock->write_wait.data=0;
820
if (upgrade_lock && lock->write.data)
821
lock->write.data->type=TL_WRITE_ONLY;
822
pthread_mutex_unlock(&lock->mutex);
687
830
This is used to abort all locks for a specific thread
690
bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
833
bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
692
836
bool found= false;
694
boost_unique_lock_t scopedLock(mutex);
695
for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
838
pthread_mutex_lock(&lock->mutex);
839
for (data= lock->read_wait.data; data ; data= data->next)
697
if (local_data->owner->info->thread_id == thread_id_arg)
841
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
699
local_data->type= TL_UNLOCK; /* Mark killed */
843
data->type= TL_UNLOCK; /* Mark killed */
700
844
/* It's safe to signal the cond first: we're still holding the mutex. */
702
local_data->cond->notify_one();
703
local_data->cond= 0; /* Removed from list */
846
pthread_cond_signal(data->cond);
847
data->cond= 0; /* Removed from list */
705
if (((*local_data->prev)= local_data->next))
706
local_data->next->prev= local_data->prev;
849
if (((*data->prev)= data->next))
850
data->next->prev= data->prev;
708
read_wait.last= local_data->prev;
852
lock->read_wait.last= data->prev;
711
for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
855
for (data= lock->write_wait.data; data ; data= data->next)
713
if (local_data->owner->info->thread_id == thread_id_arg)
857
if (data->owner->info->thread_id == thread_id) /* purecov: tested */
715
local_data->type= TL_UNLOCK;
859
data->type= TL_UNLOCK;
717
local_data->cond->notify_one();
718
local_data->cond= NULL;
861
pthread_cond_signal(data->cond);
720
if (((*local_data->prev)= local_data->next))
721
local_data->next->prev= local_data->prev;
864
if (((*data->prev)= data->next))
865
data->next->prev= data->prev;
723
write_wait.last= local_data->prev;
726
wake_up_waiters(this);
731
} /* namespace drizzled */
867
lock->write_wait.last= data->prev;
870
wake_up_waiters(lock);
871
pthread_mutex_unlock(&lock->mutex);
877
Downgrade a WRITE_* to a lower WRITE level
879
thr_downgrade_write_lock()
880
in_data Lock data of thread downgrading its lock
881
new_lock_type New write lock type
885
This can be used to downgrade a lock already owned. When the downgrade
886
occurs also other waiters, both readers and writers can be allowed to
888
The previous lock is often TL_WRITE_ONLY but can also be
889
TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
890
TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
891
TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
892
operation didn't need such a high lock.
893
TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
895
TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
896
already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
897
The implementation is conservative and rather don't start rather than
898
go on unknown paths to start, the common cases are handled.
901
In its current implementation it is only allowed to downgrade from
902
TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
906
void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
907
enum thr_lock_type new_lock_type)
909
THR_LOCK *lock=in_data->lock;
911
pthread_mutex_lock(&lock->mutex);
912
in_data->type= new_lock_type;
914
pthread_mutex_unlock(&lock->mutex);
918
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
920
bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
922
THR_LOCK *lock=data->lock;
924
pthread_mutex_lock(&lock->mutex);
925
if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY)
927
pthread_mutex_unlock(&lock->mutex);
928
return(data->type == TL_UNLOCK); /* Test if Aborted */
930
/* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
931
data->type=TL_WRITE; /* Upgrade lock */
933
/* Check if someone has given us the lock */
936
if (!lock->read.data) /* No read locks */
937
{ /* We have the lock */
938
if (data->lock->get_status)
939
(*data->lock->get_status)(data->status_param, 0);
940
pthread_mutex_unlock(&lock->mutex);
944
if (((*data->prev)=data->next)) /* remove from lock-list */
945
data->next->prev= data->prev;
947
lock->write.last=data->prev;
949
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
950
data->next->prev= &data->next;
952
lock->write_wait.last= &data->next;
953
data->prev= &lock->write_wait.data;
954
lock->write_wait.data=data;
957
return(wait_for_lock(&lock->write_wait,data,1));
961
/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
963
bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
965
THR_LOCK *lock=data->lock;
967
pthread_mutex_lock(&lock->mutex);
968
if (!lock->read_wait.data) /* No waiting read locks */
970
pthread_mutex_unlock(&lock->mutex);
974
data->type=TL_WRITE_DELAYED;
975
if (lock->update_status)
976
(*lock->update_status)(data->status_param);
977
if (((*data->prev)=data->next)) /* remove from lock-list */
978
data->next->prev= data->prev;
980
lock->write.last=data->prev;
982
if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
983
data->next->prev= &data->next;
985
lock->write_wait.last= &data->next;
986
data->prev= &lock->write_wait.data;
987
data->cond=get_cond(); /* This was zero */
988
lock->write_wait.data=data;
989
free_all_read_locks(lock,0);
991
pthread_mutex_unlock(&lock->mutex);
992
return(thr_upgrade_write_delay_lock(data));