Commit 0d6bfcb5 authored by marko's avatar marko

branches/zip: Fix a memory leak in fast index creation.

ha_innobase::add_index(): Add assertions about !trx->sync_cb and
!trx->dict_redo_list.  Remove a bogus comment.  Replace
row_lock_table_for_merge() with row_merge_lock_table().

row_merge_lock_table(): Renamed from row_lock_table_for_merge()
and moved from row0mysql.c to row0merge.c.  Always lock the table in
the mode LOCK_X.  Call que_graph_free() in order not to leak memory.
parent dd08a134
...@@ -8369,6 +8369,9 @@ err_exit: ...@@ -8369,6 +8369,9 @@ 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->sync_cb);
ut_a(!trx->dict_redo_list);
/* 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 all original secondary indexes from the table. These
indexes will be rebuilt below. */ indexes will be rebuilt below. */
...@@ -8393,10 +8396,8 @@ err_exit: ...@@ -8393,10 +8396,8 @@ err_exit:
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
goto err_exit; goto err_exit;
} }
} else if (!trx->dict_redo_list) { } else {
dict_redo_create_list(trx); dict_redo_create_list(trx);
ut_a(!trx->sync_cb);
trx->sync_cb = dict_rename_indexes; trx->sync_cb = dict_rename_indexes;
} }
...@@ -8444,7 +8445,7 @@ err_exit: ...@@ -8444,7 +8445,7 @@ err_exit:
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);
error = row_lock_table_for_merge(trx, innodb_table, LOCK_X); error = row_merge_lock_table(trx, innodb_table);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) { if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
...@@ -8456,7 +8457,7 @@ err_exit: ...@@ -8456,7 +8457,7 @@ err_exit:
table lock also on the table that is being created. */ table lock also on the table that is being created. */
ut_ad(indexed_table != innodb_table); ut_ad(indexed_table != innodb_table);
error = row_lock_table_for_merge(trx, indexed_table, LOCK_X); error = row_merge_lock_table(trx, indexed_table);
if (UNIV_UNLIKELY(error != DB_SUCCESS)) { if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
...@@ -8535,9 +8536,6 @@ error_handling: ...@@ -8535,9 +8536,6 @@ error_handling:
log_buffer_flush_to_disk(); log_buffer_flush_to_disk();
/* Set the commit flag to FALSE, we will commit the
transaction ourselves, required for UNDO */
error = row_merge_rename_tables(innodb_table, indexed_table, error = row_merge_rename_tables(innodb_table, indexed_table,
tmp_name, trx); tmp_name, trx);
...@@ -8561,6 +8559,8 @@ error_handling: ...@@ -8561,6 +8559,8 @@ error_handling:
func_exit: func_exit:
mem_heap_free(heap); mem_heap_free(heap);
ut_ad(new_primary || trx->dict_redo_list);
ut_ad(!new_primary || !trx->dict_redo_list);
innobase_commit_low(trx); innobase_commit_low(trx);
if (dict_locked) { if (dict_locked) {
......
...@@ -42,6 +42,15 @@ struct merge_index_def_struct { ...@@ -42,6 +42,15 @@ struct merge_index_def_struct {
typedef struct merge_index_def_struct merge_index_def_t; typedef struct merge_index_def_struct merge_index_def_t;
/*************************************************************************
Sets an exclusive lock on a table, for the duration of creating indexes. */
ulint
row_merge_lock_table(
/*=================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in/out: transaction */
dict_table_t* table); /* in: table to LOCK_X */
/************************************************************************* /*************************************************************************
Drop an index from the InnoDB system tables. */ Drop an index from the InnoDB system tables. */
......
...@@ -208,16 +208,6 @@ row_lock_table_for_mysql( ...@@ -208,16 +208,6 @@ row_lock_table_for_mysql(
prebuilt->select_lock_type */ prebuilt->select_lock_type */
ulint mode); /* in: lock mode of table ulint mode); /* in: lock mode of table
(ignored if table==NULL) */ (ignored if table==NULL) */
/*************************************************************************
Sets a table lock on the table. */
int
row_lock_table_for_merge(
/*=====================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: lock table for this trx */
dict_table_t* table, /* in: table to lock */
ulint mode); /* in: lock mode of table */
/************************************************************************* /*************************************************************************
Does an insert for MySQL. */ Does an insert for MySQL. */
......
...@@ -1398,6 +1398,83 @@ err_exit: ...@@ -1398,6 +1398,83 @@ err_exit:
return(error); return(error);
} }
/*************************************************************************
Sets an exclusive lock on a table, for the duration of creating indexes. */
ulint
row_merge_lock_table(
/*=================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in/out: transaction */
dict_table_t* table) /* in: table to LOCK_X */
{
mem_heap_t* heap;
que_thr_t* thr;
ulint err;
sel_node_t* node;
ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
heap = mem_heap_create(512);
trx->op_info = "setting table lock for index merge";
node = sel_node_create(heap);
thr = pars_complete_graph_for_exec(node, trx, heap);
thr->graph->state = QUE_FORK_ACTIVE;
/* We use the select query graph as the dummy graph needed
in the lock module call */
thr = que_fork_get_first_thr(que_node_get_parent(thr));
que_thr_move_to_run_state_for_mysql(thr, trx);
run_again:
thr->run_node = thr;
thr->prev_node = thr->common.parent;
err = lock_table(0, table, LOCK_X, thr);
trx->error_state = err;
if (UNIV_LIKELY(err == DB_SUCCESS)) {
que_thr_stop_for_mysql_no_error(thr, trx);
} else {
que_thr_stop_for_mysql(thr);
if (err != DB_QUE_THR_SUSPENDED) {
ibool was_lock_wait;
was_lock_wait = row_mysql_handle_errors(
&err, trx, thr, NULL);
if (was_lock_wait) {
goto run_again;
}
} else {
que_thr_t* run_thr;
que_node_t* parent;
parent = que_node_get_parent(thr);
run_thr = que_fork_start_command(parent);
ut_a(run_thr == thr);
/* There was a lock wait but the thread was not
in a ready to run or running state. */
trx->error_state = DB_LOCK_WAIT;
goto run_again;
}
}
que_graph_free(thr->graph);
trx->op_info = "";
return(err);
}
/************************************************************************* /*************************************************************************
Drop an index from the InnoDB system tables. */ Drop an index from the InnoDB system tables. */
......
...@@ -1086,88 +1086,6 @@ run_again: ...@@ -1086,88 +1086,6 @@ run_again:
return((int) err); return((int) err);
} }
/*************************************************************************
Sets a table lock on the table */
int
row_lock_table_for_merge(
/*=====================*/
/* out: error code or DB_SUCCESS */
trx_t* trx, /* in: lock table for this trx */
dict_table_t* table, /* in: table to lock */
ulint mode) /* in: lock mode of table */
{
mem_heap_t* heap; /* Memory heap */
que_thr_t* thr;
ulint err;
sel_node_t* node;
ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
heap = mem_heap_create(512);
trx->op_info = "setting table lock for index merge";
node = sel_node_create(heap);
thr = pars_complete_graph_for_exec(node, trx, heap);
/* SB: Not sure about this - Ask Heikki */
thr->graph->state = QUE_FORK_ACTIVE;
/* We use the select query graph as the dummy graph needed
in the lock module call */
thr = que_fork_get_first_thr(que_node_get_parent(thr));
que_thr_move_to_run_state_for_mysql(thr, trx);
run_again:
thr->run_node = thr;
thr->prev_node = thr->common.parent;
err = lock_table(0, table, mode, thr);
trx->error_state = err;
if (err != DB_SUCCESS) {
que_thr_stop_for_mysql(thr);
if (err != DB_QUE_THR_SUSPENDED) {
ibool was_lock_wait;
was_lock_wait = row_mysql_handle_errors(
&err, trx, thr, NULL);
if (was_lock_wait) {
goto run_again;
}
} else {
que_thr_t* run_thr;
que_node_t* parent;
parent = que_node_get_parent(thr);
run_thr = que_fork_start_command(parent);
ut_a(run_thr == thr);
/* There was a lock wait but the thread was not
in a ready to run or running state.*/
trx->error_state = DB_LOCK_WAIT;
goto run_again;
}
trx->op_info = "";
return((int) err);
}
que_thr_stop_for_mysql_no_error(thr, trx);
trx->op_info = "";
return((int) err);
}
/************************************************************************* /*************************************************************************
Does an insert for MySQL. */ Does an insert for MySQL. */
......
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