Commit 0623cc7c authored by Thirunarayanan Balathandayuthapani's avatar Thirunarayanan Balathandayuthapani Committed by Marko Mäkelä

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.
parent 38cad687
/***************************************************************************** /*****************************************************************************
Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -284,6 +285,7 @@ class BtrBulk ...@@ -284,6 +285,7 @@ class BtrBulk
m_trx(trx), m_trx(trx),
m_flush_observer(observer) m_flush_observer(observer)
{ {
ut_ad(!dict_index_is_spatial(index));
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
if (m_flush_observer) if (m_flush_observer)
fil_space_inc_redo_skipped_count(m_index->space); fil_space_inc_redo_skipped_count(m_index->space);
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -40,20 +40,9 @@ Created 3/26/1996 Heikki Tuuri ...@@ -40,20 +40,9 @@ Created 3/26/1996 Heikki Tuuri
// Forward declaration // Forward declaration
struct mtr_t; struct mtr_t;
// Forward declaration
class ReadView; class ReadView;
// Forward declaration
class FlushObserver; class FlushObserver;
class ut_stage_alter_t;
/** 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);
/******************************************************************//** /******************************************************************//**
Set detailed error message for the transaction. */ Set detailed error message for the transaction. */
...@@ -1132,8 +1121,11 @@ struct trx_t { ...@@ -1132,8 +1121,11 @@ struct trx_t {
/*------------------------------*/ /*------------------------------*/
char* detailed_error; /*!< detailed error message for last char* detailed_error; /*!< detailed error message for last
error, or empty. */ 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 */ /* Lock wait statistics */
ulint n_rec_lock_waits; ulint n_rec_lock_waits;
/*!< Number of record lock waits, /*!< Number of record lock waits,
...@@ -1177,6 +1169,20 @@ struct trx_t { ...@@ -1177,6 +1169,20 @@ struct trx_t {
return(assign_temp_rseg()); 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: private:
/** Assign a rollback segment for modifying temporary tables. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
......
...@@ -1673,7 +1673,7 @@ row_fts_merge_insert( ...@@ -1673,7 +1673,7 @@ row_fts_merge_insert(
/* Create bulk load instance */ /* Create bulk load instance */
ins_ctx.btr_bulk = UT_NEW_NOKEY( ins_ctx.btr_bulk = UT_NEW_NOKEY(
BtrBulk(aux_index, trx, psort_info[0].psort_common->trx BtrBulk(aux_index, trx, psort_info[0].psort_common->trx
->flush_observer)); ->get_flush_observer()));
/* Create tuple for insert */ /* Create tuple for insert */
ins_ctx.tuple = dtuple_create(heap, dict_index_get_n_fields(aux_index)); ins_ctx.tuple = dtuple_create(heap, dict_index_get_n_fields(aux_index));
......
...@@ -1736,7 +1736,6 @@ row_merge_read_clustered_index( ...@@ -1736,7 +1736,6 @@ row_merge_read_clustered_index(
mem_heap_t* mtuple_heap = NULL; mem_heap_t* mtuple_heap = NULL;
mtuple_t prev_mtuple; mtuple_t prev_mtuple;
mem_heap_t* conv_heap = NULL; mem_heap_t* conv_heap = NULL;
FlushObserver* observer = trx->flush_observer;
double curr_progress = 0.0; double curr_progress = 0.0;
ib_uint64_t read_rows = 0; ib_uint64_t read_rows = 0;
ib_uint64_t table_total_rows = 0; ib_uint64_t table_total_rows = 0;
...@@ -2211,9 +2210,8 @@ row_merge_read_clustered_index( ...@@ -2211,9 +2210,8 @@ row_merge_read_clustered_index(
bool skip_sort = skip_pk_sort bool skip_sort = skip_pk_sort
&& dict_index_is_clust(merge_buf[0]->index); && 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]; row_merge_buf_t* buf = merge_buf[i];
merge_file_t* file = &files[i];
ulint rows_added = 0; ulint rows_added = 0;
if (dict_index_is_spatial(buf->index)) { if (dict_index_is_spatial(buf->index)) {
...@@ -2237,6 +2235,8 @@ row_merge_read_clustered_index( ...@@ -2237,6 +2235,8 @@ row_merge_read_clustered_index(
continue; continue;
} }
merge_file_t* file = &files[k++];
if (UNIV_LIKELY if (UNIV_LIKELY
(row && (rows_added = row_merge_buf_add( (row && (rows_added = row_merge_buf_add(
buf, fts_index, old_table, new_table, buf, fts_index, old_table, new_table,
...@@ -2244,6 +2244,15 @@ row_merge_read_clustered_index( ...@@ -2244,6 +2244,15 @@ row_merge_read_clustered_index(
conv_heap, &err, conv_heap, &err,
&v_heap, eval_table, trx)))) { &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, /* If we are creating FTS index,
a single row can generate more a single row can generate more
records for tokenized word */ records for tokenized word */
...@@ -2383,7 +2392,7 @@ row_merge_read_clustered_index( ...@@ -2383,7 +2392,7 @@ row_merge_read_clustered_index(
clust_btr_bulk = UT_NEW_NOKEY( clust_btr_bulk = UT_NEW_NOKEY(
BtrBulk(index[i], BtrBulk(index[i],
trx, trx,
observer/**/)); trx->get_flush_observer()));
} else { } else {
clust_btr_bulk->latch(); clust_btr_bulk->latch();
} }
...@@ -2495,8 +2504,9 @@ row_merge_read_clustered_index( ...@@ -2495,8 +2504,9 @@ row_merge_read_clustered_index(
trx->error_key_num = i; trx->error_key_num = i;
goto all_done;); goto all_done;);
BtrBulk btr_bulk(index[i], trx, BtrBulk btr_bulk(
observer); index[i], trx,
trx->get_flush_observer());
err = row_merge_insert_index_tuples( err = row_merge_insert_index_tuples(
index[i], old_table, index[i], old_table,
...@@ -4597,47 +4607,26 @@ row_merge_build_indexes( ...@@ -4597,47 +4607,26 @@ row_merge_build_indexes(
} }
trx_start_if_not_started_xa(trx, true); trx_start_if_not_started_xa(trx, true);
ulint n_merge_files = 0;
/* Check if we need a flush observer to flush dirty pages. for (ulint i = 0; i < n_indexes; i++)
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])) { if (!dict_index_is_spatial(indexes[i])) {
need_flush_observer = true; 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<merge_file_t*>( merge_files = static_cast<merge_file_t*>(
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 /* Initialize all the merge file descriptors, so that we
don't call row_merge_file_destroy() on uninitialized don't call row_merge_file_destroy() on uninitialized
merge file descriptor */ 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].fd = -1;
merge_files[i].offset = 0; merge_files[i].offset = 0;
merge_files[i].n_rec = 0;
} }
total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX; total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX;
...@@ -4720,7 +4709,7 @@ row_merge_build_indexes( ...@@ -4720,7 +4709,7 @@ row_merge_build_indexes(
" and create temporary files"); " 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; total_index_blocks += merge_files[i].offset;
} }
...@@ -4733,7 +4722,7 @@ row_merge_build_indexes( ...@@ -4733,7 +4722,7 @@ row_merge_build_indexes(
/* Now we have files containing index entries ready for /* Now we have files containing index entries ready for
sorting and inserting. */ 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]; dict_index_t* sort_idx = indexes[i];
if (dict_index_is_spatial(sort_idx)) { if (dict_index_is_spatial(sort_idx)) {
...@@ -4812,13 +4801,13 @@ row_merge_build_indexes( ...@@ -4812,13 +4801,13 @@ row_merge_build_indexes(
#ifdef FTS_INTERNAL_DIAG_PRINT #ifdef FTS_INTERNAL_DIAG_PRINT
DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Insert\n"); DEBUG_FTS_SORT_PRINT("FTS_SORT: Complete Insert\n");
#endif #endif
} else if (merge_files[i].fd >= 0) { } else if (merge_files[k].fd >= 0) {
char buf[NAME_LEN + 1]; char buf[NAME_LEN + 1];
row_merge_dup_t dup = { row_merge_dup_t dup = {
sort_idx, table, col_map, 0}; sort_idx, table, col_map, 0};
pct_cost = (COST_BUILD_INDEX_STATIC + pct_cost = (COST_BUILD_INDEX_STATIC +
(total_dynamic_cost * merge_files[i].offset / (total_dynamic_cost * merge_files[k].offset /
total_index_blocks)) / total_index_blocks)) /
(total_static_cost + total_dynamic_cost) (total_static_cost + total_dynamic_cost)
* PCT_COST_MERGESORT_INDEX * 100; * PCT_COST_MERGESORT_INDEX * 100;
...@@ -4842,7 +4831,7 @@ row_merge_build_indexes( ...@@ -4842,7 +4831,7 @@ row_merge_build_indexes(
} }
error = row_merge_sort( error = row_merge_sort(
trx, &dup, &merge_files[i], trx, &dup, &merge_files[k],
block, &tmpfd, true, block, &tmpfd, true,
pct_progress, pct_cost, pct_progress, pct_cost,
crypt_block, new_table->space, stage); crypt_block, new_table->space, stage);
...@@ -4864,10 +4853,10 @@ row_merge_build_indexes( ...@@ -4864,10 +4853,10 @@ row_merge_build_indexes(
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
BtrBulk btr_bulk(sort_idx, trx, BtrBulk btr_bulk(sort_idx, trx,
flush_observer); trx->get_flush_observer());
pct_cost = (COST_BUILD_INDEX_STATIC + pct_cost = (COST_BUILD_INDEX_STATIC +
(total_dynamic_cost * merge_files[i].offset / (total_dynamic_cost * merge_files[k].offset /
total_index_blocks)) / total_index_blocks)) /
(total_static_cost + total_dynamic_cost) * (total_static_cost + total_dynamic_cost) *
PCT_COST_INSERT_INDEX * 100; PCT_COST_INSERT_INDEX * 100;
...@@ -4884,9 +4873,9 @@ row_merge_build_indexes( ...@@ -4884,9 +4873,9 @@ row_merge_build_indexes(
error = row_merge_insert_index_tuples( error = row_merge_insert_index_tuples(
sort_idx, old_table, sort_idx, old_table,
merge_files[i].fd, block, NULL, merge_files[k].fd, block, NULL,
&btr_bulk, &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); crypt_block, new_table->space, stage);
error = btr_bulk.finish(error); error = btr_bulk.finish(error);
...@@ -4904,7 +4893,7 @@ row_merge_build_indexes( ...@@ -4904,7 +4893,7 @@ row_merge_build_indexes(
} }
/* Close the temporary file to free up space. */ /* 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) { if (indexes[i]->type & DICT_FTS) {
row_fts_psort_info_destroy(psort_info, merge_info); row_fts_psort_info_destroy(psort_info, merge_info);
...@@ -4916,7 +4905,12 @@ row_merge_build_indexes( ...@@ -4916,7 +4905,12 @@ row_merge_build_indexes(
ut_ad(sort_idx->online_status ut_ad(sort_idx->online_status
== ONLINE_INDEX_COMPLETE); == ONLINE_INDEX_COMPLETE);
} else { } 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(); flush_observer->flush();
row_merge_write_redo(indexes[i]); row_merge_write_redo(indexes[i]);
} }
...@@ -4958,7 +4952,7 @@ row_merge_build_indexes( ...@@ -4958,7 +4952,7 @@ row_merge_build_indexes(
row_merge_file_destroy_low(tmpfd); 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]); row_merge_file_destroy(&merge_files[i]);
} }
...@@ -5015,8 +5009,7 @@ row_merge_build_indexes( ...@@ -5015,8 +5009,7 @@ row_merge_build_indexes(
DBUG_EXECUTE_IF("ib_index_crash_after_bulk_load", DBUG_SUICIDE();); DBUG_EXECUTE_IF("ib_index_crash_after_bulk_load", DBUG_SUICIDE(););
if (flush_observer != NULL) { if (FlushObserver* flush_observer = trx->get_flush_observer()) {
ut_ad(need_flush_observer);
DBUG_EXECUTE_IF("ib_index_build_fail_before_flush", DBUG_EXECUTE_IF("ib_index_build_fail_before_flush",
error = DB_INTERRUPTED; error = DB_INTERRUPTED;
...@@ -5028,7 +5021,7 @@ row_merge_build_indexes( ...@@ -5028,7 +5021,7 @@ row_merge_build_indexes(
flush_observer->flush(); flush_observer->flush();
UT_DELETE(flush_observer); trx->remove_flush_observer();
if (trx_is_interrupted(trx)) { if (trx_is_interrupted(trx)) {
error = DB_INTERRUPTED; error = DB_INTERRUPTED;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -64,17 +64,6 @@ typedef std::set< ...@@ -64,17 +64,6 @@ typedef std::set<
std::less<table_id_t>, std::less<table_id_t>,
ut_allocator<table_id_t> > table_id_set; ut_allocator<table_id_t> > 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. */ Set detailed error message for the transaction. */
void void
...@@ -165,7 +154,7 @@ trx_init( ...@@ -165,7 +154,7 @@ trx_init(
trx->lock.table_cached = 0; 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 /** 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() ...@@ -1088,6 +1077,21 @@ static trx_rseg_t* trx_assign_rseg_low()
return(rseg); 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. /** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */ @return the assigned rollback segment */
trx_rseg_t* trx_rseg_t*
......
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