Commit e1e958d4 authored by marko's avatar marko

branches/zip: Fast index creation: Release locks on system tables before

creating indexes.  Lock the user table inside the user transaction.

enum trx_dict_op: Remove TRX_OP_INDEX_MAY_WAIT.

ha_innobase::add_index(): Lock the user tables within prebuilt->trx.
Commit the data dictionary transaction before creating indexes.

ha_innobase::final_drop_index(): Lock the user table within prebuilt->trx.
parent 0a63ed9c
...@@ -657,6 +657,7 @@ ha_innobase::add_index( ...@@ -657,6 +657,7 @@ ha_innobase::add_index(
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
trans_register_ha(user_thd, FALSE, ht); trans_register_ha(user_thd, FALSE, ht);
prebuilt->trx->active_trans = 1;
trx->mysql_thd = user_thd; trx->mysql_thd = user_thd;
trx->mysql_query_str = thd_query(user_thd); trx->mysql_query_str = thd_query(user_thd);
...@@ -694,14 +695,11 @@ err_exit: ...@@ -694,14 +695,11 @@ err_exit:
heap, num_of_idx * sizeof *index); heap, num_of_idx * sizeof *index);
/* Flag this transaction as a dictionary operation, so that /* Flag this transaction as a dictionary operation, so that
the data dictionary will be locked in crash recovery. Prevent the data dictionary will be locked in crash recovery. */
warnings if row_merge_lock_table() results in a lock wait, trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
i.e., when another transaction is holding a conflicting lock
on the table, e.g., because of SELECT ... FOR UPDATE. */
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX_MAY_WAIT);
/* Acquire a lock on the table before creating any indexes. */ /* Acquire a lock on the table before creating any indexes. */
error = row_merge_lock_table(trx, innodb_table, error = row_merge_lock_table(prebuilt->trx, innodb_table,
new_primary ? LOCK_X : LOCK_S); new_primary ? LOCK_X : LOCK_S);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) { if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
...@@ -709,8 +707,6 @@ err_exit: ...@@ -709,8 +707,6 @@ err_exit:
goto error_handling; goto error_handling;
} }
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks /* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during an index create operation. */ or lock waits can happen in it during an index create operation. */
...@@ -772,6 +768,13 @@ err_exit: ...@@ -772,6 +768,13 @@ err_exit:
ut_ad(error == DB_SUCCESS); ut_ad(error == DB_SUCCESS);
/* Commit the data dictionary transaction in order to release
the table locks on the system tables. Unfortunately, this
means that if MySQL crashes while creating a new primary key
inside row_merge_build_indexes(), indexed_table will not be
dropped on crash recovery. Thus, it will become orphaned. */
trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
dict_locked = FALSE; dict_locked = FALSE;
...@@ -783,7 +786,8 @@ err_exit: ...@@ -783,7 +786,8 @@ err_exit:
table lock also on the table that is being created. */ table lock also on the table that is being created. */
ut_ad(indexed_table != innodb_table); ut_ad(indexed_table != innodb_table);
error = row_merge_lock_table(trx, indexed_table, LOCK_X); error = row_merge_lock_table(prebuilt->trx, indexed_table,
LOCK_X);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) { if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
...@@ -793,7 +797,8 @@ err_exit: ...@@ -793,7 +797,8 @@ err_exit:
/* Read the clustered index of the table and build indexes /* Read the clustered index of the table and build indexes
based on this information using temporary files and merge sort. */ based on this information using temporary files and merge sort. */
error = row_merge_build_indexes(trx, innodb_table, indexed_table, error = row_merge_build_indexes(prebuilt->trx,
innodb_table, indexed_table,
index, num_of_idx, table); index, num_of_idx, table);
error_handling: error_handling:
...@@ -861,6 +866,7 @@ error_handling: ...@@ -861,6 +866,7 @@ error_handling:
break; break;
} }
trx_commit_for_mysql(prebuilt->trx);
row_prebuilt_free(prebuilt, TRUE); row_prebuilt_free(prebuilt, TRUE);
prebuilt = row_create_prebuilt(indexed_table); prebuilt = row_create_prebuilt(indexed_table);
...@@ -878,7 +884,6 @@ error_handling: ...@@ -878,7 +884,6 @@ error_handling:
case DB_DUPLICATE_KEY: case DB_DUPLICATE_KEY:
error: error:
prebuilt->trx->error_info = NULL; prebuilt->trx->error_info = NULL;
prebuilt->trx->error_key_num = trx->error_key_num;
/* fall through */ /* fall through */
default: default:
if (new_primary) { if (new_primary) {
...@@ -894,6 +899,9 @@ convert_error: ...@@ -894,6 +899,9 @@ convert_error:
mem_heap_free(heap); mem_heap_free(heap);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
if (prebuilt->trx) {
trx_commit_for_mysql(prebuilt->trx);
}
if (dict_locked) { if (dict_locked) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
...@@ -1096,21 +1104,19 @@ ha_innobase::final_drop_index( ...@@ -1096,21 +1104,19 @@ ha_innobase::final_drop_index(
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
trans_register_ha(user_thd, FALSE, ht); trans_register_ha(user_thd, FALSE, ht);
prebuilt->trx->active_trans = 1;
trx->mysql_thd = user_thd; trx->mysql_thd = user_thd;
trx->mysql_query_str = thd_query(user_thd); trx->mysql_query_str = thd_query(user_thd);
/* Flag this transaction as a dictionary operation, so that /* Flag this transaction as a dictionary operation, so that
the data dictionary will be locked in crash recovery. Prevent the data dictionary will be locked in crash recovery. */
warnings if row_merge_lock_table() results in a lock wait, trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
i.e., when another transaction is holding a conflicting lock
on the table, e.g., because of SELECT ... FOR UPDATE. */
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX_MAY_WAIT);
/* Lock the table exclusively, to ensure that no active /* Lock the table exclusively, to ensure that no active
transaction depends on an index that is being dropped. */ transaction depends on an index that is being dropped. */
err = convert_error_code_to_mysql( err = convert_error_code_to_mysql(
row_merge_lock_table(trx, prebuilt->table, LOCK_X), row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
user_thd); user_thd);
if (UNIV_UNLIKELY(err)) { if (UNIV_UNLIKELY(err)) {
...@@ -1128,8 +1134,6 @@ ha_innobase::final_drop_index( ...@@ -1128,8 +1134,6 @@ ha_innobase::final_drop_index(
goto func_exit; goto func_exit;
} }
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
/* Drop indexes marked to be dropped */ /* Drop indexes marked to be dropped */
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
...@@ -1162,6 +1166,7 @@ ha_innobase::final_drop_index( ...@@ -1162,6 +1166,7 @@ ha_innobase::final_drop_index(
func_exit: func_exit:
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
/* Flush the log to reduce probability that the .frm files and /* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs the InnoDB data dictionary get out-of-sync if the user runs
......
...@@ -369,12 +369,7 @@ enum trx_dict_op { ...@@ -369,12 +369,7 @@ enum trx_dict_op {
/** The transaction is creating or dropping an index in an /** The transaction is creating or dropping an index in an
existing table. In crash recovery, the the data dictionary existing table. In crash recovery, the the data dictionary
must be locked, but the table must not be dropped. */ must be locked, but the table must not be dropped. */
TRX_DICT_OP_INDEX = 2, TRX_DICT_OP_INDEX = 2
/** The transaction is creating or dropping an index in an
existing table. In crash recovery, the the data dictionary
must be locked, but the table must not be dropped. A lock
wait timeout is allowed to occur. */
TRX_DICT_OP_INDEX_MAY_WAIT = 3
}; };
/************************************************************************** /**************************************************************************
......
...@@ -162,7 +162,6 @@ trx_get_dict_operation( ...@@ -162,7 +162,6 @@ trx_get_dict_operation(
case TRX_DICT_OP_NONE: case TRX_DICT_OP_NONE:
case TRX_DICT_OP_TABLE: case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
case TRX_DICT_OP_INDEX_MAY_WAIT:
return(op); return(op);
} }
ut_error; ut_error;
...@@ -192,18 +191,11 @@ trx_set_dict_operation( ...@@ -192,18 +191,11 @@ trx_set_dict_operation(
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
case TRX_DICT_OP_TABLE: case TRX_DICT_OP_TABLE:
goto ok; goto ok;
case TRX_DICT_OP_INDEX_MAY_WAIT:
break;
} }
ut_error; ut_error;
break; break;
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
ut_ad(old_op == TRX_DICT_OP_NONE ut_ad(old_op == TRX_DICT_OP_NONE);
|| old_op == TRX_DICT_OP_INDEX_MAY_WAIT);
break;
case TRX_DICT_OP_INDEX_MAY_WAIT:
ut_ad(old_op == TRX_DICT_OP_NONE
|| old_op == TRX_DICT_OP_INDEX);
break; break;
} }
ok: ok:
......
...@@ -1758,7 +1758,6 @@ lock_rec_enqueue_waiting( ...@@ -1758,7 +1758,6 @@ lock_rec_enqueue_waiting(
switch (trx_get_dict_operation(trx)) { switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE: case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
break; break;
case TRX_DICT_OP_TABLE: case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
...@@ -3621,7 +3620,6 @@ lock_table_enqueue_waiting( ...@@ -3621,7 +3620,6 @@ lock_table_enqueue_waiting(
switch (trx_get_dict_operation(trx)) { switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE: case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
break; break;
case TRX_DICT_OP_TABLE: case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
......
...@@ -1679,7 +1679,6 @@ trx_undo_mark_as_dict_operation( ...@@ -1679,7 +1679,6 @@ trx_undo_mark_as_dict_operation(
switch (trx_get_dict_operation(trx)) { switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE: case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
ut_error; ut_error;
case TRX_DICT_OP_INDEX: case TRX_DICT_OP_INDEX:
/* Do not discard the table on recovery. */ /* Do not discard the table on recovery. */
......
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