25
25
The current lock types are:
27
TL_READ # Low priority read
27
TL_READ # Low priority read
28
28
TL_READ_WITH_SHARED_LOCKS
29
29
TL_READ_HIGH_PRIORITY # High priority read
30
30
TL_READ_NO_INSERT # Read without concurrent inserts
57
57
In MyISAM this is a simple check if the insert can be done
58
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
60
in thr_reschedule_write_lock(), when an insert delayed thread
61
downgrades TL_WRITE lock to TL_WRITE_DELAYED, to allow SELECT
63
A storage engine should also call update_status internally
64
in the ::external_lock(F_UNLCK) method.
65
In MyISAM and CSV this functions updates the length of the datafile.
63
67
When one gets a lock this functions is called.
64
68
In MyISAM this stores the number of rows and size of the datafile
65
69
for concurrent reads.
67
71
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
68
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
72
TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same
73
time as multiple read locks.
75
In addition, if lock->allow_multiple_concurrent_insert is set then there can
76
be any number of TL_WRITE_CONCURRENT_INSERT locks aktive at the same time.
73
79
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
149
155
if (same_owner &&
150
156
!thr_lock_owner_equal(data->owner, first_owner) &&
151
last_lock_type != TL_WRITE_ALLOW_WRITE)
157
last_lock_type != TL_WRITE_ALLOW_WRITE &&
158
last_lock_type != TL_WRITE_CONCURRENT_INSERT)
154
161
"Warning: Found locks from different threads in %s: %s\n",
201
208
THR_LOCK_DATA *data;
202
209
for (data=lock->read.data ; data ; data=data->next)
204
if ((int) data->type == (int) TL_READ_NO_INSERT)
211
if (data->type == TL_READ_NO_INSERT)
206
213
/* Protect against infinite loop. */
207
214
DBUG_ASSERT(count <= lock->read_no_write_count);
253
{ /* Have write lock */
261
/* We have at least one write lock */
262
if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
265
for (data=lock->write.data->next ; data ; data=data->next)
267
if (data->type != TL_WRITE_CONCURRENT_INSERT)
270
"Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write locks\n",
254
276
if (lock->write_wait.data)
256
278
if (!allow_no_locks &&
317
339
DBUG_ENTER("thr_lock_init");
318
340
bzero((char*) lock,sizeof(*lock));
319
VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST));
341
pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST);
320
342
lock->read.last= &lock->read.data;
321
343
lock->read_wait.last= &lock->read_wait.data;
322
344
lock->write_wait.last= &lock->write_wait.data;
333
355
void thr_lock_delete(THR_LOCK *lock)
335
357
DBUG_ENTER("thr_lock_delete");
336
VOID(pthread_mutex_destroy(&lock->mutex));
337
358
pthread_mutex_lock(&THR_LOCK_lock);
338
359
thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list);
339
360
pthread_mutex_unlock(&THR_LOCK_lock);
361
pthread_mutex_destroy(&lock->mutex);
340
362
DBUG_VOID_RETURN;
387
409
static void wake_up_waiters(THR_LOCK *lock);
411
#if defined(ENABLED_DEBUG_SYNC)
413
Global pointer to be set if callback function is defined
414
(e.g. in mysqld). See debug_sync.cc.
416
void (*debug_sync_wait_for_lock_callback_ptr)(void);
417
#endif /* defined(ENABLED_DEBUG_SYNC) */
390
420
static enum enum_thr_lock_result
391
421
wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
398
428
my_bool can_deadlock= test(data->owner->info->n_cursors);
399
429
DBUG_ENTER("wait_for_lock");
431
#if defined(ENABLED_DEBUG_SYNC)
433
One can use this to signal when a thread is going to wait for a lock.
436
if (debug_sync_wait_for_lock_callback_ptr)
437
(*debug_sync_wait_for_lock_callback_ptr)();
438
#endif /* defined(ENABLED_DEBUG_SYNC) */
401
440
if (!in_wait_list)
403
442
(*wait->last)=data; /* Wait for lock */
500
539
data->cond=0; /* safety */
501
540
data->type=lock_type;
502
541
data->owner= owner; /* Must be reset ! */
503
VOID(pthread_mutex_lock(&lock->mutex));
504
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
505
(long) data, data->owner->info->thread_id,
506
(long) lock, (int) lock_type));
542
pthread_mutex_lock(&lock->mutex);
543
DBUG_PRINT("lock",("data: %p thread: 0x%lx lock: %p type: %d",
544
data, data->owner->info->thread_id,
545
lock, (int) lock_type));
507
546
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
508
547
"enter read_lock" : "enter write_lock",0);
509
548
if ((int) lock_type <= (int) TL_READ_NO_INSERT)
511
550
/* Request for READ lock */
512
551
if (lock->write.data)
514
/* We can allow a read lock even if there is already a write lock
554
We can allow a read lock even if there is already a write lock
515
555
on the table in one the following cases:
516
556
- This thread alread have a write lock on the table
517
557
- The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
555
595
(*lock->read.last)=data; /* Add to running FIFO */
556
596
data->prev=lock->read.last;
557
597
lock->read.last= &data->next;
558
if (lock->get_status)
559
(*lock->get_status)(data->status_param, 0);
560
598
if (lock_type == TL_READ_NO_INSERT)
561
599
lock->read_no_write_count++;
562
600
check_locks(lock,"read lock with no write locks",0);
601
if (lock->get_status)
602
(*lock->get_status)(data->status_param, 0);
563
603
statistic_increment(locks_immediate,&THR_LOCK_lock);
610
650
if (lock->write.data->type == TL_WRITE_ONLY)
652
/* purecov: begin tested */
612
653
/* Allow lock owner to bypass TL_WRITE_ONLY. */
613
654
if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
617
658
result= THR_LOCK_ABORTED; /* Can't wait for this one */
623
665
The following test will not work if the old lock was a
624
666
TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
625
667
the same thread, but this will never happen within MySQL.
669
The idea is to allow us to get a lock at once if we already have
670
a write lock or if there is no pending write locks and if all
671
write locks are of the same type and are either
672
TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT
627
674
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
628
(lock_type == TL_WRITE_ALLOW_WRITE &&
629
!lock->write_wait.data &&
630
lock->write.data->type == TL_WRITE_ALLOW_WRITE))
675
(!lock->write_wait.data && lock_type == lock->write.data->type &&
676
(lock_type == TL_WRITE_ALLOW_WRITE ||
677
(lock_type == TL_WRITE_CONCURRENT_INSERT &&
678
lock->allow_multiple_concurrent_insert))))
633
We have already got a write lock or all locks are
636
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
637
(ulong) lock->write_wait.data,
680
DBUG_PRINT("info", ("write_wait.data: %p old_type: %d",
681
lock->write_wait.data,
638
682
lock->write.data->type));
640
684
(*lock->write.last)=data; /* Add to running fifo */
641
685
data->prev=lock->write.last;
642
686
lock->write.last= &data->next;
643
687
check_locks(lock,"second write lock",0);
644
if (data->lock->get_status)
645
(*data->lock->get_status)(data->status_param, 0);
688
if (lock->get_status)
689
(*lock->get_status)(data->status_param,
690
lock_type == TL_WRITE_CONCURRENT_INSERT);
646
691
statistic_increment(locks_immediate,&THR_LOCK_lock);
654
DBUG_PRINT("info", ("write_wait.data: 0x%lx",
655
(ulong) lock->write_wait.data));
699
DBUG_PRINT("info", ("write_wait.data: %p",
700
lock->write_wait.data));
656
701
if (!lock->write_wait.data)
657
702
{ /* no scheduled write locks */
658
703
my_bool concurrent_insert= 0;
675
720
(*lock->write.last)=data; /* Add as current write lock */
676
721
data->prev=lock->write.last;
677
722
lock->write.last= &data->next;
678
if (data->lock->get_status)
679
(*data->lock->get_status)(data->status_param, concurrent_insert);
723
if (lock->get_status)
724
(*lock->get_status)(data->status_param, concurrent_insert);
680
725
check_locks(lock,"only write lock",0);
681
726
statistic_increment(locks_immediate,&THR_LOCK_lock);
750
795
data->owner->info->thread_id));
751
796
/* purecov: end */
752
797
data->cond=0; /* Mark thread free */
753
VOID(pthread_cond_signal(cond));
798
pthread_cond_signal(cond);
754
799
} while ((data=data->next));
755
800
*lock->read_wait.last=0;
756
801
if (!lock->read_wait.data)
765
810
THR_LOCK *lock=data->lock;
766
811
enum thr_lock_type lock_type=data->type;
767
812
DBUG_ENTER("thr_unlock");
768
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
769
(long) data, data->owner->info->thread_id, (long) lock));
813
DBUG_PRINT("lock",("data: %p thread: 0x%lx lock: %p",
814
data, data->owner->info->thread_id, lock));
770
815
pthread_mutex_lock(&lock->mutex);
771
816
check_locks(lock,"start of release lock",0);
786
831
lock->write.last=data->prev;
787
if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
789
if (lock->update_status)
790
(*lock->update_status)(data->status_param);
794
if (lock->restore_status)
795
(*lock->restore_status)(data->status_param);
797
832
if (lock_type == TL_READ_NO_INSERT)
798
833
lock->read_no_write_count--;
799
834
data->type=TL_UNLOCK; /* Mark unlocked */
861
895
pthread_cond_t *cond=data->cond;
862
896
data->cond=0; /* Mark thread free */
863
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
897
pthread_cond_signal(cond); /* Start waiting thread */
865
899
if (data->type != TL_WRITE_ALLOW_WRITE ||
866
900
!lock->write_wait.data ||
911
945
lock->write.last= &data->next;
912
946
data->next=0; /* Only one write lock */
913
947
data->cond=0; /* Mark thread free */
914
VOID(pthread_cond_signal(cond)); /* Start waiting thread */
948
pthread_cond_signal(cond); /* Start waiting thread */
915
949
} while (lock_type == TL_WRITE_ALLOW_WRITE &&
916
950
(data=lock->write_wait.data) &&
917
951
data->type == TL_WRITE_ALLOW_WRITE);
965
999
THR_LOCK_DATA **pos,**end;
966
1000
DBUG_ENTER("thr_multi_lock");
967
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
1001
DBUG_PRINT("lock",("data: %p count: %d", data, count));
969
1003
sort_locks(data,count);
970
1004
/* lock everything */
981
1015
(long) pos[0]->lock, pos[0]->type); fflush(stdout);
985
Ensure that all get_locks() have the same status
986
If we lock the same table multiple times, we must use the same
1018
thr_lock_merge_status(data, count);
1019
DBUG_RETURN(THR_LOCK_SUCCESS);
1024
Ensure that all locks for a given table have the same
1027
This is a MyISAM and possibly Maria specific crutch. MyISAM
1028
engine stores data file length, record count and other table
1029
properties in status_param member of handler. When a table is
1030
locked, connection-local copy is made from a global copy
1031
(myisam_share) by mi_get_status(). When a table is unlocked,
1032
the changed status is transferred back to the global share by
1035
One thing MyISAM doesn't do is to ensure that when the same
1036
table is opened twice in a connection all instances share the
1037
same status_param. This is necessary, however: for one, to keep
1038
all instances of a connection "on the same page" with regard to
1039
the current state of the table. For other, unless this is done,
1040
myisam_share will always get updated from the last unlocked
1041
instance (in mi_update_status()), and when this instance was not
1042
the one that was used to update data, records may be lost.
1044
For each table, this function looks up the last lock_data in the
1045
list of acquired locks, and makes sure that all other instances
1046
share status_param with it.
1050
thr_lock_merge_status(THR_LOCK_DATA **data, uint count)
989
1052
#if !defined(DONT_USE_RW_LOCKS)
1053
THR_LOCK_DATA **pos= data;
1054
THR_LOCK_DATA **end= data + count;
992
1057
THR_LOCK_DATA *last_lock= end[-1];
1038
1102
THR_LOCK_DATA **pos,**end;
1039
1103
DBUG_ENTER("thr_multi_unlock");
1040
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
1104
DBUG_PRINT("lock",("data: %p count: %d", data, count));
1042
1106
for (pos=data,end=data+count; pos < end ; pos++)
1050
1114
thr_unlock(*pos);
1053
DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
1054
(long) *pos, (*pos)->owner->info->thread_id,
1055
(long) (*pos)->lock));
1117
DBUG_PRINT("lock",("Free lock: data: %p thread: 0x%lx lock: %p",
1118
*pos, (*pos)->owner->info->thread_id,
1058
1122
DBUG_VOID_RETURN;
1380
1444
if (!lock->read.data) /* No read locks */
1381
1445
{ /* We have the lock */
1382
if (data->lock->get_status)
1383
(*data->lock->get_status)(data->status_param, 0);
1446
if (lock->get_status)
1447
(*lock->get_status)(data->status_param, 0);
1384
1448
pthread_mutex_unlock(&lock->mutex);
1385
1449
DBUG_RETURN(0);
1478
1542
list= list_rest(list))
1480
1544
THR_LOCK *lock=(THR_LOCK*) list->data;
1481
VOID(pthread_mutex_lock(&lock->mutex));
1545
pthread_mutex_lock(&lock->mutex);
1482
1546
printf("lock: 0x%lx:",(ulong) lock);
1483
1547
if ((lock->write_wait.data || lock->read_wait.data) &&
1484
1548
(! lock->read.data && ! lock->write.data))
1496
1560
thr_print_lock("write_wait",&lock->write_wait);
1497
1561
thr_print_lock("read",&lock->read);
1498
1562
thr_print_lock("read_wait",&lock->read_wait);
1499
VOID(pthread_mutex_unlock(&lock->mutex));
1563
pthread_mutex_unlock(&lock->mutex);
1502
1566
fflush(stdout);
1518
1582
enum thr_lock_type lock_type;
1521
THR_LOCK locks[5]; /* 4 locks */
1585
THR_LOCK locks[6]; /* Number of locks +1 */
1523
1587
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
1524
1588
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
1538
1602
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
1539
1603
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
1541
struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
1542
test_7,test_8,test_9,test_10,test_11,test_12,
1543
test_13,test_14,test_15,test_16};
1605
struct st_test test_17[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
1606
struct st_test test_18[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
1607
struct st_test test_19[] = {{5,TL_READ}};
1608
struct st_test test_20[] = {{5,TL_READ_NO_INSERT}};
1609
struct st_test test_21[] = {{5,TL_WRITE}};
1612
struct st_test *tests[]=
1614
test_0, test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8,
1615
test_9, test_10, test_11, test_12, test_13, test_14, test_15, test_16,
1616
test_17, test_18, test_19, test_20, test_21
1544
1619
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
1545
1620
sizeof(test_1)/sizeof(struct st_test),
1546
1621
sizeof(test_2)/sizeof(struct st_test),
1557
1632
sizeof(test_13)/sizeof(struct st_test),
1558
1633
sizeof(test_14)/sizeof(struct st_test),
1559
1634
sizeof(test_15)/sizeof(struct st_test),
1560
sizeof(test_16)/sizeof(struct st_test)
1635
sizeof(test_16)/sizeof(struct st_test),
1636
sizeof(test_17)/sizeof(struct st_test),
1637
sizeof(test_18)/sizeof(struct st_test),
1638
sizeof(test_19)/sizeof(struct st_test),
1639
sizeof(test_20)/sizeof(struct st_test),
1640
sizeof(test_21)/sizeof(struct st_test)
1602
1682
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
1605
1684
thr_lock_info_init(&lock_info);
1606
1685
thr_lock_owner_init(&owner, &lock_info);
1607
1686
for (i=0; i < lock_counts[param] ; i++)
1670
for (i=0 ; i < (int) array_elements(locks) ; i++)
1750
for (i=0 ; i < array_elements(locks) ; i++)
1672
1752
thr_lock_init(locks+i);
1673
1753
locks[i].check_status= test_check_status;
1674
1754
locks[i].update_status=test_update_status;
1675
1755
locks[i].copy_status= test_copy_status;
1676
1756
locks[i].get_status= test_get_status;
1757
locks[i].allow_multiple_concurrent_insert= 1;
1678
1759
if ((error=pthread_attr_init(&thr_attr)))
1699
1780
#ifdef HAVE_THR_SETCONCURRENCY
1700
VOID(thr_setconcurrency(2));
1781
(void) thr_setconcurrency(2);
1702
for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
1783
for (i=0 ; i < array_elements(lock_counts) ; i++)
1704
1785
param=(int*) malloc(sizeof(int));
1732
1813
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
1733
1814
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
1734
for (i=0 ; i < (int) array_elements(locks) ; i++)
1815
for (i=0 ; i < array_elements(locks) ; i++)
1735
1816
thr_lock_delete(locks+i);
1736
1817
#ifdef EXTRA_DEBUG
1737
1818
if (found_errors)