@@ -2031,7 +2031,8 @@ wsrep_print_wait_locks(
2031
2031
2032
2032
/* ********************************************************************/ /* *
2033
2033
Check if lock1 has higher priority than lock2.
2034
- NULL has lowest priority..
2034
+ NULL has lowest priority.
2035
+ If either is a high priority transaction, the lock has higher priority.
2035
2036
If neither of them is wait lock, the first one has higher priority.
2036
2037
If only one of them is a wait lock, it has lower priority.
2037
2038
Otherwise, the one with an older transaction has higher priority.
@@ -2055,13 +2056,19 @@ has_higher_priority(
2055
2056
// lock2 is preferred as a victim, so lock1 has higher priority
2056
2057
return true ;
2057
2058
}
2059
+ if (trx_is_high_priority (lock1->trx )) {
2060
+ return true ;
2061
+ }
2062
+ if (trx_is_high_priority (lock2->trx )) {
2063
+ return false ;
2064
+ }
2058
2065
// No preference. Compre them by wait mode and trx age.
2059
2066
if (!lock_get_wait (lock1)) {
2060
2067
return true ;
2061
2068
} else if (!lock_get_wait (lock2)) {
2062
2069
return false ;
2063
2070
}
2064
- return lock1->trx ->start_time < lock2->trx ->start_time ;
2071
+ return lock1->trx ->start_time_micro <= lock2->trx ->start_time_micro ;
2065
2072
}
2066
2073
2067
2074
/* ********************************************************************/ /* *
@@ -2071,7 +2078,7 @@ If the lock is not a wait lock, insert it to the head of the hash list.
2071
2078
Otherwise, insert it to the middle of the wait locks according to the age of
2072
2079
the transaciton. */
2073
2080
static
2074
- void
2081
+ dberr_t
2075
2082
lock_rec_insert_by_trx_age (
2076
2083
lock_t *in_lock) /* !< in: lock to be insert */ {
2077
2084
ulint space;
@@ -2085,7 +2092,7 @@ lock_rec_insert_by_trx_age(
2085
2092
space = in_lock->un_member .rec_lock .space ;
2086
2093
page_no = in_lock->un_member .rec_lock .page_no ;
2087
2094
rec_fold = lock_rec_fold (space, page_no);
2088
- hash = lock_sys-> rec_hash ;
2095
+ hash = lock_hash_get (in_lock-> type_mode ) ;
2089
2096
cell = hash_get_nth_cell (hash,
2090
2097
hash_calc_hash (rec_fold, hash));
2091
2098
@@ -2094,7 +2101,11 @@ lock_rec_insert_by_trx_age(
2094
2101
if (node == NULL || !lock_get_wait (in_lock) || has_higher_priority (in_lock, node)) {
2095
2102
cell->node = in_lock;
2096
2103
in_lock->hash = node;
2097
- return ;
2104
+ if (lock_get_wait (in_lock)) {
2105
+ lock_grant (in_lock, true );
2106
+ return DB_SUCCESS_LOCKED_REC;
2107
+ }
2108
+ return DB_SUCCESS;
2098
2109
}
2099
2110
while (node != NULL && has_higher_priority ((lock_t *) node->hash ,
2100
2111
in_lock)) {
@@ -2103,6 +2114,20 @@ lock_rec_insert_by_trx_age(
2103
2114
next = (lock_t *) node->hash ;
2104
2115
node->hash = in_lock;
2105
2116
in_lock->hash = next;
2117
+
2118
+ if (lock_get_wait (in_lock) && !lock_rec_has_to_wait_in_queue (in_lock)) {
2119
+ lock_grant (in_lock, true );
2120
+ if (cell->node != in_lock) {
2121
+ // Move it to the front of the queue
2122
+ node->hash = in_lock->hash ;
2123
+ next = (lock_t *) cell->node ;
2124
+ cell->node = in_lock;
2125
+ in_lock->hash = next;
2126
+ }
2127
+ return DB_SUCCESS_LOCKED_REC;
2128
+ }
2129
+
2130
+ return DB_SUCCESS;
2106
2131
}
2107
2132
2108
2133
static
@@ -2327,7 +2352,7 @@ lock_rec_create(
2327
2352
trx_mutex_exit (c_lock->trx );
2328
2353
} else {
2329
2354
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
2330
- && !is_slave_replication ) {
2355
+ && !thd_is_replication_slave_thread (trx-> mysql_thd ) ) {
2331
2356
if (type_mode & LOCK_WAIT) {
2332
2357
HASH_INSERT (lock_t , hash, lock_sys->rec_hash , rec_fold, lock);
2333
2358
} else {
@@ -2339,7 +2364,7 @@ lock_rec_create(
2339
2364
}
2340
2365
#else
2341
2366
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
2342
- && !is_slave_replication ) {
2367
+ && !thd_is_replication_slave_thread (trx-> mysql_thd ) ) {
2343
2368
if (type_mode & LOCK_WAIT) {
2344
2369
HASH_INSERT (lock_t , hash, lock_sys->rec_hash , rec_fold, lock);
2345
2370
} else {
@@ -2512,18 +2537,19 @@ lock_rec_enqueue_waiting(
2512
2537
result = DB_LOCK_WAIT;
2513
2538
}
2514
2539
2540
+
2515
2541
// Move it only when it does not cause a deadlock.
2516
- if (innodb_lock_schedule_algorithm
2542
+ if (err != DB_DEADLOCK
2543
+ && innodb_lock_schedule_algorithm
2517
2544
== INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
2518
- && !is_slave_replication) {
2545
+ && !thd_is_replication_slave_thread (lock->trx ->mysql_thd )
2546
+ && !trx_is_high_priority (lock->trx )) {
2519
2547
2520
- HASH_DELETE (lock_t , hash, lock_sys->rec_hash ,
2521
- lock_rec_fold (lock->un_member .rec_lock .space ,
2522
- lock->un_member .rec_lock .page_noo ), lock);
2523
- lock_rec_insert_by_trx_age (lock);
2524
- if (lock_get_wait (lock) && !lock_rec_has_to_wait_in_queue (lock)) {
2525
- lock_grant (lock, true );
2526
- result = DB_SUCCESS_LOCKED_REC;
2548
+ HASH_DELETE (lock_t , hash, lock_hash_get (lock->type_mode ),
2549
+ m_rec_id.fold (), lock);
2550
+ dberr_t res = lock_rec_insert_by_trx_age (lock);
2551
+ if (res != DB_SUCCESS) {
2552
+ return res;
2527
2553
}
2528
2554
}
2529
2555
@@ -2963,6 +2989,7 @@ lock_grant(
2963
2989
bool owns_trx_mutex) /* !< in: whether lock->trx->mutex is owned */
2964
2990
{
2965
2991
ut_ad (lock_mutex_own ());
2992
+ ut_ad (trx_mutex_own (lock->trx ) == owns_trx_mutex);
2966
2993
2967
2994
lock_reset_lock_and_trx_wait (lock);
2968
2995
@@ -3060,29 +3087,45 @@ lock_rec_cancel(
3060
3087
static
3061
3088
void
3062
3089
lock_grant_and_move_on_page (
3090
+ hash_table_t *lock_hash,
3063
3091
ulint space,
3064
3092
ulint page_no)
3065
3093
{
3066
3094
lock_t * lock;
3067
3095
lock_t * previous;
3068
3096
ulint rec_fold = lock_rec_fold (space, page_no);
3069
3097
3070
- previous = (lock_t *) hash_get_nth_cell (lock_sys->rec_hash ,
3071
- hash_calc_hash (rec_fold, lock_sys->rec_hash ))->node ;
3098
+ previous = (lock_t *) hash_get_nth_cell (lock_hash,
3099
+ hash_calc_hash (rec_fold, lock_hash))->node ;
3100
+ if (previous == NULL ) {
3101
+ return ;
3102
+ }
3103
+ if (previous->un_member .rec_lock .space == space &&
3104
+ previous->un_member .rec_lock .page_no == page_no) {
3105
+ lock = previous;
3106
+ }
3107
+ else {
3108
+ while (previous->hash &&
3109
+ (previous->hash ->un_member .rec_lock .space != space ||
3110
+ previous->hash ->un_member .rec_lock .page_no != page_no)) {
3111
+ previous = previous->hash ;
3112
+ }
3113
+ lock = previous->hash ;
3114
+ }
3115
+
3116
+ ut_ad (previous->hash == lock || previous == lock);
3072
3117
/* Grant locks if there are no conflicting locks ahead.
3073
3118
Move granted locks to the head of the list. */
3074
- for (lock = lock_rec_get_first_on_page_addr (lock_sys->rec_hash , space,
3075
- page_no);
3076
- lock != NULL ;) {
3119
+ for (;lock != NULL ;) {
3077
3120
3078
3121
/* If the lock is a wait lock on this page, and it does not need to wait. */
3079
3122
if ((lock->un_member .rec_lock .space == space)
3080
3123
&& (lock->un_member .rec_lock .page_no == page_no)
3081
3124
&& lock_get_wait (lock)
3082
3125
&& !lock_rec_has_to_wait_in_queue (lock)) {
3083
-
3126
+
3084
3127
lock_grant (lock, false );
3085
-
3128
+
3086
3129
if (previous != NULL ) {
3087
3130
/* Move the lock to the head of the list. */
3088
3131
HASH_GET_NEXT (hash, previous) = HASH_GET_NEXT (hash, lock);
@@ -3144,7 +3187,8 @@ lock_rec_dequeue_from_page(
3144
3187
MONITOR_DEC (MONITOR_NUM_RECLOCK);
3145
3188
3146
3189
if (innodb_lock_schedule_algorithm
3147
- == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS || is_slave_replication) {
3190
+ == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
3191
+ thd_is_replication_slave_thread (in_lock->trx ->mysql_thd )) {
3148
3192
3149
3193
/* Check if waiting locks in the queue can now be granted:
3150
3194
grant locks if there are no conflicting locks ahead. Stop at
@@ -5479,6 +5523,7 @@ lock_table_dequeue(
5479
5523
static
5480
5524
void
5481
5525
lock_grant_and_move_on_rec (
5526
+ hash_table_t *lock_hash,
5482
5527
lock_t *first_lock,
5483
5528
ulint heap_no)
5484
5529
{
@@ -5492,11 +5537,23 @@ lock_grant_and_move_on_rec(
5492
5537
page_no = first_lock->un_member .rec_lock .page_no ;
5493
5538
rec_fold = lock_rec_fold (space, page_no);
5494
5539
5495
- previous = (lock_t *) hash_get_nth_cell (lock_sys->rec_hash ,
5496
- hash_calc_hash (rec_fold, lock_sys->rec_hash ))->node ;
5540
+ previous = (lock_t *) hash_get_nth_cell (lock_hash,
5541
+ hash_calc_hash (rec_fold, lock_hash))->node ;
5542
+ if (previous == NULL ) {
5543
+ return ;
5544
+ }
5545
+ if (previous == first_lock) {
5546
+ lock = previous;
5547
+ } else {
5548
+ while (previous->hash &&
5549
+ previous->hash != first_lock) {
5550
+ previous = previous->hash ;
5551
+ }
5552
+ lock = previous->hash ;
5553
+ }
5497
5554
/* Grant locks if there are no conflicting locks ahead.
5498
5555
Move granted locks to the head of the list. */
5499
- for (lock = first_lock; lock != NULL ;) {
5556
+ for (; lock != NULL ;) {
5500
5557
5501
5558
/* If the lock is a wait lock on this page, and it does not need to wait. */
5502
5559
if (lock->un_member .rec_lock .space == space
@@ -5587,7 +5644,8 @@ lock_rec_unlock(
5587
5644
lock_rec_reset_nth_bit (lock, heap_no);
5588
5645
5589
5646
if (innodb_lock_schedule_algorithm
5590
- == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS || is_slave_replication) {
5647
+ == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
5648
+ thd_is_replication_slave_thread (lock->trx ->mysql_thd )) {
5591
5649
5592
5650
/* Check if we can now grant waiting lock requests */
5593
5651
0 commit comments