From 627e7334ec8b9528a4e1f93916cefe7980eabdac Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Tue, 7 May 2013 13:30:25 +0530 Subject: [PATCH] Bug#16513588:"PREPARE_COMMIT_MUTEX" IS NOT FREED DURING TRANSACTION ROLLBACK Problem: ======= "prepare_commit_mutex" is acquired during "innobase_xa_prepare" and it is freed only in "innobase_commit". After prepare, if the commit operation fails the transaction is rolled back but the mutex is not released. Analysis: ======== During transaction commit process transaction is prepared and the "prepare_commit_mutex" is acquired to preserve the order of commit. After prepare write to binlog is initiated. File: sql/handler.cc if (error || (is_real_trans && xid && -----> (error= !(cookie= tc_log->log_xid(thd, xid))))) { ha_rollback_trans(thd, all); In the above code "tc_log->log_xid" operation fails. When the write to binlog fails the transaction is rolled back with out freeing the mutex. A subsequent "INSERT" operation tries to acquire the same mutex during its commit process and the server aborts. Fix: === "prepare_commit_mutex" is freed during "innobase_rollback". --- storage/innobase/handler/ha_innodb.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5df84d7cd04..7f610854a8e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2881,6 +2881,9 @@ innobase_rollback( || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { error = trx_rollback_for_mysql(trx); + if (trx_has_prepare_commit_mutex(trx)) { + mysql_mutex_unlock(&prepare_commit_mutex); + } trx_deregister_from_2pc(trx); } else { error = trx_rollback_last_sql_stat_for_mysql(trx);