Commit 84ff5781 authored by marko's avatar marko

branches/zip: Simplify crash recovery in fast index creation.

trx_t: Remove dict_undo_list and dict_redo_list.

innobase_create_temporary_tablename(): Replace TEMP_TABLE_PREFIX with
a table name suffix "#1" or "#2".  In this way, the user can restore
precious data, should anything go wrong.  It is possible to reach an
inconsistent state, because the creation, deletion and renaming of
single-table tablespaces are not transactional.

ut_print_namel(), fil_make_ibd_name(), innobase_rename_table(): Remove
the special treatment of TEMP_TABLE_PREFIX.

Introduce TEMP_INDEX_PREFIX == 0xff for temporary indexes.  This byte
cannot occur in index names since MySQL 4.1.  However, it might have
been possible to use this byte in MySQL 4.0.

recv_recovery_from_checkpoint_finish(): Call the new function
row_merge_drop_temp_indexes(), to drop all indexes whose name starts
with the byte 0xff.

row_merge_rename_indexes(): Renamed from row_merge_rename_index().
Remove the parameter "index".

row_drop_table_for_mysql(): Unconditionally call trx_commit_for_mysql().

row_drop_table_for_mysql_no_commit(): Correct the function commit,
based on the corrected comment of row_drop_table_for_mysql().  Rely on
table->to_be_dropped instead of TEMP_TABLE_PREFIX.

