From 0623cc7c16c3280d1f81b9049e1561d1b4b6c1d0 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 27 Mar 2019 18:58:43 +0530 Subject: [PATCH] MDEV-19051 Avoid unnecessary writing MLOG_INDEX_LOAD 1) Avoid writing of MLOG_INDEX_LOAD redo log record during inplace alter table when the table is empty and also for spatial index. 2) Avoid creation of temporary merge file for spatial index during index creation process. --- storage/innobase/include/btr0bulk.h | 2 + storage/innobase/include/trx0trx.h | 36 ++++++----- storage/innobase/row/row0ftsort.cc | 2 +- storage/innobase/row/row0merge.cc | 93 +++++++++++++---------------- storage/innobase/trx/trx0trx.cc | 30 ++++++---- 5 files changed, 84 insertions(+), 79 deletions(-) diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h index a63ab9ded0d..7e277adfbc3 100644 --- a/storage/innobase/include/btr0bulk.h +++ b/storage/innobase/include/btr0bulk.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -284,6 +285,7 @@ public: m_trx(trx), m_flush_observer(observer) { + ut_ad(!dict_index_is_spatial(index)); #ifdef UNIV_DEBUG if (m_flush_observer) fil_space_inc_redo_skipped_count(m_index->space); diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 8fde5689e40..159dcca2581 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -40,20 +40,9 @@ Created 3/26/1996 Heikki Tuuri // Forward declaration struct mtr_t; - -// Forward declaration class ReadView; - -// Forward declaration class FlushObserver; - -/** Set flush observer for the transaction -@param[in/out] trx transaction struct -@param[in] observer flush observer */ -void -trx_set_flush_observer( - trx_t* trx, - FlushObserver* observer); +class ut_stage_alter_t; /******************************************************************//** Set detailed error message for the transaction. */ @@ -1132,8 +1121,11 @@ struct trx_t { /*------------------------------*/ char* detailed_error; /*!< detailed error message for last error, or empty. */ - FlushObserver* flush_observer; /*!< flush observer */ - +private: + /** flush observer used to track flushing of non-redo logged pages + during bulk create index */ + FlushObserver* flush_observer; +public: /* Lock wait statistics */ ulint n_rec_lock_waits; /*!< Number of record lock waits, @@ -1177,6 +1169,20 @@ struct trx_t { return(assign_temp_rseg()); } + /** Set the innodb_log_optimize_ddl page flush observer + @param[in] space_id tablespace id + @param[in,out] stage performance_schema accounting */ + void set_flush_observer(ulint space_id, ut_stage_alter_t* stage); + + /** Remove the flush observer */ + void remove_flush_observer(); + + /** @return the flush observer */ + FlushObserver* get_flush_observer() const + { + return flush_observer; + } + private: /** Assign a rollback segment for modifying temporary tables. @return the assigned rollback segment */ diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index de622527766..2e321411a9a 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1673,7 +1673,7 @@ row_fts_merge_insert( /* Create bulk load instance */ ins_ctx.btr_bulk = UT_NEW_NOKEY( BtrBulk(aux_index, trx, psort_info[0].psort_common->trx - ->flush_observer)); + ->get_flush_observer())); /* Create tuple for insert */ ins_ctx.tuple = dtuple_create(heap, dict_index_get_n_fields(aux_index)); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 72e0a055af3..a12a2a73ace 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1736,7 +1736,6 @@ row_merge_read_clustered_index( mem_heap_t* mtuple_heap = NULL; mtuple_t prev_mtuple; mem_heap_t* conv_heap = NULL; - FlushObserver* observer = trx->flush_observer; double curr_progress = 0.0; ib_uint64_t read_rows = 0; ib_uint64_t table_total_rows = 0; @@ -2211,9 +2210,8 @@ write_buffers: bool skip_sort = skip_pk_sort && dict_index_is_clust(merge_buf[0]->index); - for (ulint i = 0; i < n_index; i++, skip_sort = false) { + for (ulint k = 0, i = 0; i < n_index; i++, skip_sort = false) { row_merge_buf_t* buf = merge_buf[i]; - merge_file_t* file = &files[i]; ulint rows_added = 0; if (dict_index_is_spatial(buf->index)) { @@ -2237,6 +2235,8 @@ write_buffers: continue; } + merge_file_t* file = &files[k++]; + if (UNIV_LIKELY (row && (rows_added = row_merge_buf_add( buf, fts_index, old_table, new_table, @@ -2244,6 +2244,15 @@ write_buffers: conv_heap, &err, &v_heap, eval_table, trx)))) { + /* Set the page flush observer for the + transaction when buffering the very first + record for a non-redo-logged operation. */ + if (file->n_rec == 0 && i == 0 + && innodb_log_optimize_ddl) { + trx->set_flush_observer( + new_table->space, stage); + } + /* If we are creating FTS index, a single row can generate more records for tokenized word */ @@ -2383,7 +2392,7 @@ write_buffers: clust_btr_bulk = UT_NEW_NOKEY( BtrBulk(index[i], trx, - observer/**/)); + trx->get_flush_observer())); } else { clust_btr_bulk->latch(); } @@ -2495,8 +2504,9 @@ write_buffers: trx->error_key_num = i; goto all_done;); - BtrBulk btr_bulk(index[i], trx, - observer); + BtrBulk btr_bulk( + index[i], trx, + trx->get_flush_observer()); err = row_merge_insert_index_tuples( index[i], old_table, @@ -4597,47 +4607,26 @@ row_merge_build_indexes( } trx_start_if_not_started_xa(trx, true); + ulint n_merge_files = 0; - /* Check if we need a flush observer to flush dirty pages. - Since we disable redo logging in bulk load, so we should flush - dirty pages before online log apply, because online log apply enables - redo logging(we can do further optimization here). - 1. online add index: flush dirty pages right before row_log_apply(). - 2. table rebuild: flush dirty pages before row_log_table_apply(). - - we use bulk load to create all types of indexes except spatial index, - for which redo logging is enabled. If we create only spatial indexes, - we don't need to flush dirty pages at all. */ - bool need_flush_observer = bool(innodb_log_optimize_ddl); - - if (need_flush_observer) { - need_flush_observer = old_table != new_table; - - for (i = 0; i < n_indexes; i++) { - if (!dict_index_is_spatial(indexes[i])) { - need_flush_observer = true; - } + for (ulint i = 0; i < n_indexes; i++) + { + if (!dict_index_is_spatial(indexes[i])) { + n_merge_files++; } } - FlushObserver* flush_observer = NULL; - if (need_flush_observer) { - flush_observer = UT_NEW_NOKEY( - FlushObserver(new_table->space, trx, stage)); - - trx_set_flush_observer(trx, flush_observer); - } - merge_files = static_cast( - ut_malloc_nokey(n_indexes * sizeof *merge_files)); + ut_malloc_nokey(n_merge_files * sizeof *merge_files)); /* Initialize all the merge file descriptors, so that we don't call row_merge_file_destroy() on uninitialized merge file descriptor */ - for (i = 0; i < n_indexes; i++) { + for (i = 0; i < n_merge_files; i++) { merge_files[i].fd = -1; merge_files[i].offset = 0; + merge_files[i].n_rec = 0; } total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX; @@ -4720,7 +4709,7 @@ row_merge_build_indexes( " and create temporary files"); } - for (i = 0; i < n_indexes; i++) { + for (i = 0; i < n_merge_files; i++) { total_index_blocks += merge_files[i].offset; } @@ -4733,7 +4722,7 @@ row_merge_build_indexes( /* Now we have files containing index entries ready for sorting and inserting. */ - for (i = 0; i < n_indexes; i++) { + for (ulint k = 0, i = 0; i < n_indexes; i++) { dict_index_t* sort_idx = indexes[i]; if (dict_index_is_spatial(sort_idx)) { @@ -4812,13 +4801,13 @@ wait_again: #ifdef FTS_INTERNAL_DIAG_PRINT DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Insert\n"); #endif - } else if (merge_files[i].fd >= 0) { + } else if (merge_files[k].fd >= 0) { char buf[NAME_LEN + 1]; row_merge_dup_t dup = { sort_idx, table, col_map, 0}; pct_cost = (COST_BUILD_INDEX_STATIC + - (total_dynamic_cost * merge_files[i].offset / + (total_dynamic_cost * merge_files[k].offset / total_index_blocks)) / (total_static_cost + total_dynamic_cost) * PCT_COST_MERGESORT_INDEX * 100; @@ -4842,7 +4831,7 @@ wait_again: } error = row_merge_sort( - trx, &dup, &merge_files[i], + trx, &dup, &merge_files[k], block, &tmpfd, true, pct_progress, pct_cost, crypt_block, new_table->space, stage); @@ -4864,10 +4853,10 @@ wait_again: if (error == DB_SUCCESS) { BtrBulk btr_bulk(sort_idx, trx, - flush_observer); + trx->get_flush_observer()); pct_cost = (COST_BUILD_INDEX_STATIC + - (total_dynamic_cost * merge_files[i].offset / + (total_dynamic_cost * merge_files[k].offset / total_index_blocks)) / (total_static_cost + total_dynamic_cost) * PCT_COST_INSERT_INDEX * 100; @@ -4884,9 +4873,9 @@ wait_again: error = row_merge_insert_index_tuples( sort_idx, old_table, - merge_files[i].fd, block, NULL, + merge_files[k].fd, block, NULL, &btr_bulk, - merge_files[i].n_rec, pct_progress, pct_cost, + merge_files[k].n_rec, pct_progress, pct_cost, crypt_block, new_table->space, stage); error = btr_bulk.finish(error); @@ -4904,7 +4893,7 @@ wait_again: } /* Close the temporary file to free up space. */ - row_merge_file_destroy(&merge_files[i]); + row_merge_file_destroy(&merge_files[k++]); if (indexes[i]->type & DICT_FTS) { row_fts_psort_info_destroy(psort_info, merge_info); @@ -4916,7 +4905,12 @@ wait_again: ut_ad(sort_idx->online_status == ONLINE_INDEX_COMPLETE); } else { - if (flush_observer) { + if (dict_index_is_spatial(indexes[i])) { + /* We never disable redo logging for + creating SPATIAL INDEX. Avoid writing any + unnecessary MLOG_INDEX_LOAD record. */ + } else if (FlushObserver* flush_observer = + trx->get_flush_observer()) { flush_observer->flush(); row_merge_write_redo(indexes[i]); } @@ -4958,7 +4952,7 @@ func_exit: row_merge_file_destroy_low(tmpfd); - for (i = 0; i < n_indexes; i++) { + for (i = 0; i < n_merge_files; i++) { row_merge_file_destroy(&merge_files[i]); } @@ -5015,8 +5009,7 @@ func_exit: DBUG_EXECUTE_IF("ib_index_crash_after_bulk_load", DBUG_SUICIDE();); - if (flush_observer != NULL) { - ut_ad(need_flush_observer); + if (FlushObserver* flush_observer = trx->get_flush_observer()) { DBUG_EXECUTE_IF("ib_index_build_fail_before_flush", error = DB_INTERRUPTED; @@ -5028,7 +5021,7 @@ func_exit: flush_observer->flush(); - UT_DELETE(flush_observer); + trx->remove_flush_observer(); if (trx_is_interrupted(trx)) { error = DB_INTERRUPTED; diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 704c52ff9af..e548ffbe62b 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2018, MariaDB Corporation. +Copyright (c) 2015, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -64,17 +64,6 @@ typedef std::set< std::less, ut_allocator > table_id_set; -/** Set flush observer for the transaction -@param[in/out] trx transaction struct -@param[in] observer flush observer */ -void -trx_set_flush_observer( - trx_t* trx, - FlushObserver* observer) -{ - trx->flush_observer = observer; -} - /*************************************************************//** Set detailed error message for the transaction. */ void @@ -165,7 +154,7 @@ trx_init( trx->lock.table_cached = 0; - trx->flush_observer = NULL; + ut_ad(trx->get_flush_observer() == NULL); } /** For managing the life-cycle of the trx_t instance that we get @@ -1088,6 +1077,21 @@ static trx_rseg_t* trx_assign_rseg_low() return(rseg); } +/** Set the innodb_log_optimize_ddl page flush observer +@param[in] space_id tablespace id +@param[in,out] stage performance_schema accounting */ +void trx_t::set_flush_observer(ulint space_id, ut_stage_alter_t* stage) +{ + flush_observer = UT_NEW_NOKEY(FlushObserver(space_id, this, stage)); +} + +/** Remove the flush observer */ +void trx_t::remove_flush_observer() +{ + UT_DELETE(flush_observer); + flush_observer = NULL; +} + /** Assign a rollback segment for modifying temporary tables. @return the assigned rollback segment */ trx_rseg_t*