List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:May 2 2011 9:49am
Subject:bzr commit into mysql-5.1 branch (vasil.dimov:3679)
View as plain text  
#At file:///usr/local/devel/bzrroot/server/mysql-5.1/ based on revid:nirbhay.choubey@stripped

 3679 Vasil Dimov	2011-05-02 [merge]
      Merge mysql-5.1-innodb -> mysql-5.1

    added:
      mysql-test/suite/innodb/r/innodb_bug59410.result
      mysql-test/suite/innodb/r/innodb_bug59641.result
      mysql-test/suite/innodb/t/innodb_bug59410.test
      mysql-test/suite/innodb/t/innodb_bug59641.test
      mysql-test/suite/innodb_plugin/r/innodb_bug59410.result
      mysql-test/suite/innodb_plugin/r/innodb_bug59641.result
      mysql-test/suite/innodb_plugin/t/innodb_bug59410.test
      mysql-test/suite/innodb_plugin/t/innodb_bug59641.test
    modified:
      client/mysqltest.cc
      mysql-test/include/wait_until_disconnected.inc
      sql/sql_class.cc
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/trx0trx.h
      storage/innobase/log/log0log.c
      storage/innobase/trx/trx0trx.c
      storage/innodb_plugin/ChangeLog
      storage/innodb_plugin/handler/ha_innodb.cc
      storage/innodb_plugin/handler/ha_innodb.h
      storage/innodb_plugin/handler/handler0alter.cc
      storage/innodb_plugin/include/trx0trx.h
      storage/innodb_plugin/include/trx0undo.h
      storage/innodb_plugin/log/log0log.c
      storage/innodb_plugin/trx/trx0sys.c
      storage/innodb_plugin/trx/trx0trx.c
      storage/innodb_plugin/trx/trx0undo.c
=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	revid:nirbhay.choubey@stripped
+++ b/client/mysqltest.cc	revid:vasil.dimov@stripped
@@ -4461,13 +4461,14 @@ static int my_kill(int pid, int sig)
   command  called command
 
   DESCRIPTION
-  shutdown [<timeout>]
+  shutdown_server [<timeout>]
 
 */
 
 void do_shutdown_server(struct st_command *command)
 {
-  int timeout=60, pid;
+  long timeout=60;
+  int pid;
   DYNAMIC_STRING ds_pidfile_name;
   MYSQL* mysql = &cur_con->mysql;
   static DYNAMIC_STRING ds_timeout;
@@ -4482,8 +4483,9 @@ void do_shutdown_server(struct st_comman
 
   if (ds_timeout.length)
   {
-    timeout= atoi(ds_timeout.str);
-    if (timeout == 0)
+    char* endptr;
+    timeout= strtol(ds_timeout.str, &endptr, 10);
+    if (*endptr != '\0')
       die("Illegal argument for timeout: '%s'", ds_timeout.str);
   }
   dynstr_free(&ds_timeout);
@@ -4525,7 +4527,7 @@ void do_shutdown_server(struct st_comman
       DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
       DBUG_VOID_RETURN;
     }
-    DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
+    DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout));
     my_sleep(1000000L);
   }
 

=== modified file 'mysql-test/include/wait_until_disconnected.inc'
--- a/mysql-test/include/wait_until_disconnected.inc	revid:nirbhay.choubey@stripped
+++ b/mysql-test/include/wait_until_disconnected.inc	revid:vasil.dimov@stripped
@@ -7,7 +7,7 @@ let $counter= 500;
 let $mysql_errno= 0;
 while (!$mysql_errno)
 {
-  --error 0,1053,2002,2006,2013
+  --error 0,1040,1053,2002,2003,2006,2013
   show status;
 
   dec $counter;

=== added file 'mysql-test/suite/innodb/r/innodb_bug59410.result'
--- a/mysql-test/suite/innodb/r/innodb_bug59410.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_bug59410.result	revid:vasil.dimov@stripped
@@ -0,0 +1,17 @@
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+1
+1
+1
+drop table bug59410_1;
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;

=== added file 'mysql-test/suite/innodb/r/innodb_bug59641.result'
--- a/mysql-test/suite/innodb/r/innodb_bug59641.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_bug59641.result	revid:vasil.dimov@stripped
@@ -0,0 +1,57 @@
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+call mtr.add_suppression("Found 3 prepared XA transactions");
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a	b
+1	1
+2	2
+3	47
+4	4
+5	134
+8	16
+16	16
+32	128
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a	b
+1	1
+2	2
+3	47
+4	4
+5	134
+8	16
+16	16
+32	128
+COMMIT;
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	3	0	789
+1	3	0	456
+1	3	0	123
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+a	b
+2	2
+4	4
+8	8
+16	16
+32	128
+DROP TABLE t;

=== added file 'mysql-test/suite/innodb/t/innodb_bug59410.test'
--- a/mysql-test/suite/innodb/t/innodb_bug59410.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_bug59410.test	revid:vasil.dimov@stripped
@@ -0,0 +1,24 @@
+#
+# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record
+#
+-- source include/have_innodb.inc
+
+# only interested that the following do not produce something like
+# InnoDB: Error: unlock row could not find a 2 mode lock on the record
+# in the error log
+
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+drop table bug59410_1;
+
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;

=== added file 'mysql-test/suite/innodb/t/innodb_bug59641.test'
--- a/mysql-test/suite/innodb/t/innodb_bug59641.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_bug59641.test	revid:vasil.dimov@stripped
@@ -0,0 +1,66 @@
+# Bug #59641 Prepared XA transaction causes shutdown hang after a crash
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+
+CONNECT (con1,localhost,root,,);
+CONNECTION con1;
+
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+
+CONNECT (con2,localhost,root,,);
+CONNECTION con2;
+
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+
+# The server would issue this warning on restart.
+call mtr.add_suppression("Found 3 prepared XA transactions");
+
+# Kill the server without sending a shutdown command
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server 0
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+
+# Shut down the server. This would hang because of the bug.
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+XA RECOVER;
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+
+DROP TABLE t;

=== added file 'mysql-test/suite/innodb_plugin/r/innodb_bug59410.result'
--- a/mysql-test/suite/innodb_plugin/r/innodb_bug59410.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59410.result	revid:vasil.dimov@stripped
@@ -0,0 +1,17 @@
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+1
+1
+1
+drop table bug59410_1;
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;

=== added file 'mysql-test/suite/innodb_plugin/r/innodb_bug59641.result'
--- a/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb_plugin/r/innodb_bug59641.result	revid:vasil.dimov@stripped
@@ -0,0 +1,57 @@
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+call mtr.add_suppression("Found 3 prepared XA transactions");
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a	b
+1	1
+2	2
+3	47
+4	4
+5	134
+8	16
+16	16
+32	128
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a	b
+1	1
+2	2
+3	47
+4	4
+5	134
+8	16
+16	16
+32	128
+COMMIT;
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	3	0	789
+1	3	0	456
+1	3	0	123
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+a	b
+2	2
+4	4
+8	8
+16	16
+32	128
+DROP TABLE t;

=== added file 'mysql-test/suite/innodb_plugin/t/innodb_bug59410.test'
--- a/mysql-test/suite/innodb_plugin/t/innodb_bug59410.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59410.test	revid:vasil.dimov@stripped
@@ -0,0 +1,24 @@
+#
+# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record
+#
+-- source include/have_innodb_plugin.inc
+
+# only interested that the following do not produce something like
+# InnoDB: Error: unlock row could not find a 2 mode lock on the record
+# in the error log
+
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+drop table bug59410_1;
+
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;

=== added file 'mysql-test/suite/innodb_plugin/t/innodb_bug59641.test'
--- a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test	revid:vasil.dimov@stripped
@@ -0,0 +1,70 @@
+# Bug #59641 Prepared XA transaction causes shutdown hang after a crash
+
+-- source include/not_embedded.inc
+-- source include/have_innodb_plugin.inc
+
+let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
+
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+
+CONNECT (con1,localhost,root,,);
+CONNECTION con1;
+
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+
+CONNECT (con2,localhost,root,,);
+CONNECTION con2;
+
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+
+# The server would issue this warning on restart.
+call mtr.add_suppression("Found 3 prepared XA transactions");
+
+# Kill the server without sending a shutdown command
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server 0
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+
+# Shut down the server. This would hang because of the bug.
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+XA RECOVER;
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+
+DROP TABLE t;
+--disable_query_log
+eval set global innodb_file_format_check=$innodb_file_format_check_orig;

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	revid:nirbhay.choubey@stripped
+++ b/sql/sql_class.cc	revid:vasil.dimov@stripped
@@ -3383,6 +3383,7 @@ bool xid_cache_insert(XID *xid, enum xa_
     xs->xa_state=xa_state;
     xs->xid.set(xid);
     xs->in_thd=0;
+    xs->rm_error=0;
     res=my_hash_insert(&xid_cache, (uchar*)xs);
   }
   pthread_mutex_unlock(&LOCK_xid_cache);

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:nirbhay.choubey@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
@@ -189,7 +189,7 @@ innobase_index_name_is_reserved(
 /*============================*/
 					/* out: true if index name matches a
 					reserved name */
-	const trx_t*	trx,		/* in: InnoDB transaction handle */
+	THD*		thd,		/* in/out: MySQL connection */
 	const TABLE*	form,		/* in: information on table
 					columns and indexes */
 	const char*	norm_name);	/* in: table name */
@@ -5285,10 +5285,6 @@ create_table_def(
 	DBUG_PRINT("enter", ("table_name: %s", table_name));
 
 	ut_a(trx->mysql_thd != NULL);
-	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name,
-						  (THD*) trx->mysql_thd)) {
-		DBUG_RETURN(HA_ERR_GENERIC);
-	}
 
 	n_cols = form->s->fields;
 
@@ -5397,6 +5393,8 @@ err_col:
 			col_len);
 	}
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_create_table_for_mysql(table, trx);
 
 	innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error);