ha_innobase::add_index(): Simplify the control flow.
parent 44aa4feb
...@@ -4493,224 +4493,3 @@ dict_table_check_for_dup_indexes( ...@@ -4493,224 +4493,3 @@ dict_table_check_for_dup_indexes(
} }
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/**************************************************************************
Create an undo list for the trx.*/
void
dict_undo_create_list(
/*==================*/
trx_t* trx) /* out: dict_undo_t list */
{
ut_a(!trx->dict_undo_list);
trx->dict_undo_list = mem_alloc(sizeof(*trx->dict_undo_list));
UT_LIST_INIT(*trx->dict_undo_list);
}
/**************************************************************************
Create an dict_undo_t element and append to the undo list of the trx.*/
dict_undo_t*
dict_undo_create_element(
/*=====================*/ /* out: dict_undo_t element*/
trx_t* trx) /* in: create & add elem to this trx */
{
dict_undo_t* dict_undo;
ut_a(trx->dict_undo_list);
dict_undo = mem_zalloc(sizeof *dict_undo);
UT_LIST_ADD_LAST(node, *trx->dict_undo_list, dict_undo);
return(dict_undo);
}
/**************************************************************************
Free all the nodes on the undo list and free list.*/
void
dict_undo_free_list(
/*================*/
trx_t* trx)
{
dict_undo_t* dict_undo;
ut_a(trx->dict_undo_list);
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
while (dict_undo) {
UT_LIST_REMOVE(node, *trx->dict_undo_list, dict_undo);
mem_free(dict_undo);
dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
}
mem_free(trx->dict_undo_list);
trx->dict_undo_list = NULL;
}
/**************************************************************************
Create an undo list for the trx.*/
void
dict_redo_create_list(
/*==================*/
trx_t* trx) /* out: dict_undo_t list */
{
ut_a(!trx->dict_redo_list);
trx->dict_redo_list = mem_alloc(sizeof(*trx->dict_redo_list));
UT_LIST_INIT(*trx->dict_redo_list);
}
/**************************************************************************
Create an dict_undo_t element and append to the undo list of the trx.*/
dict_redo_t*
dict_redo_create_element(
/*=====================*/ /* out: dict_undo_t element*/
trx_t* trx) /* in: create & add elem to this trx */
{
dict_redo_t* dict_redo;
ut_a(trx->dict_redo_list);
dict_redo = mem_zalloc(sizeof *dict_redo);
UT_LIST_ADD_LAST(node, *trx->dict_redo_list, dict_redo);
return(dict_redo);
}
/**************************************************************************
Free all the nodes on the undo list and free list.*/
void
dict_redo_free_list(
/*================*/
trx_t* trx)
{
dict_redo_t* dict_redo;
ut_a(trx->dict_redo_list);
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
while (dict_redo) {
UT_LIST_REMOVE(node, *trx->dict_redo_list, dict_redo);
mem_free(dict_redo);
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
}
mem_free(trx->dict_redo_list);
trx->dict_redo_list = NULL;
}
/**************************************************************************
Get the index by name from the transaction's REDO list.*/
dict_index_t*
dict_redo_get_index_on_name(
/*========================*/
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: table the index belongs to */
const char* name) /* in: index name */
{
dict_redo_t* dict_redo;
ut_a(trx->dict_redo_list);
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
while (dict_redo) {
if (dict_redo->index->table == table
&& ut_strcmp(dict_redo->index->name, name) == 0) {
return(dict_redo->index);
}
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
}
return(NULL);
}
/**************************************************************************
Remove the index from the transaction's REDO list.*/
void
dict_redo_remove_index(
/*===================*/
trx_t* trx, /* in: transaction */
dict_index_t* index) /* in: index to remove */
{
dict_redo_t* dict_redo;
ut_a(trx->dict_redo_list);
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
while (dict_redo) {
if (dict_redo->index == index) {
UT_LIST_REMOVE(node, *trx->dict_redo_list, dict_redo);
break;
}
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
}
}
/**************************************************************************
Add the indexes to SYS_INDEX. */
ulint
dict_rename_indexes(
/*================*/
trx_t* trx) /* in: transaction */
{
dict_redo_t* dict_redo;
ulint err = DB_SUCCESS;
ut_a(trx->dict_redo_list);
dict_redo = UT_LIST_GET_FIRST(*trx->dict_redo_list);
while (dict_redo && err == DB_SUCCESS) {
dict_index_t* index;
index = dict_redo->index;
ut_a(index->table);
ut_a(!ut_dulint_is_zero(index->id));
ut_a(index->space == index->table->space);
#if 0
fprintf(stderr, "Renaming index: %s\n", index->name);
#endif
err = row_merge_rename_index(trx, index->table, index);
dict_redo = UT_LIST_GET_NEXT(node, dict_redo);
}
/* We free the list anyway - even if there is an error of some sort,
let the UNDO code handle the errors.*/
dict_redo_free_list(trx);
return(err);
}
...@@ -2398,16 +2398,6 @@ fil_make_ibd_name( ...@@ -2398,16 +2398,6 @@ fil_make_ibd_name(
if (is_temp) { if (is_temp) {
memcpy(filename, name, namelen); memcpy(filename, name, namelen);
memcpy(filename + namelen, ".ibd", sizeof ".ibd"); memcpy(filename + namelen, ".ibd", sizeof ".ibd");
} else if (name[0] == TEMP_TABLE_PREFIX) {
/* Create a temporary tablespace for fast index creation.
See innobase_create_temporary_tablename(). */
memcpy(filename, fil_path_to_mysql_datadir, dirlen);
filename[dirlen] = '/';
memcpy(filename + dirlen + 1, name + 2, namelen - 2);
memcpy(filename + dirlen + namelen - 1, ".ibd", sizeof ".ibd");
/* Replace the 'd' in ".ibd" with the tablename prefix. */
filename[dirlen + namelen + 2] = name[1];
} else { } else {
memcpy(filename, fil_path_to_mysql_datadir, dirlen); memcpy(filename, fil_path_to_mysql_datadir, dirlen);
filename[dirlen] = '/'; filename[dirlen] = '/';
......
...@@ -5372,17 +5372,8 @@ innobase_rename_table( ...@@ -5372,17 +5372,8 @@ innobase_rename_table(
norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0)); norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0)); norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
if (*to != TEMP_TABLE_PREFIX) { normalize_table_name(norm_to, to);
normalize_table_name(norm_to, to); normalize_table_name(norm_from, from);
} else {
strcpy(norm_to, to);
}
if (*from != TEMP_TABLE_PREFIX) {
normalize_table_name(norm_from, from);
} else {
strcpy(norm_from, from);
}
/* Serialize data dictionary operations with dictionary mutex: /* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */ no deadlocks can occur then in these operations */
...@@ -8216,20 +8207,19 @@ innobase_create_temporary_tablename( ...@@ -8216,20 +8207,19 @@ innobase_create_temporary_tablename(
/*================================*/ /*================================*/
/* out: temporary tablename */ /* out: temporary tablename */
mem_heap_t* heap, /* in: memory heap */ mem_heap_t* heap, /* in: memory heap */
char id, /* in: identifier */ char id, /* in: identifier [0-9a-zA-Z] */
const char* table_name) /* in: table name */ const char* table_name) /* in: table name */
{ {
char* name; char* name;
ulint len; ulint len;
static const char suffix[] = "@0023 "; /* "# " */
len = strlen(table_name) + 3; len = strlen(table_name);
name = (char*) mem_heap_alloc(heap, len); name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
/* The prefix must be 2 bytes, and the second byte must not be 'd'. memcpy(name, table_name, len);
See fil_make_ibd_name(). */ memcpy(name + len, suffix, sizeof suffix);
name[0] = TEMP_TABLE_PREFIX; name[len + (sizeof suffix - 2)] = id;
name[1] = id;
memcpy(name + 2, table_name, len - 2);
return(name); return(name);
} }
...@@ -8304,11 +8294,26 @@ err_exit: ...@@ -8304,11 +8294,26 @@ 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);
ut_a(!trx->dict_redo_list); /* Allocate memory for dictionary index definitions */
index = (dict_index_t**) mem_heap_alloc(
heap, num_of_idx * sizeof *index);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during an index create operation. */
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;
/* 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 all original secondary indexes from the table. These to drop the original table and rebuild all indexes. */
indexes will be rebuilt below. */
new_primary = DICT_CLUSTERED & index_defs[0].ind_type; new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
...@@ -8316,10 +8321,7 @@ err_exit: ...@@ -8316,10 +8321,7 @@ err_exit:
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);
row_mysql_lock_data_dictionary(trx); /* Clone the table. */
dict_locked = TRUE;
/* Clone table and write UNDO log record */
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);
...@@ -8330,26 +8332,13 @@ err_exit: ...@@ -8330,26 +8332,13 @@ err_exit:
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
goto err_exit; goto err_exit;
} }
} else {
dict_redo_create_list(trx);
}
/* Allocate memory for dictionary index definitions */ trx->table_id = indexed_table->id;
index = (dict_index_t**) mem_heap_alloc(
heap, num_of_idx * sizeof *index);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during an index create operation. */
if (UNIV_LIKELY(!dict_locked)) {
row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE;
} }
num_created = 0; 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++) {
...@@ -8419,61 +8408,42 @@ error_handling: ...@@ -8419,61 +8408,42 @@ error_handling:
dictionary which were defined. */ dictionary which were defined. */
switch (error) { switch (error) {
const char* old_name;
const char* tmp_name;
case DB_SUCCESS: case DB_SUCCESS:
ut_ad(!dict_locked); ut_ad(!dict_locked);
break;
case DB_PRIMARY_KEY_IS_NULL:
case DB_DUPLICATE_KEY:
prebuilt->trx->error_info = NULL;
prebuilt->trx->error_key_num = trx->error_key_num;
/* fall through */
default:
if (new_primary) {
row_merge_drop_table(trx, indexed_table);
} else {
row_merge_drop_indexes(trx, indexed_table,
index, num_created);
}
goto func_exit; if (!new_primary) {
} error = row_merge_rename_indexes(trx, indexed_table);
/* If a new primary key was defined for the table and if (error != DB_SUCCESS) {
there was no error at this point, we can now rename the row_merge_drop_indexes(trx, indexed_table,
old table as a temporary table, rename the new temporary index, num_created);
table as a old table and drop the old table. */ }
if (new_primary) { break;
const char* old_name }
= innodb_table->name;
const char* tmp_name
= innobase_create_temporary_tablename(heap, '2',
old_name);
trx_start_if_not_started(trx); /* If a new primary key was defined for the table and
there was no error at this point, we can now rename
the old table as a temporary table, rename the new
temporary table as the old table and drop the old table. */
old_name = innodb_table->name;
tmp_name = innobase_create_temporary_tablename(heap, '2',
old_name);
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dict_locked = TRUE; dict_locked = TRUE;
row_prebuilt_table_obsolete(innodb_table); row_prebuilt_table_obsolete(innodb_table);
/* Write entry for UNDO */
error = row_undo_report_rename_table_dict_operation(
trx, old_name, indexed_table->name, tmp_name);
if (error != DB_SUCCESS) {
goto func_exit;
}
log_buffer_flush_to_disk();
error = row_merge_rename_tables(innodb_table, indexed_table, error = row_merge_rename_tables(innodb_table, indexed_table,
tmp_name, trx); tmp_name, trx);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
goto func_exit; row_merge_drop_table(trx, indexed_table);
break;
} }
row_prebuilt_free(prebuilt, TRUE); row_prebuilt_free(prebuilt, TRUE);
...@@ -8487,15 +8457,25 @@ error_handling: ...@@ -8487,15 +8457,25 @@ error_handling:
are no more references to it. */ are no more references to it. */
error = row_merge_drop_table(trx, innodb_table); error = row_merge_drop_table(trx, innodb_table);
} break;
func_exit: case DB_PRIMARY_KEY_IS_NULL:
mem_heap_free(heap); my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
if (!new_primary) { /* fall through */
dict_rename_indexes(trx); case DB_DUPLICATE_KEY:
prebuilt->trx->error_info = NULL;
prebuilt->trx->error_key_num = trx->error_key_num;
/* fall through */
default:
if (new_primary) {
row_merge_drop_table(trx, indexed_table);
} else {
row_merge_drop_indexes(trx, indexed_table,
index, num_created);
}
} }
ut_ad(!trx->dict_redo_list);
mem_heap_free(heap);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
if (dict_locked) { if (dict_locked) {
...@@ -8505,12 +8485,6 @@ func_exit: ...@@ -8505,12 +8485,6 @@ func_exit:
/* There might be work for utility threads.*/ /* There might be work for utility threads.*/
srv_active_wake_master_thread(); srv_active_wake_master_thread();
switch (error) {
case DB_PRIMARY_KEY_IS_NULL:
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
break;
}
DBUG_RETURN(convert_error_code_to_mysql(error, user_thd)); DBUG_RETURN(convert_error_code_to_mysql(error, user_thd));
} }
......
...@@ -1067,72 +1067,6 @@ dict_table_get_index_on_name_and_min_id( ...@@ -1067,72 +1067,6 @@ dict_table_get_index_on_name_and_min_id(
/* out: index, NULL if does not exist */ /* out: index, NULL if does not exist */
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
const char* name); /* in: name of the index to find */ const char* name); /* in: name of the index to find */
/**************************************************************************
Create and return an undo list. */
void
dict_undo_create_list(
/*==================*/
trx_t* trx); /* in: create undo list for this trx.*/
/**************************************************************************
Create element of the undo list and append to the passed in list. */
dict_undo_t*
dict_undo_create_element(
/*=====================*/ /* out: dict_undo_t element*/
trx_t* trx); /* in: create & add elem to this trx.*/
/**************************************************************************
Free all the nodes on the undo list and free list.*/
void
dict_undo_free_list(
/*================*/
trx_t* trx); /* in: free this trx's undo list */
/**************************************************************************
Create and return a redo list. */
void
dict_redo_create_list(
/*==================*/
trx_t* trx); /* in: create redo list for this trx.*/
/**************************************************************************
Create element of the redo list and append to the passed in transaction. */
dict_redo_t*
dict_redo_create_element(
/*=====================*/ /* out: dict_redo_t element*/
trx_t* trx); /* in: create & add elem to this trx.*/
/**************************************************************************
Free all the nodes on the redo list and free list.*/
void
dict_redo_free_list(
/*================*/
trx_t* trx); /* in: free this trx's redo list */
/**************************************************************************
Add the indexes to SYS_INDEX. */
ulint
dict_rename_indexes(
/*================*/
trx_t* trx); /* in/out: transaction */
/**************************************************************************
Remove the index from the transaction's REDO list.*/
void
dict_redo_remove_index(
/*===================*/
trx_t* trx, /* in: transaction */
dict_index_t* index); /* in: index to remove */
/**************************************************************************
Get the index by name from the transaction's REDO list.*/
dict_index_t*
dict_redo_get_index_on_name(
/*========================*/
trx_t* trx, /* in: transaction */
dict_table_t* table, /* in: the table the index belongs to */
const char* name); /* in: index name */
/* Buffers for storing detailed information about the latest foreign key /* Buffers for storing detailed information about the latest foreign key
and unique key errors */ and unique key errors */
extern FILE* dict_foreign_err_file; extern FILE* dict_foreign_err_file;
......
...@@ -26,48 +26,4 @@ typedef dict_table_t dict_cluster_t; ...@@ -26,48 +26,4 @@ typedef dict_table_t dict_cluster_t;
typedef struct ind_node_struct ind_node_t; typedef struct ind_node_struct ind_node_t;
typedef struct tab_node_struct tab_node_t; typedef struct tab_node_struct tab_node_t;
/* Data types for dict_undo */
union dict_undo_data_union {
dict_index_t* index; /* The index to be dropped */
struct {
dict_table_t* old_table; /* All fields are required only for*/
dict_table_t* tmp_table; /*RENAME, for CREATE and DROP we */
dict_table_t* new_table; /*use only old_table */
} table;
};
typedef union dict_undo_data_union dict_undo_data_t;
/* During recovery these are the operations that need to be undone */
struct dict_undo_struct {
ulint op_type; /* Discriminator one of :
TRX_UNDO_INDEX_CREATE_REC,
TRX_UNDO_TABLE_DROP_REC,
TRX_UNDO_TABLE_CREATE_REC,
TRX_UNDO_TABLE_RENAME_REC.*/
dict_undo_data_t
data; /* Data required for UNDO */
UT_LIST_NODE_T(struct dict_undo_struct)
node; /* UNDO list node */
};
typedef struct dict_undo_struct dict_undo_t;
typedef UT_LIST_BASE_NODE_T(dict_undo_t) dict_undo_list_t;
/* TODO: Currently this data structure is a place holder for indexes
created by a transaction.* The REDO is a misnomer*/
struct dict_redo_struct {
ulint op_type; /* Discriminator one of :
TRX_UNDO_INDEX_CREATE_REC.*/
dict_index_t* index; /* The index created.*/
UT_LIST_NODE_T(struct dict_redo_struct)
node; /* REDO list node */
};
typedef struct dict_redo_struct dict_redo_t;
typedef UT_LIST_BASE_NODE_T(dict_redo_t) dict_redo_list_t;
#endif #endif
...@@ -71,7 +71,12 @@ row_merge_drop_indexes( ...@@ -71,7 +71,12 @@ row_merge_drop_indexes(
dict_table_t* table, /* in: table containing the indexes */ dict_table_t* table, /* in: table containing the indexes */
dict_index_t** index, /* in: indexes to drop */ dict_index_t** index, /* in: indexes to drop */
ulint num_created); /* in: number of elements in index[] */ ulint num_created); /* in: number of elements in index[] */
/*************************************************************************
Drop all partially created indexes during crash recovery. */
void
row_merge_drop_temp_indexes(void);
/*=============================*/
/************************************************************************* /*************************************************************************
Rename the tables in the data dictionary. */ Rename the tables in the data dictionary. */
...@@ -102,15 +107,14 @@ row_merge_create_temporary_table( ...@@ -102,15 +107,14 @@ row_merge_create_temporary_table(
trx_t* trx); /* in/out: transaction trx_t* trx); /* in/out: transaction
(sets error_state) */ (sets error_state) */
/************************************************************************* /*************************************************************************
Rename the indexes in the dictionary. */ Rename the temporary indexes in the dictionary to permanent ones. */
ulint ulint
row_merge_rename_index( row_merge_rename_indexes(
/*===================*/ /*=====================*/
/* out: DB_SUCCESS if all OK */ /* out: DB_SUCCESS if all OK */
trx_t* trx, /* in: Transaction */ trx_t* trx, /* in/out: transaction */
dict_table_t* table, /* in: Table for index */ dict_table_t* table); /* in/out: table with new indexes */
dict_index_t* index); /* in: Index to rename */
/************************************************************************* /*************************************************************************
Create the index and load in to the dictionary. */ Create the index and load in to the dictionary. */
......
...@@ -436,10 +436,11 @@ row_drop_table_for_mysql( ...@@ -436,10 +436,11 @@ row_drop_table_for_mysql(
ibool drop_db);/* in: TRUE=dropping whole database */ ibool drop_db);/* in: TRUE=dropping whole database */
/************************************************************************* /*************************************************************************
Drops a table for MySQL. If the name of the dropped table ends to Drops a table for MySQL but does not commit the transaction. If the
characters INNODB_MONITOR, then this also stops printing of monitor name of the dropped table ends in one of "innodb_monitor",
output by the master thread. But does not commit the transaction, this "innodb_lock_monitor", "innodb_tablespace_monitor",
is required for UNDOing dictionary records during recovery.*/ "innodb_table_monitor", then this will also stop the printing of
monitor output by the master thread. */
int int
row_drop_table_for_mysql_no_commit( row_drop_table_for_mysql_no_commit(
...@@ -509,48 +510,6 @@ row_create_index_graph_for_mysql( ...@@ -509,48 +510,6 @@ row_create_index_graph_for_mysql(
trx_t* trx, /* in: trx */ trx_t* trx, /* in: trx */
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
dict_index_t* index); /* in: index */ dict_index_t* index); /* in: index */
/***************************************************************************
Writes information to an undo log about dictionary operation, create_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* table_name); /* in: table name created. */
/***************************************************************************
Writes information to an undo log about dictionary operation, rename_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_index_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
dict_index_t* index); /* in: index created. */
/***************************************************************************
Writes information to an undo log about dictionary operation, rename_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_rename_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* from_table_name,/* in: rename from table name. */
const char* to_table_name, /* in: rename to table table. */
const char* tmp_table_name);/* in: intermediate table name */
/***************************************************************************
Writes information to an undo log about dictionary operation, drop table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_drop_table_dict_operation(
/*======================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: query thread */
const char* table_name); /* in: table name dropped */
/* A struct describing a place for an individual column in the MySQL /* A struct describing a place for an individual column in the MySQL
row format which is presented to the table handler in ha_innobase. row format which is presented to the table handler in ha_innobase.
......
...@@ -28,16 +28,6 @@ row_undo_ins( ...@@ -28,16 +28,6 @@ row_undo_ins(
/* out: DB_SUCCESS */ /* out: DB_SUCCESS */
undo_node_t* node); /* in: row undo node */ undo_node_t* node); /* in: row undo node */
/***************************************************************
Parses the rec_type undo record. */
byte*
row_undo_ins_parse_rec_type_and_table_id(
/*=====================================*/
/* out: ptr to next field to parse */
undo_node_t* node, /* in: row undo node */
dulint* table_id); /* out: table id */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "row0uins.ic" #include "row0uins.ic"
#endif #endif
......
...@@ -51,23 +51,6 @@ row_undo_step( ...@@ -51,23 +51,6 @@ row_undo_step(
/*==========*/ /*==========*/
/* out: query thread to run next or NULL */ /* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */ que_thr_t* thr); /* in: query thread */
/***************************************************************
Build the dict undo list*/
ulint
row_undo_build_dict_undo_list(
/*==========================*/
/* out: DB_SUCCESS or error code */
undo_node_t* node); /* in: row undo node */
/***************************************************************
Undo or redo a dictionary change */
void
row_undo_dictionary(
/*================*/
trx_t* trx, /* in: the transaction */
dict_undo_t* dict_undo); /* in: dict op to undo */
/* A single query thread will try to perform the undo for all successive /* A single query thread will try to perform the undo for all successive
versions of a clustered index record, if the transaction has modified it versions of a clustered index record, if the transaction has modified it
...@@ -95,20 +78,6 @@ struct undo_node_struct{ ...@@ -95,20 +78,6 @@ struct undo_node_struct{
dulint undo_no;/* undo number of the record */ dulint undo_no;/* undo number of the record */
ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC, ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
... */ ... */
ulint rec_sub_type; /* undo log record subtype:
used when rec_type is
TRX_UNDO_DICTIONARY_REC or 0*/
char* new_table_name;/* table name in
TRX_UNDO_TABLE_CREATE_REC or
TRX_UNDO_TABLE_RENAME_REC or
TRX_UNDO_TABLE_DROP_REC or NULL */
char* old_table_name;/* old table name in
TRX_UNDO_TABLE_RENAME_REC or NULL */
char* tmp_table_name; /* intermediate table name used
during rename & drop operation in
ha_innobase::add_index().*/
dulint index_id;/* index id in TRX_UNDO_INDEX_CREATE_REC
or ut_dulint_zero */
dulint new_roll_ptr; /* roll ptr to restore to clustered index dulint new_roll_ptr; /* roll ptr to restore to clustered index
record */ record */
dulint new_trx_id; /* trx id to restore to clustered index dulint new_trx_id; /* trx id to restore to clustered index
......
...@@ -212,31 +212,6 @@ trx_undo_report_row_operation( ...@@ -212,31 +212,6 @@ trx_undo_report_row_operation(
inserted undo log record, inserted undo log record,
ut_dulint_zero if BTR_NO_UNDO_LOG ut_dulint_zero if BTR_NO_UNDO_LOG
flag was specified */ flag was specified */
/***************************************************************************
Writes information to an undo log about dictionary operation e.g.
rename_table, create_table, create_index, drop table. This information
is used in a rollback of the transaction. */
ulint
trx_undo_report_dict_operation(
/*===========================*/
/* out: DB_SUCCESS or error code */
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
TRX_UNDO_TABLE_RENAME_OP,
TRX_UNDO_TABLE_DROP_OP, or
TRX_UNDO_INDEX_CREATE_OP */
trx_t* trx, /* in: transaction */
dict_index_t* index, /* in:
if TRX_UNDO_INDEX_CREATE_OP
index to be created*/
const char* table_name, /* in: table name or NULL, used in
create table, rename table and
drop table*/
const char* old_table_name, /* in: old table name or NULL.
used in rename table */
const char* tmp_table_name, /* in: the intermediate name used */
dulint* roll_ptr); /* out: rollback pointer to the
inserted undo log record */
/********************************************************************** /**********************************************************************
Copies an undo record to heap. This function can be called if we know that Copies an undo record to heap. This function can be called if we know that
the undo log record exists. */ the undo log record exists. */
...@@ -324,9 +299,6 @@ record */ ...@@ -324,9 +299,6 @@ record */
fields of the record can change */ fields of the record can change */
#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields #define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
do not change */ do not change */
#define TRX_UNDO_DICTIONARY_REC 15 /* dictionary operation, detailed
operation type can be found from
undo log records subtype */
#define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by #define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by
this and ORed to the type above */ this and ORed to the type above */
#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl #define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
...@@ -334,21 +306,9 @@ record */ ...@@ -334,21 +306,9 @@ record */
storage fields: used by purge to storage fields: used by purge to
free the external storage */ free the external storage */
/* Operation type flags used in trx_undo_report_row_operation /* Operation type flags used in trx_undo_report_row_operation */
and trx_undo_report_dict_operation */
#define TRX_UNDO_INSERT_OP 1 #define TRX_UNDO_INSERT_OP 1
#define TRX_UNDO_MODIFY_OP 2 #define TRX_UNDO_MODIFY_OP 2
#define TRX_UNDO_INDEX_CREATE_OP 3 /* alter table add index */
#define TRX_UNDO_TABLE_CREATE_OP 4 /* create table */
#define TRX_UNDO_TABLE_RENAME_OP 5 /* rename table */
#define TRX_UNDO_TABLE_DROP_OP 6 /* drop table */
/* Subtypes for dictionary operation */
#define TRX_UNDO_NULL_REC 0 /* No subtype */
#define TRX_UNDO_INDEX_CREATE_REC 1 /* index create record */
#define TRX_UNDO_TABLE_CREATE_REC 2 /* table create record */
#define TRX_UNDO_TABLE_RENAME_REC 3 /* table rename record */
#define TRX_UNDO_TABLE_DROP_REC 4 /* table drop record */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "trx0rec.ic" #include "trx0rec.ic"
......
...@@ -408,8 +408,8 @@ trx_get_que_state_str( ...@@ -408,8 +408,8 @@ trx_get_que_state_str(
/* Signal to a transaction */ /* Signal to a transaction */
struct trx_sig_struct{ struct trx_sig_struct{
ulint type; /* signal type */ unsigned type:3; /* signal type */
ulint sender; /* TRX_SIG_SELF or unsigned sender:1; /* TRX_SIG_SELF or
TRX_SIG_OTHER_SESS */ TRX_SIG_OTHER_SESS */
que_thr_t* receiver; /* non-NULL if the sender of the signal que_thr_t* receiver; /* non-NULL if the sender of the signal
wants reply after the operation induced wants reply after the operation induced
...@@ -437,66 +437,78 @@ struct trx_struct{ ...@@ -437,66 +437,78 @@ struct trx_struct{
current operation, or an empty current operation, or an empty
string */ string */
unsigned is_purge:1; /* 0=user transaction, 1=purge */ unsigned is_purge:1; /* 0=user transaction, 1=purge */
ulint conc_state; /* state of the trx from the point unsigned conc_state:2; /* state of the trx from the point
of view of concurrency control: of view of concurrency control:
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY, TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY,
... */ ... */
time_t start_time; /* time the trx object was created unsigned que_state:2; /* valid when conc_state == TRX_ACTIVE:
or the state last time became TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
TRX_ACTIVE */ ... */
ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */ unsigned isolation_level:2;/* TRX_ISO_REPEATABLE_READ, ... */
ibool check_foreigns; /* normally TRUE, but if the user unsigned check_foreigns:1;/* normally TRUE, but if the user
wants to suppress foreign key checks, wants to suppress foreign key checks,
(in table imports, for example) we (in table imports, for example) we
set this FALSE */ set this FALSE */
ibool check_unique_secondary; unsigned check_unique_secondary:1;
/* normally TRUE, but if the user /* normally TRUE, but if the user
wants to speed up inserts by wants to speed up inserts by
suppressing unique key checks suppressing unique key checks
for secondary indexes when we decide for secondary indexes when we decide
if we can use the insert buffer for if we can use the insert buffer for
them, we set this FALSE */ them, we set this FALSE */
dulint id; /* transaction id */ unsigned support_xa:1; /* normally we do the XA two-phase
XID xid; /* X/Open XA transaction
identification to identify a
transaction branch */
ibool support_xa; /* normally we do the XA two-phase
commit steps, but by setting this to commit steps, but by setting this to
FALSE, one can save CPU time and about FALSE, one can save CPU time and about
150 bytes in the undo log size as then 150 bytes in the undo log size as then
we skip XA steps */ we skip XA steps */
dulint no; /* transaction serialization number == unsigned flush_log_later:1;/* when we commit the transaction
max trx id when the transaction is
moved to COMMITTED_IN_MEMORY state */
ibool flush_log_later;/* when we commit the transaction
in MySQL's binlog write, we will in MySQL's binlog write, we will
flush the log to disk later in flush the log to disk later in
a separate call */ a separate call */
ibool must_flush_log_later;/* this flag is set to TRUE in unsigned must_flush_log_later:1;/* this flag is set to TRUE in
trx_commit_off_kernel() if trx_commit_off_kernel() if
flush_log_later was TRUE, and there flush_log_later was TRUE, and there
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() */
ib_uint64_t commit_lsn; /* lsn at the time of the commit */ unsigned dict_operation:1;/* nonzero if the trx is used
ibool dict_operation; /* TRUE if the trx is used to create to create a table, create an
a table, create an index, or drop a index, or drop a table. This
table. This is a hint that the table is a hint that the table may
may need to be dropped in crash need to be dropped in crash
recovery. */ recovery. */
dict_undo_list_t*
dict_undo_list; /* List of undo records created
during recovery. */
dict_redo_list_t*
dict_redo_list; /* List of indexes created by this
transaction. */
dulint table_id; /* Table to drop iff dict_operation
is TRUE. */
/*------------------------------*/
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
was taken */ was taken */
unsigned has_search_latch:1;
/* TRUE if this trx has latched the
search system latch in S-mode */
unsigned declared_to_be_inside_innodb:1;
/* this is TRUE if we have declared
this transaction in
srv_conc_enter_innodb to be inside the
InnoDB engine */
unsigned handling_signals:1;/* this is TRUE as long as the trx
is handling signals */
unsigned dict_operation_lock_mode:2;
/* 0, RW_S_LATCH, or RW_X_LATCH:
the latch mode trx currently holds
on dict_operation_lock */
time_t start_time; /* time the trx object was created
or the state last time became
TRX_ACTIVE */
dulint id; /* transaction id */
XID xid; /* X/Open XA transaction
identification to identify a
transaction branch */
dulint no; /* transaction serialization number ==
max trx id when the transaction is
moved to COMMITTED_IN_MEMORY state */
ib_uint64_t commit_lsn; /* lsn at the time of the commit */
dulint table_id; /* Table to drop iff dict_operation
is TRUE, or ut_dulint_zero. */
/*------------------------------*/
void* mysql_thd; /* MySQL thread handle corresponding void* mysql_thd; /* MySQL thread handle corresponding
to this trx, or NULL */ to this trx, or NULL */
char** mysql_query_str;/* pointer to the field in mysqld_thd char** mysql_query_str;/* pointer to the field in mysqld_thd
...@@ -523,13 +535,6 @@ struct trx_struct{ ...@@ -523,13 +535,6 @@ struct trx_struct{
/* how many tables the current SQL /* how many tables the current SQL
statement uses, except those statement uses, except those
in consistent read */ in consistent read */
ibool dict_operation_lock_mode;
/* 0, RW_S_LATCH, or RW_X_LATCH:
the latch mode trx currently holds
on dict_operation_lock */
ibool has_search_latch;
/* TRUE if this trx has latched the
search system latch in S-mode */
ulint search_latch_timeout; ulint search_latch_timeout;
/* If we notice that someone is /* If we notice that someone is
waiting for our S-lock on the search waiting for our S-lock on the search
...@@ -541,11 +546,6 @@ struct trx_struct{ ...@@ -541,11 +546,6 @@ struct trx_struct{
to reduce contention on the search to reduce contention on the search
latch */ latch */
/*------------------------------*/ /*------------------------------*/
ibool declared_to_be_inside_innodb;
/* this is TRUE if we have declared
this transaction in
srv_conc_enter_innodb to be inside the
InnoDB engine */
ulint n_tickets_to_enter_innodb; ulint n_tickets_to_enter_innodb;
/* this can be > 0 only when /* this can be > 0 only when
declared_to_... is TRUE; when we come declared_to_... is TRUE; when we come
...@@ -587,8 +587,6 @@ struct trx_struct{ ...@@ -587,8 +587,6 @@ struct trx_struct{
duplicate key error, a mysql key duplicate key error, a mysql key
number of that index is stored here */ number of that index is stored here */
sess_t* sess; /* session of the trx, NULL if none */ sess_t* sess; /* session of the trx, NULL if none */
ulint que_state; /* TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT,
... */
que_t* graph; /* query currently run in the session, que_t* graph; /* query currently run in the session,
or NULL if none; NOTE that the query or NULL if none; NOTE that the query
belongs to the session, and it can belongs to the session, and it can
...@@ -596,8 +594,6 @@ struct trx_struct{ ...@@ -596,8 +594,6 @@ struct trx_struct{
it is a stored procedure with a COMMIT it is a stored procedure with a COMMIT
WORK statement, for instance */ WORK statement, for instance */
ulint n_active_thrs; /* number of active query threads */ ulint n_active_thrs; /* number of active query threads */
ibool handling_signals;/* this is TRUE as long as the trx
is handling signals */
que_t* graph_before_signal_handling; que_t* graph_before_signal_handling;
/* value of graph when signal handling /* value of graph when signal handling
for this trx started: this is used to for this trx started: this is used to
...@@ -631,7 +627,10 @@ struct trx_struct{ ...@@ -631,7 +627,10 @@ struct trx_struct{
trx that are in the QUE_THR_LOCK_WAIT trx that are in the QUE_THR_LOCK_WAIT
state */ state */
ulint deadlock_mark; /* a mark field used in deadlock ulint deadlock_mark; /* a mark field used in deadlock
checking algorithm */ checking algorithm. This must be
in its own machine word, because
it can be changed by other
threads while holding kernel_mutex. */
/*------------------------------*/ /*------------------------------*/
mem_heap_t* lock_heap; /* memory heap for the locks of the mem_heap_t* lock_heap; /* memory heap for the locks of the
transaction */ transaction */
...@@ -701,19 +700,19 @@ struct trx_struct{ ...@@ -701,19 +700,19 @@ struct trx_struct{
transaction, e.g., a parallel transaction, e.g., a parallel
query */ query */
/* Transaction concurrency states (trx->conc_state) */ /* Transaction concurrency states (trx->conc_state) */
#define TRX_NOT_STARTED 1 #define TRX_NOT_STARTED 0
#define TRX_ACTIVE 2 #define TRX_ACTIVE 1
#define TRX_COMMITTED_IN_MEMORY 3 #define TRX_COMMITTED_IN_MEMORY 2
#define TRX_PREPARED 4 /* Support for 2PC/XA */ #define TRX_PREPARED 3 /* Support for 2PC/XA */
/* Transaction execution states when trx->conc_state == TRX_ACTIVE */ /* Transaction execution states when trx->conc_state == TRX_ACTIVE */
#define TRX_QUE_RUNNING 1 /* transaction is running */ #define TRX_QUE_RUNNING 0 /* transaction is running */
#define TRX_QUE_LOCK_WAIT 2 /* transaction is waiting for a lock */ #define TRX_QUE_LOCK_WAIT 1 /* transaction is waiting for a lock */
#define TRX_QUE_ROLLING_BACK 3 /* transaction is rolling back */ #define TRX_QUE_ROLLING_BACK 2 /* transaction is rolling back */
#define TRX_QUE_COMMITTING 4 /* transaction is committing */ #define TRX_QUE_COMMITTING 3 /* transaction is committing */
/* Transaction isolation levels (trx->isolation_level) */ /* Transaction isolation levels (trx->isolation_level) */
#define TRX_ISO_READ_UNCOMMITTED 1 /* dirty read: non-locking #define TRX_ISO_READ_UNCOMMITTED 0 /* dirty read: non-locking
SELECTs are performed so that SELECTs are performed so that
we do not look at a possible we do not look at a possible
earlier version of a record; earlier version of a record;
...@@ -722,7 +721,7 @@ struct trx_struct{ ...@@ -722,7 +721,7 @@ struct trx_struct{
level; otherwise like level level; otherwise like level
2 */ 2 */
#define TRX_ISO_READ_COMMITTED 2 /* somewhat Oracle-like #define TRX_ISO_READ_COMMITTED 1 /* somewhat Oracle-like
isolation, except that in isolation, except that in
range UPDATE and DELETE we range UPDATE and DELETE we
must block phantom rows must block phantom rows
...@@ -735,7 +734,7 @@ struct trx_struct{ ...@@ -735,7 +734,7 @@ struct trx_struct{
each consistent read reads its each consistent read reads its
own snapshot */ own snapshot */
#define TRX_ISO_REPEATABLE_READ 3 /* this is the default; #define TRX_ISO_REPEATABLE_READ 2 /* this is the default;
all consistent reads in the all consistent reads in the
same trx read the same same trx read the same
snapshot; snapshot;
...@@ -743,7 +742,7 @@ struct trx_struct{ ...@@ -743,7 +742,7 @@ struct trx_struct{
in locking reads to block in locking reads to block
insertions into gaps */ insertions into gaps */
#define TRX_ISO_SERIALIZABLE 4 /* all plain SELECTs are #define TRX_ISO_SERIALIZABLE 3 /* all plain SELECTs are
converted to LOCK IN SHARE converted to LOCK IN SHARE
MODE reads */ MODE reads */
...@@ -754,7 +753,7 @@ Multiple flags can be combined with bitwise OR. */ ...@@ -754,7 +753,7 @@ Multiple flags can be combined with bitwise OR. */
/* Types of a trx signal */ /* Types of a trx signal */
#define TRX_SIG_NO_SIGNAL 100 #define TRX_SIG_NO_SIGNAL 0
#define TRX_SIG_TOTAL_ROLLBACK 1 #define TRX_SIG_TOTAL_ROLLBACK 1
#define TRX_SIG_ROLLBACK_TO_SAVEPT 2 #define TRX_SIG_ROLLBACK_TO_SAVEPT 2
#define TRX_SIG_COMMIT 3 #define TRX_SIG_COMMIT 3
...@@ -762,10 +761,10 @@ Multiple flags can be combined with bitwise OR. */ ...@@ -762,10 +761,10 @@ Multiple flags can be combined with bitwise OR. */
#define TRX_SIG_BREAK_EXECUTION 5 #define TRX_SIG_BREAK_EXECUTION 5
/* Sender types of a signal */ /* Sender types of a signal */
#define TRX_SIG_SELF 1 /* sent by the session itself, or #define TRX_SIG_SELF 0 /* sent by the session itself, or
by an error occurring within this by an error occurring within this
session */ session */
#define TRX_SIG_OTHER_SESS 2 /* sent by another session (which #define TRX_SIG_OTHER_SESS 1 /* sent by another session (which
must hold rights to this) */ must hold rights to this) */
/* Commit command node in a query graph */ /* Commit command node in a query graph */
......
...@@ -15,8 +15,6 @@ Created 1/20/1994 Heikki Tuuri ...@@ -15,8 +15,6 @@ Created 1/20/1994 Heikki Tuuri
#include <ctype.h> #include <ctype.h>
#endif #endif
#define TEMP_TABLE_PREFIX '/' /* Table name prefix for temporary
tables used in fast index creation */
#define TEMP_INDEX_PREFIX '\377' /* Index name prefix in fast index #define TEMP_INDEX_PREFIX '\377' /* Index name prefix in fast index
creation */ creation */
......
...@@ -35,6 +35,7 @@ Created 9/20/1997 Heikki Tuuri ...@@ -35,6 +35,7 @@ Created 9/20/1997 Heikki Tuuri
#include "dict0boot.h" #include "dict0boot.h"
#include "fil0fil.h" #include "fil0fil.h"
#include "sync0sync.h" #include "sync0sync.h"
#include "row0merge.h"
#ifdef UNIV_HOTBACKUP #ifdef UNIV_HOTBACKUP
/* This is set to FALSE if the backup was originally taken with the /* This is set to FALSE if the backup was originally taken with the
...@@ -2933,6 +2934,9 @@ recv_recovery_from_checkpoint_finish(void) ...@@ -2933,6 +2934,9 @@ recv_recovery_from_checkpoint_finish(void)
recv_sys_free(); recv_sys_free();
#endif #endif
/* Drop partially created indexes. */
row_merge_drop_temp_indexes();
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/* Wait for a while so that created threads have time to suspend /* Wait for a while so that created threads have time to suspend
themselves before we switch the latching order checks on */ themselves before we switch the latching order checks on */
......
...@@ -1523,11 +1523,6 @@ row_merge_drop_index( ...@@ -1523,11 +1523,6 @@ row_merge_drop_index(
foreign key constraints on this table where this index is used */ foreign key constraints on this table where this index is used */
dict_table_replace_index_in_foreign_list(table, index); dict_table_replace_index_in_foreign_list(table, index);
if (trx->dict_redo_list) {
dict_redo_remove_index(trx, index);
}
dict_index_remove_from_cache(table, index); dict_index_remove_from_cache(table, index);
if (dict_lock) { if (dict_lock) {
...@@ -1556,6 +1551,53 @@ row_merge_drop_indexes( ...@@ -1556,6 +1551,53 @@ row_merge_drop_indexes(
} }
} }
/*************************************************************************
Drop all partially created indexes during crash recovery. */
void
row_merge_drop_temp_indexes(void)
/*=============================*/
{
trx_t* trx;
ulint err;
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system
tables in Innobase. Deleting a row from SYS_INDEXES table also
frees the file segments of the B-tree associated with the index. */
#if TEMP_INDEX_PREFIX != '\377'
# error "TEMP_INDEX_PREFIX != '\377'"
#endif
static const char drop_temp_indexes[] =
"PROCEDURE DROP_TEMP_INDEXES_PROC () IS\n"
"indexid CHAR;\n"
"DECLARE CURSOR c IS SELECT ID FROM SYS_INDEXES\n"
"WHERE SUBSTR(NAME,0,1)='\377' FOR UPDATE;\n"
"BEGIN\n"
"\tOPEN c;\n"
"\tWHILE 1 LOOP\n"
"\t\tFETCH c INTO indexid;\n"
"\t\tIF (SQL % NOTFOUND) THEN\n"
"\t\t\tEXIT;\n"
"\t\tEND IF;\n"
"\t\tDELETE FROM SYS_FIELDS WHERE INDEX_ID = indexid;\n"
"\t\tDELETE FROM SYS_INDEXES WHERE CURRENT OF c;\n"
"\tEND LOOP;\n"
"\tCLOSE c;\n"
"END;\n";
trx = trx_allocate_for_background();
trx->op_info = "dropping partially created indexes";
row_mysql_lock_data_dictionary(trx);
err = que_eval_sql(NULL, drop_temp_indexes, FALSE, trx);
ut_a(err == DB_SUCCESS);
row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx);
trx_free_for_background(trx);
}
/************************************************************************* /*************************************************************************
Create a merge file. */ Create a merge file. */
static static
...@@ -1638,87 +1680,72 @@ row_merge_create_temporary_table( ...@@ -1638,87 +1680,72 @@ row_merge_create_temporary_table(
dict_table_t* new_table = NULL; dict_table_t* new_table = NULL;
ulint n_cols = dict_table_get_n_user_cols(table); ulint n_cols = dict_table_get_n_user_cols(table);
ulint error; ulint error;
mem_heap_t* heap = mem_heap_create(1000);
ut_ad(table_name); ut_ad(table_name);
ut_ad(index_def); ut_ad(index_def);
ut_ad(table); ut_ad(table);
ut_ad(mutex_own(&dict_sys->mutex)); ut_ad(mutex_own(&dict_sys->mutex));
error = row_undo_report_create_table_dict_operation(trx, table_name); new_table = dict_mem_table_create(table_name, 0, n_cols, table->flags);
if (error == DB_SUCCESS) { for (i = 0; i < n_cols; i++) {
const dict_col_t* col;
mem_heap_t* heap = mem_heap_create(1000); const char* col_name;
log_buffer_flush_to_disk();
new_table = dict_mem_table_create(
table_name, 0, n_cols, table->flags);
for (i = 0; i < n_cols; i++) {
const dict_col_t* col;
const char* col_name;
col = dict_table_get_nth_col(table, i);
col_name = dict_table_get_col_name(table, i);
dict_mem_table_add_col(
new_table, heap, col_name, col->mtype,
row_merge_col_prtype(col, col_name, index_def),
col->len);
}
error = row_create_table_for_mysql(new_table, trx); col = dict_table_get_nth_col(table, i);
mem_heap_free(heap); col_name = dict_table_get_col_name(table, i);
if (error != DB_SUCCESS) { dict_mem_table_add_col(new_table, heap, col_name, col->mtype,
new_table = NULL; row_merge_col_prtype(col, col_name,
} index_def),
col->len);
} }
error = row_create_table_for_mysql(new_table, trx);
mem_heap_free(heap);
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
trx->error_state = error; trx->error_state = error;
new_table = NULL;
} }
return(new_table); return(new_table);
} }
/************************************************************************* /*************************************************************************
Rename the indexes in the dictionary. */ Rename the temporary indexes in the dictionary to permanent ones. */
ulint ulint
row_merge_rename_index( row_merge_rename_indexes(
/*===================*/ /*=====================*/
/* out: DB_SUCCESS if all OK */ /* out: DB_SUCCESS if all OK */
trx_t* trx, /* in: Transaction */ trx_t* trx, /* in/out: transaction */
dict_table_t* table, /* in: Table for index */ dict_table_t* table) /* in/out: table with new indexes */
dict_index_t* index) /* in: Index to rename */
{ {
ibool dict_lock = FALSE; ibool dict_lock = FALSE;
ulint err = DB_SUCCESS; ulint err = DB_SUCCESS;
pars_info_t* info = pars_info_create(); pars_info_t* info = pars_info_create();
/* Only rename from temp names */
ut_a(*index->name == TEMP_INDEX_PREFIX);
/* We use the private SQL parser of Innobase to generate the /* We use the private SQL parser of Innobase to generate the
query graphs needed in renaming index. */ query graphs needed in renaming indexes. */
static const char str1[] = #if TEMP_INDEX_PREFIX != '\377'
"PROCEDURE RENAME_INDEX_PROC () IS\n" # error "TEMP_INDEX_PREFIX != '\377'"
#endif
static const char rename_indexes[] =
"PROCEDURE RENAME_INDEXES_PROC () IS\n"
"BEGIN\n" "BEGIN\n"
"UPDATE SYS_INDEXES SET NAME = :name\n" "UPDATE SYS_INDEXES SET NAME=SUBSTR(NAME,1,LENGTH(NAME)-1)\n"
" WHERE ID = :indexid AND TABLE_ID = :tableid;\n" "WHERE TABLE_ID = :tableid AND SUBSTR(NAME,0,1)='\377';\n"
"END;\n"; "END;\n";
table = index->table; ut_ad(table && trx);
ut_ad(index && table && trx);
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
trx->op_info = "renaming index"; trx->op_info = "renaming indexes";
pars_info_add_str_literal(info, "name", index->name + 1);
pars_info_add_dulint_literal(info, "indexid", index->id);
pars_info_add_dulint_literal(info, "tableid", table->id); pars_info_add_dulint_literal(info, "tableid", table->id);
if (trx->dict_operation_lock_mode == 0) { if (trx->dict_operation_lock_mode == 0) {
...@@ -1726,10 +1753,16 @@ row_merge_rename_index( ...@@ -1726,10 +1753,16 @@ row_merge_rename_index(
dict_lock = TRUE; dict_lock = TRUE;
} }
err = que_eval_sql(info, str1, FALSE, trx); err = que_eval_sql(info, rename_indexes, FALSE, trx);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
index->name++; dict_index_t* index = dict_table_get_first_index(table);
do {
if (*index->name == TEMP_INDEX_PREFIX) {
index->name++;
}
index = dict_table_get_next_index(index);
} while (index);
} }
if (dict_lock) { if (dict_lock) {
...@@ -1826,8 +1859,9 @@ row_merge_create_index( ...@@ -1826,8 +1859,9 @@ row_merge_create_index(
index_def) index_def)
{ {
dict_index_t* index; dict_index_t* index;
ulint err = DB_SUCCESS; ulint err;
ulint n_fields = index_def->n_fields; ulint n_fields = index_def->n_fields;
ulint i;
/* Create the index prototype, using the passed in def, this is not /* Create the index prototype, using the passed in def, this is not
a persistent operation. We pass 0 as the space id, and determine at a persistent operation. We pass 0 as the space id, and determine at
...@@ -1846,56 +1880,33 @@ row_merge_create_index( ...@@ -1846,56 +1880,33 @@ row_merge_create_index(
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID); index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
index->table = table; index->table = table;
/* Write the UNDO record for the create index */ for (i = 0; i < n_fields; i++) {
err = row_undo_report_create_index_dict_operation(trx, index); merge_index_field_t* ifield = &index_def->fields[i];
if (err == DB_SUCCESS) {
ulint i;
/* Make sure the UNDO record gets to disk */
log_buffer_flush_to_disk();
for (i = 0; i < n_fields; i++) {
merge_index_field_t* ifield;
ifield = &index_def->fields[i];
dict_mem_index_add_field(index, dict_mem_index_add_field(index, ifield->field_name,
ifield->field_name, ifield->prefix_len);
ifield->prefix_len); }
}
/* Add the index to SYS_INDEXES, this will use the prototype /* Add the index to SYS_INDEXES, this will use the prototype
to create an entry in SYS_INDEXES. */ to create an entry in SYS_INDEXES. */
err = row_create_index_graph_for_mysql(trx, table, index); err = row_create_index_graph_for_mysql(trx, table, index);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
index = row_merge_dict_table_get_index( index = row_merge_dict_table_get_index(
table, index_def); table, index_def);
ut_a(index); ut_a(index);
#ifdef ROW_MERGE_IS_INDEX_USABLE #ifdef ROW_MERGE_IS_INDEX_USABLE
/* Note the id of the transaction that created this /* Note the id of the transaction that created this
index, we use it to restrict readers from accessing index, we use it to restrict readers from accessing
this index, to ensure read consistency. */ this index, to ensure read consistency. */
index->trx_id = trx->id; index->trx_id = trx->id;
#endif /* ROW_MERGE_IS_INDEX_USABLE */ #endif /* ROW_MERGE_IS_INDEX_USABLE */
} else {
/* Create element and append to list in trx. So that
we can rename from temp name to real name. */
if (trx->dict_redo_list) {
dict_redo_t* dict_redo;
dict_redo = dict_redo_create_element(trx);
dict_redo->index = index;
}
}
}
if (err != DB_SUCCESS) {
trx->error_state = err; trx->error_state = err;
index = NULL;
} }
return(index); return(index);
...@@ -1937,8 +1948,6 @@ row_merge_drop_table( ...@@ -1937,8 +1948,6 @@ row_merge_drop_table(
dict_locked = TRUE; dict_locked = TRUE;
} }
ut_a(*table->name == TEMP_TABLE_PREFIX);
/* Drop the table immediately if it is not referenced by MySQL */ /* Drop the table immediately if it is not referenced by MySQL */
if (table->n_mysql_handles_opened == 0) { if (table->n_mysql_handles_opened == 0) {
err = row_drop_table_for_mysql_no_commit(table->name, trx, err = row_drop_table_for_mysql_no_commit(table->name, trx,
......
...@@ -732,7 +732,6 @@ row_prebuilt_free( ...@@ -732,7 +732,6 @@ row_prebuilt_free(
references to it now.*/ references to it now.*/
if (prebuilt->table->to_be_dropped if (prebuilt->table->to_be_dropped
&& prebuilt->table->n_mysql_handles_opened == 0) { && prebuilt->table->n_mysql_handles_opened == 0) {
ut_a(*prebuilt->table->name == TEMP_TABLE_PREFIX);
if (!row_add_table_to_background_drop_list(prebuilt->table)) { if (!row_add_table_to_background_drop_list(prebuilt->table)) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -3045,18 +3044,17 @@ row_drop_table_for_mysql( ...@@ -3045,18 +3044,17 @@ row_drop_table_for_mysql(
ulint err; ulint err;
err = row_drop_table_for_mysql_no_commit(name, trx, drop_db); err = row_drop_table_for_mysql_no_commit(name, trx, drop_db);
trx_commit_for_mysql(trx);
if (!srv_created_new_raw) { return(err);
trx_commit_for_mysql(trx);
}
return err;
} }
/************************************************************************* /*************************************************************************
Drops a table for MySQL. If the name of the table to be dropped is equal Drops a table for MySQL but does not commit the transaction. If the
with one of the predefined magic table names, then this also stops printing name of the dropped table ends in one of "innodb_monitor",
the corresponding monitor output by the master thread. */ "innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also stop the printing of
monitor output by the master thread. */
int int
row_drop_table_for_mysql_no_commit( row_drop_table_for_mysql_no_commit(
...@@ -3212,7 +3210,7 @@ check_next_foreign: ...@@ -3212,7 +3210,7 @@ check_next_foreign:
if (added) { if (added) {
/* Temporary tables can have read views and we don't /* Temporary tables can have read views and we don't
print any warning. */ print any warning. */
if (*table->name != TEMP_TABLE_PREFIX) { if (!table->to_be_dropped) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: MySQL is" fputs(" InnoDB: Warning: MySQL is"
" trying to drop table ", stderr); " trying to drop table ", stderr);
...@@ -3223,8 +3221,6 @@ check_next_foreign: ...@@ -3223,8 +3221,6 @@ check_next_foreign:
"InnoDB: Adding the table to the" "InnoDB: Adding the table to the"
" background drop queue.\n", " background drop queue.\n",
stderr); stderr);
} else {
ut_a(table->to_be_dropped);
} }
/* We return DB_SUCCESS to MySQL though the drop will /* We return DB_SUCCESS to MySQL though the drop will
...@@ -4171,99 +4167,6 @@ row_check_table_for_mysql( ...@@ -4171,99 +4167,6 @@ row_check_table_for_mysql(
return(ret); return(ret);
} }
/***************************************************************************
Writes information to an undo log about dictionary operation e.g.
rename_table, create_table, create_index, drop table. This information
is used in a rollback of the transaction. */
static
ulint
row_undo_report_dict_operation(
/*===========================*/
/* out: DB_SUCCESS or error code */
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
TRX_UNDO_TABLE_RENAME_OP,
TRX_UNDO_TABLE_DROP_OP, or
TRX_UNDO_INDEX_CREATE_OP */
trx_t* trx, /* in: transaction */
dict_index_t* index, /* in:
if TRX_UNDO_INDEX_CREATE_OP
index to be created*/
const char* table_name, /* in: table name or NULL, used in
create table, rename table and
drop table*/
const char* old_table_name, /* in: old table name or NULL. */
const char* tmp_table_name) /* in: the intermediate name or NULL */
{
dulint roll_ptr;
return trx_undo_report_dict_operation(
op_type, trx, index, table_name, old_table_name,
tmp_table_name, &roll_ptr);
}
/***************************************************************************
Writes information to an undo log about dictionary operation, create_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* table_name) /* in: table name to create. */
{
return row_undo_report_dict_operation(
TRX_UNDO_TABLE_CREATE_OP, trx, NULL, table_name, NULL, NULL);
}
/***************************************************************************
Writes information to an undo log about dictionary operation, create_index.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_create_index_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
dict_index_t* index) /* in: index created. */
{
return row_undo_report_dict_operation(
TRX_UNDO_INDEX_CREATE_OP, trx, index, NULL, NULL, NULL);
}
/***************************************************************************
Writes information to an undo log about dictionary operation, rename_table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_rename_table_dict_operation(
/*========================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: transaction */
const char* from_table_name,/* in: rename from table table. */
const char* to_table_name, /* in: rename to table name. */
const char* tmp_table_name) /* in: intermediate name for table */
{
return row_undo_report_dict_operation(
TRX_UNDO_TABLE_RENAME_OP, trx, NULL,
to_table_name, from_table_name, tmp_table_name);
}
/***************************************************************************
Writes information to an undo log about dictionary operation, drop table.
This information is used in a rollback of the transaction. */
ulint
row_undo_report_drop_table_dict_operation(
/*======================================*/
/* out: DB_SUCCESS or error code */
trx_t* trx, /* in: query thread */
const char* table_name) /* in: table name dropped */
{
return row_undo_report_dict_operation(
TRX_UNDO_TABLE_DROP_OP, trx, NULL, table_name, NULL, NULL);
}
/************************************************************************* /*************************************************************************
Create query graph for an index creation */ Create query graph for an index creation */
...@@ -4278,7 +4181,7 @@ row_create_index_graph_for_mysql( ...@@ -4278,7 +4181,7 @@ row_create_index_graph_for_mysql(
ind_node_t* node; /* Index creation node */ ind_node_t* node; /* Index creation node */
mem_heap_t* heap; /* Memory heap */ mem_heap_t* heap; /* Memory heap */
que_thr_t* thr; /* Query thread */ que_thr_t* thr; /* Query thread */
ulint err = DB_SUCCESS; ulint err;
ut_ad(trx && index); ut_ad(trx && index);
......
...@@ -28,7 +28,6 @@ Created 2/25/1997 Heikki Tuuri ...@@ -28,7 +28,6 @@ Created 2/25/1997 Heikki Tuuri
#include "que0que.h" #include "que0que.h"
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
#include "log0log.h" #include "log0log.h"
#include "row0mysql.h"
/******************************************************************* /*******************************************************************
Removes a clustered index record. The pcur in node was positioned on the Removes a clustered index record. The pcur in node was positioned on the
...@@ -213,36 +212,6 @@ retry: ...@@ -213,36 +212,6 @@ retry:
return(err); return(err);
} }
/***************************************************************
Parses the rec_type undo record. */
byte*
row_undo_ins_parse_rec_type_and_table_id(
/*=====================================*/
/* out: ptr to next field to parse */
undo_node_t* node, /* in: row undo node */
dulint* table_id) /* out: table id */
{
byte* ptr;
dulint undo_no;
ulint type;
ulint dummy;
ibool dummy_extern;
ut_ad(node && node->trx);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
&dummy_extern, &undo_no, table_id);
node->rec_type = type;
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
node->trx->dict_operation = TRUE;
}
return ptr;
}
/*************************************************************** /***************************************************************
Parses the row reference and other info in a fresh insert undo record. */ Parses the row reference and other info in a fresh insert undo record. */
static static
...@@ -251,33 +220,32 @@ row_undo_ins_parse_undo_rec( ...@@ -251,33 +220,32 @@ row_undo_ins_parse_undo_rec(
/*========================*/ /*========================*/
undo_node_t* node) /* in: row undo node */ undo_node_t* node) /* in: row undo node */
{ {
dict_index_t* clust_index;
byte* ptr; byte* ptr;
dulint undo_no;
dulint table_id; dulint table_id;
ulint type;
ulint dummy;
ibool dummy_extern;
ut_ad(node); ut_ad(node);
ptr = row_undo_ins_parse_rec_type_and_table_id(node, &table_id); ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy,
&dummy_extern, &undo_no, &table_id);
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC ut_ad(type == TRX_UNDO_INSERT_REC);
|| node->rec_type == TRX_UNDO_DICTIONARY_REC); node->rec_type = type;
if (node->rec_type == TRX_UNDO_INSERT_REC) {
node->table = dict_table_get_on_id(table_id, node->trx);
/* If we can't find the table or .ibd file is missing, node->table = dict_table_get_on_id(table_id, node->trx);
we skip the UNDO.*/
if (node->table == NULL || node->table->ibd_file_missing) {
node->table = NULL; /* Skip the UNDO if we can't find the table or the .ibd file. */
} else { if (UNIV_UNLIKELY(node->table == NULL)) {
dict_index_t* clust_index; } else if (UNIV_UNLIKELY(node->table->ibd_file_missing)) {
node->table = NULL;
clust_index = dict_table_get_first_index(node->table); } else {
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_rec_get_row_ref( ptr = trx_undo_rec_get_row_ref(
ptr, clust_index, &node->ref, node->heap); ptr, clust_index, &node->ref, node->heap);
}
} }
} }
...@@ -297,14 +265,6 @@ row_undo_ins( ...@@ -297,14 +265,6 @@ row_undo_ins(
row_undo_ins_parse_undo_rec(node); row_undo_ins_parse_undo_rec(node);
/* Dictionary records are undone in a separate function */
if (node->rec_type == TRX_UNDO_DICTIONARY_REC) {
return(row_undo_build_dict_undo_list(node));
}
if (!node->table || !row_undo_search_clust_to_pcur(node)) { if (!node->table || !row_undo_search_clust_to_pcur(node)) {
trx_undo_rec_release(node->trx, node->undo_no); trx_undo_rec_release(node->trx, node->undo_no);
......
...@@ -125,7 +125,6 @@ row_undo_node_create( ...@@ -125,7 +125,6 @@ row_undo_node_create(
undo->state = UNDO_NODE_FETCH_NEXT; undo->state = UNDO_NODE_FETCH_NEXT;
undo->trx = trx; undo->trx = trx;
undo->rec_sub_type = TRX_UNDO_NULL_REC;
btr_pcur_init(&(undo->pcur)); btr_pcur_init(&(undo->pcur));
...@@ -352,360 +351,3 @@ row_undo_step( ...@@ -352,360 +351,3 @@ row_undo_step(
return(thr); return(thr);
} }
/***************************************************************
Parses the info in a fresh insert undo record containing a
dictionary change. */
static
ulint
row_undo_dictionary_parse_undo_rec(
/*===============================*/
/* out: DB_SUCCESS or DB_ERROR */
undo_node_t* node) /* in: row undo node */
{
byte* ptr;
dulint table_id;
dulint index_id;
ulint len;
ut_ad(node);
node->rec_type = trx_undo_rec_get_type(node->undo_rec);
node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec);
ptr = trx_undo_rec_get_ptr(node->undo_rec, node->undo_no);
ut_a(node->rec_type == TRX_UNDO_DICTIONARY_REC);
/* Read dictionary rec sub type */
node->rec_sub_type = mach_read_from_1(ptr);
ptr++;
/* Parse subtype parameters */
switch (node->rec_sub_type) {
case TRX_UNDO_INDEX_CREATE_REC:
table_id = mach_dulint_read_much_compressed(ptr);
len = mach_dulint_get_much_compressed_size(table_id);
ptr += len;
index_id = mach_dulint_read_much_compressed(ptr);
len = mach_dulint_get_much_compressed_size(index_id);
ptr += len;
node->table = dict_table_get_on_id(table_id, node->trx);
node->index = NULL;
if (!node->table) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Error]: Table %lu %lu not found "
"in index create undo rec\n",
(ulong) ut_dulint_get_high(table_id),
(ulong) ut_dulint_get_low(table_id));
goto err_exit;
} else if (ut_dulint_is_zero(index_id)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Error]: Index id missing from "
"index create undo rec\n");
err_exit:
mutex_enter(&kernel_mutex);
trx_print(stderr, node->trx, 1024);
mutex_exit(&kernel_mutex);
return(DB_ERROR);
} else {
node->index = dict_index_get_on_id_low(
node->table, index_id);
}
if (node->table->ibd_file_missing || !node->index) {
/* We skip undo operations to missing .ibd files
and missing indexes */
node->table = NULL;
node->index = NULL;
return(DB_SUCCESS);
}
break;
case TRX_UNDO_TABLE_CREATE_REC:
case TRX_UNDO_TABLE_DROP_REC:
len = strlen((char *)ptr) + 1;
node->new_table_name = mem_heap_strdup(node->heap, (char *)ptr);
ptr += len;
ut_ad(*node->new_table_name == TEMP_TABLE_PREFIX);
break;
case TRX_UNDO_TABLE_RENAME_REC:
len = strlen((char *)ptr) + 1;
node->new_table_name = mem_heap_strdup(node->heap, (char *)ptr);
ptr += len;
ut_ad(*node->new_table_name == TEMP_TABLE_PREFIX);
len = strlen((char *)ptr) + 1;
node->old_table_name = mem_heap_strdup(node->heap, (char *)ptr);
ptr += len;
len = strlen((char *)ptr) + 1;
node->tmp_table_name = mem_heap_strdup(node->heap, (char *)ptr);
ptr += len;
ut_ad(*node->tmp_table_name == TEMP_TABLE_PREFIX);
break;
default:
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Error]: Undefined rec_sub_type = %lu at "
"row_undo_dictionary_parse_undo_rec\n",
(ulong)node->rec_sub_type);
mutex_enter(&kernel_mutex);
trx_print(stderr, node->trx, 1024);
mutex_exit(&kernel_mutex);
return(DB_ERROR);
}
return(DB_SUCCESS);
}
/***************************************************************
Currently we gather all the information that is required to do the
UNDO. The actual UNDO is done later in row_undo_dictionary(). */
ulint
row_undo_build_dict_undo_list(
/*==========================*/
/* out: DB_SUCCESS or error code */
undo_node_t* node) /* in: row undo node */
{
trx_t* trx;
dict_undo_t* dict_undo;
ulint err = DB_SUCCESS;
ibool locked_dictionary = FALSE;
ibool thawed_dictionary = FALSE;
ut_ad(node);
ut_ad(node->state == UNDO_NODE_INSERT);
ut_a(node->trx->dict_operation);
err = row_undo_dictionary_parse_undo_rec(node);
if (err != DB_SUCCESS) {
goto func_exit;
}
trx = node->trx;
if (trx->dict_operation_lock_mode == RW_S_LATCH) {
row_mysql_unfreeze_data_dictionary(trx);
thawed_dictionary = TRUE;
}
if (trx->dict_operation_lock_mode == 0
|| trx->dict_operation_lock_mode != RW_X_LATCH) {
row_mysql_lock_data_dictionary(trx);
locked_dictionary = TRUE;
}
/* We will do our own deletes */
trx->table_id = ut_dulint_zero;
if (trx->dict_undo_list == NULL) {
dict_undo_create_list(trx);
}
/* Create an element and append to the list */
dict_undo = dict_undo_create_element(trx);
dict_undo->op_type = node->rec_sub_type;
switch (node->rec_sub_type) {
case TRX_UNDO_INDEX_CREATE_REC:
if (node->table && node->index) {
ut_a(node->index->table == node->table);
dict_undo->data.index = node->index;
} else {
dict_undo->data.index = NULL;
}
break;
case TRX_UNDO_TABLE_DROP_REC:
case TRX_UNDO_TABLE_CREATE_REC:
dict_undo->data.table.old_table = dict_table_get_low(
node->new_table_name);
break;
case TRX_UNDO_TABLE_RENAME_REC:
dict_undo->data.table.old_table = dict_table_get_low(
node->old_table_name);
dict_undo->data.table.tmp_table = dict_table_get_low(
node->tmp_table_name);
dict_undo->data.table.new_table = dict_table_get_low(
node->new_table_name);
if (dict_undo->data.table.tmp_table
&& dict_undo->data.table.old_table
&& dict_undo->data.table.new_table) {
/* This can't happen */
ut_error;
}
break;
default:
ut_error;
break;
}
if (locked_dictionary) {
row_mysql_unlock_data_dictionary(trx);
}
if (thawed_dictionary) {
row_mysql_freeze_data_dictionary(trx);
}
func_exit:
trx_undo_rec_release(node->trx, node->undo_no);
return(err);
}
/***************************************************************
Undo or redo a dictionary change. */
void
row_undo_dictionary(
/*================*/
trx_t* trx, /* in: transaction */
dict_undo_t* dict_undo) /* in: dict undo info */
{
ulint err;
switch (dict_undo->op_type) {
case TRX_UNDO_INDEX_CREATE_REC:
if (dict_undo->data.index) {
row_merge_drop_index(dict_undo->data.index,
dict_undo->data.index->table,
trx);
}
break;
/* TODO: We are REDOing the DROP ? */
case TRX_UNDO_TABLE_DROP_REC:
case TRX_UNDO_TABLE_CREATE_REC:
if (dict_undo->data.table.old_table) {
err = row_drop_table_for_mysql_no_commit(
dict_undo->data.table.old_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
}
break;
case TRX_UNDO_TABLE_RENAME_REC:
if (!dict_undo->data.table.new_table) {
/* Old name to tmp name succeeded and new name to old
name succeeded too. We have to be very careful here as
the user could loose the entire table if not done
carefully.*/
ut_ad(dict_undo->data.table.old_table);
err = row_rename_table_for_mysql(
dict_undo->data.table.old_table->name,
dict_undo->data.table.new_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
err = row_rename_table_for_mysql(
dict_undo->data.table.tmp_table->name,
dict_undo->data.table.old_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
err = row_drop_table_for_mysql_no_commit(
dict_undo->data.table.new_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
} else if (dict_undo->data.table.old_table) {
/* Rename to tmp failed.*/
ut_a(!dict_undo->data.table.tmp_table);
if (dict_undo->data.table.new_table) {
err = row_drop_table_for_mysql_no_commit(
dict_undo->data.table.new_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
}
} else if (dict_undo->data.table.tmp_table) {
/* Rename to tmp was OK. We need to UNDO it.*/
ut_ad(!dict_undo->data.table.old_table);
err = row_rename_table_for_mysql(
dict_undo->data.table.tmp_table->name,
dict_undo->data.table.old_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
if (dict_undo->data.table.new_table) {
err = row_drop_table_for_mysql_no_commit(
dict_undo->data.table.new_table->name,
trx, FALSE);
ut_a(err == DB_SUCCESS);
}
} else {
/* Shouldn't happen */
ut_error;
}
default:
ut_error;
}
}
...@@ -130,52 +130,6 @@ trx_undo_left( ...@@ -130,52 +130,6 @@ trx_undo_left(
return(UNIV_PAGE_SIZE - (ptr - page) - 10 - FIL_PAGE_DATA_END); return(UNIV_PAGE_SIZE - (ptr - page) - 10 - FIL_PAGE_DATA_END);
} }
/**************************************************************************
Get the pointer to where the data for the undo log record will be written.*/
static
byte*
trx_undo_page_get_ptr(
/*==================*/
/* out: ptr to where the undo log
record data will be written,
0 if not enough space.*/
page_t* undo_page, /* in: undo log page */
ulint need) /* in: need these man bytes */
{
byte* ptr; /* pointer within undo_page */
ulint first_free; /* offset within undo page */
ut_ad(undo_page);
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
first_free = mach_read_from_2(
undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE);
/* Start writing the undo information from the first free
bytes in the undo page */
ptr = undo_page + first_free;
ut_ad(first_free <= UNIV_PAGE_SIZE);
/* NOTE: the value need must be big enough such that the
general fields written below fit on the undo log page */
if (UNIV_UNLIKELY(trx_undo_left(undo_page, ptr) < need)) {
/* Error, not enough space */
ptr = 0;
} else {
/* Reserve 2 bytes for the pointer to the next undo log
record */
ptr += 2;
}
return(ptr);
}
/************************************************************************** /**************************************************************************
Set the next and previous pointers in the undo page for the undo record Set the next and previous pointers in the undo page for the undo record
that was written to ptr. Update the first free value by the number of bytes that was written to ptr. Update the first free value by the number of bytes
...@@ -301,191 +255,6 @@ trx_undo_page_report_insert( ...@@ -301,191 +255,6 @@ trx_undo_page_report_insert(
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr)); return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
} }
/**************************************************************************
Reports in the undo log of an index create */
static
ulint
trx_undo_page_report_index_create(
/*==============================*/
/* out: offset of the inserted entry
on the page if succeed, 0 if fail */
page_t* undo_page, /* in: undo log page */
trx_t* trx, /* in: transaction */
dict_index_t* index, /* in: index */
mtr_t* mtr) /* in: mtr */
{
byte* ptr;
ut_ad(undo_page && trx && index && mtr);
/* Get the pointer to where we will write our undo data. */
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + 11 + 11);
if (UNIV_UNLIKELY(!ptr)) {
return(0);
}
/* This is our internal dictionary undo log record. */
*ptr++ = TRX_UNDO_DICTIONARY_REC;
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
/* The sub type (discriminator) of this undo dictionary record */
*ptr++ = TRX_UNDO_INDEX_CREATE_REC;
/* For index create, we need both the table id and the index id
to be stored in the undo log record.*/
ptr += mach_dulint_write_much_compressed(ptr, index->table->id);
ptr += mach_dulint_write_much_compressed(ptr, index->id);
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
}
/**************************************************************************
Reports in the undo log of a table create */
static
ulint
trx_undo_page_report_table_create(
/*==============================*/
/* out: offset of the inserted entry
on the page if succeed, 0 if fail */
page_t* undo_page, /* in: undo log page */
trx_t* trx, /* in: transaction */
const char* table_name, /* in: table name */
mtr_t* mtr) /* in: mtr */
{
byte* ptr;
ulint name_len;
ut_ad(undo_page && trx && table_name && mtr);
name_len = strlen(table_name) + 1;
/* Get the pointer to where we will write our undo data */
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + name_len);
if (UNIV_UNLIKELY(!ptr)) {
return(0);
}
/* The type (discriminator) of this undo log */
*ptr++ = TRX_UNDO_DICTIONARY_REC;
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
/* The sub type (discriminator) of this dictionary undo log */
*ptr++ = TRX_UNDO_TABLE_CREATE_REC;
/* For table create we need to store table name */
memcpy(ptr, table_name, name_len);
ptr += name_len;
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
}
/**************************************************************************
Reports in the undo log of a table drop */
static
ulint
trx_undo_page_report_table_drop(
/*============================*/
/* out: offset of the inserted entry
on the page if succeed, 0 if fail */
page_t* undo_page, /* in: undo log page */
trx_t* trx, /* in: transaction */
const char* table_name, /* in: table name */
mtr_t* mtr) /* in: mtr */
{
byte* ptr;
ulint name_len;
ut_ad(undo_page && trx && table_name && mtr);
name_len = strlen(table_name) + 1;
/* Get the pointer to where we will write our undo data */
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1 + name_len);
if (UNIV_UNLIKELY(!ptr)) {
return(0);
}
*ptr++ = TRX_UNDO_DICTIONARY_REC;
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
/* The sub type (discriminator) of this dictionary undo log */
*ptr++ = TRX_UNDO_TABLE_DROP_REC;
/* For table drop we need to store a table name */
memcpy(ptr, table_name, name_len);
ptr += name_len;
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
}
/**************************************************************************
Reports in the undo log of a table rename */
static
ulint
trx_undo_page_report_table_rename(
/*==============================*/
/* out: offset of the inserted entry
on the page if succeed, 0 if fail */
page_t* undo_page, /* in: undo log page */
trx_t* trx, /* in: transaction */
const char* new_table_name, /* in: new table name */
const char* old_table_name, /* in: old table name */
const char* tmp_table_name, /* in: the temp name */
mtr_t* mtr) /* in: mtr */
{
byte* ptr;
ulint new_name_len;
ulint old_name_len;
ulint tmp_name_len;
ut_ad(undo_page && trx && new_table_name && old_table_name && mtr);
new_name_len = strlen(new_table_name) + 1;
old_name_len = strlen(old_table_name) + 1;
tmp_name_len = strlen(tmp_table_name) + 1;
/* Get the pointer to where we will write our undo data. */
ptr = trx_undo_page_get_ptr(undo_page, 1 + 11 + 1
+ new_name_len + old_name_len
+ tmp_name_len);
if (UNIV_UNLIKELY(!ptr)) {
return(0);
}
/* The type (discriminator) of this undo log */
*ptr++ = TRX_UNDO_DICTIONARY_REC;
ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no);
/* The sub type (discriminator) of this dictionary undo log */
*ptr++ = TRX_UNDO_TABLE_RENAME_REC;
/* For table rename we need to store the new table name and
the old table name */
memcpy(ptr, new_table_name, new_name_len);
ptr += new_name_len;
memcpy(ptr, old_table_name, old_name_len);
ptr += old_name_len;
memcpy(ptr, tmp_table_name, tmp_name_len);
ptr += tmp_name_len;
return(trx_undo_page_set_next_prev_and_add(undo_page, ptr, mtr));
}
/************************************************************************** /**************************************************************************
Reads from an undo log record the general parameters. */ Reads from an undo log record the general parameters. */
...@@ -1391,187 +1160,6 @@ trx_undo_report_row_operation( ...@@ -1391,187 +1160,6 @@ trx_undo_report_row_operation(
} }
} }
/***************************************************************************
Writes information to an undo log about dictionary operation e.g.
rename_table, create_table, create_index, drop table. This information
is used in a rollback of the transaction. */
ulint
trx_undo_report_dict_operation(
/*===========================*/
/* out: DB_SUCCESS or error code */
ulint op_type, /* in: TRX_UNDO_TABLE_CREATE_OP,
TRX_UNDO_TABLE_RENAME_OP,
TRX_UNDO_TABLE_DROP_OP, or
TRX_UNDO_INDEX_CREATE_OP */
trx_t* trx, /* in: trx */
dict_index_t* index, /* in:
if TRX_UNDO_INDEX_CREATE_OP
index to be created*/
const char* table_name, /* in: table name or NULL, used in
create table, rename table and
drop table*/
const char* old_table_name, /* in: old table name or NULL.
used in rename table */
const char* tmp_table_name, /* in: the intermediate name used
for renaming */
dulint* roll_ptr) /* out: rollback pointer to the
inserted undo log record */
{
trx_undo_t* undo;
ulint page_no;
trx_rseg_t* rseg;
mtr_t mtr;
ut_ad(trx);
#ifdef UNIV_DEBUG
switch (op_type) {
case TRX_UNDO_TABLE_RENAME_OP:
ut_ad(old_table_name);
case TRX_UNDO_TABLE_DROP_OP:
case TRX_UNDO_TABLE_CREATE_OP:
ut_ad(table_name);
break;
case TRX_UNDO_INDEX_CREATE_OP:
ut_ad(index);
break;
default:
ut_error;
}
#endif
rseg = trx->rseg;
mutex_enter(&(trx->undo_mutex));
/* If the undo log is not assigned yet, assign one */
if (trx->insert_undo == NULL) {
trx_undo_assign_undo(trx, TRX_UNDO_INSERT);
}
undo = trx->insert_undo;
if (undo == NULL) {
/* Did not succeed: out of space */
mutex_exit(&(trx->undo_mutex));
return(DB_OUT_OF_FILE_SPACE);
}
page_no = undo->last_page_no;
mtr_start(&mtr);
for (;;) {
buf_block_t* undo_block;
ulint offset;
undo_block = buf_page_get_gen(undo->space, undo->zip_size,
page_no, RW_X_LATCH,
undo->guess_block, BUF_GET,
__FILE__, __LINE__, &mtr);
#ifdef UNIV_SYNC_DEBUG
buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
#endif /* UNIV_SYNC_DEBUG */
switch (op_type) {
case TRX_UNDO_TABLE_CREATE_OP:
offset = trx_undo_page_report_table_create(
undo_block->frame, trx, table_name, &mtr);
break;
case TRX_UNDO_INDEX_CREATE_OP:
offset = trx_undo_page_report_index_create(
undo_block->frame, trx, index, &mtr);
break;
case TRX_UNDO_TABLE_RENAME_OP:
offset = trx_undo_page_report_table_rename(
undo_block->frame, trx, table_name,
old_table_name, tmp_table_name, &mtr);
break;
case TRX_UNDO_TABLE_DROP_OP:
offset = trx_undo_page_report_table_drop(
undo_block->frame, trx, table_name, &mtr);
break;
default:
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: [Error]: Undefined op_type = %lu "
"at trx_undo_report_dict_operation\n",
(ulong) op_type);
mutex_enter(&kernel_mutex);
trx_print(stderr, trx, 1024);
mutex_exit(&kernel_mutex);
return(DB_ERROR);
}
if (UNIV_UNLIKELY(offset == 0)) {
/* The record did not fit on the page. We erase the
end segment of the undo log page and write a log
record of it: this is to ensure that in the debug
version the replicate page constructed using the log
records stays identical to the original page */
trx_undo_erase_page_end(undo_block->frame, &mtr);
mtr_commit(&mtr);
} else {
/* Success */
mtr_commit(&mtr);
undo->empty = FALSE;
undo->top_page_no = page_no;
undo->top_offset = offset;
undo->top_undo_no = trx->undo_no;
undo->guess_block = undo_block;
UT_DULINT_INC(trx->undo_no);
mutex_exit(&(trx->undo_mutex));
*roll_ptr = trx_undo_build_roll_ptr(TRUE, rseg->id,
page_no, offset);
return(DB_SUCCESS);
}
ut_ad(page_no == undo->last_page_no);
/* We have to extend the undo log by one page */
mtr_start(&mtr);
/* When we add a page to an undo log, this is analogous to
a pessimistic insert in a B-tree, and we must reserve the
counterpart of the tree latch, which is the rseg mutex. */
mutex_enter(&(rseg->mutex));
page_no = trx_undo_add_page(trx, undo, &mtr);
mutex_exit(&(rseg->mutex));
if (page_no == FIL_NULL) {
/* Did not succeed: out of space */
mutex_exit(&(trx->undo_mutex));
mtr_commit(&mtr);
return(DB_OUT_OF_FILE_SPACE);
}
}
}
/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/ /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/
/********************************************************************** /**********************************************************************
......
...@@ -447,7 +447,6 @@ trx_rollback_active( ...@@ -447,7 +447,6 @@ trx_rollback_active(
trx->mysql_process_no = os_proc_get_number(); trx->mysql_process_no = os_proc_get_number();
/* TODO: Doesn't seem right */
if (trx->dict_operation) { if (trx->dict_operation) {
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE; dictionary_locked = TRUE;
...@@ -495,23 +494,6 @@ trx_rollback_active( ...@@ -495,23 +494,6 @@ trx_rollback_active(
ut_a(err == (int) DB_SUCCESS); ut_a(err == (int) DB_SUCCESS);
} }
} else if (trx->dict_undo_list) {
dict_undo_t* dict_undo;
ut_a(trx->dict_undo_list);
for (dict_undo = UT_LIST_GET_FIRST(*trx->dict_undo_list);
dict_undo;
dict_undo = UT_LIST_GET_NEXT(node, dict_undo)) {
row_undo_dictionary(trx, dict_undo);
}
dict_undo_free_list(trx);
mutex_enter(&kernel_mutex);
trx_commit_off_kernel(trx);
mutex_exit(&kernel_mutex);
} }
if (dictionary_locked) { if (dictionary_locked) {
...@@ -1239,11 +1221,7 @@ trx_finish_rollback_off_kernel( ...@@ -1239,11 +1221,7 @@ trx_finish_rollback_off_kernel(
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/* If there are dict UNDO records that need to be undone then trx_commit_off_kernel(trx);
we commit the transaction after these dictionary changes are undone.*/
if (!trx->dict_undo_list) {
trx_commit_off_kernel(trx);
}
/* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and /* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and
send reply messages to them */ send reply messages to them */
......
...@@ -99,8 +99,6 @@ trx_create( ...@@ -99,8 +99,6 @@ trx_create(
trx->dict_operation = FALSE; trx->dict_operation = FALSE;
trx->table_id = ut_dulint_zero; trx->table_id = ut_dulint_zero;
trx->dict_undo_list = NULL;
trx->dict_redo_list = NULL;
trx->mysql_thd = NULL; trx->mysql_thd = NULL;
trx->mysql_query_str = NULL; trx->mysql_query_str = NULL;
...@@ -306,8 +304,6 @@ trx_free( ...@@ -306,8 +304,6 @@ trx_free(
trx->global_read_view = NULL; trx->global_read_view = NULL;
ut_a(trx->read_view == NULL); ut_a(trx->read_view == NULL);
ut_a(trx->dict_undo_list == NULL);
ut_a(trx->dict_redo_list == NULL);
mem_free(trx); mem_free(trx);
} }
...@@ -699,10 +695,6 @@ trx_commit_off_kernel( ...@@ -699,10 +695,6 @@ trx_commit_off_kernel(
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
/* Can't commit if we have dictionary UNDO records */
ut_a(!trx->dict_undo_list);
ut_a(!trx->dict_redo_list);
trx->must_flush_log_later = FALSE; trx->must_flush_log_later = FALSE;
rseg = trx->rseg; rseg = trx->rseg;
......
...@@ -439,35 +439,13 @@ ut_print_namel( ...@@ -439,35 +439,13 @@ ut_print_namel(
fwrite(name, 1, namelen, f); fwrite(name, 1, namelen, f);
#else #else
if (table_id) { if (table_id) {
char* slash; char* slash = memchr(name, '/', namelen);
if (UNIV_UNLIKELY(*name == TEMP_TABLE_PREFIX)) {
slash = memchr(name + 1, '/', namelen);
ut_ad(slash && slash >= name + 2);
/* Database */
innobase_print_identifier(f, trx, TRUE, name + 2,
slash - (name + 2));
putc('.', f);
/* Table */
innobase_print_identifier(f, trx, TRUE, slash + 1,
namelen
- (slash - (name + 3)));
/* Identifier of temporary table */
fprintf(f, "--temporary %c--", name[1]);
return;
}
slash = memchr(name, '/', namelen);
if (!slash) { if (!slash) {
goto no_db_name; goto no_db_name;
} }
/* Print the database name and table name separately. */ /* Print the database name and table name separately. */
innobase_print_identifier(f, trx, TRUE, name, slash - name); innobase_print_identifier(f, trx, TRUE, name, slash - name);
putc('.', f); putc('.', f);
innobase_print_identifier(f, trx, TRUE, slash + 1, innobase_print_identifier(f, trx, TRUE, slash + 1,
......
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