1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-09 22:24:09 +03:00

A few fixes for VATS in 10.1

This commit is contained in:
sensssz
2016-10-25 18:57:03 -04:00
parent 183c02839f
commit 74961760a4
12 changed files with 709 additions and 268 deletions

1
libmariadb Submodule

Submodule libmariadb added at c8dd0899d4

View File

@@ -1335,6 +1335,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON ENUM_VALUE_LIST OFF,ON
READ_ONLY YES READ_ONLY YES
COMMAND_LINE_ARGUMENT NONE COMMAND_LINE_ARGUMENT NONE
VARIABLE_NAME INNODB_LOCK_SCHEDULE_ALGORITHM
SESSION_VALUE NULL
GLOBAL_VALUE fcfs
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE fcfs
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE ENUM
VARIABLE_COMMENT The algorithm Innodb uses for deciding which locks to grant next when a lock is released. Possible values are FCFS grant the locks in First-Come-First-Served order; VATS use the Variance-Aware-Transaction-Scheduling algorithm, which uses an Eldest-Transaction-First heuristic.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST fcfs,vats
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_LOCK_WAIT_TIMEOUT VARIABLE_NAME INNODB_LOCK_WAIT_TIMEOUT
SESSION_VALUE 50 SESSION_VALUE 50
GLOBAL_VALUE 50 GLOBAL_VALUE 50

View File

@@ -1553,7 +1553,7 @@ thd_is_replication_slave_thread(
/*============================*/ /*============================*/
THD* thd) /*!< in: thread handle */ THD* thd) /*!< in: thread handle */
{ {
return((ibool) thd_slave_thread(thd)); return thd && ((ibool) thd_slave_thread(thd));
} }
/******************************************************************//** /******************************************************************//**

View File

@@ -844,6 +844,8 @@ struct trx_t{
time_t start_time; /*!< time the trx state last time became time_t start_time; /*!< time the trx state last time became
TRX_STATE_ACTIVE */ TRX_STATE_ACTIVE */
clock_t start_time_micro; /*!< start time of transaction in
microseconds */
trx_id_t id; /*!< transaction id */ trx_id_t id; /*!< transaction id */
XID xid; /*!< X/Open XA transaction XID xid; /*!< X/Open XA transaction
identification to identify a identification to identify a

View File

@@ -383,6 +383,25 @@ struct lock_stack_t {
ulint heap_no; /*!< heap number if rec lock */ ulint heap_no; /*!< heap number if rec lock */
}; };
/*********************************************************************//**
Checks if a waiting record lock request still has to wait in a queue.
@return lock that is causing the wait */
static
const lock_t*
lock_rec_has_to_wait_in_queue(
/*==========================*/
const lock_t* wait_lock); /*!< in: waiting record lock */
/*************************************************************//**
Grants a lock to a waiting lock request and releases the waiting transaction.
The caller must hold lock_sys->mutex. */
static
void
lock_grant(
/*=======*/
lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex); /*!< in: whether lock->trx->mutex is owned */
extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd); extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_for(const MYSQL_THD thd); extern "C" int thd_need_wait_for(const MYSQL_THD thd);
extern "C" extern "C"
@@ -1988,82 +2007,26 @@ wsrep_print_wait_locks(
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/*********************************************************************//**
Check if lock1 has higher priority than lock2.
NULL has lowest priority.
Respect the preference of the upper server layer to reduce conflict
during in-order parallel replication.
If neither of them is wait lock, the first one has higher priority.
If only one of them is a wait lock, it has lower priority.
Otherwise, the one with an older transaction has higher priority.
@returns true if lock1 has higher priority, false otherwise. */
bool
has_higher_priority(
lock_t *lock1,
lock_t *lock2)
{
if (lock1 == NULL) {
return false;
} else if (lock2 == NULL) {
return true;
}
// Ask the upper server layer if any of the two trx should be prefered.
int preference = thd_deadlock_victim_preference(lock1->trx->mysql_thd, lock2->trx->mysql_thd);
if (preference == -1) {
// lock1 is preferred as a victim, so lock2 has higher priority
return false;
} else if (preference == 1) {
// lock2 is preferred as a victim, so lock1 has higher priority
return true;
}
// No preference. Compre them by wait mode and trx age.
if (!lock_get_wait(lock1)) {
return true;
} else if (!lock_get_wait(lock2)) {
return false;
}
return lock1->trx->start_time < lock2->trx->start_time;
}
/*********************************************************************//**
Insert a lock to the hash list according to the mode (whether it is a wait lock)
and the age of the transaction the it is associated with.
If the lock is not a wait lock, insert it to the head of the hash list.
Otherwise, insert it to the middle of the wait locks according to the age of the
transaciton.
*/
static static
void void
lock_rec_insert_by_trx_age( lock_rec_insert_to_head(
lock_t *in_lock, /*!< in: lock to be insert */ lock_t *in_lock, /*!< in: lock to be insert */
bool wait) /*!< in: whether it's a wait lock */ ulint rec_fold) /*!< in: rec_fold of the page */
{ {
ulint space;
ulint page_no;
ulint rec_fold;
hash_cell_t* cell; hash_cell_t* cell;
lock_t* node; lock_t* node;
lock_t* next;
space = in_lock->un_member.rec_lock.space; if (in_lock == NULL) {
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
node = (lock_t *) cell->node;
// If in_lock is not a wait lock, we insert it to the head of the list.
if (node == NULL || !wait || has_higher_priority(in_lock, node)) {
cell->node = in_lock;
in_lock->hash = node;
return; return;
} }
while (node != NULL && has_higher_priority((lock_t *) node->hash, in_lock)) {
node = (lock_t *) node->hash; cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
node = (lock_t *) cell->node;
if (node != in_lock) {
cell->node = in_lock;
in_lock->hash = node;
} }
next = (lock_t *) node->hash;
node->hash = in_lock;
in_lock->hash = next;
} }
/*********************************************************************//** /*********************************************************************//**
@@ -2093,8 +2056,10 @@ lock_rec_create(
lock_t* lock; lock_t* lock;
ulint page_no; ulint page_no;
ulint space; ulint space;
ulint rec_fold;
ulint n_bits; ulint n_bits;
ulint n_bytes; ulint n_bytes;
bool wait_lock;
const page_t* page; const page_t* page;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
@@ -2121,6 +2086,8 @@ lock_rec_create(
type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP); type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP);
} }
wait_lock = type_mode & LOCK_WAIT;
/* Make lock bitmap bigger by a safety margin */ /* Make lock bitmap bigger by a safety margin */
n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
n_bytes = 1 + n_bits / 8; n_bytes = 1 + n_bits / 8;
@@ -2136,6 +2103,7 @@ lock_rec_create(
lock->un_member.rec_lock.space = space; lock->un_member.rec_lock.space = space;
lock->un_member.rec_lock.page_no = page_no; lock->un_member.rec_lock.page_no = page_no;
lock->un_member.rec_lock.n_bits = n_bytes * 8; lock->un_member.rec_lock.n_bits = n_bytes * 8;
rec_fold = lock_rec_fold(space, page_no);
/* Reset to zero the bitmap which resides immediately after the /* Reset to zero the bitmap which resides immediately after the
lock struct */ lock struct */
@@ -2228,13 +2196,27 @@ lock_rec_create(
return(lock); return(lock);
} }
trx_mutex_exit(c_lock->trx); trx_mutex_exit(c_lock->trx);
} else if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
if (wait_lock) {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} else { } else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_insert_to_head(lock, rec_fold);
lock_rec_fold(space, page_no), lock); }
} else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} }
#else #else
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
lock_rec_fold(space, page_no), lock); && !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
if (wait_lock) {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} else {
lock_rec_insert_to_head(lock, rec_fold);
}
} else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
}
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
if (!caller_owns_trx_mutex) { if (!caller_owns_trx_mutex) {
@@ -2257,6 +2239,135 @@ lock_rec_create(
return(lock); return(lock);
} }
/*********************************************************************//**
Check if lock1 has higher priority than lock2.
NULL has lowest priority.
Respect the preference of the upper server layer to reduce conflict
during in-order parallel replication.
If neither of them is wait lock, the first one has higher priority.
If only one of them is a wait lock, it has lower priority.
Otherwise, the one with an older transaction has higher priority.
@returns true if lock1 has higher priority, false otherwise. */
bool
has_higher_priority(
lock_t *lock1,
lock_t *lock2)
{
if (lock1 == NULL) {
return false;
} else if (lock2 == NULL) {
return true;
}
// Ask the upper server layer if any of the two trx should be prefered.
int preference = thd_deadlock_victim_preference(lock1->trx->mysql_thd, lock2->trx->mysql_thd);
if (preference == -1) {
// lock1 is preferred as a victim, so lock2 has higher priority
return false;
} else if (preference == 1) {
// lock2 is preferred as a victim, so lock1 has higher priority
return true;
}
// No preference. Compre them by wait mode and trx age.
if (!lock_get_wait(lock1)) {
return true;
} else if (!lock_get_wait(lock2)) {
return false;
}
return lock1->trx->start_time_micro <= lock2->trx->start_time_micro;
}
/*********************************************************************//**
Insert a lock to the hash list according to the mode (whether it is a wait
lock) and the age of the transaction the it is associated with.
If the lock is not a wait lock, insert it to the head of the hash list.
Otherwise, insert it to the middle of the wait locks according to the age of
the transaciton. */
static
dberr_t
lock_rec_insert_by_trx_age(
lock_t *in_lock) /*!< in: lock to be insert */{
ulint space;
ulint page_no;
ulint rec_fold;
lock_t* node;
lock_t* next;
hash_cell_t* cell;
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
node = (lock_t *) cell->node;
// If in_lock is not a wait lock, we insert it to the head of the list.
if (node == NULL || !lock_get_wait(in_lock) || has_higher_priority(in_lock, node)) {
cell->node = in_lock;
in_lock->hash = node;
if (lock_get_wait(in_lock)) {
lock_grant(in_lock, true);
return DB_SUCCESS_LOCKED_REC;
}
return DB_SUCCESS;
}
while (node != NULL && has_higher_priority((lock_t *) node->hash,
in_lock)) {
node = (lock_t *) node->hash;
}
next = (lock_t *) node->hash;
node->hash = in_lock;
in_lock->hash = next;
if (lock_get_wait(in_lock) && !lock_rec_has_to_wait_in_queue(in_lock)) {
lock_grant(in_lock, true);
if (cell->node != in_lock) {
// Move it to the front of the queue
node->hash = in_lock->hash;
next = (lock_t *) cell->node;
cell->node = in_lock;
in_lock->hash = next;
}
return DB_SUCCESS_LOCKED_REC;
}
return DB_SUCCESS;
}
static
bool
lock_queue_validate(
const lock_t *in_lock) /*!< in: lock whose hash list is to be validated */
{
ulint space;
ulint page_no;
ulint rec_fold;
hash_table_t* hash;
hash_cell_t* cell;
lock_t* next;
bool wait_lock = false;
if (in_lock == NULL) {
return true;
}
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
next = (lock_t *) cell->node;
while (next != NULL) {
// If this is a granted lock, check that there's no wait lock before it.
if (!lock_get_wait(next)) {
ut_ad(!wait_lock);
} else {
wait_lock = true;
}
next = (lock_t *) next->hash;
}
return true;
}
/*********************************************************************//** /*********************************************************************//**
Enqueues a waiting request for a lock which cannot be granted immediately. Enqueues a waiting request for a lock which cannot be granted immediately.
Checks for deadlocks. Checks for deadlocks.
@@ -2289,6 +2400,9 @@ lock_rec_enqueue_waiting(
trx_t* trx; trx_t* trx;
lock_t* lock; lock_t* lock;
trx_id_t victim_trx_id; trx_id_t victim_trx_id;
ulint space;
ulint page_no;
dberr_t err;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
@@ -2362,16 +2476,8 @@ lock_rec_enqueue_waiting(
transaction as a victim, it is possible that we transaction as a victim, it is possible that we
already have the lock now granted! */ already have the lock now granted! */
return(DB_SUCCESS_LOCKED_REC); err = DB_SUCCESS_LOCKED_REC;
} } else {
// Move it only when it does not cause a deadlock.
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS) {
HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(buf_block_get_space(block), buf_block_get_page_no(block)), lock);
lock_rec_insert_by_trx_age(lock, true);
}
trx->lock.que_state = TRX_QUE_LOCK_WAIT; trx->lock.que_state = TRX_QUE_LOCK_WAIT;
trx->lock.was_chosen_as_deadlock_victim = FALSE; trx->lock.was_chosen_as_deadlock_victim = FALSE;
@@ -2391,7 +2497,25 @@ lock_rec_enqueue_waiting(
trx->n_rec_lock_waits++; trx->n_rec_lock_waits++;
return(DB_LOCK_WAIT); err = DB_LOCK_WAIT;
}
// Move it only when it does not cause a deadlock.
if (err != DB_DEADLOCK
&& innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
space = buf_block_get_space(block);
page_no = buf_block_get_page_no(block);
HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(space, page_no), lock);
dberr_t res = lock_rec_insert_by_trx_age(lock);
if (res != DB_SUCCESS) {
return res;
}
}
return err;
} }
/*********************************************************************//** /*********************************************************************//**
@@ -2820,13 +2944,16 @@ static
void void
lock_grant( lock_grant(
/*=======*/ /*=======*/
lock_t* lock) /*!< in/out: waiting lock request */ lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex) /*!< in: whether lock->trx->mutex is owned */
{ {
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
lock_reset_lock_and_trx_wait(lock); lock_reset_lock_and_trx_wait(lock);
if (!owns_trx_mutex) {
trx_mutex_enter(lock->trx); trx_mutex_enter(lock->trx);
}
if (lock_get_mode(lock) == LOCK_AUTO_INC) { if (lock_get_mode(lock) == LOCK_AUTO_INC) {
dict_table_t* table = lock->un_member.tab_lock.table; dict_table_t* table = lock->un_member.tab_lock.table;
@@ -2875,8 +3002,10 @@ lock_grant(
lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time); lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time);
if (!owns_trx_mutex) {
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
}
/*************************************************************//** /*************************************************************//**
Cancels a waiting record lock request and releases the waiting transaction Cancels a waiting record lock request and releases the waiting transaction
@@ -2913,23 +3042,62 @@ lock_rec_cancel(
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
/*************************************************************//**
Move the lock to the head of the hash list. */
static static
void void
lock_rec_move_to_front( lock_grant_and_move_on_page(
lock_t *lock_to_move, /*!< in: lock to be moved */ ulint space,
ulint rec_fold) /*!< in: rec fold of the lock */ ulint page_no)
{ {
if (lock_to_move != NULL) lock_t* lock;
{ lock_t* next;
// Move the target lock to the head of the list lock_t* previous;
hash_cell_t* cell = hash_get_nth_cell(lock_sys->rec_hash, ulint rec_fold = lock_rec_fold(space, page_no);
hash_calc_hash(rec_fold, lock_sys->rec_hash));
if (lock_to_move != cell->node) { previous = (lock_t *) hash_get_nth_cell(lock_sys->rec_hash,
lock_t *next = (lock_t *) cell->node; hash_calc_hash(rec_fold, lock_sys->rec_hash))->node;
cell->node = lock_to_move; if (previous == NULL) {
lock_to_move->hash = next; return;
}
if (previous->un_member.rec_lock.space == space &&
previous->un_member.rec_lock.page_no == page_no) {
lock = previous;
}
else {
next = (lock_t *) previous->hash;
while (next &&
(next->un_member.rec_lock.space != space ||
next->un_member.rec_lock.page_no != page_no)) {
previous = next;
next = (lock_t *) previous->hash;
}
lock = (lock_t *) previous->hash;
}
ut_ad(previous->hash == lock || previous == lock);
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock, false);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
} }
} }
} }
@@ -2951,9 +3119,7 @@ lock_rec_dequeue_from_page(
{ {
ulint space; ulint space;
ulint page_no; ulint page_no;
ulint rec_fold;
lock_t* lock; lock_t* lock;
lock_t* previous = NULL;
trx_lock_t* trx_lock; trx_lock_t* trx_lock;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
@@ -2964,7 +3130,6 @@ lock_rec_dequeue_from_page(
space = in_lock->un_member.rec_lock.space; space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no; page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
in_lock->index->table->n_rec_locks--; in_lock->index->table->n_rec_locks--;
@@ -2976,7 +3141,9 @@ lock_rec_dequeue_from_page(
MONITOR_INC(MONITOR_RECLOCK_REMOVED); MONITOR_INC(MONITOR_RECLOCK_REMOVED);
MONITOR_DEC(MONITOR_NUM_RECLOCK); MONITOR_DEC(MONITOR_NUM_RECLOCK);
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS) { if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(in_lock->trx->mysql_thd)) {
/* Check if waiting locks in the queue can now be granted: grant /* Check if waiting locks in the queue can now be granted: grant
locks if there are no conflicting locks ahead. Stop at the first locks if there are no conflicting locks ahead. Stop at the first
X lock that is waiting or has been granted. */ X lock that is waiting or has been granted. */
@@ -2990,38 +3157,11 @@ lock_rec_dequeue_from_page(
/* Grant the lock */ /* Grant the lock */
ut_ad(lock->trx != in_lock->trx); ut_ad(lock->trx != in_lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} else { } else {
/* Grant locks if there are no conflicting locks ahead. lock_grant_and_move_on_page(space, page_no);
Move granted locks to the head of the list. */
for (lock = lock_rec_get_first_on_page_addr(space, page_no);
lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_move_to_front(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
} }
} }
@@ -5319,12 +5459,71 @@ lock_table_dequeue(
/* Grant the lock */ /* Grant the lock */
ut_ad(in_lock->trx != lock->trx); ut_ad(in_lock->trx != lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} }
/*=========================== LOCK RELEASE ==============================*/ /*=========================== LOCK RELEASE ==============================*/
static
void
lock_grant_and_move_on_rec(
lock_t* first_lock,
ulint heap_no)
{
lock_t* lock;
lock_t* previous;
ulint space;
ulint page_no;
ulint rec_fold;
space = first_lock->un_member.rec_lock.space;
page_no = first_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
previous = (lock_t *) hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash))->node;
if (previous == NULL) {
return;
}
if (previous == first_lock) {
lock = previous;
} else {
while (previous->hash &&
previous->hash != first_lock) {
previous = (lock_t *) previous->hash;
}
lock = (lock_t *) previous->hash;
}
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if (lock->un_member.rec_lock.space == space
&& lock->un_member.rec_lock.page_no == page_no
&& lock_rec_get_nth_bit(lock, heap_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock, false);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
}
/*************************************************************//** /*************************************************************//**
Removes a granted record lock of a transaction from the queue and grants Removes a granted record lock of a transaction from the queue and grants
@@ -5388,6 +5587,10 @@ released:
ut_a(!lock_get_wait(lock)); ut_a(!lock_get_wait(lock));
lock_rec_reset_nth_bit(lock, heap_no); lock_rec_reset_nth_bit(lock, heap_no);
if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
/* Check if we can now grant waiting lock requests */ /* Check if we can now grant waiting lock requests */
for (lock = first_lock; lock != NULL; for (lock = first_lock; lock != NULL;
@@ -5397,9 +5600,12 @@ released:
/* Grant the lock */ /* Grant the lock */
ut_ad(trx != lock->trx); ut_ad(trx != lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} else {
lock_grant_and_move_on_rec(first_lock, heap_no);
}
lock_mutex_exit(); lock_mutex_exit();
trx_mutex_exit(trx); trx_mutex_exit(trx);
@@ -6442,6 +6648,9 @@ lock_rec_queue_validate(
} }
} }
ut_ad(innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
lock_queue_validate(lock));
func_exit: func_exit:
if (!locked_lock_trx_sys) { if (!locked_lock_trx_sys) {
lock_mutex_exit(); lock_mutex_exit();

View File

@@ -919,6 +919,8 @@ trx_start_low(
trx->start_time = ut_time(); trx->start_time = ut_time();
trx->start_time_micro = clock();
MONITOR_INC(MONITOR_TRX_ACTIVE); MONITOR_INC(MONITOR_TRX_ACTIVE);
} }

View File

@@ -1826,7 +1826,7 @@ thd_is_replication_slave_thread(
/*============================*/ /*============================*/
THD* thd) /*!< in: thread handle */ THD* thd) /*!< in: thread handle */
{ {
return((ibool) thd_slave_thread(thd)); return thd && ((ibool) thd_slave_thread(thd));
} }
/******************************************************************//** /******************************************************************//**

View File

@@ -877,6 +877,8 @@ struct trx_t{
time_t start_time; /*!< time the trx state last time became time_t start_time; /*!< time the trx state last time became
TRX_STATE_ACTIVE */ TRX_STATE_ACTIVE */
clock_t start_time_micro; /*!< start time of transaction in
microseconds */
trx_id_t id; /*!< transaction id */ trx_id_t id; /*!< transaction id */
XID xid; /*!< X/Open XA transaction XID xid; /*!< X/Open XA transaction
identification to identify a identification to identify a

View File

@@ -383,6 +383,25 @@ struct lock_stack_t {
ulint heap_no; /*!< heap number if rec lock */ ulint heap_no; /*!< heap number if rec lock */
}; };
/*********************************************************************//**
Checks if a waiting record lock request still has to wait in a queue.
@return lock that is causing the wait */
static
const lock_t*
lock_rec_has_to_wait_in_queue(
/*==========================*/
const lock_t* wait_lock); /*!< in: waiting record lock */
/*************************************************************//**
Grants a lock to a waiting lock request and releases the waiting transaction.
The caller must hold lock_sys->mutex. */
static
void
lock_grant(
/*=======*/
lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex); /*!< in: whether lock->trx->mutex is owned */
extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd); extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_for(const MYSQL_THD thd); extern "C" int thd_need_wait_for(const MYSQL_THD thd);
extern "C" extern "C"
@@ -2045,28 +2064,25 @@ has_higher_priority(
} else if (!lock_get_wait(lock2)) { } else if (!lock_get_wait(lock2)) {
return false; return false;
} }
return lock1->trx->start_time < lock2->trx->start_time; return lock1->trx->start_time_micro <= lock2->trx->start_time_micro;
} }
/*********************************************************************//** /*********************************************************************//**
Insert a lock to the hash list according to the mode (whether it is a wait lock) Insert a lock to the hash list according to the mode (whether it is a wait
and the age of the transaction the it is associated with. lock) and the age of the transaction the it is associated with.
If the lock is not a wait lock, insert it to the head of the hash list. If the lock is not a wait lock, insert it to the head of the hash list.
Otherwise, insert it to the middle of the wait locks according to the age of the Otherwise, insert it to the middle of the wait locks according to the age of
transaciton. the transaciton. */
*/
static static
void dberr_t
lock_rec_insert_by_trx_age( lock_rec_insert_by_trx_age(
lock_t *in_lock, /*!< in: lock to be insert */ lock_t *in_lock) /*!< in: lock to be insert */{
bool wait) /*!< in: whether it's a wait lock */
{
ulint space; ulint space;
ulint page_no; ulint page_no;
ulint rec_fold; ulint rec_fold;
hash_cell_t* cell;
lock_t* node; lock_t* node;
lock_t* next; lock_t* next;
hash_cell_t* cell;
space = in_lock->un_member.rec_lock.space; space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no; page_no = in_lock->un_member.rec_lock.page_no;
@@ -2076,17 +2092,93 @@ lock_rec_insert_by_trx_age(
node = (lock_t *) cell->node; node = (lock_t *) cell->node;
// If in_lock is not a wait lock, we insert it to the head of the list. // If in_lock is not a wait lock, we insert it to the head of the list.
if (node == NULL || !wait || has_higher_priority(in_lock, node)) { if (node == NULL || !lock_get_wait(in_lock) || has_higher_priority(in_lock, node)) {
cell->node = in_lock; cell->node = in_lock;
in_lock->hash = node; in_lock->hash = node;
return; if (lock_get_wait(in_lock)) {
lock_grant(in_lock, true);
return DB_SUCCESS_LOCKED_REC;
} }
while (node != NULL && has_higher_priority((lock_t *) node->hash, in_lock)) { return DB_SUCCESS;
}
while (node != NULL && has_higher_priority((lock_t *) node->hash,
in_lock)) {
node = (lock_t *) node->hash; node = (lock_t *) node->hash;
} }
next = (lock_t *) node->hash; next = (lock_t *) node->hash;
node->hash = in_lock; node->hash = in_lock;
in_lock->hash = next; in_lock->hash = next;
if (lock_get_wait(in_lock) && !lock_rec_has_to_wait_in_queue(in_lock)) {
lock_grant(in_lock, true);
if (cell->node != in_lock) {
// Move it to the front of the queue
node->hash = in_lock->hash;
next = (lock_t *) cell->node;
cell->node = in_lock;
in_lock->hash = next;
}
return DB_SUCCESS_LOCKED_REC;
}
return DB_SUCCESS;
}
static
bool
lock_queue_validate(
const lock_t *in_lock) /*!< in: lock whose hash list is to be validated */
{
ulint space;
ulint page_no;
ulint rec_fold;
hash_table_t* hash;
hash_cell_t* cell;
lock_t* next;
bool wait_lock = false;
if (in_lock == NULL) {
return true;
}
space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
next = (lock_t *) cell->node;
while (next != NULL) {
// If this is a granted lock, check that there's no wait lock before it.
if (!lock_get_wait(next)) {
ut_ad(!wait_lock);
} else {
wait_lock = true;
}
next = (lock_t *) next->hash;
}
return true;
}
static
void
lock_rec_insert_to_head(
lock_t *in_lock, /*!< in: lock to be insert */
ulint rec_fold) /*!< in: rec_fold of the page */
{
hash_cell_t* cell;
lock_t* node;
if (in_lock == NULL) {
return;
}
cell = hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash));
node = (lock_t *) cell->node;
if (node != in_lock) {
cell->node = in_lock;
in_lock->hash = node;
}
} }
/*********************************************************************//** /*********************************************************************//**
@@ -2116,8 +2208,10 @@ lock_rec_create(
lock_t* lock; lock_t* lock;
ulint page_no; ulint page_no;
ulint space; ulint space;
ulint rec_fold;
ulint n_bits; ulint n_bits;
ulint n_bytes; ulint n_bytes;
bool wait_lock;
const page_t* page; const page_t* page;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
@@ -2144,6 +2238,8 @@ lock_rec_create(
type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP); type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP);
} }
wait_lock = type_mode & LOCK_WAIT;
/* Make lock bitmap bigger by a safety margin */ /* Make lock bitmap bigger by a safety margin */
n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
n_bytes = 1 + n_bits / 8; n_bytes = 1 + n_bits / 8;
@@ -2159,6 +2255,7 @@ lock_rec_create(
lock->un_member.rec_lock.space = space; lock->un_member.rec_lock.space = space;
lock->un_member.rec_lock.page_no = page_no; lock->un_member.rec_lock.page_no = page_no;
lock->un_member.rec_lock.n_bits = n_bytes * 8; lock->un_member.rec_lock.n_bits = n_bytes * 8;
rec_fold = lock_rec_fold(space, page_no);
/* Reset to zero the bitmap which resides immediately after the /* Reset to zero the bitmap which resides immediately after the
lock struct */ lock struct */
@@ -2251,13 +2348,27 @@ lock_rec_create(
return(lock); return(lock);
} }
trx_mutex_exit(c_lock->trx); trx_mutex_exit(c_lock->trx);
} else if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
if (wait_lock) {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} else { } else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, lock_rec_insert_to_head(lock, rec_fold);
lock_rec_fold(space, page_no), lock); }
} else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} }
#else #else
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
lock_rec_fold(space, page_no), lock); && !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
if (wait_lock) {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
} else {
lock_rec_insert_to_head(lock, rec_fold);
}
} else {
HASH_INSERT(lock_t, hash, lock_sys->rec_hash, rec_fold, lock);
}
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
lock_sys->rec_num++; lock_sys->rec_num++;
@@ -2316,6 +2427,9 @@ lock_rec_enqueue_waiting(
trx_id_t victim_trx_id; trx_id_t victim_trx_id;
ulint sec; ulint sec;
ulint ms; ulint ms;
ulint space;
ulint page_no;
dberr_t err;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
@@ -2390,16 +2504,8 @@ lock_rec_enqueue_waiting(
transaction as a victim, it is possible that we transaction as a victim, it is possible that we
already have the lock now granted! */ already have the lock now granted! */
return(DB_SUCCESS_LOCKED_REC); err = DB_SUCCESS_LOCKED_REC;
} } else {
// Move it only when it does not cause a deadlock.
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS) {
HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(buf_block_get_space(block), buf_block_get_page_no(block)), lock);
lock_rec_insert_by_trx_age(lock, true);
}
trx->lock.que_state = TRX_QUE_LOCK_WAIT; trx->lock.que_state = TRX_QUE_LOCK_WAIT;
trx->lock.was_chosen_as_deadlock_victim = FALSE; trx->lock.was_chosen_as_deadlock_victim = FALSE;
@@ -2424,7 +2530,25 @@ lock_rec_enqueue_waiting(
trx->n_rec_lock_waits++; trx->n_rec_lock_waits++;
return(DB_LOCK_WAIT); err = DB_LOCK_WAIT;
}
// Move it only when it does not cause a deadlock.
if (err != DB_DEADLOCK
&& innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_VATS
&& !thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
space = buf_block_get_space(block);
page_no = buf_block_get_page_no(block);
HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
lock_rec_fold(space, page_no), lock);
dberr_t res = lock_rec_insert_by_trx_age(lock);
if (res != DB_SUCCESS) {
return res;
}
}
return err;
} }
/*********************************************************************//** /*********************************************************************//**
@@ -2856,13 +2980,16 @@ static
void void
lock_grant( lock_grant(
/*=======*/ /*=======*/
lock_t* lock) /*!< in/out: waiting lock request */ lock_t* lock, /*!< in/out: waiting lock request */
bool owns_trx_mutex) /*!< in: whether lock->trx->mutex is owned */
{ {
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
lock_reset_lock_and_trx_wait(lock); lock_reset_lock_and_trx_wait(lock);
if (!owns_trx_mutex) {
trx_mutex_enter(lock->trx); trx_mutex_enter(lock->trx);
}
if (lock_get_mode(lock) == LOCK_AUTO_INC) { if (lock_get_mode(lock) == LOCK_AUTO_INC) {
dict_table_t* table = lock->un_member.tab_lock.table; dict_table_t* table = lock->un_member.tab_lock.table;
@@ -2911,8 +3038,10 @@ lock_grant(
lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time); lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time);
if (!owns_trx_mutex) {
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
}
/*************************************************************//** /*************************************************************//**
Cancels a waiting record lock request and releases the waiting transaction Cancels a waiting record lock request and releases the waiting transaction
@@ -2949,23 +3078,62 @@ lock_rec_cancel(
trx_mutex_exit(lock->trx); trx_mutex_exit(lock->trx);
} }
/*************************************************************//**
Move the lock to the head of the hash list. */
static static
void void
lock_rec_move_to_front( lock_grant_and_move_on_page(
lock_t *lock_to_move, /*!< in: lock to be moved */ ulint space,
ulint rec_fold) /*!< in: rec fold of the lock */ ulint page_no)
{ {
if (lock_to_move != NULL) lock_t* lock;
{ lock_t* next;
// Move the target lock to the head of the list lock_t* previous;
hash_cell_t* cell = hash_get_nth_cell(lock_sys->rec_hash, ulint rec_fold = lock_rec_fold(space, page_no);
hash_calc_hash(rec_fold, lock_sys->rec_hash));
if (lock_to_move != cell->node) { previous = (lock_t *) hash_get_nth_cell(lock_sys->rec_hash,
lock_t *next = (lock_t *) cell->node; hash_calc_hash(rec_fold, lock_sys->rec_hash))->node;
cell->node = lock_to_move; if (previous == NULL) {
lock_to_move->hash = next; return;
}
if (previous->un_member.rec_lock.space == space &&
previous->un_member.rec_lock.page_no == page_no) {
lock = previous;
}
else {
next = (lock_t *) previous->hash;
while (next &&
(next->un_member.rec_lock.space != space ||
next->un_member.rec_lock.page_no != page_no)) {
previous = next;
next = (lock_t *) previous->hash;
}
lock = (lock_t *) previous->hash;
}
ut_ad(previous->hash == lock || previous == lock);
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock, false);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
} }
} }
} }
@@ -2987,9 +3155,7 @@ lock_rec_dequeue_from_page(
{ {
ulint space; ulint space;
ulint page_no; ulint page_no;
ulint rec_fold;
lock_t* lock; lock_t* lock;
lock_t* previous = NULL;
trx_lock_t* trx_lock; trx_lock_t* trx_lock;
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
@@ -3000,7 +3166,6 @@ lock_rec_dequeue_from_page(
space = in_lock->un_member.rec_lock.space; space = in_lock->un_member.rec_lock.space;
page_no = in_lock->un_member.rec_lock.page_no; page_no = in_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
in_lock->index->table->n_rec_locks--; in_lock->index->table->n_rec_locks--;
@@ -3013,7 +3178,9 @@ lock_rec_dequeue_from_page(
MONITOR_INC(MONITOR_RECLOCK_REMOVED); MONITOR_INC(MONITOR_RECLOCK_REMOVED);
MONITOR_DEC(MONITOR_NUM_RECLOCK); MONITOR_DEC(MONITOR_NUM_RECLOCK);
if (innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS) { if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(in_lock->trx->mysql_thd)) {
/* Check if waiting locks in the queue can now be granted: grant /* Check if waiting locks in the queue can now be granted: grant
locks if there are no conflicting locks ahead. Stop at the first locks if there are no conflicting locks ahead. Stop at the first
X lock that is waiting or has been granted. */ X lock that is waiting or has been granted. */
@@ -3027,38 +3194,11 @@ lock_rec_dequeue_from_page(
/* Grant the lock */ /* Grant the lock */
ut_ad(lock->trx != in_lock->trx); ut_ad(lock->trx != in_lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} else { } else {
/* Grant locks if there are no conflicting locks ahead. lock_grant_and_move_on_page(space, page_no);
Move granted locks to the head of the list. */
for (lock = lock_rec_get_first_on_page_addr(space, page_no);
lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if ((lock->un_member.rec_lock.space == space)
&& (lock->un_member.rec_lock.page_no == page_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_move_to_front(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
} }
} }
@@ -5370,12 +5510,71 @@ lock_table_dequeue(
/* Grant the lock */ /* Grant the lock */
ut_ad(in_lock->trx != lock->trx); ut_ad(in_lock->trx != lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} }
/*=========================== LOCK RELEASE ==============================*/ /*=========================== LOCK RELEASE ==============================*/
static
void
lock_grant_and_move_on_rec(
lock_t* first_lock,
ulint heap_no)
{
lock_t* lock;
lock_t* previous;
ulint space;
ulint page_no;
ulint rec_fold;
space = first_lock->un_member.rec_lock.space;
page_no = first_lock->un_member.rec_lock.page_no;
rec_fold = lock_rec_fold(space, page_no);
previous = (lock_t *) hash_get_nth_cell(lock_sys->rec_hash,
hash_calc_hash(rec_fold, lock_sys->rec_hash))->node;
if (previous == NULL) {
return;
}
if (previous == first_lock) {
lock = previous;
} else {
while (previous->hash &&
previous->hash != first_lock) {
previous = (lock_t *) previous->hash;
}
lock = (lock_t *) previous->hash;
}
/* Grant locks if there are no conflicting locks ahead.
Move granted locks to the head of the list. */
for (;lock != NULL;) {
/* If the lock is a wait lock on this page, and it does not need to wait. */
if (lock->un_member.rec_lock.space == space
&& lock->un_member.rec_lock.page_no == page_no
&& lock_rec_get_nth_bit(lock, heap_no)
&& lock_get_wait(lock)
&& !lock_rec_has_to_wait_in_queue(lock)) {
lock_grant(lock, false);
if (previous != NULL) {
/* Move the lock to the head of the list. */
HASH_GET_NEXT(hash, previous) = HASH_GET_NEXT(hash, lock);
lock_rec_insert_to_head(lock, rec_fold);
} else {
/* Already at the head of the list. */
previous = lock;
}
/* Move on to the next lock. */
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, previous));
} else {
previous = lock;
lock = static_cast<lock_t *>(HASH_GET_NEXT(hash, lock));
}
}
}
/*************************************************************//** /*************************************************************//**
Removes a granted record lock of a transaction from the queue and grants Removes a granted record lock of a transaction from the queue and grants
@@ -5439,6 +5638,10 @@ released:
ut_a(!lock_get_wait(lock)); ut_a(!lock_get_wait(lock));
lock_rec_reset_nth_bit(lock, heap_no); lock_rec_reset_nth_bit(lock, heap_no);
if (innodb_lock_schedule_algorithm
== INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
thd_is_replication_slave_thread(lock->trx->mysql_thd)) {
/* Check if we can now grant waiting lock requests */ /* Check if we can now grant waiting lock requests */
for (lock = first_lock; lock != NULL; for (lock = first_lock; lock != NULL;
@@ -5448,9 +5651,12 @@ released:
/* Grant the lock */ /* Grant the lock */
ut_ad(trx != lock->trx); ut_ad(trx != lock->trx);
lock_grant(lock); lock_grant(lock, false);
} }
} }
} else {
lock_grant_and_move_on_rec(first_lock, heap_no);
}
lock_mutex_exit(); lock_mutex_exit();
trx_mutex_exit(trx); trx_mutex_exit(trx);
@@ -6505,6 +6711,9 @@ lock_rec_queue_validate(
} }
} }
ut_ad(innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS ||
lock_queue_validate(lock));
func_exit: func_exit:
if (!locked_lock_trx_sys) { if (!locked_lock_trx_sys) {
lock_mutex_exit(); lock_mutex_exit();

View File

@@ -1117,6 +1117,8 @@ trx_start_low(
trx->start_time = ut_time(); trx->start_time = ut_time();
trx->start_time_micro = clock();
MONITOR_INC(MONITOR_TRX_ACTIVE); MONITOR_INC(MONITOR_TRX_ACTIVE);
} }