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*