Commit 0b717e0c authored by unknown's avatar unknown

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

into hundin.mysql.fi:/home/marko/k/mysql-4.1
parents fdbd7701 e3b9dd2a
...@@ -463,13 +463,32 @@ lock_rec_hash( ...@@ -463,13 +463,32 @@ lock_rec_hash(
ulint space, /* in: space */ ulint space, /* in: space */
ulint page_no);/* in: page number */ 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* dict_table_t*
lock_get_ix_table( lock_get_src_table(
/*==============*/ /*===============*/
/* out: the table covered by the lock */ /* out: the source table of transaction,
lock_t* lock); /* in: table lock */ 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. */ Checks that a transaction id is sensible, i.e., not in the future. */
......
...@@ -177,10 +177,12 @@ row_lock_table_for_mysql( ...@@ -177,10 +177,12 @@ row_lock_table_for_mysql(
/* out: error code or DB_SUCCESS */ /* out: error code or DB_SUCCESS */
row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
table handle */ 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 if prebuilt->table should be
locked as LOCK_TABLE_EXP | locked as LOCK_TABLE_EXP |
prebuilt->select_lock_type */ prebuilt->select_lock_type */
ulint mode); /* in: lock mode of table */
/************************************************************************* /*************************************************************************
Does an insert for MySQL. */ Does an insert for MySQL. */
......
...@@ -395,19 +395,6 @@ lock_rec_get_nth_bit( ...@@ -395,19 +395,6 @@ lock_rec_get_nth_bit(
return(ut_bit_get_nth(b, bit_index)); 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) #define lock_mutex_enter_kernel() mutex_enter(&kernel_mutex)
...@@ -614,6 +601,128 @@ lock_get_wait( ...@@ -614,6 +601,128 @@ lock_get_wait(
return(FALSE); 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. */ Sets the wait flag of a lock and the back pointer in trx to lock. */
UNIV_INLINE UNIV_INLINE
......
...@@ -782,10 +782,11 @@ row_lock_table_for_mysql( ...@@ -782,10 +782,11 @@ row_lock_table_for_mysql(
/* out: error code or DB_SUCCESS */ /* out: error code or DB_SUCCESS */
row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
table handle */ 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 if prebuilt->table should be
locked as LOCK_TABLE_EXP | locked as LOCK_TABLE_EXP |
prebuilt->select_lock_type */ prebuilt->select_lock_type */
ulint mode) /* in: lock mode of table */
{ {
trx_t* trx = prebuilt->trx; trx_t* trx = prebuilt->trx;
que_thr_t* thr; que_thr_t* thr;
...@@ -819,7 +820,7 @@ row_lock_table_for_mysql( ...@@ -819,7 +820,7 @@ row_lock_table_for_mysql(
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
if (table) { if (table) {
err = lock_table(0, table, LOCK_IX, thr); err = lock_table(0, table, mode, thr);
} else { } else {
err = lock_table(LOCK_TABLE_EXP, prebuilt->table, err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
prebuilt->select_lock_type, thr); prebuilt->select_lock_type, thr);
......
...@@ -2324,20 +2324,58 @@ ha_innobase::write_row( ...@@ -2324,20 +2324,58 @@ ha_innobase::write_row(
position in the source table need not be adjusted after the position in the source table need not be adjusted after the
intermediate COMMIT, since writes by other transactions are intermediate COMMIT, since writes by other transactions are
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */ 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* src_table;
dict_table_t* table = lock_get_ix_table( ibool mode;
UT_LIST_GET_FIRST(prebuilt->trx->trx_locks));
num_write_row = 0; num_write_row = 0;
/* Commit the transaction. This will release the table /* Commit the transaction. This will release the table
locks, so they have to be acquired again. */ 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); innobase_commit(user_thd, prebuilt->trx);
/* Note that this transaction is still active. */ /* Note that this transaction is still active. */
user_thd->transaction.all.innodb_active_trans = 1; 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. */ /* We will need an IX lock on the destination table. */
prebuilt->sql_stat_start = TRUE; 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++; num_write_row++;
...@@ -5015,7 +5053,8 @@ ha_innobase::external_lock( ...@@ -5015,7 +5053,8 @@ ha_innobase::external_lock(
if (thd->in_lock_tables && if (thd->in_lock_tables &&
thd->variables.innodb_table_locks) { thd->variables.innodb_table_locks) {
ulint error; 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) { if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql( error = convert_error_code_to_mysql(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment