Commit 1561b414 authored by marko's avatar marko

branches/zip: Introduce two new dictionary operation modes for transactions.

enum trx_dict_op: dictionary operation modes

trx_get_dict_operation(), trx_set_dict_operation(): Accessors for
trx->dict_operation.

lock_table_enqueue_waiting(), lock_rec_enqueue_waiting(): Do not complain
about lock waits if the dictionary mode is TRX_DICT_OP_INDEX_MAY_WAIT.

row_merge_lock_table(): Remove the work-around for avoiding the warning
in lock_table_enqueue_waiting().

trx_undo_mark_as_dict_operation(): Do not write trx->table_id to the
undo log unless the dict_operation is TRX_DICT_OP_TABLE.

ha_innobase::add_index(): Set the dict_operation mode initially to
TRX_DICT_OP_INDEX_MAY_WAIT, then lock the table exclusively, and set the
mode to TRX_DICT_OP_INDEX, and optionally to TRX_DICT_OP_TABLE when
creating a temporary table.
parent e6f452c7
...@@ -629,7 +629,7 @@ ha_innobase::add_index( ...@@ -629,7 +629,7 @@ ha_innobase::add_index(
mem_heap_t* heap; /* Heap for index definitions */ mem_heap_t* heap; /* Heap for index definitions */
trx_t* trx; /* Transaction */ trx_t* trx; /* Transaction */
ulint num_of_idx; ulint num_of_idx;
ulint num_created; ulint num_created = 0;
ibool dict_locked = FALSE; ibool dict_locked = FALSE;
ulint new_primary; ulint new_primary;
ulint error; ulint error;
...@@ -684,6 +684,8 @@ err_exit: ...@@ -684,6 +684,8 @@ err_exit:
index_defs = innobase_create_key_def( index_defs = innobase_create_key_def(
trx, innodb_table, heap, key_info, num_of_idx); trx, innodb_table, heap, key_info, num_of_idx);
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
/* Allocate memory for dictionary index definitions */ /* Allocate memory for dictionary index definitions */
index = (dict_index_t**) mem_heap_alloc( index = (dict_index_t**) mem_heap_alloc(
...@@ -695,23 +697,31 @@ err_exit: ...@@ -695,23 +697,31 @@ err_exit:
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE; dict_locked = TRUE;
/* Flag this transaction as a dictionary operation, so that the /* Flag this transaction as a dictionary operation, so that
data dictionary will be locked in crash recovery. Clear the the data dictionary will be locked in crash recovery. Prevent
table_id, so that no table will be dropped in crash recovery, warnings if row_merge_lock_table() results in a lock wait. */
unless a new primary key is defined. */ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX_MAY_WAIT);
trx->dict_operation = TRUE;
trx->table_id = ut_dulint_zero; /* Acquire an exclusive lock on the table
before creating any indexes. */
error = row_merge_lock_table(trx, innodb_table);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
goto error_handling;
}
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
/* If a new primary key is defined for the table we need /* If a new primary key is defined for the table we need
to drop the original table and rebuild all indexes. */ to drop the original table and rebuild all indexes. */
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
if (UNIV_UNLIKELY(new_primary)) { if (UNIV_UNLIKELY(new_primary)) {
char* new_table_name = innobase_create_temporary_tablename( char* new_table_name = innobase_create_temporary_tablename(
heap, '1', innodb_table->name); heap, '1', innodb_table->name);
/* Clone the table. */ /* Clone the table. */
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
indexed_table = row_merge_create_temporary_table( indexed_table = row_merge_create_temporary_table(
new_table_name, index_defs, innodb_table, trx); new_table_name, index_defs, innodb_table, trx);
...@@ -737,19 +747,6 @@ err_exit: ...@@ -737,19 +747,6 @@ err_exit:
trx->table_id = indexed_table->id; trx->table_id = indexed_table->id;
} }
ut_ad(!error);
/* Acquire an exclusive lock on the table
before creating any indexes. */
error = row_merge_lock_table(trx, innodb_table);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
goto error_handling;
}
num_created = 0;
/* Create the indexes in SYS_INDEXES and load into dictionary. */ /* Create the indexes in SYS_INDEXES and load into dictionary. */
for (ulint i = 0; i < num_of_idx; i++) { for (ulint i = 0; i < num_of_idx; i++) {
......
...@@ -357,6 +357,45 @@ trx_print( ...@@ -357,6 +357,45 @@ trx_print(
ulint max_query_len); /* in: max query length to print, or 0 to ulint max_query_len); /* in: max query length to print, or 0 to
use the default max length */ use the default max length */
/** Type of data dictionary operation */
enum trx_dict_op {
/** The transaction is not modifying the data dictionary. */
TRX_DICT_OP_NONE = 0,
/** The transaction is creating a table or an index, or
dropping a table. The table must be dropped in crash
recovery. This and TRX_DICT_OP_NONE are the only possible
operation modes in crash recovery. */
TRX_DICT_OP_TABLE = 1,
/** The transaction is creating an index in an existing table,
In crash recovery, the the data dictionary must be locked, but
the table must not be dropped. */
TRX_DICT_OP_INDEX = 2,
/** The transaction is creating 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
};
/**************************************************************************
Determine if a transaction is a dictionary operation. */
UNIV_INLINE
enum trx_dict_op
trx_get_dict_operation(
/*===================*/
/* out: dictionary operation mode */
const trx_t* trx) /* in: transaction */
__attribute__((pure));
/**************************************************************************
Flag a transaction a dictionary operation. */
UNIV_INLINE
void
trx_set_dict_operation(
/*===================*/
trx_t* trx, /* in/out: transaction */
enum trx_dict_op op); /* in: operation, not
TRX_DICT_OP_NONE */
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/************************************************************************** /**************************************************************************
Determines if the currently running transaction has been interrupted. */ Determines if the currently running transaction has been interrupted. */
...@@ -471,12 +510,7 @@ struct trx_struct{ ...@@ -471,12 +510,7 @@ struct trx_struct{
were modifications by the transaction; were modifications by the transaction;
in that case we must flush the log in that case we must flush the log
in trx_commit_complete_for_mysql() */ in trx_commit_complete_for_mysql() */
unsigned dict_operation:1;/* nonzero if the trx is used unsigned dict_operation:2;/**< @see enum trx_dict_op */
to create a table, create an
index, or drop a table. This
is a hint that the table may
need to be dropped in crash
recovery. */
unsigned duplicates:2; /* TRX_DUP_IGNORE | TRX_DUP_REPLACE */ unsigned duplicates:2; /* TRX_DUP_IGNORE | TRX_DUP_REPLACE */
unsigned active_trans:2; /* 1 - if a transaction in MySQL unsigned active_trans:2; /* 1 - if a transaction in MySQL
is active. 2 - if prepare_commit_mutex is active. 2 - if prepare_commit_mutex
......
...@@ -145,3 +145,61 @@ trx_get_que_state_str( ...@@ -145,3 +145,61 @@ trx_get_que_state_str(
return("UNKNOWN"); return("UNKNOWN");
} }
} }
/**************************************************************************
Determine if a transaction is a dictionary operation. */
UNIV_INLINE
enum trx_dict_op
trx_get_dict_operation(
/*===================*/
/* out: dictionary operation mode */
const trx_t* trx) /* in: transaction */
{
enum trx_dict_op op = (enum trx_dict_op) trx->dict_operation;
#ifdef UNIV_DEBUG
switch (op) {
case TRX_DICT_OP_NONE:
case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX:
case TRX_DICT_OP_INDEX_MAY_WAIT:
return(op);
}
ut_error;
#endif /* UNIV_DEBUG */
return((enum trx_dict_op) UNIV_EXPECT(op, TRX_DICT_OP_NONE));
}
/**************************************************************************
Flag a transaction a dictionary operation. */
UNIV_INLINE
void
trx_set_dict_operation(
/*===================*/
trx_t* trx, /* in/out: transaction */
enum trx_dict_op op) /* in: operation, not
TRX_DICT_OP_NONE */
{
#ifdef UNIV_DEBUG
enum trx_dict_op old_op = trx_get_dict_operation(trx);
switch (op) {
case TRX_DICT_OP_NONE:
ut_error;
break;
case TRX_DICT_OP_TABLE:
ut_ad(old_op == TRX_DICT_OP_NONE
|| old_op == TRX_DICT_OP_INDEX);
break;
case TRX_DICT_OP_INDEX:
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;
}
#endif /* UNIV_DEBUG */
trx->dict_operation = op;
}
...@@ -1783,7 +1783,12 @@ lock_rec_enqueue_waiting( ...@@ -1783,7 +1783,12 @@ lock_rec_enqueue_waiting(
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
if (UNIV_UNLIKELY(trx->dict_operation)) { switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
break;
case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX:
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: a record lock wait happens" fputs(" InnoDB: Error: a record lock wait happens"
" in a dictionary operation!\n" " in a dictionary operation!\n"
...@@ -3641,7 +3646,12 @@ lock_table_enqueue_waiting( ...@@ -3641,7 +3646,12 @@ lock_table_enqueue_waiting(
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
if (trx->dict_operation) { switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
break;
case TRX_DICT_OP_TABLE:
case TRX_DICT_OP_INDEX:
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: a table lock wait happens" fputs(" InnoDB: Error: a table lock wait happens"
" in a dictionary operation!\n" " in a dictionary operation!\n"
......
...@@ -1674,16 +1674,8 @@ run_again: ...@@ -1674,16 +1674,8 @@ run_again:
thr->run_node = thr; thr->run_node = thr;
thr->prev_node = thr->common.parent; thr->prev_node = thr->common.parent;
/* Temporarily clear the dict_operation flag in order to
avoid a bogus warning in lock_table_enqueue_waiting(). */
ut_ad(trx->dict_operation == 1);
trx->dict_operation = 0;
err = lock_table(0, table, LOCK_X, thr); err = lock_table(0, table, LOCK_X, thr);
/* Restore the dict_operation flag. */
trx->dict_operation = 1;
trx->error_state = err; trx->error_state = err;
if (UNIV_LIKELY(err == DB_SUCCESS)) { if (UNIV_LIKELY(err == DB_SUCCESS)) {
......
...@@ -1938,7 +1938,7 @@ row_create_table_for_mysql( ...@@ -1938,7 +1938,7 @@ row_create_table_for_mysql(
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
node = tab_create_graph_create(table, heap); node = tab_create_graph_create(table, heap);
...@@ -2089,7 +2089,7 @@ row_create_index_for_mysql( ...@@ -2089,7 +2089,7 @@ row_create_index_for_mysql(
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
/* Note that the space id where we store the index is inherited from /* Note that the space id where we store the index is inherited from
the table in dict_build_index_def_step() in dict0crea.c. */ the table in dict_build_index_def_step() in dict0crea.c. */
...@@ -2161,7 +2161,7 @@ row_table_add_foreign_constraints( ...@@ -2161,7 +2161,7 @@ row_table_add_foreign_constraints(
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
trx->dict_operation = TRUE; trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
err = dict_create_foreign_constraints(trx, sql_string, name, err = dict_create_foreign_constraints(trx, sql_string, name,
reject_fks); reject_fks);
...@@ -3286,7 +3286,7 @@ check_next_foreign: ...@@ -3286,7 +3286,7 @@ check_next_foreign:
lock_reset_all_on_table(table); lock_reset_all_on_table(table);
trx->dict_operation = TRUE; trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
trx->table_id = table->id; trx->table_id = table->id;
/* We use the private SQL parser of Innobase to generate the /* We use the private SQL parser of Innobase to generate the
......
...@@ -447,7 +447,7 @@ trx_rollback_active( ...@@ -447,7 +447,7 @@ trx_rollback_active(
trx->mysql_process_no = os_proc_get_number(); trx->mysql_process_no = os_proc_get_number();
if (trx->dict_operation) { if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE; dictionary_locked = TRUE;
} }
...@@ -470,7 +470,8 @@ trx_rollback_active( ...@@ -470,7 +470,8 @@ trx_rollback_active(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
if (trx->dict_operation && !ut_dulint_is_zero(trx->table_id)) { if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE
&& !ut_dulint_is_zero(trx->table_id)) {
/* If the transaction was for a dictionary operation, we /* If the transaction was for a dictionary operation, we
drop the relevant table, if it still exists */ drop the relevant table, if it still exists */
......
...@@ -97,7 +97,7 @@ trx_create( ...@@ -97,7 +97,7 @@ trx_create(
trx->flush_log_later = FALSE; trx->flush_log_later = FALSE;
trx->must_flush_log_later = FALSE; trx->must_flush_log_later = FALSE;
trx->dict_operation = FALSE; trx_set_dict_operation(trx, TRX_DICT_OP_NONE);
trx->table_id = ut_dulint_zero; trx->table_id = ut_dulint_zero;
trx->mysql_thd = NULL; trx->mysql_thd = NULL;
...@@ -469,7 +469,8 @@ trx_lists_init_at_db_start(void) ...@@ -469,7 +469,8 @@ trx_lists_init_at_db_start(void)
} }
if (undo->dict_operation) { if (undo->dict_operation) {
trx->dict_operation = undo->dict_operation; trx_set_dict_operation(
trx, TRX_DICT_OP_TABLE);
trx->table_id = undo->table_id; trx->table_id = undo->table_id;
} }
...@@ -548,8 +549,8 @@ trx_lists_init_at_db_start(void) ...@@ -548,8 +549,8 @@ trx_lists_init_at_db_start(void)
trx_list_insert_ordered(trx); trx_list_insert_ordered(trx);
if (undo->dict_operation) { if (undo->dict_operation) {
trx->dict_operation trx_set_dict_operation(
= undo->dict_operation; trx, TRX_DICT_OP_TABLE);
trx->table_id = undo->table_id; trx->table_id = undo->table_id;
} }
} }
......
...@@ -1674,20 +1674,30 @@ trx_undo_mark_as_dict_operation( ...@@ -1674,20 +1674,30 @@ trx_undo_mark_as_dict_operation(
{ {
page_t* hdr_page; page_t* hdr_page;
ut_a(trx->dict_operation);
hdr_page = trx_undo_page_get(undo->space, undo->zip_size, hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
undo->hdr_page_no, mtr); undo->hdr_page_no, mtr);
switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE:
case TRX_DICT_OP_INDEX_MAY_WAIT:
ut_error;
case TRX_DICT_OP_INDEX:
/* Do not discard the table on recovery. */
undo->table_id = ut_dulint_zero;
break;
case TRX_DICT_OP_TABLE:
undo->table_id = trx->table_id;
break;
}
mlog_write_ulint(hdr_page + undo->hdr_offset mlog_write_ulint(hdr_page + undo->hdr_offset
+ TRX_UNDO_DICT_TRANS, + TRX_UNDO_DICT_TRANS,
trx->dict_operation, MLOG_1BYTE, mtr); TRUE, MLOG_1BYTE, mtr);
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID, mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
trx->table_id, mtr); undo->table_id, mtr);
undo->dict_operation = trx->dict_operation; undo->dict_operation = TRUE;
undo->table_id = trx->table_id;
} }
/************************************************************************** /**************************************************************************
...@@ -1743,7 +1753,7 @@ trx_undo_assign_undo( ...@@ -1743,7 +1753,7 @@ trx_undo_assign_undo(
trx->update_undo = undo; trx->update_undo = undo;
} }
if (trx->dict_operation) { if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
trx_undo_mark_as_dict_operation(trx, undo, &mtr); trx_undo_mark_as_dict_operation(trx, undo, &mtr);
} }
......
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