Commit 795045d9 authored by unknown's avatar unknown
Browse files

Merge marko@bk-internal.mysql.com:/home/bk/mysql-4.1

into hundin.mysql.fi:/home/marko/k/mysql-4.1

parents fc157af3 d6180d37
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -463,13 +463,32 @@ lock_rec_hash(
	ulint	space,	/* in: space */
	ulint	page_no);/* in: page number */
/*************************************************************************
Gets the table covered by an IX table lock. */
Gets the source table of an ALTER TABLE transaction.  The table must be
covered by an IX or IS table lock. */

dict_table_t*
lock_get_ix_table(
/*==============*/
			/* out: the table covered by the lock */
	lock_t*	lock);	/* in: table lock */
lock_get_src_table(
/*===============*/
				/* out: the source table of transaction,
				if it is covered by an IX or IS table lock;
				dest if there is no source table, and
				NULL if the transaction is locking more than
				two tables or an inconsistency is found */
	trx_t*		trx,	/* in: transaction */
	dict_table_t*	dest,	/* in: destination of ALTER TABLE */
	ulint*		mode);	/* out: lock mode of the source table */
/*************************************************************************
Determine if the given table is exclusively "owned" by the given
transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
on the table. */

ibool
lock_table_exclusive(
/*=================*/
				/* out: TRUE if table is only locked by trx,
				with LOCK_IX, and possibly LOCK_AUTO_INC */
	dict_table_t*	table,	/* in: table */
	trx_t*		trx);	/* in: transaction */
/*************************************************************************
Checks that a transaction id is sensible, i.e., not in the future. */

+3 −1
Original line number Diff line number Diff line
@@ -177,10 +177,12 @@ row_lock_table_for_mysql(
					/* out: error code or DB_SUCCESS */
	row_prebuilt_t*	prebuilt,	/* in: prebuilt struct in the MySQL
					table handle */
	dict_table_t*	table);		/* in: table to LOCK_IX, or NULL
	dict_table_t*	table,		/* in: table to lock, or NULL
					if prebuilt->table should be
					locked as LOCK_TABLE_EXP |
					prebuilt->select_lock_type */
	ulint		mode);		/* in: lock mode of table */
					   
/*************************************************************************
Does an insert for MySQL. */

+122 −13
Original line number Diff line number Diff line
@@ -395,19 +395,6 @@ lock_rec_get_nth_bit(
	return(ut_bit_get_nth(b, bit_index));
}	

/*************************************************************************
Gets the table covered by an IX table lock. */

dict_table_t*
lock_get_ix_table(
/*==============*/
			/* out: the table covered by the lock */
	lock_t*	lock)	/* in: table lock */
{
	ut_a(lock->type_mode == (LOCK_TABLE | LOCK_IX));
	return(lock->un_member.tab_lock.table);
}

/*************************************************************************/

#define lock_mutex_enter_kernel()	mutex_enter(&kernel_mutex)
@@ -614,6 +601,128 @@ lock_get_wait(
	return(FALSE);
}

/*************************************************************************
Gets the source table of an ALTER TABLE transaction.  The table must be
covered by an IX or IS table lock. */

dict_table_t*
lock_get_src_table(
/*===============*/
				/* out: the source table of transaction,
				if it is covered by an IX or IS table lock;
				dest if there is no source table, and
				NULL if the transaction is locking more than
				two tables or an inconsistency is found */
	trx_t*		trx,	/* in: transaction */
	dict_table_t*	dest,	/* in: destination of ALTER TABLE */
	ulint*		mode)	/* out: lock mode of the source table */
{
	dict_table_t*	src;
	lock_t*		lock;

	src = NULL;
	*mode = LOCK_NONE;

	for (lock = UT_LIST_GET_FIRST(trx->trx_locks);
	     lock;
	     lock = UT_LIST_GET_NEXT(trx_locks, lock)) {
		lock_table_t*	tab_lock;
		ulint		lock_mode;
		if (!(lock_get_type(lock) & LOCK_TABLE)) {
			/* We are only interested in table locks. */
			continue;
		}
		tab_lock = &lock->un_member.tab_lock;
		if (dest == tab_lock->table) {
			/* We are not interested in the destination table. */
			continue;
		} else if (!src) {
			/* This presumably is the source table. */
			src = tab_lock->table;
			if (UT_LIST_GET_LEN(src->locks) != 1 ||
			    UT_LIST_GET_FIRST(src->locks) != lock) {
				/* We only support the case when
				there is only one lock on this table. */
				return(NULL);
			}
		} else if (src != tab_lock->table) {
			/* The transaction is locking more than
			two tables (src and dest): abort */
			return(NULL);
		}

		/* Check that the source table is locked by
		LOCK_IX or LOCK_IS. */
		lock_mode = lock_get_mode(lock);
		switch (lock_mode) {
		case LOCK_IX:
		case LOCK_IS:
			if (*mode != LOCK_NONE && *mode != lock_mode) {
				/* There are multiple locks on src. */
				return(NULL);
			}
			*mode = lock_mode;
			break;
		}
	}

	if (!src) {
		/* No source table lock found: flag the situation to caller */
		src = dest;
	}

	return(src);
}

/*************************************************************************
Determine if the given table is exclusively "owned" by the given
transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
on the table. */

