List:Commits« Previous MessageNext Message »
From:Mikael Ronstrom Date:May 31 2012 1:59pm
Subject:bzr push into mysql-trunk branch (mikael.ronstrom:3916 to 3917) Bug#13903821
View as plain text  
 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<const dict_table_t*>(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<byte*>(
-				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_fork_t*>(
-			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<byte*>(
+			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_fork_t*>(
+		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).
Thread
bzr push into mysql-trunk branch (mikael.ronstrom:3916 to 3917) Bug#13903821Mikael Ronstrom31 May