Commit 5378db6e authored by marko's avatar marko

branches/zip: More cleanup of fast index creation.

innobase_create_temporary_tablename(): Add static qualifier.  Allocate
the memory from heap.  Return a fixed identifier.

ha_innobase::add_index(): Allocate all memory from a single heap.
Simplify error handling.  Use a fixed prefix for temporary table names,
because only one add_index() can be active for a given table.

mem_heap_empty_noninline(): New function, to be called from ha_innodb.cc.

row_build_index_for_mysql(): Remove the parameter new_primary.
parent 0e31dbac
...@@ -8074,29 +8074,26 @@ innobase_create_key_def( ...@@ -8074,29 +8074,26 @@ innobase_create_key_def(
/*********************************************************************** /***********************************************************************
Create a temporary tablename using query id, thread id, and id */ Create a temporary tablename using query id, thread id, and id */
static
char* char*
innobase_create_temporary_tablename( innobase_create_temporary_tablename(
/*================================*/ /*================================*/
/* out: New temporary tablename */ /* out: temporary tablename */
THD* thd, /* in: User thread */ mem_heap_t* heap, /* in: memory heap */
const char* table_name, /* in: Old table name */ char id, /* in: identifier */
ulint id) /* in: id */ const char* table_name) /* in: table name */
{ {
char* new_name; char* name;
ulint old_len; ulint len;
ulint new_len;
old_len = strlen(table_name);
new_len = old_len + 1 + 64;
new_name = (char *)mem_alloc_noninline(new_len); len = strlen(table_name) + 3;
sprintf(new_name,"%c%s-%lx_%lx", name = (char*) mem_heap_alloc_noninline(heap, len);
TEMP_TABLE_PREFIX, table_name, thd->thread_id, id); name[0] = TEMP_TABLE_PREFIX;
name[1] = id;
memcpy(name + 2, table_name, len - 2);
fprintf(stderr, "NEW TABLE NAME: %s\n", new_name); return(name);
return(new_name);
} }
/*********************************************************************** /***********************************************************************
...@@ -8120,16 +8117,16 @@ ha_innobase::add_index( ...@@ -8120,16 +8117,16 @@ ha_innobase::add_index(
ulint num_of_idx; ulint num_of_idx;
ulint num_created; ulint num_created;
ibool dict_locked = FALSE; ibool dict_locked = FALSE;
ibool new_primary = FALSE; ibool new_primary;
ibool new_unique = FALSE; ibool new_unique = FALSE;
ulint error = DB_SUCCESS;/* DB_SUCCESS or error code */ ulint error;
DBUG_ENTER("ha_innobase::add_index"); DBUG_ENTER("ha_innobase::add_index");
ut_a(table && key_info && num_of_keys); ut_a(table && key_info && num_of_keys);
update_thd(current_thd); update_thd(current_thd);
index = NULL; heap = mem_heap_create_noninline(1024);
parent_trx = check_trx_exists(ht, user_thd); parent_trx = check_trx_exists(ht, user_thd);
trx_search_latch_release_if_reserved(parent_trx); trx_search_latch_release_if_reserved(parent_trx);
...@@ -8150,20 +8147,19 @@ ha_innobase::add_index( ...@@ -8150,20 +8147,19 @@ ha_innobase::add_index(
trx->check_unique_secondary = FALSE; trx->check_unique_secondary = FALSE;
} }
indexed_table = dict_table_get(prebuilt->table->name, FALSE); innodb_table = indexed_table
innodb_table = indexed_table; = dict_table_get(prebuilt->table->name, FALSE);
/* Check that index keys are sensible */ /* Check that index keys are sensible */
error = innobase_check_index_keys( error = innobase_check_index_keys(
table, innodb_table, trx, key_info, num_of_keys); table, innodb_table, trx, key_info, num_of_keys);
if (error != DB_SUCCESS) { if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
err_exit:
mem_heap_free_noninline(heap);
trx_general_rollback_for_mysql(trx, FALSE, NULL); trx_general_rollback_for_mysql(trx, FALSE, NULL);
DBUG_RETURN(convert_error_code_to_mysql(error, user_thd));
error = convert_error_code_to_mysql(error, user_thd);
DBUG_RETURN((int)error);
} }
/* Create table containing all indexes to be built in this /* Create table containing all indexes to be built in this
...@@ -8172,8 +8168,6 @@ ha_innobase::add_index( ...@@ -8172,8 +8168,6 @@ ha_innobase::add_index(
num_of_idx = num_of_keys; num_of_idx = num_of_keys;
heap = mem_heap_create_noninline(1024);
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);
...@@ -8181,13 +8175,11 @@ ha_innobase::add_index( ...@@ -8181,13 +8175,11 @@ ha_innobase::add_index(
to drop all original secondary indexes from the table. These to drop all original secondary indexes from the table. These
indexes will be rebuilt below. */ indexes will be rebuilt below. */
if (index_defs[0]->ind_type & DICT_CLUSTERED) { new_primary = 0 != (DICT_CLUSTERED & index_defs[0]->ind_type);
char* new_table_name;
new_primary = TRUE;
new_table_name = innobase_create_temporary_tablename( if (new_primary) {
user_thd, (const char *)innodb_table->name, 17431); char* new_table_name = innobase_create_temporary_tablename(
heap, '1', innodb_table->name);
row_mysql_lock_data_dictionary(trx); row_mysql_lock_data_dictionary(trx);
...@@ -8197,14 +8189,9 @@ ha_innobase::add_index( ...@@ -8197,14 +8189,9 @@ ha_innobase::add_index(
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
mem_free_noninline(new_table_name); if (!indexed_table) {
if (error != DB_SUCCESS) {
mem_heap_free_noninline(heap);
trx_general_rollback_for_mysql(trx, FALSE, NULL);
error = convert_error_code_to_mysql(error, user_thd);
DBUG_RETURN((int)error); goto err_exit;
} }
} else if (!trx->dict_redo_list) { } else if (!trx->dict_redo_list) {
dict_redo_create_list(trx); dict_redo_create_list(trx);
...@@ -8215,8 +8202,8 @@ ha_innobase::add_index( ...@@ -8215,8 +8202,8 @@ ha_innobase::add_index(
/* Allocate memory for dictionary index definitions */ /* Allocate memory for dictionary index definitions */
index = (dict_index_t**) mem_alloc_noninline( index = (dict_index_t**) mem_heap_alloc_noninline(
sizeof(dict_index_t*) * num_of_idx); heap, num_of_idx * sizeof *index);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks /* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during an index create operation. or lock waits can happen in it during an index create operation.
...@@ -8251,9 +8238,7 @@ ha_innobase::add_index( ...@@ -8251,9 +8238,7 @@ ha_innobase::add_index(
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
dict_locked = FALSE; dict_locked = FALSE;
/* Free index definition table */ mem_heap_empty_noninline(heap);
mem_heap_free_noninline(heap);
heap = 0;
ut_a(trx->n_active_thrs == 0); ut_a(trx->n_active_thrs == 0);
ut_a(UT_LIST_GET_LEN(trx->signals) == 0); ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
...@@ -8276,8 +8261,12 @@ ha_innobase::add_index( ...@@ -8276,8 +8261,12 @@ ha_innobase::add_index(
based on this information using temporary files and merge based on this information using temporary files and merge
sort.*/ sort.*/
error = row_build_index_for_mysql( error = row_build_index_for_mysql(
trx, innodb_table, indexed_table, index, new_primary, trx, innodb_table, indexed_table, index,
num_of_idx); num_of_idx);
if (error == DB_SUCCESS && new_primary) {
row_merge_mark_prebuilt_obsolete(trx, innodb_table);
}
} }
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
...@@ -8292,32 +8281,28 @@ ha_innobase::add_index( ...@@ -8292,32 +8281,28 @@ ha_innobase::add_index(
//dict_table_check_for_dup_indexes(prebuilt->table); //dict_table_check_for_dup_indexes(prebuilt->table);
#endif #endif
/* Free index definition table */
if (heap) {
mem_heap_free_noninline(heap);
heap = 0;
}
if (dict_locked) { if (dict_locked) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
} }
/* After a error, remove all those index definitions from the /* After an error, remove all those index definitions from the
dictionary which were defined.*/ dictionary which were defined.*/
if (error != DB_SUCCESS) { switch (error) {
if (error == DB_DUPLICATE_KEY) { case DB_SUCCESS:
prebuilt->trx->error_info = NULL; break;
prebuilt->trx->error_key_num = trx->error_key_num; case DB_DUPLICATE_KEY:
} prebuilt->trx->error_info = NULL;
prebuilt->trx->error_key_num = trx->error_key_num;
/* fall through */
default:
row_remove_indexes_for_mysql( row_remove_indexes_for_mysql(
trx, indexed_table, index, num_created); trx, indexed_table, index, num_created);
} if (indexed_table != innodb_table) {
row_merge_drop_table(trx, indexed_table);
if (index) { }
mem_free_noninline(index); mem_heap_free_noninline(heap);
index = 0; DBUG_RETURN(convert_error_code_to_mysql(error, user_thd));
} }
/* If a new primary key was defined for the table and /* If a new primary key was defined for the table and
...@@ -8325,17 +8310,11 @@ ha_innobase::add_index( ...@@ -8325,17 +8310,11 @@ ha_innobase::add_index(
old table as a temporary table, rename the new temporary old table as a temporary table, rename the new temporary
table as a old table and drop the old table. */ table as a old table and drop the old table. */
if (new_primary == TRUE && error == DB_SUCCESS) { if (new_primary) {
char* old_name; char* old_name = mem_heap_strdup(
char* tmp_table_name; heap, innodb_table->name);
char* tmp_table_name = innobase_create_temporary_tablename(
old_name = (char *)mem_alloc_noninline( heap, '2', innodb_table->name);
strlen(innodb_table->name) + 1);
strcpy(old_name, innodb_table->name);
tmp_table_name = innobase_create_temporary_tablename(
user_thd, (const char *)innodb_table->name, 232125);
trx_start_if_not_started_noninline(trx); trx_start_if_not_started_noninline(trx);
...@@ -8343,45 +8322,51 @@ ha_innobase::add_index( ...@@ -8343,45 +8322,51 @@ ha_innobase::add_index(
error = row_undo_report_rename_table_dict_operation( error = row_undo_report_rename_table_dict_operation(
trx, old_name, indexed_table->name, tmp_table_name); trx, old_name, indexed_table->name, tmp_table_name);
if (error == DB_SUCCESS) { if (error != DB_SUCCESS) {
log_buffer_flush_to_disk();
/* Set the commit flag to FALSE, we will commit the goto func_exit;
transaction ourselves, required for UNDO */ }
error = innobase_rename_table(
trx, innodb_table->name, tmp_table_name, FALSE);
if (error == DB_SUCCESS) { log_buffer_flush_to_disk();
error = innobase_rename_table(
trx, indexed_table->name, old_name,
FALSE);
}
row_prebuilt_free(prebuilt); /* Set the commit flag to FALSE, we will commit the
prebuilt = row_create_prebuilt(indexed_table); transaction ourselves, required for UNDO */
error = innobase_rename_table(trx, innodb_table->name,
tmp_table_name, FALSE);
if (error != DB_SUCCESS) {
row_mysql_lock_data_dictionary(trx); goto func_exit;
prebuilt->table->n_mysql_handles_opened++; }
row_mysql_unlock_data_dictionary(trx);
/* Drop the old table iff there are no views that error = innobase_rename_table(trx, indexed_table->name,
refer to the old table. If there are views that refer old_name, FALSE);
to the old table then we will drop the table when if (error != DB_SUCCESS) {
we free the prebuilts and there are no more references
to it. */ goto func_exit;
error = row_merge_drop_table(trx, innodb_table);
} }
mem_free_noninline(old_name); row_prebuilt_free(prebuilt);
mem_free_noninline(tmp_table_name); prebuilt = row_create_prebuilt(indexed_table);
row_mysql_lock_data_dictionary(trx);
prebuilt->table->n_mysql_handles_opened++;
row_mysql_unlock_data_dictionary(trx);
/* Drop the old table if there are no open views
referring to it. If there such views, we will drop
the table when we free the prebuilts and there are no
more references to it. */
error = row_merge_drop_table(trx, innodb_table);
} }
func_exit:
/* There might be work for utility threads.*/ /* There might be work for utility threads.*/
srv_active_wake_master_thread(); mem_heap_free_noninline(heap);
error = convert_error_code_to_mysql(error, user_thd); srv_active_wake_master_thread();
DBUG_RETURN((int)error); DBUG_RETURN(convert_error_code_to_mysql(error, user_thd));
} }
/*********************************************************************** /***********************************************************************
......
...@@ -213,6 +213,13 @@ mem_heap_empty( ...@@ -213,6 +213,13 @@ mem_heap_empty(
/*===========*/ /*===========*/
mem_heap_t* heap); /* in: heap to empty */ mem_heap_t* heap); /* in: heap to empty */
/********************************************************************* /*********************************************************************
Empties a memory heap. The first memory block of the heap is not freed. */
void
mem_heap_empty_noninline(
/*=====================*/
mem_heap_t* heap); /* in: heap to empty */
/*********************************************************************
Returns a pointer to the topmost element in a memory heap. Returns a pointer to the topmost element in a memory heap.
The size of the element must be given. */ The size of the element must be given. */
UNIV_INLINE UNIV_INLINE
......
...@@ -501,7 +501,7 @@ these index entries and inserting sorted index entries to indexes. */ ...@@ -501,7 +501,7 @@ these index entries and inserting sorted index entries to indexes. */
ulint ulint
row_build_index_for_mysql( row_build_index_for_mysql(
/*====================*/ /*=====================*/
/* out: 0 or error code */ /* out: 0 or error code */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
dict_table_t* old_table, /* in: Table where rows are dict_table_t* old_table, /* in: Table where rows are
...@@ -511,9 +511,6 @@ row_build_index_for_mysql( ...@@ -511,9 +511,6 @@ row_build_index_for_mysql(
new_table if we are creating a new_table if we are creating a
secondary keys. */ secondary keys. */
dict_index_t** index, /* in: Indexes to be created */ dict_index_t** index, /* in: Indexes to be created */
ibool new_primary, /* in: new primary key
i.e. clustered index will be build
for this table */
ulint num_of_keys); /* in: Number of indexes to be ulint num_of_keys); /* in: Number of indexes to be
created */ created */
/************************************************************************* /*************************************************************************
......
...@@ -84,6 +84,16 @@ UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list; ...@@ -84,6 +84,16 @@ UT_LIST_BASE_NODE_T(mem_block_t) mem_block_list;
#endif #endif
/*********************************************************************
Empties a memory heap. The first memory block of the heap is not freed. */
void
mem_heap_empty_noninline(
/*=====================*/
mem_heap_t* heap) /* in: heap to empty */
{
return(mem_heap_empty(heap));
}
/******************************************************************* /*******************************************************************
NOTE: Use the corresponding macro instead of this function. NOTE: Use the corresponding macro instead of this function.
Allocates a single buffer of memory from the dynamic memory of Allocates a single buffer of memory from the dynamic memory of
...@@ -596,7 +606,7 @@ mem_heap_alloc_noninline( ...@@ -596,7 +606,7 @@ mem_heap_alloc_noninline(
to grow into the buffer pool, this must be to grow into the buffer pool, this must be
<= MEM_MAX_ALLOC_IN_BUF */ <= MEM_MAX_ALLOC_IN_BUF */
{ {
return (mem_heap_alloc(heap, n)); return(mem_heap_alloc(heap, n));
} }
/********************************************************************* /*********************************************************************
......
...@@ -4479,15 +4479,12 @@ row_build_index_for_mysql( ...@@ -4479,15 +4479,12 @@ row_build_index_for_mysql(
new_table if we are creating a new_table if we are creating a
secondary keys. */ secondary keys. */
dict_index_t** index, /* in: Indexes to be created */ dict_index_t** index, /* in: Indexes to be created */
ibool new_primary, /* in: new primary key
i.e. clustered index will be build
for this table */
ulint num_of_keys) /* in: Number of indexes to be ulint num_of_keys) /* in: Number of indexes to be
created */ created */
{ {
merge_file_t* merge_files; merge_file_t* merge_files;
ulint index_num; ulint index_num;
ulint error = DB_SUCCESS; ulint error;
ut_ad(trx && old_table && new_table && index && num_of_keys); ut_ad(trx && old_table && new_table && index && num_of_keys);
...@@ -4511,7 +4508,7 @@ row_build_index_for_mysql( ...@@ -4511,7 +4508,7 @@ row_build_index_for_mysql(
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
return(error); goto func_exit;
} }
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
...@@ -4535,20 +4532,13 @@ row_build_index_for_mysql( ...@@ -4535,20 +4532,13 @@ row_build_index_for_mysql(
merge_files[index_num].file, merge_files[index_num].file,
(int *)&error); (int *)&error);
if (error != DB_SUCCESS) { if (error == DB_SUCCESS) {
trx->error_key_num = index_num; error = row_merge_insert_index_tuples(
goto func_exit; trx, index[index_num], new_table,
merge_files[index_num].file,
ut_dulint_zero);
} }
/* Insert sorted index entries to the table. */
error = row_merge_insert_index_tuples(
trx,
index[index_num],
new_table,
merge_files[index_num].file,
ut_dulint_create(0,0));
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
trx->error_key_num = index_num; trx->error_key_num = index_num;
goto func_exit; goto func_exit;
...@@ -4557,10 +4547,6 @@ row_build_index_for_mysql( ...@@ -4557,10 +4547,6 @@ row_build_index_for_mysql(
} }
func_exit: func_exit:
if (error == DB_SUCCESS && new_primary) {
row_merge_mark_prebuilt_obsolete(trx, old_table);
}
mem_free(merge_files); mem_free(merge_files);
return(error); return(error);
......
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