@@ -5642,6 +5640,35 @@ ha_innobase::create(
 		DBUG_RETURN(HA_ERR_TO_BIG_ROW);
 	}
 
+	strcpy(name2, name);
+
+	normalize_table_name(norm_name, name2);
+
+	/* Create the table definition in InnoDB */
+
+	flags = form->s->row_type != ROW_TYPE_REDUNDANT ? DICT_TF_COMPACT : 0;
+
+	/* Look for a primary key */
+
+	primary_key_no= (form->s->primary_key != MAX_KEY ?
+			 (int) form->s->primary_key :
+			 -1);
+
+	/* Our function row_get_mysql_key_number_for_index assumes
+	the primary key is always number 0, if it exists */
+
+	DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
+
+	/* Check for name conflicts (with reserved name) for
+	any user indices to be created. */
+	if (innobase_index_name_is_reserved(thd, form, norm_name)) {
+		DBUG_RETURN(-1);
+	}
+
+	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
+		DBUG_RETURN(HA_ERR_GENERIC);
+	}
+
 	/* Get the transaction associated with the current thd, or create one
 	if not yet created */
 
@@ -5665,48 +5692,12 @@ ha_innobase::create(
 		trx->check_unique_secondary = FALSE;
 	}
 
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
-	strcpy(name2, name);
-
-	normalize_table_name(norm_name, name2);
-
 	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
 	or lock waits can happen in it during a table create operation.
 	Drop table etc. do this latching in row0mysql.c. */
 
 	row_mysql_lock_data_dictionary(trx);
 
-	/* Create the table definition in InnoDB */
-
-	flags = 0;
-
-	if (form->s->row_type != ROW_TYPE_REDUNDANT) {
-		flags |= DICT_TF_COMPACT;
-	}
-
-	/* Look for a primary key */
-
-	primary_key_no= (form->s->primary_key != MAX_KEY ?
-			 (int) form->s->primary_key :
-			 -1);
-
-	/* Our function row_get_mysql_key_number_for_index assumes
-	the primary key is always number 0, if it exists */
-
-	DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
-
-	/* Check for name conflicts (with reserved name) for
-	any user indices to be created. */
-	if (innobase_index_name_is_reserved(trx, form, norm_name)) {
-		error = -1;
-		goto cleanup;
-	}
-
 	error = create_table_def(trx, form, norm_name,
 		create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
 		flags);
