From: Mikael Ronstrom Date: May 31 2012 1:59pm Subject: bzr push into mysql-trunk branch (mikael.ronstrom:3916 to 3917) Bug#13903821 List-Archive: http://lists.mysql.com/commits/144055 X-Bug: 13903821 Message-Id: <201205311400.q4VE0nXF011949@dator6> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3917 Mikael Ronstrom 2012-05-31 BUG#13903821, fix a memory leak at inserts modified: storage/innobase/btr/btr0cur.cc storage/innobase/include/dict0dict.h storage/innobase/include/dict0dict.ic storage/innobase/include/row0mysql.h storage/innobase/row/row0ins.cc storage/innobase/row/row0mysql.cc 3916 Sunanda Menon 2012-05-31 changed VERSION string for this branch modified: VERSION === modified file 'storage/innobase/btr/btr0cur.cc' --- a/storage/innobase/btr/btr0cur.cc revid:sunanda.menon@stripped +++ b/storage/innobase/btr/btr0cur.cc revid:mikael.ronstrom@stripped @@ -482,7 +482,7 @@ btr_cur_search_to_nth_level( #else switch (latch_mode) { default: - if (level == 0) { + if (level == 0 || !dict_index_is_online_ddl(index)) { break; } /* fall through */ === modified file 'storage/innobase/include/dict0dict.h' --- a/storage/innobase/include/dict0dict.h revid:sunanda.menon@stripped +++ b/storage/innobase/include/dict0dict.h revid:mikael.ronstrom@stripped @@ -666,6 +666,15 @@ dict_table_get_first_index( const dict_table_t* table) /*!< in: table */ __attribute__((nonnull, warn_unused_result)); /********************************************************************//** +Gets the last index on the table. +@return index, NULL if none exists */ +UNIV_INLINE +dict_index_t* +dict_table_get_last_index( +/*=======================*/ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, warn_unused_result)); +/********************************************************************//** Gets the next index on the table. @return index, NULL if none left */ UNIV_INLINE @@ -676,6 +685,7 @@ dict_table_get_next_index( __attribute__((nonnull, warn_unused_result)); #else /* UNIV_DEBUG */ # define dict_table_get_first_index(table) UT_LIST_GET_FIRST((table)->indexes) +# define dict_table_get_last_index(table) UT_LIST_GET_LAST((table)->indexes) # define dict_table_get_next_index(index) UT_LIST_GET_NEXT(indexes, index) #endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ === modified file 'storage/innobase/include/dict0dict.ic' --- a/storage/innobase/include/dict0dict.ic revid:sunanda.menon@stripped +++ b/storage/innobase/include/dict0dict.ic revid:mikael.ronstrom@stripped @@ -224,6 +224,22 @@ dict_table_get_first_index( } /********************************************************************//** +Gets the last index on the table. +@return index, NULL if none exists */ +UNIV_INLINE +dict_index_t* +dict_table_get_last_index( +/*=======================*/ + const dict_table_t* table) /*!< in: table */ +{ + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + return(UT_LIST_GET_LAST((const_cast(table)) + ->indexes)); +} + +/********************************************************************//** Gets the next index on the table. @return index, NULL if none left */ UNIV_INLINE === modified file 'storage/innobase/include/row0mysql.h' --- a/storage/innobase/include/row0mysql.h revid:sunanda.menon@stripped +++ b/storage/innobase/include/row0mysql.h revid:mikael.ronstrom@stripped @@ -724,6 +724,11 @@ struct row_prebuilt_struct { columns in the table */ upd_node_t* upd_node; /*!< Innobase SQL update node used to perform updates and deletes */ + trx_id_t trx_id; /*!< The transaction id of the last + index of the table, when the insert + query graph was built. We use it for + checking whether the insert query + graphs needs to be rebuilt */ que_fork_t* ins_graph; /*!< Innobase SQL query graph used in inserts */ que_fork_t* upd_graph; /*!< Innobase SQL query graph used === modified file 'storage/innobase/row/row0ins.cc' --- a/storage/innobase/row/row0ins.cc revid:sunanda.menon@stripped +++ b/storage/innobase/row/row0ins.cc revid:mikael.ronstrom@stripped @@ -111,7 +111,6 @@ ins_node_create_entry_list( dict_index_t* index; dtuple_t* entry; - ut_ad(node->ins_type != INS_DIRECT); ut_ad(node->entry_sys_heap); UT_LIST_INIT(node->entry_list); @@ -207,9 +206,7 @@ ins_node_set_new_row( /* Create templates for index entries */ - if (node->ins_type != INS_DIRECT) { - ins_node_create_entry_list(node); - } + ins_node_create_entry_list(node); /* Allocate from entry_sys_heap buffers for sys fields */ @@ -2460,7 +2457,7 @@ row_ins_index_entry( /***********************************************************//** Sets the values of the dtuple fields in entry from the values of appropriate columns in row. */ -static +static __attribute__((nonnull)) void row_ins_index_entry_set_vals( /*=========================*/ @@ -2471,9 +2468,6 @@ row_ins_index_entry_set_vals( ulint n_fields; ulint i; - ut_ad(row); - ut_ad(entry); - n_fields = dtuple_get_n_fields(entry); for (i = 0; i < n_fields; i++) { @@ -2637,24 +2631,22 @@ row_ins( ins_node_t* node, /*!< in: row insert node */ que_thr_t* thr) /*!< in: query thread */ { + dberr_t err; + if (node->state == INS_NODE_ALLOC_ROW_ID) { row_ins_alloc_row_id_step(node); node->index = dict_table_get_first_index(node->table); + node->entry = UT_LIST_GET_FIRST(node->entry_list); + + if (node->ins_type == INS_SEARCHED) { - switch (node->ins_type) { - case INS_DIRECT: - node->entry = NULL; - break; - case INS_SEARCHED: - node->entry = UT_LIST_GET_FIRST(node->entry_list); row_ins_get_row_from_select(node); - break; - case INS_VALUES: - node->entry = UT_LIST_GET_FIRST(node->entry_list); + + } else if (node->ins_type == INS_VALUES) { + row_ins_get_row_from_values(node); - break; } node->state = INS_NODE_INSERT_ENTRIES; @@ -2663,42 +2655,23 @@ row_ins( ut_ad(node->state == INS_NODE_INSERT_ENTRIES); while (node->index != NULL) { - dberr_t err; - - if (node->index->type & DICT_FTS) { - goto next_index; - } - - if (node->ins_type == INS_DIRECT) { - /* node->entry == NULL here, except when - row_ins_index_entry_step() returned - DB_LOCK_WAIT on the previous call and - row_insert_for_mysql() retried the insert. */ - node->entry = row_build_index_entry( - node->row, NULL, node->index, - node->entry_sys_heap); - } - - err = row_ins_index_entry_step(node, thr); + if (node->index->type != DICT_FTS) { + err = row_ins_index_entry_step(node, thr); - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS) { - return(err); + return(err); + } } -next_index: node->index = dict_table_get_next_index(node->index); - node->entry = (node->ins_type != INS_DIRECT) - ? UT_LIST_GET_NEXT(tuple_list, node->entry) - : NULL; + node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); /* Skip corrupted secondary index and its entry */ while (node->index && dict_index_is_corrupted(node->index)) { node->index = dict_table_get_next_index(node->index); - node->entry = (node->ins_type != INS_DIRECT) - ? UT_LIST_GET_NEXT(tuple_list, node->entry) - : NULL; + node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); } } === modified file 'storage/innobase/row/row0mysql.cc' --- a/storage/innobase/row/row0mysql.cc revid:sunanda.menon@stripped +++ b/storage/innobase/row/row0mysql.cc revid:mikael.ronstrom@stripped @@ -957,44 +957,60 @@ row_get_prebuilt_insert_row( row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL handle */ { - ins_node_t* node; - dtuple_t* row; - dict_table_t* table = prebuilt->table; + dict_table_t* table = prebuilt->table; + const dict_index_t* last_index = dict_table_get_last_index(table); ut_ad(prebuilt && table && prebuilt->trx); - if (prebuilt->ins_node == NULL) { + /* Check if a new index has been added that prebuilt doesn't know + about. We need to rebuild the query graph. */ - /* Not called before for this handle: create an insert node - and query graph to the prebuilt struct */ + if (prebuilt->ins_node != 0) { - node = ins_node_create(INS_DIRECT, table, prebuilt->heap); + if (prebuilt->trx_id >= last_index->trx_id) { + return(prebuilt->ins_node->row); + } - prebuilt->ins_node = node; + que_graph_free_recursive(prebuilt->ins_graph); - if (prebuilt->ins_upd_rec_buff == NULL) { - prebuilt->ins_upd_rec_buff = static_cast( - mem_heap_alloc( - prebuilt->heap, - prebuilt->mysql_row_len)); - } + prebuilt->ins_graph = 0; + } - row = dtuple_create(prebuilt->heap, - dict_table_get_n_cols(table)); + /* Create an insert node and query graph to the prebuilt struct */ - dict_table_copy_types(row, table); + ins_node_t* node; - ins_node_set_new_row(node, row); + node = ins_node_create(INS_DIRECT, table, prebuilt->heap); - prebuilt->ins_graph = static_cast( - que_node_get_parent( - pars_complete_graph_for_exec( - node, - prebuilt->trx, prebuilt->heap))); + prebuilt->ins_node = node; - prebuilt->ins_graph->state = QUE_FORK_ACTIVE; + if (prebuilt->ins_upd_rec_buff == 0) { + prebuilt->ins_upd_rec_buff = static_cast( + mem_heap_alloc( + prebuilt->heap, + prebuilt->mysql_row_len)); } + dtuple_t* row; + + row = dtuple_create(prebuilt->heap, dict_table_get_n_cols(table)); + + dict_table_copy_types(row, table); + + ins_node_set_new_row(node, row); + + prebuilt->ins_graph = static_cast( + que_node_get_parent( + pars_complete_graph_for_exec( + node, + prebuilt->trx, prebuilt->heap))); + + prebuilt->ins_graph->state = QUE_FORK_ACTIVE; + + ut_ad(prebuilt->trx_id == 0 || prebuilt->trx_id <= last_index->trx_id); + + prebuilt->trx_id = last_index->trx_id; + return(prebuilt->ins_node->row); } @@ -1073,10 +1089,8 @@ row_lock_table_autoinc_for_mysql( trx->op_info = "setting auto-inc lock"; - if (node == NULL) { - row_get_prebuilt_insert_row(prebuilt); - node = prebuilt->ins_node; - } + row_get_prebuilt_insert_row(prebuilt); + node = prebuilt->ins_node; /* We use the insert query graph as the dummy graph needed in the lock module call */ @@ -1266,10 +1280,8 @@ row_insert_for_mysql( trx_start_if_not_started_xa(trx); - if (node == NULL) { - row_get_prebuilt_insert_row(prebuilt); - node = prebuilt->ins_node; - } + row_get_prebuilt_insert_row(prebuilt); + node = prebuilt->ins_node; row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec); No bundle (reason: useless for push emails).