forked from yuanrongxi/innodb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lock0lock.cc
2635 lines (1991 loc) · 62.8 KB
/
lock0lock.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "lock0lock.h"
#include "usr0sess.h"
#include "trx0purge.h"
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
#define LOCK_RELEASE_KERNEL_INTERVAL 1000
#define LOCK_PAGE_BITMAP_MARGIN 64
ibool lock_print_waits = FALSE;
/*事务行锁全局HASH表,表锁不会放入其中,表锁只通过dict table做关联*/
lock_sys_t* lock_sys = NULL;
/*表事务锁对象定义*/
typedef struct lock_table_struct
{
dict_table_t* table; /*字典元数据中的表对象句柄*/
UT_LIST_NODE_T(lock_t) locks; /*在表上的事务锁列表*/
}lock_table_t;
typedef struct lock_rec_struct
{
ulint space; /*记录所处的space的ID*/
ulint page_no; /*记录所处的page页号*/
ulint n_bits; /*行锁的bitmap位数,lock_t结构后面会跟一个BUF,长度为n_bits / 8*/
}lock_rec_t;
/*锁对象*/
struct lock_struct
{
trx_t* trx; /*执行事务指针*/
ulint type_mode; /*锁类型和状态,类型有LOCK_ERC和LOCK_TABLE,状态有LOCK_WAIT, LOCK_GAP,强弱:LOCK_X,LOCK_S等*/
hash_node_t hash; /*hash表的对应节点,table lock是无效的*/
dict_index_t* index; /*行锁的行记录索引*/
UT_LIST_NODE_T(lock_t) trx_locks; /*一个trx_locks的列表前后关系*/
union{
lock_table_t tab_lock; /*表锁*/
lock_rec_t rec_lock; /*行锁*/
}un_member;
};
/*死锁标识*/
ibool lock_deadlock_found = FALSE;
/*错误信息缓冲区,5000字节*/
char* lock_latest_err_buf;
/*死锁检测函数*/
static ibool lock_deadlock_occurs(lock_t* lock, trx_t* trx);
static ibool lock_deadlock_recursive(trx_t* start, trx_t* trx, lock_t* wait_lock, ulint* cost);
/************************************************************************/
/*kernel_mutex是在srv0srv.h定义的全局内核mutex latch*/
UNIV_INLINE void lock_mutex_enter_kernel()
{
mutex_enter(&kernel_mutex);
}
UNIV_INLINE void lock_mutex_exit_kernel()
{
mutex_exit(&kernel_mutex);
}
/*通过聚合索引检查记录是否可以进行一致性锁定读*/
ibool lock_clust_rec_cons_read_sees(rec_t* rec, dict_index_t* index, read_view_t* view)
{
dulint trx_id;
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(page_rec_is_user_rec(rec));
trx_id = row_get_rec_trx_id(rec, index);
if(read_view_sees_trx_id(view, trx_id))
return TRUE;
return FALSE;
}
/*检查非聚集索引记录是否可以进行一致性读*/
ulint lock_sec_rec_cons_read_sees(rec_t* rec, dict_index_t* index, read_view_t* view)
{
dulint max_trx_id;
ut_ad(index->type & DICT_CLUSTERED);
ut_ad(page_rec_is_user_rec(rec));
if(recv_recovery_is_on()) /*检查redo log是否在进行日志恢复*/
return FALSE;
/*获得对应page的二级索引最大操作的事务ID*/
max_trx_id = page_get_max_trx_id(buf_frame_align(rec));
if(ut_dulint_cmp(max_trx_id, view->up_limit_id) >= 0) /*view中的事务ID大于页中的max trx id,不能进行一致性锁定读*/
return FALSE;
return TRUE;
}
/*建立一个系统行锁哈希表对象*/
void lock_sys_create(ulint n_cells)
{
/*创建lock sys对象*/
lock_sys = mem_alloc(sizeof(lock_sys_t));
/*创建一个lock_sys中的哈希表*/
lock_sys->rec_hash = hash_create(n_cells);
/*分配锁错误信息的缓冲区*/
lock_latest_err_buf = mem_alloc(5000);
}
ulint lock_get_size()
{
return (ulint)(sizeof(lock_t));
}
/*获得事务锁的模式(IS, IX, S, X, AINC,NONE)*/
UNIV_INLINE ulint lock_get_mode(lock_t* lock)
{
ut_ad(lock);
return lock->type_mode & LOCK_MODE_MASK;
}
/*获得锁的类型(table lock, rec lock)*/
UNIV_INLINE ulint lock_get_type(lock_t* lock)
{
ut_ad(lock);
return lock->type_mode & LOCK_TYPE_MASK;
}
/*检查所是否在LOCK_WAIT状态*/
UNIV_INLINE ibool lock_get_wait(lock_t* lock)
{
ut_ad(lock);
if(lock->type_mode & LOCK_WAIT) /*锁处于等待状态*/
return TRUE;
return FALSE;
}
/*设置事务锁的等待状态LOCK_WAIT*/
UNIV_INLINE void lock_set_lock_and_trx_wait(lock_t* lock, trx_t* trx)
{
ut_ad(lock);
ut_ad(trx->wait_lock == NULL);
trx->wait_lock = lock;
lock->type_mode = lock->type_mode | LOCK_WAIT;
}
/*清除锁的等待LOCK_WAIT状态*/
UNIV_INLINE void lock_reset_lock_and_trx_wait(lock_t* lock)
{
ut_ad((lock->trx)->wait_lock == lock);
ut_ad(lock_get_wait(lock));
(lock->trx)->wait_lock = NULL;
lock->type_mode = lock->type_mode & ~LOCK_WAIT;
}
/*判断锁是否是LOCK_GAP范围锁状态*/
UNIV_INLINE ibool lock_rec_get_gap(lock_t* lock)
{
ut_ad(lock);
ut_ad(lock_get_type(lock) == LOCK_REC);
if(lock->type_mode & LOCK_GAP)
return TRUE;
return FALSE;
}
/*设置事务锁的记录LOCK_GAP范围锁状态*/
UNIV_INLINE void lock_rec_set_gap(lock_t* lock, ibool val)
{
ut_ad(lock);
ut_ad((val == TRUE) || (val == FALSE));
ut_ad(lock_get_type(lock) == LOCK_REC);
if(val)
lock->type_mode = lock->type_mode | LOCK_GAP;
else
lock->type_mode = lock->type_mode & ~LOCK_GAP;
}
/*判断锁的mode1是否比mode2更高强度,一般LOCK_X > LOCK_S > LOCK_IX >= LOCK_IS*/
UNIV_INLINE ibool lock_mode_stronger_or_eq(ulint mode1, ulint mode2)
{
ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
|| mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
|| mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
if(mode1 == LOCK_X)
return TRUE;
else if(mode1 == LOCK_AUTO_INC && mode2 == LOCK_AUTO_INC)
return TRUE;
else if(mode1 == LOCK_S && (mode2 == LOCK_S || mode2 == LOCK_IS))
return TRUE;
else if(mode1 == LOCK_IX && (mode2 == LOCK_IX || mode2 == LOCK_IS))
return TRUE;
return FALSE;
}
/*判断事务锁的mode1是否兼容mode2模式
AINC IS IX S X
AINC n y y n n
IS y y y y n
IX y y y n n
S n y n y n
X n n n n n
*****************************************/
UNIV_INLINE ibool lock_mode_compatible(ulint mode1, ulint mode2)
{
ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
|| mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
|| mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
/*共享锁是兼容共享锁和意向共享锁的*/
if(mode1 == LOCK_S && (mode2 == LOCK_IS || mode2 == LOCK_S))
return TRUE;
/*独享锁是不兼容任何其他形式的锁*/
else if(mode1 == LOCK_X)
return FALSE;
/*自增长锁是兼容意向锁的*/
else if(mode1 == LOCK_AUTO_INC && (mode2 == LOCK_IS || mode2 == LOCK_IX))
return TRUE;
/*意向共享锁模式兼容共享锁、意向独享锁、自增长锁和共享意向锁*/
else if(mode1 == LOCK_IS && (mode2 == LOCK_IS || mode2 == LOCK_IX
|| mode2 == LOCK_AUTO_INC || mode2 == LOCK_S))
return TRUE;
/*意向独占锁模式兼容意向共享锁、自增长锁和意向独占锁*/
else if(mode1 == LOCK_IX &&(mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC || mode2 == LOCK_IX))
return TRUE;
return FALSE;
}
/*假如mode == LOCK_S,返回LOCK_X;mode = LOCK_X返回LOCK_S*/
UNIV_INLINE ulint lock_get_confl_mode(ulint mode)
{
ut_ad(mode == LOCK_X || mode == LOCK_S);
if(mode == LOCK_S)
return LOCK_X;
return LOCK_S;
}
/*判断lock1是否会因为lock2的存在而阻塞事务*/
UNIV_INLINE ibool lock_has_to_wait(lock_t* lock1, lock_t* lock2)
{
if(lock1->trx != lock2->trx && !lock_mode_compatible(lock_get_mode(lock1), lock_get_mode(lock2)))
return TRUE;
return FALSE;
}
/*获得记录行锁所的bitmap长度*/
UNIV_INLINE ulint lock_rec_get_n_bits(lock_t* lock)
{
return lock->un_member.rec_lock.n_bits;
}
/*获得页第i行的记录行锁*/
UNIV_INLINE ibool lock_rec_get_nth_bit(lock_t* lock, ulint i)
{
ulint byte_index;
ulint bit_index;
ulint b;
ut_ad(lock);
ut_ad(lock_get_type(lock) == LOCK_REC);
if(i >= lock->un_member.rec_lock.n_bits)
return FALSE;
byte_index = i / 8;
bit_index = i % 8;
/*进行bitmap定位*/
b = (ulint)*((byte*)lock + sizeof(lock_t) + byte_index);
return ut_bit_get_nth(b, bit_index);
}
/*页第i行添加一个lock行锁*/
UNIV_INLINE void lock_rec_set_nth_bit(lock_t* lock, ulint i)
{
ulint byte_index;
ulint bit_index;
byte* ptr;
ulint b;
ut_ad(lock);
ut_ad(lock_get_type(lock) == LOCK_REC);
ut_ad(i < lock->un_member.rec_lock.n_bits);
byte_index = i / 8;
bit_index = i % 8;
ptr = (byte*)lock + sizeof(lock_t) + byte_index;
b = (ulint)*ptr;
b = ut_bit_set_nth(b, bit_index, TRUE);
*ptr = (byte)b;
}
/*获得rec lock bitmap第一个有lock行锁的行序号*/
static ulint lock_rec_find_set_bit(lock_t* lock)
{
ulint i;
for(i = 0; i < lock_rec_get_n_bits(lock); i ++){
if(lock_rec_get_nth_bit(lock, i))
return i;
}
return ULINT_UNDEFINED;
}
/*清除页的第i行的lock行锁状态*/
UNIV_INLINE void lock_rec_reset_nth_bit(lock_t* lock, ulint i)
{
ulint byte_index;
ulint bit_index;
byte* ptr;
ulint b;
ut_ad(lock);
ut_ad(lock_get_type(lock) == LOCK_REC);
ut_ad(i < lock->un_member.rec_lock.n_bits);
byte_index = i / 8;
bit_index = i % 8;
ptr = (byte*)lock + sizeof(lock_t) + byte_index;
b = (ulint)*ptr;
b = ut_bit_set_nth(b, bit_index, FALSE);
*ptr = (byte)b;
}
/*获取也得记录同一个页的下一个锁*/
UNIV_INLINE lock_t* lock_rec_get_next_on_page(lock_t* lock)
{
ulint space;
ulint page_no;
ut_ad(mutex_own(&kernel_mutex));
space = lock->un_member.rec_lock.space;
page_no = lock->un_member.rec_lock.page_no;
/*在lock_sys的哈希表中查找*/
for(;;){
lock = HASH_GET_NEXT(hash, lock);
if(lock == NULL)
break;
/*LOCK还是在同一页中*/
if(lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no = page_no)
break;
}
return lock;
}
/*获得(space, page_no)指向的page的第一个行锁*/
UNIV_INLINE lock_t* lock_rec_get_first_on_page_addr(ulint space, ulint page_no)
{
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
/*lock_sys哈希表中找*/
lock = HASH_GET_FIRST(lock_sys->rec_hash, lock_rec_hash(space, page_no));
while(lock){
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no))
break;
lock = HASH_GET_NEXT(hash, lock);
}
return lock;
}
/*判断(space page_no)指向的页是否有显式行锁*/
ibool lock_rec_expl_exist_on_page(ulint space, ulint page_no)
{
ibool ret;
mutex_enter(&kernel_mutex);
if(lock_rec_get_first_on_page_addr(space, page_no))
ret = TRUE;
else
ret = FALSE;
mutex_exit(&kernel_mutex);
return ret;
}
/*获得ptr所在页的第一个锁*/
UNIV_INLINE lock_t* lock_rec_get_first_on_page(byte* ptr)
{
ulint hash;
lock_t* lock;
ulint space;
ulint page_no;
ut_ad(mutex_own(&kernel_mutex));
hash = buf_frame_get_lock_hash_val(ptr);
lock = HASH_GET_FIRST(lock_sys->rec_hash, hash);
while(lock){
/*为什么不是放在外面呢?个人觉得应该放在外面比较好*/
space = buf_frame_get_space_id(ptr);
page_no = buf_frame_get_page_no(ptr);
if(space == lock->un_member.rec_lock.space && page_no == lock->un_member.rec_lock.page_no)
break;
lock = HASH_GET_NEXT(hash, lock);
}
return lock;
}
/*获得行记录的lock下一个显式行锁*/
UNIV_INLINE lock_t* lock_rec_get_next(rec_t* rec, lock_t* lock)
{
ut_ad(mutex_own(&kernel_mutex));
for(;;){
lock = lock_rec_get_next_on_page(lock);
if(lock == NULL)
return NULL;
if(lock_rec_get_nth_bit(lock, rec_get_heap_no(rec)))
return lock;
}
}
/*获得rec记录第一个显式行锁*/
UNIV_INLINE lock_t* lock_rec_get_first(rec_t* rec)
{
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
lock = lock_rec_get_first_on_page(rec);
while(lock){
if(lock_rec_get_nth_bit(lock, rec_get_heap_no(rec))) /*判断lock的bitmap是否有对应的位状态*/
break;
lock = lock_rec_get_next_on_page(lock);
}
return lock;
}
/*清空lock的bitmap,这个函数不能在事务因为这个行锁阻塞的时候调用,只能在锁建立时初始化用*/
static void lock_rec_bitmap_reset(lock_t* lock)
{
byte* ptr;
ulint n_bytes;
ulint i;
ptr = (byte*)lock + sizeof(lock_t);
n_bytes = lock_rec_get_n_bits(lock) / 8;
ut_ad(lock_rec_get_n_bits(lock) % 8 == 0);
/*将lock的bitmap置为0*/
for(i = 0; i < n_bytes; i ++){
*ptr = 0;
ptr ++;
}
}
/*分配一个行记录锁,并将lock中的内容拷贝到新分配的行锁中*/
static lock_t* lock_rec_copy(lock_t* lock, mem_heap_t* heap)
{
lock_t* dupl_lock;
ulint size;
/*获得lock对象占用的空间大小*/
size = sizeof(lock_t) + lock_rec_get_n_bits(lock) / 8;
dupl_lock = mem_heap_alloc(heap, size);
ut_memcpy(dupl_lock, lock, size);
return dupl_lock;
}
/*获得in_lock的前一个的行记录锁,这个记录行锁的行序号是heap_no*/
static lock_t* lock_rec_get_prev(lock_t* in_lock, ulint heap_no)
{
lock_t* lock;
ulint space;
ulint page_no;
lock_t* found_lock = NULL;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(lock_get_type(in_lock) == LOCK_REC);
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
lock = lock_rec_get_first_on_page_addr(space, page_no);
for(;;){
ut_ad(lock);
if(lock == in_lock)
return found_lock;
if(lock_rec_get_nth_bit(lock, heap_no)) /*判断是否是本行记录的lock*/
found_lock = lock;
lock = lock_rec_get_next_on_page(lock);
}
return NULL;
}
/*判断事务trx是否持有table的锁比mode更高强度的锁,如果有,返回lock指针*/
UNIV_INLINE lock_t* lock_table_has(trx_t* trx, dict_table_t* table, ulint mode)
{
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
/*从后面扫描到前面, 可能trx事务已经有更高强度的锁在这个table上,一般锁表示先加意向锁,再加S-LOCK或者X-LOCK*/
lock = UT_LIST_GET_LAST(table->locks);
while(lock != NULL){
if(lock->trx == trx && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)){
ut_ad(!lock_get_wait(lock));
return lock;
}
lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
}
return NULL;
}
/*获得一个比mode更高强度的rec行记录锁(显式锁),这个锁必须是trx发起的,并且处于non_gap状态*/
UNIV_INLINE lock_t* lock_rec_has_expl(ulint mode, rec_t* rec, trx_t* trx)
{
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
ut_ad((mode == LOCK_X) || (mode == LOCK_S));
lock = lock_rec_get_first(rec);
while(lock != NULL){
if(lock->trx == trx && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)
&& !lock_get_wait(lock) && !(lock_rec_get_gap(lock) || page_rec_is_supremum(rec)))
return lock;
lock = lock_rec_get_next(rec, lock);
}
return NULL;
}
/*检查是否除trx以外的事务在rec记录上持有比mode更高强度的锁(显式锁)*/
UNIV_INLINE lock_t* lock_rec_other_has_expl_req(ulint mode, ulint gap, ulint wait, rec_t* rec, trx_t* trx)
{
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
ut_ad((mode == LOCK_X) || (mode == LOCK_S));
lock = lock_rec_get_first(rec);
while(lock != NULL){
if(lock->trx != trx && (gap || !(lock_rec_get_gap(lock) || page_rec_is_supremum(rec))) /*gap锁在supremum,就是+无穷范围*/
&& (wait || !lock_get_wait(lock))
&& lock_mode_stronger_or_eq(lock_get_mode(lock), mode))
return lock;
lock = lock_rec_get_next(rec, lock);
}
return NULL;
}
/*在记录所在的page中,查找trx事务发起的type_mode模式的的锁,并且锁所在行的序号必须大于rec的序号*/
UNIV_INLINE lock_t* lock_rec_find_similar_on_page(ulint type_mode, rec_t* rec, trx_t* trx)
{
lock_t* lock;
ulint heap_no;
ut_ad(mutex_own(&kernel_mutex));
heap_no = rec_get_heap_no(rec);
lock = lock_rec_get_first_on_page(rec);
while(lock != NULL){
if(lock->trx == trx && lock->type_mode == type_mode
&& lock_rec_get_n_bits(lock) > heap_no)
return lock;
lock = lock_rec_get_next_on_page(lock);
}
return NULL;
}
/*查找rec记录的二级索引是否隐式锁,如果有返回其对应TRX对象,其实就是历史记录版本的修改还没有提交,X-LOCK还被其继续持有*/
trx_t* lock_sec_rec_some_has_impl_off_kernel(rec_t* rec, dict_index_t* index)
{
page_t* page;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(!(index->type & DICT_CLUSTERED));
ut_ad(page_rec_is_user_rec(rec));
/*获得rec对应的page*/
page = buf_frame_align(rec);
if(!(ut_dulint_cmp(page_get_max_trx_id(page), trx_list_get_min_trx_id()) >= 0)
&& !recv_recovery_is_on())
return NULL;
return row_vers_impl_x_locked_off_kernel(rec, index);
}
/*建立一个记录行锁*/
static lock_t* lock_rec_create(ulint type_mode, rec_t* rec, dict_index_t* index, trx_t* trx)
{
page_t* page;
lock_t* lock;
ulint page_no;
ulint heap_no;
ulint space;
ulint n_bits;
ulint n_bytes;
ut_ad(mutex_own(&kernel_mutex));
page = buf_frame_align(rec);
space = buf_frame_get_space_id(page);
page_no = buf_frame_get_page_no(page);
heap_no = rec_get_heap_no(rec);
/*supremum记录是不能使用LOCK_GAP范围锁的*/
if(rec == page_get_supremum_rec(page))
type_mode = type_mode & ~LOCK_GAP;
/*计算rec_lock bitmap,是page已经分配出去的记录数 + 阈值修正值64(为了缓冲区安全)*/
n_bits = page_header_get_field(page, PAGE_N_HEAP) + LOCK_PAGE_BITMAP_MARGIN;
n_bytes = n_bits / 8 + 1;
/*分配lock_t*/
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
if(lock == NULL)
return NULL;
/*将lock加入到trx事务对象中*/
UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
lock->trx = trx;
lock->type_mode = (type_mode & ~LOCK_TYPE_MASK) | LOCK_REC;
lock->index = index;
lock->un_member.rec_lock.space = space;
lock->un_member.rec_lock.page_no = page_no;
lock->un_member.rec_lock.n_bits = n_bytes * 8;
/*初始化lock bitmap*/
lock_rec_bitmap_reset(lock);
lock_rec_set_nth_bit(lock, heap_no);
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), lock);
if(type_mode & LOCK_WAIT) /*设置wait flag*/
lock_set_lock_and_trx_wait(lock, trx);
return lock;
}
/*创建一个记录行锁,并进行lock wait状态排队,*/
static ulint lock_rec_enqueue_waiting(ulint type_mode, rec_t* rec, dict_index_t* index, que_thr_t* thr)
{
lock_t* lock;
trx_t* trx;
ut_ad(mutex_own(&kernel_mutex));
/*查询线程暂停*/
if(que_thr_stop(thr)){
ut_a(0);
return DB_QUE_THR_SUSPENDED;
}
trx = thr_get_trx(thr);
if(trx->dict_operation){
ut_print_timestamp(stderr);
fprintf(stderr," InnoDB: Error: a record lock wait happens in a dictionary operation!\n"
"InnoDB: Table name %s. Send a bug report to [email protected]\n", index->table_name);
}
/*创建一个行锁并进入lock wait状态*/
lock = lock_rec_create(type_mode | LOCK_WAIT, rec, index, trx);
/*检查死锁*/
if(lock_deadlock_occurs(lock, trx)){
/*进行lock wait复位*/
lock_reset_lock_and_trx_wait(lock);
lock_rec_reset_nth_bit(lock, rec_get_heap_no(rec));
return DB_DEADLOCK;
}
trx->que_state = TRX_QUE_LOCK_WAIT;
trx->wait_started = time(NULL);
ut_a(que_thr_stop(thr));
if(lock_print_waits)
printf("Lock wait for trx %lu in index %s\n", ut_dulint_get_low(trx->id), index->name);
return DB_LOCK_WAIT;
}
/*增加一个记录行锁,并将锁放入锁的队列中*/
static lock_t* lock_rec_add_to_queue(ulint type_mode, rec_t* rec, dict_index_t* index, trx_t* trx)
{
lock_t* lock;
lock_t* similar_lock = NULL;
ulint heap_no;
page_t* page;
ibool somebody_waits = FALSE;
ut_ad(mutex_own(&kernel_mutex));
/*对锁的严格度做检验*/
ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP))
|| ((type_mode & LOCK_MODE_MASK) != LOCK_S)
|| !lock_rec_other_has_expl_req(LOCK_X, 0, LOCK_WAIT, rec, trx));
ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP))
|| ((type_mode & LOCK_MODE_MASK) != LOCK_X)
|| !lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT, rec, trx));
type_mode = type_mode | LOCK_REC;
page = buf_frame_align(rec);
/*记录是supremum*/
if(rec == page_get_supremum_rec(page)){
type_mode = type_mode & ~LOCK_GAP;
}
heap_no = rec_get_heap_no(rec);
lock = lock_rec_get_first_on_page(rec);
/*查找行记录rec是否用处于lock wait状态的行锁*/
while(lock != NULL){
if(lock_get_wait(lock) && lock_rec_get_nth_bit(lock, heap_no))
somebody_waits = TRUE;
lock = lock_rec_get_next_on_page(lock);
}
/*查找trx事务发起模式为type_mode的记录行锁,必须是在rec所处的page中的行记录*/
similar_lock = lock_rec_find_similar_on_page(type_mode, rec, trx);
/*可以重用similar_lock,一个执行事务在一个行上只会有一个行锁*/
if(similar_lock != NULL && !somebody_waits && !(type_mode & LOCK_WAIT)){
lock_rec_set_nth_bit(similar_lock, heap_no); /*在对应行位上加上锁标识,只有目标行是在事务在等待才会添加标识,否则有可能可以直接执行*/
return similar_lock;
}
/*没有对应的行锁,直接创建一个,并进行排队*/
return lock_rec_create(type_mode, rec, index, trx);
}
/*快速获得行锁,大部分流程都是这样的,没有任何锁在这个行记录上*/
UNIV_INLINE ibool lock_rec_lock_fast(ibool impl, ulint mode, rec_t* rec, dict_index_t* index, que_thr_t* thr)
{
lock_t* lock;
ulint heap_no;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(mode == LOCK_X || mode == LOCK_S);
heap_no = rec_get_heap_no(rec);
lock = lock_rec_get_first_on_page(rec);
if(lock == NULL){ /*page中没有其他的锁, 创建一个mode类型的锁*/
if(!impl) /*没有隐式锁,创建一个显式锁在这个行记录上*/
lock_rec_create(mode, rec, index, thr_get_trx(thr));
return TRUE;
}
/*page的有多个LOCK,不能快速获得锁,进入SLOW模式*/
if(lock_rec_get_next_on_page(lock))
return FALSE;
/*lock的事务与thr中的trx不相同、或者不是行锁、或者lock的记录与rec不相同,直接返回进入SLOW模式*/
if(lock->trx != thr_get_trx(thr) || lock->type_mode != (mode | LOCK_REC)
|| lock_rec_get_n_bits(lock) <= heap_no)
return FALSE;
/*有且只有个1行锁(不存在隐身锁)在这个行上,并且这个行锁指向的记录rec,直接认为可以获得锁权*/
if(!impl)
lock_rec_set_nth_bit(lock, heap_no);
return TRUE;
}
/*从排队队列中选择lock,并获得锁权,会检查锁的兼容性*/
static ulint lock_rec_lock_slow(ibool impl, ulint mode, rec_t* rec, dict_index_t* index, que_thr_t* thr)
{
ulint confl_mode;
trx_t* trx;
ulint err;
ut_ad(mutex_own(&kernel_mutex));
ut_ad((mode == LOCK_X) || (mode == LOCK_S));
trx = thr_get_trx(thr);
confl_mode = lock_get_confl_mode(mode);
ut_ad((mode != LOCK_S) || lock_table_has(trx, index->table, LOCK_IS));
ut_ad((mode != LOCK_X) || lock_table_has(trx, index->table, LOCK_IX));
/*trx有比mode更加严格的锁模式存在rec行锁(显式锁),没必要对行上锁*/
if(lock_rec_has_expl(mode, rec, trx))
err = DB_SUCCESS;
else if(lock_rec_other_has_expl_req(confl_mode, 0, LOCK_WAIT, rec, trx)) /*其他事务有更严格的锁(行)在rec行上*/
err = lock_rec_enqueue_waiting(mode, rec, index, thr); /*创建一个新显式锁并进行等待*/
else{
if(!impl) /*增加一个行锁,并加入到锁队列中*/
lock_rec_add_to_queue(LOCK_REC | mode, rec, index, trx);
err = DB_SUCCESS;
}
return err;
}
/*对记录行上锁请求*/
ulint lock_rec_lock(ibool impl, ulint mode, rec_t* rec, dict_index_t* index, que_thr_t* thr)
{
ulint err;
ut_ad(mutex_own(&kernel_mutex));
ut_ad((mode != LOCK_S) || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
ut_ad((mode != LOCK_X) || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
/*先尝试快速加锁*/
if(lock_rec_lock_fast(impl, mode, rec, index, thr))
err = DB_SUCCESS;
else
err = lock_rec_lock_slow(impl, mode, rec, index, thr);
return err;
}
/*检查wait_lock是否还有指向同一行记录并且不兼容的锁,O(n)*/
static ibool lock_rec_has_to_wait_in_queue(lock_t* wait_lock)
{
lock_t* lock;
ulint space;
ulint page_no;
ulint heap_no;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(lock_get_wait(wait_lock));
/*获得的定位信息space page rec*/
space = wait_lock->un_member.rec_lock.space;
page_no = wait_lock->un_member.rec_lock.page_no;
heap_no = lock_rec_find_set_bit(wait_lock);
lock = lock_rec_get_first_on_page_addr(space, page_no);
while(lock != wait_lock){
/*wait_lock和lock不兼容,并且处于同一rec记录行*/
if (lock_has_to_wait(wait_lock, lock) && lock_rec_get_nth_bit(lock, heap_no))
return TRUE;
lock = lock_rec_get_next_on_page(lock);
}
return FALSE;
}
/*获得锁权*/
void lock_grant(lock_t* lock)
{
ut_ad(mutex_own(&kernel_mutex));
/*锁的lock wait标识复位*/
lock_reset_lock_and_trx_wait(lock);
/*主键自增长锁模式,这种锁在*/
if(lock_get_mode(lock) == LOCK_AUTO_INC){
if(lock->trx->auto_inc_lock != NULL)
fprintf(stderr, "InnoDB: Error: trx already had an AUTO-INC lock!\n");
lock->trx->auto_inc_lock = lock;
}
if(lock_print_waits)
printf("Lock wait for trx %lu ends\n", ut_dulint_get_low(lock->trx->id));
/*结束事务等待,进行事务执行*/
trx_end_lock_wait(lock->trx);
}
/*取消正在等待的锁,唤醒锁请求对应的事务*/
static void lock_rec_cancel(lock_t* lock)
{
ut_ad(mutex_own(&kernel_mutex));
/*复位锁的bitmap位*/
lock_rec_reset_nth_bit(lock, lock_rec_find_set_bit(lock));
/*复位锁的lock wait状态*/
lock_reset_lock_and_trx_wait(lock);
/*结束对应事物的等待*/
trx_end_lock_wait(lock->trx);
}
/*将in_lock从lock_sys中删除, 并唤醒其对应页的一个等待行锁的事务, in_lock可能是一个waiting或者granted状态的锁*/
void lock_rec_dequeue_from_page(lock_t* in_lock)
{
ulint space;
ulint page_no;
lock_t* lock;
trx_t* trx;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(lock_get_type(in_lock) == LOCK_REC);
trx = in_lock->trx;
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
/*将in_lock从lock_sys和trx中删除*/
HASH_DELETE(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), in_lock);
UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock);
/*激活同一个页中可以激活(grant)的行锁*/
lock = lock_rec_get_first_on_page_addr(space, page_no);
while(lock != NULL){
if(lock_get_wait(lock) && !lock_rec_has_to_wait_in_queue(lock)) /*lock处于等待状态并且其指向的行记录没有其他的排斥锁*/
lock_grant(lock);
lock = lock_rec_get_next_on_page(lock);
}
}
/*将in_lock从lock_sys中删除, in_lock可能是一个waiting或者granted状态的锁*/
static void lock_rec_discard(lock_t* in_lock)
{
ulint space;
ulint page_no;
trx_t* trx;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(lock_get_type(in_lock) == LOCK_REC);
trx = in_lock->trx;
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
HASH_DELETE(lock_t, hash, lock_sys->rec_hash, lock_rec_fold(space, page_no), in_lock);
UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock);
}
/*遗弃page中所有行记录锁请求*/
static void lock_rec_free_all_from_discard_page(page_t* page)
{
ulint space;
ulint page_no;
lock_t* lock;
lock_t* next_lock;
ut_ad(mutex_own(&kernel_mutex));
space = buf_frame_get_space_id(page);
page_no = buf_frame_get_page_no(page);
lock = lock_rec_get_first_on_page_addr(space, page_no);
while(lock != NULL){
ut_ad(lock_rec_find_set_bit(lock) == ULINT_UNDEFINED);
ut_ad(!lock_get_wait(lock));
next_lock = lock_rec_get_next_on_page(lock);
lock_rec_discard(lock);
lock = next_lock;
}
}
/*复位rec的锁bitmap,并取消对应锁事务的等待*/
void lock_rec_reset_and_release_wait(rec_t* rec)
{
lock_t* lock;
ulint heap_no;
ut_ad(mutex_own(&kernel_mutex));
/*获得记录序号*/
heap_no = rec_get_heap_no(rec);
lock = lock_rec_get_first(rec);