@@ -5936,12 +5927,6 @@ ha_innobase::delete_table(
 
 	trx_search_latch_release_if_reserved(parent_trx);
 
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
 	trx = trx_allocate_for_mysql();
 
 	trx->mysql_thd = thd;
@@ -5961,6 +5946,8 @@ ha_innobase::delete_table(
 
 	/* Drop the table in InnoDB */
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_drop_table_for_mysql(norm_name, trx,
 					 thd_sql_command(thd)
 					 == SQLCOM_DROP_DB);
@@ -6089,12 +6076,6 @@ ha_innobase::rename_table(
 
 	trx_search_latch_release_if_reserved(parent_trx);
 
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
 	trx = trx_allocate_for_mysql();
 	trx->mysql_thd = thd;
 	INNOBASE_COPY_STMT(thd, trx);
@@ -6114,6 +6095,8 @@ ha_innobase::rename_table(
 
 	/* Rename the table in InnoDB */
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_rename_table_for_mysql(norm_from, norm_to, trx);
 
 	/* Flush the log to reduce probability that the .frm files and
@@ -8565,7 +8548,7 @@ innobase_commit_by_xid(
 
 	if (trx) {
 		innobase_commit_low(trx);
-
+		trx_free_for_background(trx);
 		return(XA_OK);
 	} else {
 		return(XAER_NOTA);
@@ -8588,7 +8571,9 @@ innobase_rollback_by_xid(
 	trx = trx_get_trx_by_xid(xid);
 
 	if (trx) {
-		return(innobase_rollback_trx(trx));
+		int	ret = innobase_rollback_trx(trx);
+		trx_free_for_background(trx);
+		return(ret);
 	} else {
 		return(XAER_NOTA);
 	}
@@ -8824,7 +8809,7 @@ innobase_index_name_is_reserved(
 /*============================*/
 					/* out: true if an index name
 					matches the reserved name */
-	const trx_t*	trx,		/* in: InnoDB transaction handle */
+	THD*		thd,		/* in/out: MySQL connection */
 	const TABLE*	form,		/* in: information on table
 					columns and indexes */
 	const char*	norm_name)	/* in: table name */
@@ -8838,7 +8823,7 @@ innobase_index_name_is_reserved(
 		if (innobase_strcasecmp(key->name,
 					innobase_index_reserve_name) == 0) {
 			/* Push warning to mysql */
-			push_warning_printf((THD*) trx->mysql_thd,
+			push_warning_printf(thd,
 					    MYSQL_ERROR::WARN_LEVEL_WARN,
 					    ER_CANT_CREATE_TABLE,
 					    "Cannot Create Index with name "

=== modified file 'storage/innobase/include/trx0trx.h'
--- a/storage/innobase/include/trx0trx.h	revid:nirbhay.choubey@stripped
+++ b/storage/innobase/include/trx0trx.h	revid:vasil.dimov@stripped
@@ -19,7 +19,12 @@ Created 3/26/1996 Heikki Tuuri
 #include "dict0types.h"
 #include "trx0xa.h"
 
+/* Number of transactions currently allocated for MySQL: protected by
+the kernel mutex */
 extern ulint	trx_n_mysql_transactions;
+/* Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+extern ulint	trx_n_prepared;
 
 /************************************************************************
 Releases the search latch if trx has reserved it. */

=== modified file 'storage/innobase/log/log0log.c'
--- a/storage/innobase/log/log0log.c	revid:nirbhay.choubey@stripped
+++ b/storage/innobase/log/log0log.c	revid:vasil.dimov@stripped
@@ -3052,12 +3052,13 @@ loop:
 		goto loop;
 	}
 
-	/* Check that there are no longer transactions. We need this wait even
-	for the 'very fast' shutdown, because the InnoDB layer may have
-	committed or prepared transactions and we don't want to lose them. */
+	/* Check that there are no longer transactions, except for
+	PREPARED ones. We need this wait even for the 'very fast'
+	shutdown, because the InnoDB layer may have committed or
+	prepared transactions and we don't want to lose them. */
 
 	if (trx_n_mysql_transactions > 0
-	    || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
+	    || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) {
 
 		mutex_exit(&kernel_mutex);
 

=== modified file 'storage/innobase/trx/trx0trx.c'
--- a/storage/innobase/trx/trx0trx.c	revid:nirbhay.choubey@stripped
+++ b/storage/innobase/trx/trx0trx.c	revid:vasil.dimov@stripped
@@ -41,6 +41,9 @@ sess_t*		trx_dummy_sess = NULL;
 /* Number of transactions currently allocated for MySQL: protected by
 the kernel mutex */
 ulint	trx_n_mysql_transactions = 0;
+/* Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+ulint	trx_n_prepared = 0;
 
 /*****************************************************************
 Starts the transaction if it is not yet started. */
@@ -480,6 +483,7 @@ trx_lists_init_at_db_start(void)
 					if (srv_force_recovery == 0) {
 
 						trx->conc_state = TRX_PREPARED;
+						trx_n_prepared++;
 					} else {
 						fprintf(stderr,
 							"InnoDB: Since"
@@ -558,6 +562,7 @@ trx_lists_init_at_db_start(void)
 
 							trx->conc_state
 								= TRX_PREPARED;
+							trx_n_prepared++;
 						} else {
 							fprintf(stderr,
 								"InnoDB: Since"
@@ -832,6 +837,11 @@ trx_commit_off_kernel(
 	      || trx->conc_state == TRX_PREPARED);
 	ut_ad(mutex_own(&kernel_mutex));
 
+	if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
+		ut_a(trx_n_prepared > 0);
+		trx_n_prepared--;
+	}
+
 	/* The following assignment makes the transaction committed in memory
 	and makes its changes to data visible to other transactions.
 	NOTE that there is a small discrepancy from the strict formal
@@ -1882,6 +1892,7 @@ trx_prepare_off_kernel(
 
 	/*--------------------------------------*/
 	trx->conc_state = TRX_PREPARED;
+	trx_n_prepared++;
 	/*--------------------------------------*/
 
 	if (must_flush_log) {

=== modified file 'storage/innodb_plugin/ChangeLog'
--- a/storage/innodb_plugin/ChangeLog	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/ChangeLog	revid:vasil.dimov@stripped
@@ -1,3 +1,15 @@
+2011-04-07	The InnoDB Team
+
+	* handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc:
+	Fix Bug #52409 Assertion failure: long semaphore wait
+
+2011-04-07	The InnoDB Team
+
+	* handler/ha_innodb.cc, include/trx0trx.h, include/trx0undo.h,
+	log/log0log.c, trx/trx0sys.c, trx/trx0trx.c, trx/trx0undo.c:
+	Fix Bug #59641 Prepared XA transaction in system after hard crash
+	causes future shutdown hang
+
 2011-03-30	The InnoDB Team
 
 	* srv/srv0srv.c, sync/sync0arr.h, sync/sync0arr.c:

=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/handler/ha_innodb.cc	revid:vasil.dimov@stripped
@@ -6023,10 +6023,6 @@ create_table_def(
 	DBUG_PRINT("enter", ("table_name: %s", table_name));
 
 	ut_a(trx->mysql_thd != NULL);
-	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name,
-						  (THD*) trx->mysql_thd)) {
-		DBUG_RETURN(HA_ERR_GENERIC);
-	}
 
 	/* MySQL does the name length check. But we do additional check
 	on the name length here */
@@ -6146,6 +6142,8 @@ err_col:
 			col_len);
 	}
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_create_table_for_mysql(table, trx);
 
 	if (error == DB_DUPLICATE_KEY) {
@@ -6562,42 +6560,17 @@ ha_innobase::create(
 		DBUG_RETURN(HA_ERR_TO_BIG_ROW);
 	}
 
-	/* Get the transaction associated with the current thd, or create one
-	if not yet created */
-
-	parent_trx = check_trx_exists(thd);
-
-	/* In case MySQL calls this in the middle of a SELECT query, release
-	possible adaptive hash latch to avoid deadlocks of threads */
-
-	trx_search_latch_release_if_reserved(parent_trx);
-
-	trx = innobase_trx_allocate(thd);
-
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
 	strcpy(name2, name);
 
 	normalize_table_name(norm_name, name2);
 
-	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
-	or lock waits can happen in it during a table create operation.
-	Drop table etc. do this latching in row0mysql.c. */
-
-	row_mysql_lock_data_dictionary(trx);
-
 	/* Create the table definition in InnoDB */
 
 	flags = 0;
 
 	/* Validate create options if innodb_strict_mode is set. */
 	if (!create_options_are_valid(thd, form, create_info)) {
-		error = ER_ILLEGAL_HA_CREATE_OPTION;
-		goto cleanup;
+		DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION);
 	}
 
 	if (create_info->key_block_size) {
@@ -6739,16 +6712,37 @@ ha_innobase::create(
 
 	/* Check for name conflicts (with reserved name) for
 	any user indices to be created. */
-	if (innobase_index_name_is_reserved(trx, form->key_info,
+	if (innobase_index_name_is_reserved(thd, form->key_info,
 					    form->s->keys)) {
-		error = -1;
-		goto cleanup;
+		DBUG_RETURN(-1);
+	}
+
+	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
+		DBUG_RETURN(HA_ERR_GENERIC);
 	}
 
 	if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
 		flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
 	}
 
+	/* Get the transaction associated with the current thd, or create one
+	if not yet created */
+
+	parent_trx = check_trx_exists(thd);
+
+	/* In case MySQL calls this in the middle of a SELECT query, release
+	possible adaptive hash latch to avoid deadlocks of threads */
+
+	trx_search_latch_release_if_reserved(parent_trx);
+
+	trx = innobase_trx_allocate(thd);
+
+	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
+	or lock waits can happen in it during a table create operation.
+	Drop table etc. do this latching in row0mysql.c. */
+
+	row_mysql_lock_data_dictionary(trx);
+
 	error = create_table_def(trx, form, norm_name,
 		create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
 		flags);
@@ -6992,18 +6986,14 @@ ha_innobase::delete_table(
 
 	trx = innobase_trx_allocate(thd);
 
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
 	name_len = strlen(name);
 
 	ut_a(name_len < 1000);
 
 	/* Drop the table in InnoDB */
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_drop_table_for_mysql(norm_name, trx,
 					 thd_sql_command(thd)
 					 == SQLCOM_DROP_DB);
@@ -7119,12 +7109,6 @@ innobase_rename_table(
 	char*	norm_to;
 	char*	norm_from;
 
-	if (lower_case_table_names) {
-		srv_lower_case_table_names = TRUE;
-	} else {
-		srv_lower_case_table_names = FALSE;
-	}
-
 	// Magic number 64 arbitrary
 	norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
 	norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
@@ -7139,6 +7123,8 @@ innobase_rename_table(
 		row_mysql_lock_data_dictionary(trx);
 	}
 
+	srv_lower_case_table_names = lower_case_table_names;
+
 	error = row_rename_table_for_mysql(
 		norm_from, norm_to, trx, lock_and_commit);
 
@@ -9998,7 +9984,7 @@ innobase_commit_by_xid(
 
 	if (trx) {
 		innobase_commit_low(trx);
-
+		trx_free_for_background(trx);
 		return(XA_OK);
 	} else {
 		return(XAER_NOTA);
@@ -10024,7 +10010,9 @@ innobase_rollback_by_xid(
 	trx = trx_get_trx_by_xid(xid);
 
 	if (trx) {
-		return(innobase_rollback_trx(trx));
+		int	ret = innobase_rollback_trx(trx);
+		trx_free_for_background(trx);
+		return(ret);
 	} else {
 		return(XAER_NOTA);
 	}
@@ -10698,19 +10686,19 @@ static int show_innodb_vars(THD *thd, SH
   return 0;
 }
 
-/***********************************************************************
+/*********************************************************************//**
 This function checks each index name for a table against reserved
-system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
-this function pushes an warning message to the client, and returns true. */
+system default primary index name 'GEN_CLUST_INDEX'. If a name
+matches, this function pushes an warning message to the client,
+and returns true.
+@return true if the index name matches the reserved name */
 extern "C" UNIV_INTERN
 bool
 innobase_index_name_is_reserved(
 /*============================*/
-					/* out: true if an index name
-					matches the reserved name */
-	const trx_t*	trx,		/* in: InnoDB transaction handle */
-	const KEY*	key_info,	/* in: Indexes to be created */
-	ulint		num_of_keys)	/* in: Number of indexes to
+	THD*		thd,		/*!< in/out: MySQL connection */
+	const KEY*	key_info,	/*!< in: Indexes to be created */
+	ulint		num_of_keys)	/*!< in: Number of indexes to
 					be created. */
 {
 	const KEY*	key;
@@ -10722,7 +10710,7 @@ innobase_index_name_is_reserved(
 		if (innobase_strcasecmp(key->name,
 					innobase_index_reserve_name) == 0) {
 			/* Push warning to mysql */
-			push_warning_printf((THD*) trx->mysql_thd,
+			push_warning_printf(thd,
 					    MYSQL_ERROR::WARN_LEVEL_WARN,
 					    ER_WRONG_NAME_FOR_INDEX,
 					    "Cannot Create Index with name "

=== modified file 'storage/innodb_plugin/handler/ha_innodb.h'
--- a/storage/innodb_plugin/handler/ha_innodb.h	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/handler/ha_innodb.h	revid:vasil.dimov@stripped
@@ -317,15 +317,14 @@ innobase_trx_allocate(
 This function checks each index name for a table against reserved
 system default primary index name 'GEN_CLUST_INDEX'. If a name
 matches, this function pushes an warning message to the client,
-and returns true. */
+and returns true.
+@return true if the index name matches the reserved name */
 extern "C"
 bool
 innobase_index_name_is_reserved(
 /*============================*/
-					/* out: true if the index name
-					matches the reserved name */
-	const trx_t*	trx,		/* in: InnoDB transaction handle */
-	const KEY*	key_info,	/* in: Indexes to be created */
-	ulint		num_of_keys);	/* in: Number of indexes to
+	THD*		thd,		/*!< in/out: MySQL connection */
+	const KEY*	key_info,	/*!< in: Indexes to be created */
+	ulint		num_of_keys);	/*!< in: Number of indexes to
 					be created. */
 

=== modified file 'storage/innodb_plugin/handler/handler0alter.cc'
--- a/storage/innodb_plugin/handler/handler0alter.cc	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/handler/handler0alter.cc	revid:vasil.dimov@stripped
@@ -649,44 +649,37 @@ ha_innobase::add_index(
 
 	update_thd();
 
-	heap = mem_heap_create(1024);
-
 	/* In case MySQL calls this in the middle of a SELECT query, release
 	possible adaptive hash latch to avoid deadlocks of threads. */
 	trx_search_latch_release_if_reserved(prebuilt->trx);
-	trx_start_if_not_started(prebuilt->trx);
 
-	/* Create a background transaction for the operations on
-	the data dictionary tables. */
-	trx = innobase_trx_allocate(user_thd);
-	trx_start_if_not_started(trx);
+	/* Check if the index name is reserved. */
+	if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) {
+		DBUG_RETURN(-1);
+	}
 
 	innodb_table = indexed_table
 		= dict_table_get(prebuilt->table->name, FALSE);
 
 	if (UNIV_UNLIKELY(!innodb_table)) {
-		error = HA_ERR_NO_SUCH_TABLE;
-		goto err_exit;
+		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
 	}
 
-	/* Check if the index name is reserved. */
-	if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
-		error = -1;
-	} else {
-		/* Check that index keys are sensible */
-		error = innobase_check_index_keys(key_info, num_of_keys,
-						  innodb_table);
-	}
+	/* Check that index keys are sensible */
+	error = innobase_check_index_keys(key_info, num_of_keys, innodb_table);
 
 	if (UNIV_UNLIKELY(error)) {
-err_exit:
-		mem_heap_free(heap);
-		trx_general_rollback_for_mysql(trx, NULL);
-		trx_free_for_mysql(trx);
-		trx_commit_for_mysql(prebuilt->trx);
 		DBUG_RETURN(error);
 	}
 
+	heap = mem_heap_create(1024);
+	trx_start_if_not_started(prebuilt->trx);
+
+	/* Create a background transaction for the operations on
+	the data dictionary tables. */
+	trx = innobase_trx_allocate(user_thd);
+	trx_start_if_not_started(trx);
+
 	/* Create table containing all indexes to be built in this
 	alter table add index so that they are in the correct order
 	in the table. */
@@ -758,8 +751,12 @@ err_exit:
 
 			ut_d(dict_table_check_for_dup_indexes(innodb_table,
 							      FALSE));
+			mem_heap_free(heap);
+			trx_general_rollback_for_mysql(trx, NULL);
 			row_mysql_unlock_data_dictionary(trx);
-			goto err_exit;
+			trx_free_for_mysql(trx);
+			trx_commit_for_mysql(prebuilt->trx);
+			DBUG_RETURN(error);
 		}
 
 		trx->table_id = indexed_table->id;

=== modified file 'storage/innodb_plugin/include/trx0trx.h'
--- a/storage/innodb_plugin/include/trx0trx.h	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/include/trx0trx.h	revid:vasil.dimov@stripped
@@ -44,6 +44,9 @@ extern sess_t*	trx_dummy_sess;
 /** Number of transactions currently allocated for MySQL: protected by
 the kernel mutex */
 extern ulint	trx_n_mysql_transactions;
+/** Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+extern ulint	trx_n_prepared;
 
 /********************************************************************//**
 Releases the search latch if trx has reserved it. */
@@ -108,6 +111,14 @@ trx_free(
 /*=====*/
 	trx_t*	trx);	/*!< in, own: trx object */
 /********************************************************************//**
+At shutdown, frees a transaction object that is in the PREPARED state. */
+UNIV_INTERN
+void
+trx_free_prepared(
+/*==============*/
+	trx_t*	trx)	/*!< in, own: trx object */
+	__attribute__((nonnull));
+/********************************************************************//**
 Frees a transaction object for MySQL. */
 UNIV_INTERN
 void

=== modified file 'storage/innodb_plugin/include/trx0undo.h'
--- a/storage/innodb_plugin/include/trx0undo.h	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/include/trx0undo.h	revid:vasil.dimov@stripped
@@ -298,6 +298,15 @@ void
 trx_undo_insert_cleanup(
 /*====================*/
 	trx_t*	trx);	/*!< in: transaction handle */
+
+/********************************************************************//**
+At shutdown, frees the undo logs of a PREPARED transaction. */
+UNIV_INTERN
+void
+trx_undo_free_prepared(
+/*===================*/
+	trx_t*	trx)	/*!< in/out: PREPARED transaction */
+	__attribute__((nonnull));
 #endif /* !UNIV_HOTBACKUP */
 /***********************************************************//**
 Parses the redo log entry of an undo log page initialization.

=== modified file 'storage/innodb_plugin/log/log0log.c'
--- a/storage/innodb_plugin/log/log0log.c	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/log/log0log.c	revid:vasil.dimov@stripped
@@ -3085,12 +3085,13 @@ loop:
 		goto loop;
 	}
 
-	/* Check that there are no longer transactions. We need this wait even
-	for the 'very fast' shutdown, because the InnoDB layer may have
-	committed or prepared transactions and we don't want to lose them. */
+	/* Check that there are no longer transactions, except for
+	PREPARED ones. We need this wait even for the 'very fast'
+	shutdown, because the InnoDB layer may have committed or
+	prepared transactions and we don't want to lose them. */
 
 	if (trx_n_mysql_transactions > 0
-	    || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
+	    || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) {
 
 		mutex_exit(&kernel_mutex);
 

=== modified file 'storage/innodb_plugin/trx/trx0sys.c'
--- a/storage/innodb_plugin/trx/trx0sys.c	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/trx/trx0sys.c	revid:vasil.dimov@stripped
@@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri
 #include "trx0rseg.h"
 #include "trx0undo.h"
 #include "srv0srv.h"
+#include "srv0start.h"
 #include "trx0purge.h"
 #include "log0log.h"
 #include "os0file.h"
@@ -1548,10 +1549,12 @@ void
 trx_sys_close(void)
 /*===============*/
 {
+	trx_t*		trx;
 	trx_rseg_t*	rseg;
 	read_view_t*	view;
 
 	ut_ad(trx_sys != NULL);
+	ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
 
 	/* Check that all read views are closed except read view owned
 	by a purge. */
@@ -1583,6 +1586,13 @@ trx_sys_close(void)
 	mem_free(trx_doublewrite);
 	trx_doublewrite = NULL;
 
+	/* Only prepared transactions may be left in the system. Free them. */
+	ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == trx_n_prepared);
+
+	while ((trx = UT_LIST_GET_FIRST(trx_sys->trx_list)) != NULL) {
+		trx_free_prepared(trx);
+	}
+
 	/* There can't be any active transactions. */
 	rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
 

=== modified file 'storage/innodb_plugin/trx/trx0trx.c'
--- a/storage/innodb_plugin/trx/trx0trx.c	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/trx/trx0trx.c	revid:vasil.dimov@stripped
@@ -50,6 +50,9 @@ UNIV_INTERN sess_t*		trx_dummy_sess = NU
 /** Number of transactions currently allocated for MySQL: protected by
 the kernel mutex */
 UNIV_INTERN ulint	trx_n_mysql_transactions = 0;
+/* Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+UNIV_INTERN ulint	trx_n_prepared = 0;
 
 /*************************************************************//**
 Set detailed error message for the transaction. */
@@ -334,6 +337,60 @@ trx_free(
 }
 
 /********************************************************************//**
+At shutdown, frees a transaction object that is in the PREPARED state. */
+UNIV_INTERN
+void
+trx_free_prepared(
+/*==============*/
+	trx_t*	trx)	/*!< in, own: trx object */
+{
+	ut_ad(mutex_own(&kernel_mutex));
+	ut_a(trx->conc_state == TRX_PREPARED);
+	ut_a(trx->magic_n == TRX_MAGIC_N);
+
+	/* Prepared transactions are sort of active; they allow
+	ROLLBACK and COMMIT operations. Because the system does not
+	contain any other transactions than prepared transactions at
+	the shutdown stage and because a transaction cannot become
+	PREPARED while holding locks, it is safe to release the locks
+	held by PREPARED transactions here at shutdown.*/
+	lock_release_off_kernel(trx);
+
+	trx_undo_free_prepared(trx);
+
+	mutex_free(&trx->undo_mutex);
+
+	if (trx->undo_no_arr) {
+		trx_undo_arr_free(trx->undo_no_arr);
+	}
+
+	ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
+	ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
+
+	ut_a(trx->wait_lock == NULL);
+	ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
+
+	ut_a(!trx->has_search_latch);
+
+	ut_a(trx->dict_operation_lock_mode == 0);
+
+	if (trx->lock_heap) {
+		mem_heap_free(trx->lock_heap);
+	}
+
+	if (trx->global_read_view_heap) {
+		mem_heap_free(trx->global_read_view_heap);
+	}
+
+	ut_a(ib_vector_is_empty(trx->autoinc_locks));
+	ib_vector_free(trx->autoinc_locks);
+
+	UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
+
+	mem_free(trx);
+}
+
+/********************************************************************//**
 Frees a transaction object for MySQL. */
 UNIV_INTERN
 void
@@ -463,6 +520,7 @@ trx_lists_init_at_db_start(void)
 					if (srv_force_recovery == 0) {
 
 						trx->conc_state = TRX_PREPARED;
+						trx_n_prepared++;
 					} else {
 						fprintf(stderr,
 							"InnoDB: Since"
@@ -541,6 +599,7 @@ trx_lists_init_at_db_start(void)
 
 							trx->conc_state
 								= TRX_PREPARED;
+							trx_n_prepared++;
 						} else {
 							fprintf(stderr,
 								"InnoDB: Since"
@@ -820,6 +879,11 @@ trx_commit_off_kernel(
 	      || trx->conc_state == TRX_PREPARED);
 	ut_ad(mutex_own(&kernel_mutex));
 
+	if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
+		ut_a(trx_n_prepared > 0);
+		trx_n_prepared--;
+	}
+
 	/* The following assignment makes the transaction committed in memory
 	and makes its changes to data visible to other transactions.
 	NOTE that there is a small discrepancy from the strict formal
@@ -1857,6 +1921,7 @@ trx_prepare_off_kernel(
 
 	/*--------------------------------------*/
 	trx->conc_state = TRX_PREPARED;
+	trx_n_prepared++;
 	/*--------------------------------------*/
 
 	if (lsn) {
@@ -2031,10 +2096,11 @@ trx_get_trx_by_xid(
 	while (trx) {
 		/* Compare two X/Open XA transaction id's: their
 		length should be the same and binary comparison
-		of gtrid_lenght+bqual_length bytes should be
+		of gtrid_length+bqual_length bytes should be
 		the same */
 
-		if (trx->conc_state == TRX_PREPARED
+		if (trx->is_recovered
+		    && trx->conc_state == TRX_PREPARED
 		    && xid->gtrid_length == trx->xid.gtrid_length
 		    && xid->bqual_length == trx->xid.bqual_length
 		    && memcmp(xid->data, trx->xid.data,

=== modified file 'storage/innodb_plugin/trx/trx0undo.c'
--- a/storage/innodb_plugin/trx/trx0undo.c	revid:nirbhay.choubey@stripped
+++ b/storage/innodb_plugin/trx/trx0undo.c	revid:vasil.dimov@stripped
@@ -36,6 +36,7 @@ Created 3/26/1996 Heikki Tuuri
 #include "trx0rseg.h"
 #include "trx0trx.h"
 #include "srv0srv.h"
+#include "srv0start.h"
 #include "trx0rec.h"
 #include "trx0purge.h"
 
@@ -1976,4 +1977,31 @@ trx_undo_insert_cleanup(
 
 	mutex_exit(&(rseg->mutex));
 }
+
+/********************************************************************//**
+At shutdown, frees the undo logs of a PREPARED transaction. */
+UNIV_INTERN
+void
+trx_undo_free_prepared(
+/*===================*/
+	trx_t*	trx)	/*!< in/out: PREPARED transaction */
+{
+	mutex_enter(&trx->rseg->mutex);
+
+	ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
+
+	if (trx->update_undo) {
+		ut_a(trx->update_undo->state == TRX_UNDO_PREPARED);
+		UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list,
+			       trx->update_undo);
+		trx_undo_mem_free(trx->update_undo);
+	}
+	if (trx->insert_undo) {
+		ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED);
+		UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list,
+			       trx->insert_undo);
+		trx_undo_mem_free(trx->insert_undo);
+	}
+	mutex_exit(&trx->rseg->mutex);
+}
 #endif /* !UNIV_HOTBACKUP */

No bundle (reason: revision is a merge (you can force generation of a bundle with env var BZR_FORCE_BUNDLE=1)).
Thread
bzr commit into mysql-5.1 branch (vasil.dimov:3679) vasil.dimov2 May