ibool
lock_is_table_exclusive(
/*====================*/
				/* out: TRUE if table is only locked by trx,
				with LOCK_IX, and possibly LOCK_AUTO_INC */
	dict_table_t*	table,	/* in: table */
	trx_t*		trx)	/* in: transaction */
{
	lock_t*	lock;
	bool	ok	= FALSE;

	ut_ad(table && trx);

	for (lock = UT_LIST_GET_FIRST(table->locks);
	     lock;
	     lock = UT_LIST_GET_NEXT(locks, &lock->un_member.tab_lock)) {
		if (lock->trx != trx) {
			/* A lock on the table is held
			by some other transaction. */
			return(FALSE);
		}

		if (!(lock_get_type(lock) & LOCK_TABLE)) {
			/* We are interested in table locks only. */
			continue;
		}

		switch (lock_get_mode(lock)) {
		case LOCK_IX:
			ok = TRUE;
			break;
		case LOCK_AUTO_INC:
			/* It is allowed for trx to hold an
			auto_increment lock. */
			break;
		default:
			/* Other table locks than LOCK_IX are not allowed. */
			return(FALSE);
		}
	}

	return(ok);
}

/*************************************************************************
Sets the wait flag of a lock and the back pointer in trx to lock. */
UNIV_INLINE
+3 −2
Original line number Diff line number Diff line
@@ -782,10 +782,11 @@ row_lock_table_for_mysql(
					/* out: error code or DB_SUCCESS */
	row_prebuilt_t*	prebuilt,	/* in: prebuilt struct in the MySQL
					table handle */
	dict_table_t*	table)		/* in: table to LOCK_IX, or NULL
	dict_table_t*	table,		/* in: table to lock, or NULL
					if prebuilt->table should be
					locked as LOCK_TABLE_EXP |
					prebuilt->select_lock_type */
	ulint		mode)		/* in: lock mode of table */
{
	trx_t*		trx 		= prebuilt->trx;
	que_thr_t*	thr;
@@ -819,7 +820,7 @@ row_lock_table_for_mysql(
	trx_start_if_not_started(trx);

	if (table) {
		err = lock_table(0, table, LOCK_IX, thr);
		err = lock_table(0, table, mode, thr);
	} else {
		err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
			prebuilt->select_lock_type, thr);
+51 −12
Original line number Diff line number Diff line
@@ -2324,20 +2324,58 @@ ha_innobase::write_row(
		position in the source table need not be adjusted after the
		intermediate COMMIT, since writes by other transactions are
		being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
		ut_a(prebuilt->trx->mysql_n_tables_locked == 2);
		ut_a(UT_LIST_GET_LEN(prebuilt->trx->trx_locks) >= 2);
		dict_table_t* table = lock_get_ix_table(
				UT_LIST_GET_FIRST(prebuilt->trx->trx_locks));

		dict_table_t*	src_table;
		ibool		mode;

		num_write_row = 0;

		/* Commit the transaction.  This will release the table
		locks, so they have to be acquired again. */

		/* Altering an InnoDB table */
		/* Get the source table. */
		src_table = lock_get_src_table(
				prebuilt->trx, prebuilt->table, &mode);
		if (!src_table) {
		no_commit:
			/* Unknown situation: do not commit */
			/*
			ut_print_timestamp(stderr);
			fprintf(stderr,
				"  InnoDB error: ALTER TABLE is holding lock"
				" on %lu tables!\n",
				prebuilt->trx->mysql_n_tables_locked);
			*/
			;
		} else if (src_table == prebuilt->table) {
			/* Source table is not in InnoDB format:
			no need to re-acquire locks on it. */

			/* Altering to InnoDB format */
			innobase_commit(user_thd, prebuilt->trx);
			/* Note that this transaction is still active. */
			user_thd->transaction.all.innodb_active_trans = 1;
		/* Re-acquire the IX table lock on the source table. */
		row_lock_table_for_mysql(prebuilt, table);
			/* We will need an IX lock on the destination table. */
		        prebuilt->sql_stat_start = TRUE;
		} else {
			/* Ensure that there are no other table locks than
			LOCK_IX and LOCK_AUTO_INC on the destination table. */
			if (!lock_is_table_exclusive(prebuilt->table,
							prebuilt->trx)) {
				goto no_commit;
			}

			/* Commit the transaction.  This will release the table
			locks, so they have to be acquired again. */
			innobase_commit(user_thd, prebuilt->trx);
			/* Note that this transaction is still active. */
			user_thd->transaction.all.innodb_active_trans = 1;
			/* Re-acquire the table lock on the source table. */
			row_lock_table_for_mysql(prebuilt, src_table, mode);
			/* We will need an IX lock on the destination table. */
		        prebuilt->sql_stat_start = TRUE;
		}
	}

	num_write_row++;
@@ -5015,7 +5053,8 @@ ha_innobase::external_lock(
			if (thd->in_lock_tables &&
			    thd->variables.innodb_table_locks) {
				ulint	error;
				error = row_lock_table_for_mysql(prebuilt, 0);
				error = row_lock_table_for_mysql(prebuilt,
							NULL, LOCK_TABLE_EXP);

				if (error != DB_SUCCESS) {
					error = convert_error_code_to_mysql(