Commit 7274fd95 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 dea76966
......@@ -8369,6 +8369,9 @@ ha_innobase::add_index(
index_defs = innobase_create_key_def(
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
to drop all original secondary indexes from the table. These
indexes will be rebuilt below. */
......@@ -8393,10 +8396,8 @@ ha_innobase::add_index(
row_mysql_unlock_data_dictionary(trx);
goto err_exit;
}
} else if (!trx->dict_redo_list) {
} else {
dict_redo_create_list(trx);
ut_a(!trx->sync_cb);
trx->sync_cb = dict_rename_indexes;
}
......@@ -8444,7 +8445,7 @@ ha_innobase::add_index(
ut_a(trx->n_active_thrs == 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)) {
......@@ -8456,7 +8457,7 @@ ha_innobase::add_index(
table lock also on the table that is being created. */
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)) {
......@@ -8535,9 +8536,6 @@ ha_innobase::add_index(
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,
tmp_name, trx);
......@@ -8561,6 +8559,8 @@ ha_innobase::add_index(
func_exit:
mem_heap_free(heap);
ut_ad(new_primary || trx->dict_redo_list);
ut_ad(!new_primary || !trx->dict_redo_list);
innobase_commit_low(trx);
if (dict_locked) {
......
......@@ -42,6 +42,15 @@ struct merge_index_def_struct {
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. */
......
......@@ -208,16 +208,6 @@ row_lock_table_for_mysql(
prebuilt->select_lock_type */
ulint mode); /* in: lock mode of table
(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. */
......
......@@ -1398,6 +1398,83 @@ row_merge_insert_index_tuples(
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. */
......
......@@ -1086,88 +1086,6 @@ row_lock_table_for_mysql(
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. */
......
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