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,8 +629,8 @@ ha_innobase::add_index(
mem_heap_t* heap; /* Heap for index definitions */
trx_t* trx; /* Transaction */
ulint num_of_idx;
ulint num_created;
ibool dict_locked = FALSE;
ulint num_created = 0;
ibool dict_locked = FALSE;
ulint new_primary;
ulint error;
......@@ -684,6 +684,8 @@ err_exit:
index_defs = innobase_create_key_def(
trx, innodb_table, heap, key_info, num_of_idx);
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
/* Allocate memory for dictionary index definitions */
index = (dict_index_t**) mem_heap_alloc(
......@@ -695,23 +697,31 @@ err_exit:
row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE;
/* Flag this transaction as a dictionary operation, so that the
data dictionary will be locked in crash recovery. Clear the
table_id, so that no table will be dropped in crash recovery,
unless a new primary key is defined. */
trx->dict_operation = TRUE;
trx->table_id = ut_dulint_zero;
/* Flag this transaction as a dictionary operation, so that
the data dictionary will be locked in crash recovery. Prevent
warnings if row_merge_lock_table() results in a lock wait. */
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX_MAY_WAIT);
/* 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
to drop the original table and rebuild all indexes. */
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
if (UNIV_UNLIKELY(new_primary)) {
char* new_table_name = innobase_create_temporary_tablename(
heap, '1', innodb_table->name);
/* Clone the table. */
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
indexed_table = row_merge_create_temporary_table(
new_table_name, index_defs, innodb_table, trx);
......@@ -737,19 +747,6 @@ err_exit:
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. */
for (ulint i = 0; i < num_of_idx; i++) {
......
......@@ -357,6 +357,45 @@ trx_print(
ulint max_query_len); /* in: max query length to print, or 0 to
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
/**************************************************************************
Determines if the currently running transaction has been interrupted. */
......@@ -471,12 +510,7 @@ struct trx_struct{
were modifications by the transaction;
in that case we must flush the log
in trx_commit_complete_for_mysql() */
unsigned dict_operation:1;/* nonzero if the trx is used
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 dict_operation:2;/**< @see enum trx_dict_op */
unsigned duplicates:2; /* TRX_DUP_IGNORE | TRX_DUP_REPLACE */
unsigned active_trans:2; /* 1 - if a transaction in MySQL
is active. 2 - if prepare_commit_mutex
......
......@@ -145,3 +145,61 @@ trx_get_que_state_str(
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(
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);
fputs(" InnoDB: Error: a record lock wait happens"
" in a dictionary operation!\n"
......@@ -3641,7 +3646,12 @@ lock_table_enqueue_waiting(
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);
fputs(" InnoDB: Error: a table lock wait happens"
" in a dictionary operation!\n"
......
......@@ -1674,16 +1674,8 @@ run_again:
thr->run_node = thr;
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);
/* Restore the dict_operation flag. */
trx->dict_operation = 1;
trx->error_state = err;
if (UNIV_LIKELY(err == DB_SUCCESS)) {
......
......@@ -1938,7 +1938,7 @@ row_create_table_for_mysql(
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);
......@@ -2089,7 +2089,7 @@ row_create_index_for_mysql(
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
the table in dict_build_index_def_step() in dict0crea.c. */
......@@ -2161,7 +2161,7 @@ row_table_add_foreign_constraints(
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,
reject_fks);
......@@ -3286,7 +3286,7 @@ check_next_foreign:
lock_reset_all_on_table(table);
trx->dict_operation = TRUE;
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
trx->table_id = table->id;
/* We use the private SQL parser of Innobase to generate the
......
......@@ -447,7 +447,7 @@ trx_rollback_active(
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);
dictionary_locked = TRUE;
}
......@@ -470,7 +470,8 @@ trx_rollback_active(
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
drop the relevant table, if it still exists */
......
......@@ -97,7 +97,7 @@ trx_create(
trx->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->mysql_thd = NULL;
......@@ -469,7 +469,8 @@ trx_lists_init_at_db_start(void)
}
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;
}
......@@ -548,8 +549,8 @@ trx_lists_init_at_db_start(void)
trx_list_insert_ordered(trx);
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;
}
}
......
......@@ -1674,20 +1674,30 @@ trx_undo_mark_as_dict_operation(
{
page_t* hdr_page;
ut_a(trx->dict_operation);
hdr_page = trx_undo_page_get(undo->space, undo->zip_size,
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
+ 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,
trx->table_id, mtr);
undo->table_id, mtr);
undo->dict_operation = trx->dict_operation;
undo->table_id = trx->table_id;
undo->dict_operation = TRUE;
}
/**************************************************************************
......@@ -1743,7 +1753,7 @@ trx_undo_assign_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);
}
......
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