mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
Merge marko@bk-internal.mysql.com:/home/bk/mysql-4.1
into hundin.mysql.fi:/home/marko/k/mysql-4.1
This commit is contained in:
commit
892cec8555
5 changed files with 203 additions and 33 deletions
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 @@ run_again:
|
|||
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);
|
||||
|
|
|
@ -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. */
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
/* 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(
|
||||
|
|
Loading…
Reference in a new issue