summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/handler/ha_innodb.cc79
-rw-r--r--storage/innobase/include/lock0lock.h5
-rw-r--r--storage/innobase/lock/lock0lock.cc46
3 files changed, 95 insertions, 35 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 4440fe62fa5..7ffbe3fe374 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -18075,41 +18075,53 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
{
bool aborting= false;
wsrep_thd_LOCK(vthd);
- if (trx_t *vtrx= thd_to_trx(vthd))
+ trx_t *vtrx= thd_to_trx(vthd);
+ if (vtrx)
{
lock_sys.wr_lock(SRW_LOCK_CALL);
mysql_mutex_lock(&lock_sys.wait_mutex);
vtrx->mutex_lock();
- if (vtrx->id == trx_id && vtrx->state == TRX_STATE_ACTIVE)
+ /* victim transaction is either active or prepared, if it has already
+ proceeded to replication phase */
+ if (vtrx->id == trx_id)
{
- WSREP_LOG_CONFLICT(bf_thd, vthd, TRUE);
- WSREP_DEBUG("Aborter BF trx_id: " TRX_ID_FMT " thread: %ld "
- "seqno: %lld client_state: %s "
- "client_mode: %s transaction_mode: %s query: %s",
- bf_trx->id,
- thd_get_thread_id(bf_thd),
- wsrep_thd_trx_seqno(bf_thd),
- wsrep_thd_client_state_str(bf_thd),
- wsrep_thd_client_mode_str(bf_thd),
- wsrep_thd_transaction_state_str(bf_thd),
- wsrep_thd_query(bf_thd));
- WSREP_DEBUG("Victim %s trx_id: " TRX_ID_FMT " thread: %ld "
- "seqno: %lld client_state: %s "
- "client_mode: %s transaction_mode: %s query: %s",
- wsrep_thd_is_BF(vthd, false) ? "BF" : "normal",
- vtrx->id,
- thd_get_thread_id(vthd),
- wsrep_thd_trx_seqno(vthd),
- wsrep_thd_client_state_str(vthd),
- wsrep_thd_client_mode_str(vthd),
- wsrep_thd_transaction_state_str(vthd),
- wsrep_thd_query(vthd));
- /* Mark transaction as a victim for Galera abort */
- vtrx->lock.was_chosen_as_deadlock_victim.fetch_or(2);
- if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd))
- aborting= true;
- else
- WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set");
+ switch (vtrx->state) {
+ default:
+ break;
+ case TRX_STATE_PREPARED:
+ if (!wsrep_is_wsrep_xid(vtrx->xid))
+ break;
+ /* fall through */
+ case TRX_STATE_ACTIVE:
+ WSREP_LOG_CONFLICT(bf_thd, vthd, TRUE);
+ WSREP_DEBUG("Aborter BF trx_id: " TRX_ID_FMT " thread: %ld "
+ "seqno: %lld client_state: %s "
+ "client_mode: %s transaction_mode: %s query: %s",
+ bf_trx->id,
+ thd_get_thread_id(bf_thd),
+ wsrep_thd_trx_seqno(bf_thd),
+ wsrep_thd_client_state_str(bf_thd),
+ wsrep_thd_client_mode_str(bf_thd),
+ wsrep_thd_transaction_state_str(bf_thd),
+ wsrep_thd_query(bf_thd));
+ WSREP_DEBUG("Victim %s trx_id: " TRX_ID_FMT " thread: %ld "
+ "seqno: %lld client_state: %s "
+ "client_mode: %s transaction_mode: %s query: %s",
+ wsrep_thd_is_BF(vthd, false) ? "BF" : "normal",
+ vtrx->id,
+ thd_get_thread_id(vthd),
+ wsrep_thd_trx_seqno(vthd),
+ wsrep_thd_client_state_str(vthd),
+ wsrep_thd_client_mode_str(vthd),
+ wsrep_thd_transaction_state_str(vthd),
+ wsrep_thd_query(vthd));
+ /* Mark transaction as a victim for Galera abort */
+ vtrx->lock.was_chosen_as_deadlock_victim.fetch_or(2);
+ if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd))
+ aborting= true;
+ else
+ WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set");
+ }
}
lock_sys.wr_unlock();
mysql_mutex_unlock(&lock_sys.wait_mutex);
@@ -18118,6 +18130,11 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
wsrep_thd_UNLOCK(vthd);
if (aborting)
{
+ /* if victim is waiting for some other lock, we have to cancel
+ that waiting
+ */
+ lock_sys.cancel_lock_wait_for_trx(vtrx);
+
DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
wsrep_thd_bf_abort(bf_thd, vthd, true);
}
@@ -18146,7 +18163,7 @@ wsrep_abort_transaction(
ut_ad(bf_thd);
ut_ad(victim_thd);
- trx_t* victim_trx = thd_to_trx(victim_thd);
+ trx_t* victim_trx= thd_to_trx(victim_thd);
WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
wsrep_thd_query(bf_thd),
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 8e38b99c121..b96f54e03a3 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -859,6 +859,11 @@ public:
@param id page to be discarded
@param page whether to discard also from lock_sys.prdt_hash */
void prdt_page_free_from_discard(const page_id_t id, bool all= false);
+
+#ifdef WITH_WSREP
+ /** Cancel possible lock waiting for a transaction */
+ static void cancel_lock_wait_for_trx(trx_t *trx);
+#endif /* WITH_WSREP */
};
/** The lock system */
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 756902690c2..62582e61b0b 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -921,8 +921,13 @@ func_exit:
dict_table_t *table= wait_lock->un_member.tab_lock.table;
for (lock_t *lock= UT_LIST_GET_FIRST(table->locks); lock;
lock= UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock))
- if (lock->trx != trx)
+ /* if victim has also BF status, but has earlier seqno, we have to wait */
+ if (lock->trx != trx &&
+ !(wsrep_thd_is_BF(lock->trx->mysql_thd, false) &&
+ wsrep_thd_order_before(lock->trx->mysql_thd, trx->mysql_thd)))
+ {
victims.emplace(lock->trx);
+ }
}
else
{
@@ -936,8 +941,13 @@ func_exit:
if (!lock_rec_get_nth_bit(lock, heap_no))
lock= lock_rec_get_next(heap_no, lock);
do
- if (lock->trx != trx)
+ /* if victim has also BF status, but has earlier seqno, we have to wait */
+ if (lock->trx != trx &&
+ !(wsrep_thd_is_BF(lock->trx->mysql_thd, false) &&
+ wsrep_thd_order_before(lock->trx->mysql_thd, trx->mysql_thd)))
+ {
victims.emplace(lock->trx);
+ }
while ((lock= lock_rec_get_next(heap_no, lock)));
}
}
@@ -5362,6 +5372,21 @@ static void lock_cancel_waiting_and_release(lock_t *lock)
lock_wait_end(trx);
trx->mutex_unlock();
}
+#ifdef WITH_WSREP
+void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
+{
+ lock_sys.wr_lock(SRW_LOCK_CALL);
+ mysql_mutex_lock(&lock_sys.wait_mutex);
+ if (lock_t *lock= trx->lock.wait_lock)
+ {
+ /* check if victim is still waiting */
+ if (lock->is_waiting())
+ lock_cancel_waiting_and_release(lock);
+ }
+ lock_sys.wr_unlock();
+ mysql_mutex_unlock(&lock_sys.wait_mutex);
+}
+#endif /* WITH_WSREP */
/** Cancel a waiting lock request.
@param lock waiting lock request
@@ -5758,8 +5783,15 @@ namespace Deadlock
If current_trx=false, a concurrent commit is protected by both
lock_sys.latch and lock_sys.wait_mutex. */
const undo_no_t trx_weight= TRX_WEIGHT(trx) |
- (trx->mysql_thd && thd_has_edited_nontrans_tables(trx->mysql_thd)
+ (trx->mysql_thd &&
+#ifdef WITH_WSREP
+ (thd_has_edited_nontrans_tables(trx->mysql_thd) ||
+ (trx->is_wsrep() && wsrep_thd_is_BF(trx->mysql_thd, false)))
+#else
+ thd_has_edited_nontrans_tables(trx->mysql_thd)
+#endif /* WITH_WSREP */
? 1ULL << 63 : 0);
+
trx_t *victim= nullptr;
undo_no_t victim_weight= ~0ULL;
unsigned victim_pos= 0, trx_pos= 0;
@@ -5782,7 +5814,13 @@ namespace Deadlock
{
next= next->lock.wait_trx;
const undo_no_t next_weight= TRX_WEIGHT(next) |
- (next->mysql_thd && thd_has_edited_nontrans_tables(next->mysql_thd)
+ (next->mysql_thd &&
+#ifdef WITH_WSREP
+ (thd_has_edited_nontrans_tables(next->mysql_thd) ||
+ (next->is_wsrep() && wsrep_thd_is_BF(next->mysql_thd, false)))
+#else
+ thd_has_edited_nontrans_tables(next->mysql_thd)
+#endif /* WITH_WSREP */
? 1ULL << 63 : 0);
if (next_weight < victim_weight)
{