diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index b485daa2a9c..6fc91c9fa31 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -503,17 +503,35 @@ int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync) return state; } -my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) -{ +my_bool wsrep_thd_is_wsrep(void *thd_ptr) +{ my_bool status = FALSE; - if (thd_ptr) + if (thd_ptr) { THD* thd = (THD*)thd_ptr; - if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd); - - status = ((thd->wsrep_exec_mode == REPL_RECV) || - (thd->wsrep_exec_mode == TOTAL_ORDER)); - if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + + status = (WSREP(thd) && WSREP_PROVIDER_EXISTS); + } + return status; +} + +my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync) +{ + my_bool status = FALSE; + if (thd_ptr) + { + THD* thd = (THD*)thd_ptr; + // THD can be BF only if provider exists + if (wsrep_thd_is_wsrep(thd_ptr)) + { + if (sync) + mysql_mutex_lock(&thd->LOCK_wsrep_thd); + + status = ((thd->wsrep_exec_mode == REPL_RECV) || + (thd->wsrep_exec_mode == TOTAL_ORDER)); + if (sync) + mysql_mutex_unlock(&thd->LOCK_wsrep_thd); + } } return status; } diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index a7e34c35101..700e0f1cc56 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -29,6 +29,8 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); extern my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +extern my_bool wsrep_thd_is_wsrep(void *thd_ptr); + extern int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); //extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync); diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 336ff92a619..563a01f747d 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -294,6 +294,7 @@ wsrep_innobase_kill_one_trx(void *thd_ptr, my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, unsigned int str_length, diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e5c2266ab2f..9787286cbd2 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1075,23 +1075,23 @@ lock_rec_has_to_wait( lock_rec_print(stderr, lock2); } - if (wsrep_trx_order_before(trx->mysql_thd, + if (wsrep_trx_order_before(trx->mysql_thd, lock2->trx->mysql_thd) && (type_mode & LOCK_MODE_MASK) == LOCK_X && (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) { /* exclusive lock conflicts are not accepted */ - fprintf(stderr, "BF-BF X lock conflict," - "type_mode: %lu supremum: %lu\n", + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", type_mode, lock_is_on_supremum); - fprintf(stderr, "conflicts states: my %d locked %d\n", - wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); lock_rec_print(stderr, lock2); return FALSE; //abort(); } else { - /* if lock2->index->n_uniq <= + /* if lock2->index->n_uniq <= lock2->index->n_user_defined_cols operation is on uniq index */ @@ -1101,7 +1101,7 @@ lock_rec_has_to_wait( type_mode, lock2->type_mode, lock2->index->name, lock2->index->table_name, - lock2->index->n_uniq, + lock2->index->n_uniq, lock2->index->n_user_defined_cols); return FALSE; } @@ -1664,8 +1664,12 @@ lock_rec_other_has_expl_req( #endif /* UNIV_DEBUG */ #ifdef WITH_WSREP -static void -wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(lock->trx)); my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); @@ -1674,32 +1678,38 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { if ((bf_this && !bf_other) || (bf_this && bf_other && wsrep_trx_order_before( trx->mysql_thd, lock->trx->mysql_thd))) { - + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (wsrep_debug) + if (wsrep_debug) { fprintf(stderr, "WSREP: BF victim waiting\n"); + } /* cannot release lock, until our lock is in the queue*/ } else if (lock->trx != trx) { if (wsrep_log_conflicts) { mutex_enter(&trx_sys->mutex); - if (bf_this) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, trx, 3000); - if (bf_other) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, lock->trx, 3000); mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", stderr); @@ -1709,6 +1719,7 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { lock_table_print(stderr, lock); } } + wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); } @@ -2038,7 +2049,6 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { lock_t *hash = (lock_t *)c_lock->hash; lock_t *prev = NULL; @@ -2066,7 +2076,9 @@ lock_rec_create( c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - if (wsrep_debug) wsrep_print_wait_locks(c_lock); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } trx->lock.que_state = TRX_QUE_LOCK_WAIT; lock_set_lock_and_trx_wait(lock, trx); @@ -2080,10 +2092,15 @@ lock_rec_create( victim lock release. This will eventually call lock_grant, which wants to grant trx mutex again */ - if (caller_owns_trx_mutex) trx_mutex_exit(trx); + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } lock_cancel_waiting_and_release( c_lock->trx->lock.wait_lock); - if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } /* trx might not wait for c_lock, but some other lock does not matter if wait_lock was released above @@ -2091,12 +2108,15 @@ lock_rec_create( if (c_lock->trx->lock.wait_lock == c_lock) { lock_reset_lock_and_trx_wait(lock); } + trx_mutex_exit(c_lock->trx); - if (wsrep_debug) fprintf( - stderr, - "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } /* have to bail out here to avoid lock_set_lock... */ return(lock); @@ -2310,7 +2330,7 @@ lock_rec_add_to_queue( block, heap_no, trx); #ifdef WITH_WSREP /* this can potentionally assert with wsrep */ - if (wsrep_on(trx->mysql_thd)) { + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { if (wsrep_debug && other_lock) { fprintf(stderr, "WSREP: InnoDB assert ignored\n"); @@ -2351,8 +2371,8 @@ lock_rec_add_to_queue( #ifdef WITH_WSREP if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { if (wsrep_debug) { - fprintf(stderr, - "BF skipping wait: %lu\n", + fprintf(stderr, + "BF skipping wait: %lu\n", trx->id); lock_rec_print(stderr, lock); } @@ -2555,8 +2575,8 @@ lock_rec_lock_slow( /* c_lock is NULL here if jump to enqueue_waiting happened but it's ok because lock is not NULL in that case and c_lock is not used. */ - err= - lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); #else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); @@ -4058,19 +4078,21 @@ lock_deadlock_select_victim( choose it as the victim and roll it back. */ #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) - return(ctx->wait_lock->trx); - else + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else #endif /* WITH_WSREP */ - return(ctx->start); + return(ctx->start); } #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { return(ctx->start); + } else #endif /* WITH_WSREP */ - return(ctx->wait_lock->trx); + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -4201,12 +4223,13 @@ lock_deadlock_search( ctx->too_deep = TRUE; #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { return(ctx->wait_lock->trx->id); + } else #endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else { /* We do not need to report autoinc locks to the upper @@ -4528,42 +4551,54 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - UT_LIST_INSERT_AFTER( - un_member.tab_lock.locks, table->locks, c_lock, lock); - } else { - UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); - } - - if (c_lock) trx_mutex_enter(c_lock->trx); - if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - - if (wsrep_debug) wsrep_print_wait_locks(c_lock); - - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - /* caller has trx_mutex, have to release for lock cancel */ - trx_mutex_exit(trx); - lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); - trx_mutex_enter(trx); - - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - lock_reset_lock_and_trx_wait(lock); + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (wsrep_debug) { - fprintf(stderr, "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (c_lock) { + trx_mutex_enter(c_lock->trx); } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (c_lock) trx_mutex_exit(c_lock->trx); #else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); #endif /* WITH_WSREP */ @@ -4850,11 +4885,15 @@ lock_table_other_has_incompatible( && (wait || !lock_get_wait(lock))) { #ifdef WITH_WSREP - if (wsrep_debug) - fprintf(stderr, "WSREP: table lock abort"); - trx_mutex_enter(lock->trx); - wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); - trx_mutex_exit(lock->trx); + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } #endif return(lock); @@ -6110,15 +6149,17 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - enum lock_mode mode; + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx)); } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx)); #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 4f2305f9ff6..f78be55fa5f 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -10371,11 +10371,10 @@ ha_innobase::wsrep_append_keys( uint len; char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; char *key = &keyval[0]; - KEY *key_info = table->key_info; ibool is_null; len = wsrep_store_key_val_for_row( - thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, + thd, table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH, record0, &is_null); if (!is_null) { @@ -18218,34 +18217,34 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, if (!thd) { DBUG_PRINT("wsrep", ("no thd for conflicting lock")); - WSREP_WARN("no THD for trx: %llu", victim_trx->id); + WSREP_WARN("no THD for trx: %lu", victim_trx->id); DBUG_RETURN(1); } if (!bf_thd) { DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); - WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0); + WSREP_WARN("no BF THD for trx: %lu", (bf_trx) ? bf_trx->id : 0); DBUG_RETURN(1); } WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); - WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu", + WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu", signal, (long long)bf_seqno, wsrep_thd_thread_id(thd), victim_trx->id); - WSREP_DEBUG("Aborting query: %s", + WSREP_DEBUG("Aborting query: %s", (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void"); wsrep_thd_LOCK(thd); if (wsrep_thd_query_state(thd) == QUERY_EXITING) { - WSREP_DEBUG("kill trx EXITING for %llu", victim_trx->id); + WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); } if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) { - WSREP_DEBUG("withdraw for BF trx: %llu, state: %d", + WSREP_DEBUG("withdraw for BF trx: %lu, state: %d", victim_trx->id, wsrep_thd_conflict_state(thd)); } @@ -18255,7 +18254,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_thd_set_conflict_state(thd, MUST_ABORT); break; case MUST_ABORT: - WSREP_DEBUG("victim %llu in MUST ABORT state", + WSREP_DEBUG("victim %lu in MUST ABORT state", victim_trx->id); wsrep_thd_UNLOCK(thd); wsrep_thd_awake(thd, signal); @@ -18264,7 +18263,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, case ABORTED: case ABORTING: // fall through default: - WSREP_DEBUG("victim %llu in state %d", + WSREP_DEBUG("victim %lu in state %d", victim_trx->id, wsrep_thd_conflict_state(thd)); wsrep_thd_UNLOCK(thd); DBUG_RETURN(0); @@ -18277,7 +18276,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, WSREP_DEBUG("kill query for: %ld", wsrep_thd_thread_id(thd)); - WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu", + WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu", victim_trx->id); if (wsrep_thd_exec_mode(thd) == REPL_RECV) { @@ -18291,7 +18290,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, switch (rcode) { case WSREP_WARNING: - WSREP_DEBUG("cancel commit warning: %llu", + WSREP_DEBUG("cancel commit warning: %lu", victim_trx->id); wsrep_thd_UNLOCK(thd); wsrep_thd_awake(thd, signal); @@ -18301,8 +18300,8 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, break; default: WSREP_ERROR( - "cancel commit bad exit: %d %llu", - rcode, + "cancel commit bad exit: %d %lu", + rcode, victim_trx->id); /* unable to interrupt, must abort */ /* note: kill_mysql() will block, if we cannot. @@ -18316,10 +18315,10 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_thd_awake(thd, signal); break; case QUERY_EXEC: - /* it is possible that victim trx is itself waiting for some + /* it is possible that victim trx is itself waiting for some * other lock. We need to cancel this waiting */ - WSREP_DEBUG("kill trx QUERY_EXEC for %llu", victim_trx->id); + WSREP_DEBUG("kill trx QUERY_EXEC for %lu", victim_trx->id); victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; if (victim_trx->lock.wait_lock) { @@ -18336,7 +18335,7 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, wsrep_thd_awake(thd, signal); } else { /* abort currently executing query */ - DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", + DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld", wsrep_thd_thread_id(thd))); WSREP_DEBUG("kill query for: %ld", wsrep_thd_thread_id(thd)); @@ -18356,8 +18355,8 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, { bool skip_abort= false; wsrep_aborting_thd_t abortees; - - WSREP_DEBUG("kill IDLE for %llu", victim_trx->id); + + WSREP_DEBUG("kill IDLE for %lu", victim_trx->id); if (wsrep_thd_exec_mode(thd) == REPL_RECV) { WSREP_DEBUG("kill BF IDLE, seqno: %lld", @@ -18377,14 +18376,14 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, /* check if we have a kill message for this already */ if (abortees->aborting_thd == thd) { skip_abort = true; - WSREP_WARN("duplicate thd aborter %lu", + WSREP_WARN("duplicate thd aborter %lu", wsrep_thd_thread_id(thd)); } abortees = abortees->next; } if (!skip_abort) { wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t) - my_malloc(sizeof(struct wsrep_aborting_thd), + my_malloc(sizeof(struct wsrep_aborting_thd), MYF(0)); aborting->aborting_thd = thd; aborting->next = wsrep_aborting_thd; @@ -18404,22 +18403,22 @@ wsrep_innobase_kill_one_trx(void * const bf_thd_ptr, break; } default: - WSREP_WARN("bad wsrep query state: %d", + WSREP_WARN("bad wsrep query state: %d", wsrep_thd_query_state(thd)); wsrep_thd_UNLOCK(thd); break; } - + DBUG_RETURN(0); } static int -wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, +wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, my_bool signal) { DBUG_ENTER("wsrep_innobase_abort_thd"); trx_t* victim_trx = thd_to_trx(victim_thd); trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; - WSREP_DEBUG("abort transaction: BF: %s victim: %s", + WSREP_DEBUG("abort transaction: BF: %s victim: %s", wsrep_thd_query(bf_thd), wsrep_thd_query(victim_thd)); @@ -18439,7 +18438,7 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, wsrep_thd_LOCK(victim_thd); wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT); wsrep_thd_UNLOCK(victim_thd); - wsrep_thd_awake(victim_thd, signal); + wsrep_thd_awake(victim_thd, signal); } DBUG_RETURN(-1); } diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 1dd109eb940..4ebaee3c89e 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -293,6 +293,7 @@ wsrep_innobase_kill_one_trx(void *thd_ptr, my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe); int wsrep_thd_conflict_state(void *thd_ptr, my_bool sync); my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync); +my_bool wsrep_thd_is_wsrep(void *thd_ptr); int wsrep_trx_order_before(void *thd1, void *thd2); int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, unsigned int str_length, diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 645bad7f26c..202bed9fb88 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -1076,23 +1076,23 @@ lock_rec_has_to_wait( lock_rec_print(stderr, lock2); } - if (wsrep_trx_order_before(trx->mysql_thd, + if (wsrep_trx_order_before(trx->mysql_thd, lock2->trx->mysql_thd) && (type_mode & LOCK_MODE_MASK) == LOCK_X && (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) { /* exclusive lock conflicts are not accepted */ - fprintf(stderr, "BF-BF X lock conflict," - "type_mode: %lu supremum: %lu\n", + fprintf(stderr, "BF-BF X lock conflict," + "type_mode: %lu supremum: %lu\n", type_mode, lock_is_on_supremum); - fprintf(stderr, "conflicts states: my %d locked %d\n", - wsrep_thd_conflict_state(trx->mysql_thd, FALSE), + fprintf(stderr, "conflicts states: my %d locked %d\n", + wsrep_thd_conflict_state(trx->mysql_thd, FALSE), wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE) ); lock_rec_print(stderr, lock2); return FALSE; //abort(); } else { - /* if lock2->index->n_uniq <= + /* if lock2->index->n_uniq <= lock2->index->n_user_defined_cols operation is on uniq index */ @@ -1102,7 +1102,7 @@ lock_rec_has_to_wait( type_mode, lock2->type_mode, lock2->index->name, lock2->index->table_name, - lock2->index->n_uniq, + lock2->index->n_uniq, lock2->index->n_user_defined_cols); return FALSE; } @@ -1663,8 +1663,12 @@ lock_rec_other_has_expl_req( #endif /* UNIV_DEBUG */ #ifdef WITH_WSREP -static void -wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { +static +void +wsrep_kill_victim( + const trx_t * const trx, + const lock_t *lock) +{ ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(lock->trx)); my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); @@ -1673,32 +1677,38 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { if ((bf_this && !bf_other) || (bf_this && bf_other && wsrep_trx_order_before( trx->mysql_thd, lock->trx->mysql_thd))) { - + if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - if (wsrep_debug) + if (wsrep_debug) { fprintf(stderr, "WSREP: BF victim waiting\n"); + } /* cannot release lock, until our lock is in the queue*/ } else if (lock->trx != trx) { if (wsrep_log_conflicts) { mutex_enter(&trx_sys->mutex); - if (bf_this) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_this) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, trx, 3000); - if (bf_other) - fputs("\n*** Priority TRANSACTION:\n", + if (bf_other) { + fputs("\n*** Priority TRANSACTION:\n", stderr); - else - fputs("\n*** Victim TRANSACTION:\n", + } else { + fputs("\n*** Victim TRANSACTION:\n", stderr); + } + trx_print_latched(stderr, lock->trx, 3000); mutex_exit(&trx_sys->mutex); + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", stderr); @@ -1708,6 +1718,7 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) { lock_table_print(stderr, lock); } } + wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); } @@ -2049,7 +2060,6 @@ lock_rec_create( ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { lock_t *hash = (lock_t *)c_lock->hash; lock_t *prev = NULL; @@ -2077,7 +2087,9 @@ lock_rec_create( c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - if (wsrep_debug) wsrep_print_wait_locks(c_lock); + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + } trx->lock.que_state = TRX_QUE_LOCK_WAIT; lock_set_lock_and_trx_wait(lock, trx); @@ -2091,10 +2103,15 @@ lock_rec_create( victim lock release. This will eventually call lock_grant, which wants to grant trx mutex again */ - if (caller_owns_trx_mutex) trx_mutex_exit(trx); + if (caller_owns_trx_mutex) { + trx_mutex_exit(trx); + } lock_cancel_waiting_and_release( c_lock->trx->lock.wait_lock); - if (caller_owns_trx_mutex) trx_mutex_enter(trx); + + if (caller_owns_trx_mutex) { + trx_mutex_enter(trx); + } /* trx might not wait for c_lock, but some other lock does not matter if wait_lock was released above @@ -2102,12 +2119,15 @@ lock_rec_create( if (c_lock->trx->lock.wait_lock == c_lock) { lock_reset_lock_and_trx_wait(lock); } + trx_mutex_exit(c_lock->trx); - if (wsrep_debug) fprintf( - stderr, - "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (wsrep_debug) { + fprintf( + stderr, + "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } /* have to bail out here to avoid lock_set_lock... */ return(lock); @@ -2331,7 +2351,7 @@ lock_rec_add_to_queue( block, heap_no, trx->id); #ifdef WITH_WSREP /* this can potentionally assert with wsrep */ - if (wsrep_on(trx->mysql_thd)) { + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { if (wsrep_debug && other_lock) { fprintf(stderr, "WSREP: InnoDB assert ignored\n"); @@ -2372,8 +2392,8 @@ lock_rec_add_to_queue( #ifdef WITH_WSREP if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { if (wsrep_debug) { - fprintf(stderr, - "BF skipping wait: %lu\n", + fprintf(stderr, + "BF skipping wait: %lu\n", trx->id); lock_rec_print(stderr, lock); } @@ -2578,8 +2598,8 @@ lock_rec_lock_slow( /* c_lock is NULL here if jump to enqueue_waiting happened but it's ok because lock is not NULL in that case and c_lock is not used. */ - err= - lock_rec_enqueue_waiting(c_lock, mode, block, heap_no, index, thr); + err = lock_rec_enqueue_waiting(c_lock, + mode, block, heap_no, index, thr); #else err = lock_rec_enqueue_waiting( mode, block, heap_no, index, thr); @@ -4083,19 +4103,21 @@ lock_deadlock_select_victim( choose it as the victim and roll it back. */ #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) - return(ctx->wait_lock->trx); - else + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { + return(ctx->wait_lock->trx); + } + else #endif /* WITH_WSREP */ - return(ctx->start); + return(ctx->start); } #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->wait_lock->trx->mysql_thd, TRUE)) { return(ctx->start); + } else #endif /* WITH_WSREP */ - return(ctx->wait_lock->trx); + return(ctx->wait_lock->trx); } /********************************************************************//** @@ -4226,12 +4248,13 @@ lock_deadlock_search( ctx->too_deep = TRUE; #ifdef WITH_WSREP - if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) + if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) { return(ctx->wait_lock->trx->id); + } else #endif /* WITH_WSREP */ /* Select the joining transaction as the victim. */ - return(ctx->start->id); + return(ctx->start->id); } else { /* We do not need to report autoinc locks to the upper @@ -4555,42 +4578,54 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { - UT_LIST_INSERT_AFTER( - un_member.tab_lock.locks, table->locks, c_lock, lock); - } else { - UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); - } - - if (c_lock) trx_mutex_enter(c_lock->trx); - if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { - - c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; - - if (wsrep_debug) wsrep_print_wait_locks(c_lock); - - /* have to release trx mutex for the duration of - victim lock release. This will eventually call - lock_grant, which wants to grant trx mutex again - */ - /* caller has trx_mutex, have to release for lock cancel */ - trx_mutex_exit(trx); - lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); - trx_mutex_enter(trx); - - /* trx might not wait for c_lock, but some other lock - does not matter if wait_lock was released above - */ - if (c_lock->trx->lock.wait_lock == c_lock) { - lock_reset_lock_and_trx_wait(lock); + if (wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + UT_LIST_INSERT_AFTER( + un_member.tab_lock.locks, table->locks, c_lock, lock); + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (wsrep_debug) { - fprintf(stderr, "WSREP: c_lock canceled %llu\n", - (ulonglong) c_lock->trx->id); + if (c_lock) { + trx_mutex_enter(c_lock->trx); } + + if (c_lock && c_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + + c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; + + if (wsrep_debug) { + wsrep_print_wait_locks(c_lock); + wsrep_print_wait_locks(c_lock->trx->lock.wait_lock); + } + + /* have to release trx mutex for the duration of + victim lock release. This will eventually call + lock_grant, which wants to grant trx mutex again + */ + /* caller has trx_mutex, have to release for lock cancel */ + trx_mutex_exit(trx); + lock_cancel_waiting_and_release(c_lock->trx->lock.wait_lock); + trx_mutex_enter(trx); + + /* trx might not wait for c_lock, but some other lock + does not matter if wait_lock was released above + */ + if (c_lock->trx->lock.wait_lock == c_lock) { + lock_reset_lock_and_trx_wait(lock); + } + + if (wsrep_debug) { + fprintf(stderr, "WSREP: c_lock canceled %llu\n", + (ulonglong) c_lock->trx->id); + } + } + if (c_lock) { + trx_mutex_exit(c_lock->trx); + } + } else { + UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); } - if (c_lock) trx_mutex_exit(c_lock->trx); #else UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); #endif /* WITH_WSREP */ @@ -4884,11 +4919,15 @@ lock_table_other_has_incompatible( && (wait || !lock_get_wait(lock))) { #ifdef WITH_WSREP - if (wsrep_debug) - fprintf(stderr, "WSREP: table lock abort"); - trx_mutex_enter(lock->trx); - wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); - trx_mutex_exit(lock->trx); + if(wsrep_thd_is_wsrep(trx->mysql_thd)) { + if (wsrep_debug) { + fprintf(stderr, "WSREP: trx %ld table lock abort\n", + trx->id); + } + trx_mutex_enter(lock->trx); + wsrep_kill_victim((trx_t *)trx, (lock_t *)lock); + trx_mutex_exit(lock->trx); + } #endif return(lock); @@ -6158,15 +6197,17 @@ lock_rec_queue_validate( if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) { #ifndef WITH_WSREP - enum lock_mode mode; + if (wsrep_thd_is_wsrep(lock->trx->mysql_thd)) { + enum lock_mode mode; - if (lock_get_mode(lock) == LOCK_S) { - mode = LOCK_X; - } else { - mode = LOCK_S; + if (lock_get_mode(lock) == LOCK_S) { + mode = LOCK_X; + } else { + mode = LOCK_S; + } + ut_a(!lock_rec_other_has_expl_req( + mode, 0, 0, block, heap_no, lock->trx)); } - ut_a(!lock_rec_other_has_expl_req( - mode, 0, 0, block, heap_no, lock->trx)); #endif /* WITH_WSREP */ } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {