summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-04-13 10:26:01 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-04-13 10:26:01 +0300
commit6e6318b29b446f76f01f2ef65d1460870b607d2a (patch)
tree8c22bb7661b77c91b28532ddd7c150d4bf010146 /storage
parent450c017c2d9e490d92c949d5164b4a99b6b3f5db (diff)
parente262eb165c197083df9f4986ab54c5b2dcbd6290 (diff)
downloadmariadb-git-6e6318b29b446f76f01f2ef65d1460870b607d2a.tar.gz
Merge 10.2 into 10.3
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/dict/dict0dict.cc2
-rw-r--r--storage/innobase/dict/dict0mem.cc2
-rw-r--r--storage/innobase/dict/dict0stats_bg.cc19
-rw-r--r--storage/innobase/handler/handler0alter.cc84
-rw-r--r--storage/innobase/include/btr0bulk.h2
-rw-r--r--storage/innobase/include/dict0mem.h81
-rw-r--r--storage/innobase/include/row0merge.h20
-rw-r--r--storage/innobase/row/row0ftsort.cc2
-rw-r--r--storage/innobase/row/row0merge.cc30
-rw-r--r--storage/innobase/row/row0purge.cc2
-rw-r--r--storage/innobase/trx/trx0sys.cc2
11 files changed, 187 insertions, 59 deletions
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 8f5ad517eb9..1abcb2f9065 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -292,7 +292,7 @@ dict_table_try_drop_aborted(
&& !UT_LIST_GET_FIRST(table->locks)) {
/* Silence a debug assertion in row_merge_drop_indexes(). */
ut_d(table->acquire());
- row_merge_drop_indexes(trx, table, TRUE);
+ row_merge_drop_indexes(trx, table, true);
ut_d(table->release());
ut_ad(table->get_ref_count() == ref_count);
trx_commit_for_mysql(trx);
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 8e0edf1cf3f..ea2f51d0f04 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -931,7 +931,7 @@ dict_mem_fill_vcol_from_v_indexes(
Later virtual column set will be
refreshed during loading of table. */
if (!dict_index_has_virtual(index)
- || index->has_new_v_col) {
+ || index->has_new_v_col()) {
continue;
}
diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc
index 126de450ca5..386c7864579 100644
--- a/storage/innobase/dict/dict0stats_bg.cc
+++ b/storage/innobase/dict/dict0stats_bg.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2020, MariaDB Corporation.
+Copyright (c) 2017, 2021, 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
@@ -156,9 +156,24 @@ schedule new estimates for table and index statistics to be calculated.
void dict_stats_update_if_needed_func(dict_table_t *table)
#endif
{
- ut_ad(table->stat_initialized);
ut_ad(!mutex_own(&dict_sys->mutex));
+ if (UNIV_UNLIKELY(!table->stat_initialized)) {
+ /* The table may have been evicted from dict_sys
+ and reloaded internally by InnoDB for FOREIGN KEY
+ processing, but not reloaded by the SQL layer.
+
+ We can (re)compute the transient statistics when the
+ table is actually loaded by the SQL layer.
+
+ Note: If InnoDB persistent statistics are enabled,
+ we will skip the updates. We must do this, because
+ dict_table_get_n_rows() below assumes that the
+ statistics have been initialized. The DBA may have
+ to execute ANALYZE TABLE. */
+ return;
+ }
+
ulonglong counter = table->stat_modified_counter++;
ulonglong n_rows = dict_table_get_n_rows(table);
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 94603704324..0e17488e8aa 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -322,13 +322,6 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
@return whether the table will be rebuilt */
bool need_rebuild () const { return(old_table != new_table); }
- /** Clear uncommmitted added indexes after a failed operation. */
- void clear_added_indexes()
- {
- for (ulint i= 0; i < num_to_add_index; i++)
- add_index[i]->detach_columns(true);
- }
-
/** Convert table-rebuilding ALTER to instant ALTER. */
void prepare_instant()
{
@@ -376,6 +369,42 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
}
}
+ /** @return whether the given column is being added */
+ bool is_new_vcol(const dict_v_col_t &v_col) const
+ {
+ for (ulint i= 0; i < num_to_add_vcol; i++)
+ if (&add_vcol[i] == &v_col)
+ return true;
+ return false;
+ }
+
+ /** During rollback, make newly added indexes point to
+ newly added virtual columns. */
+ void clean_new_vcol_index()
+ {
+ ut_ad(old_table == new_table);
+ const dict_index_t *index= dict_table_get_first_index(old_table);
+ while ((index= dict_table_get_next_index(index)) != NULL)
+ {
+ if (!index->has_virtual() || index->is_committed())
+ continue;
+ ulint n_drop_new_vcol= index->get_new_n_vcol();
+ for (ulint i= 0; n_drop_new_vcol && i < index->n_fields; i++)
+ {
+ dict_col_t *col= index->fields[i].col;
+ /* Skip the non-virtual and old virtual columns */
+ if (!col->is_virtual())
+ continue;
+ dict_v_col_t *vcol= reinterpret_cast<dict_v_col_t*>(col);
+ if (!is_new_vcol(*vcol))
+ continue;
+
+ index->fields[i].col= &index->new_vcol_info->
+ add_drop_v_col(index->heap, vcol, --n_drop_new_vcol)->m_col;
+ }
+ }
+ }
+
private:
// Disable copying
ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx&);
@@ -3074,7 +3103,7 @@ online_retry_drop_indexes_low(
ut_ad(table->get_ref_count() >= 1);
if (table->drop_aborted) {
- row_merge_drop_indexes(trx, table, TRUE);
+ row_merge_drop_indexes(trx, table, true);
}
}
@@ -5660,7 +5689,7 @@ new_table_failed:
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
dict_index_t* index = ctx->add_index[a];
- const bool has_new_v_col = index->has_new_v_col;
+ const ulint n_v_col = index->get_new_n_vcol();
index = create_index_dict(ctx->trx, index, add_v);
error = ctx->trx->error_state;
if (error != DB_SUCCESS) {
@@ -5690,7 +5719,9 @@ error_handling_drop_uncached_1:
goto error_handling_drop_uncached_1;
}
index->parser = index_defs[a].parser;
- index->has_new_v_col = has_new_v_col;
+ if (n_v_col) {
+ index->assign_new_v_col(n_v_col);
+ }
/* Note the id of the transaction that created this
index, we use it to restrict readers from accessing
this index, to ensure read consistency. */
@@ -5761,7 +5792,7 @@ error_handling_drop_uncached_1:
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
dict_index_t* index = ctx->add_index[a];
- const bool has_new_v_col = index->has_new_v_col;
+ const ulint n_v_col = index->get_new_n_vcol();
DBUG_EXECUTE_IF(
"create_index_metadata_fail",
if (a + 1 == ctx->num_to_add_index) {
@@ -5793,7 +5824,9 @@ error_handling_drop_uncached:
}
index->parser = index_defs[a].parser;
- index->has_new_v_col = has_new_v_col;
+ if (n_v_col) {
+ index->assign_new_v_col(n_v_col);
+ }
/* Note the id of the transaction that created this
index, we use it to restrict readers from accessing
this index, to ensure read consistency. */
@@ -6019,7 +6052,7 @@ error_handled:
online_retry_drop_indexes_with_trx(user_table, ctx->trx);
} else {
ut_ad(!ctx->need_rebuild());
- row_merge_drop_indexes(ctx->trx, user_table, TRUE);
+ row_merge_drop_indexes(ctx->trx, user_table, true);
trx_commit_for_mysql(ctx->trx);
}
@@ -7269,7 +7302,6 @@ oom:
that we hold at most a shared lock on the table. */
m_prebuilt->trx->error_info = NULL;
ctx->trx->error_state = DB_SUCCESS;
- ctx->clear_added_indexes();
DBUG_RETURN(true);
}
@@ -7364,17 +7396,18 @@ temparary index prefix
@param table the TABLE
@param locked TRUE=table locked, FALSE=may need to do a lazy drop
@param trx the transaction
-*/
-static MY_ATTRIBUTE((nonnull))
+@param alter_trx transaction which takes S-lock on the table
+ while creating the index */
+static
void
innobase_rollback_sec_index(
-/*========================*/
- dict_table_t* user_table,
- const TABLE* table,
- ibool locked,
- trx_t* trx)
+ dict_table_t* user_table,
+ const TABLE* table,
+ bool locked,
+ trx_t* trx,
+ const trx_t* alter_trx=NULL)
{
- row_merge_drop_indexes(trx, user_table, locked);
+ row_merge_drop_indexes(trx, user_table, locked, alter_trx);
/* Free the table->fts only if there is no FTS_DOC_ID
in the table */
@@ -7469,7 +7502,12 @@ rollback_inplace_alter_table(
DBUG_ASSERT(ctx->new_table == prebuilt->table);
innobase_rollback_sec_index(
- prebuilt->table, table, FALSE, ctx->trx);
+ prebuilt->table, table,
+ (ha_alter_info->alter_info->requested_lock
+ == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE),
+ ctx->trx, prebuilt->trx);
+
+ ctx->clean_new_vcol_index();
}
trx_commit_for_mysql(ctx->trx);
diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h
index afce691de23..7b2b5c7a5d7 100644
--- a/storage/innobase/include/btr0bulk.h
+++ b/storage/innobase/include/btr0bulk.h
@@ -328,7 +328,7 @@ public:
/** Re-latch all latches */
void latch();
- dict_index_t* index() { return m_index; }
+ table_name_t table_name() { return m_index->table->name; }
private:
/** Insert a tuple to a page in a level
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 05db1a844e4..8fc82955b73 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -681,6 +681,35 @@ struct dict_v_col_t{
};
+/** Data structure for newly added virtual column in a index.
+It is used only during rollback_inplace_alter_table() of
+addition of index depending on newly added virtual columns
+and uses index heap. Should be freed when index is being
+removed from cache. */
+struct dict_add_v_col_info
+{
+ ulint n_v_col;
+ dict_v_col_t *v_col;
+
+ /** Add the newly added virtual column while rollbacking
+ the index which contains new virtual columns
+ @param col virtual column to be duplicated
+ @param offset offset where to duplicate virtual column */
+ dict_v_col_t* add_drop_v_col(mem_heap_t *heap, dict_v_col_t *col,
+ ulint offset)
+ {
+ ut_ad(n_v_col);
+ ut_ad(offset < n_v_col);
+ if (!v_col)
+ v_col= static_cast<dict_v_col_t*>
+ (mem_heap_alloc(heap, n_v_col * sizeof *v_col));
+ new (&v_col[offset]) dict_v_col_t();
+ v_col[offset].m_col= col->m_col;
+ v_col[offset].v_pos= col->v_pos;
+ return &v_col[offset];
+ }
+};
+
/** Data structure for newly added virtual column in a table */
struct dict_add_v_col_t{
/** number of new virtual column */
@@ -919,9 +948,13 @@ struct dict_index_t{
dict_field_t* fields; /*!< array of field descriptions */
st_mysql_ftparser*
parser; /*!< fulltext parser plugin */
- bool has_new_v_col;
- /*!< whether it has a newly added virtual
- column in ALTER */
+
+ /** It just indicates whether newly added virtual column
+ during alter. It stores column in case of alter failure.
+ It should use heap from dict_index_t. It should be freed
+ while removing the index from table. */
+ dict_add_v_col_info* new_vcol_info;
+
bool index_fts_syncing;/*!< Whether the fts index is
still syncing in the background;
FIXME: remove this and use MDL */
@@ -1068,9 +1101,8 @@ struct dict_index_t{
/** @return whether the index is corrupted */
inline bool is_corrupted() const;
- /** Detach the virtual columns from the index that is to be removed.
- @param whether to reset fields[].col */
- void detach_columns(bool clear= false)
+ /** Detach the virtual columns from the index that is to be removed. */
+ void detach_columns()
{
if (!has_virtual())
return;
@@ -1080,8 +1112,6 @@ struct dict_index_t{
if (!col || !col->is_virtual())
continue;
col->detach(*this);
- if (clear)
- fields[i].col= NULL;
}
}
@@ -1148,6 +1178,30 @@ struct dict_index_t{
bool
vers_history_row(const rec_t* rec, bool &history_row);
+ /** Assign the number of new column to be added as a part
+ of the index
+ @param n_vcol number of virtual columns to be added */
+ void assign_new_v_col(ulint n_vcol)
+ {
+ new_vcol_info= static_cast<dict_add_v_col_info*>(
+ mem_heap_zalloc(heap, sizeof *new_vcol_info));
+ new_vcol_info->n_v_col= n_vcol;
+ }
+
+ /* @return whether index has new virtual column */
+ bool has_new_v_col() const
+ {
+ return new_vcol_info != NULL;
+ }
+
+ /* @return number of newly added virtual column */
+ ulint get_new_n_vcol() const
+ {
+ if (new_vcol_info)
+ return new_vcol_info->n_v_col;
+ return 0;
+ }
+
#ifdef BTR_CUR_HASH_ADAPT
/** @return a clone of this */
dict_index_t* clone() const;
@@ -2041,6 +2095,17 @@ public:
/** mysql_row_templ_t for base columns used for compute the virtual
columns */
dict_vcol_templ_t* vc_templ;
+
+ /* @return whether the table has any other transcation lock
+ other than the given transaction */
+ bool has_lock_other_than(const trx_t *trx) const
+ {
+ for (lock_t *lock= UT_LIST_GET_FIRST(locks); lock;
+ lock= UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock))
+ if (lock->trx != trx)
+ return true;
+ return false;
+ }
};
inline void dict_index_t::set_modified(mtr_t& mtr) const
diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h
index e88380b94e3..3252af0062b 100644
--- a/storage/innobase/include/row0merge.h
+++ b/storage/innobase/include/row0merge.h
@@ -167,18 +167,20 @@ row_merge_drop_indexes_dict(
table_id_t table_id)/*!< in: table identifier */
MY_ATTRIBUTE((nonnull));
-/*********************************************************************//**
-Drop those indexes which were created before an error occurred.
+/** Drop indexes that were created before an error occurred.
The data dictionary must have been locked exclusively by the caller,
-because the transaction will not be committed. */
+because the transaction will not be committed.
+@param trx dictionary transaction
+@param table table containing the indexes
+@param locked True if table is locked,
+ false - may need to do lazy drop
+@param alter_trx Alter table transaction */
void
row_merge_drop_indexes(
-/*===================*/
- trx_t* trx, /*!< in/out: transaction */
- dict_table_t* table, /*!< in/out: table containing the indexes */
- ibool locked) /*!< in: TRUE=table locked,
- FALSE=may need to do a lazy drop */
- MY_ATTRIBUTE((nonnull));
+ trx_t* trx,
+ dict_table_t* table,
+ bool locked,
+ const trx_t* alter_trx=NULL);
/*********************************************************************//**
Drop all partially created indexes during crash recovery. */
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 6e179e669ec..3d9bc6f0ab1 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -1222,7 +1222,7 @@ row_merge_write_fts_word(
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
ib::error() << "Failed to write word to FTS auxiliary"
" index table "
- << ins_ctx->btr_bulk->index()->table->name
+ << ins_ctx->btr_bulk->table_name()
<< ", error " << error;
ret = error;
}
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 0638465527c..2d3ce298f56 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2020, MariaDB Corporation.
+Copyright (c) 2014, 2021, 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
@@ -3828,17 +3828,20 @@ row_merge_drop_indexes_dict(
trx->op_info = "";
}
-/*********************************************************************//**
-Drop indexes that were created before an error occurred.
+/** Drop indexes that were created before an error occurred.
The data dictionary must have been locked exclusively by the caller,
-because the transaction will not be committed. */
+because the transaction will not be committed.
+@param trx dictionary transaction
+@param table table containing the indexes
+@param locked True if table is locked,
+ false - may need to do lazy drop
+@param alter_trx Alter table transaction */
void
row_merge_drop_indexes(
-/*===================*/
- trx_t* trx, /*!< in/out: dictionary transaction */
- dict_table_t* table, /*!< in/out: table containing the indexes */
- ibool locked) /*!< in: TRUE=table locked,
- FALSE=may need to do a lazy drop */
+ trx_t* trx,
+ dict_table_t* table,
+ bool locked,
+ const trx_t* alter_trx)
{
dict_index_t* index;
dict_index_t* next_index;
@@ -3864,7 +3867,7 @@ row_merge_drop_indexes(
A concurrent purge will be prevented by dict_operation_lock. */
if (!locked && (table->get_ref_count() > 1
- || UT_LIST_GET_FIRST(table->locks))) {
+ || table->has_lock_other_than(alter_trx))) {
/* We will have to drop the indexes later, when the
table is guaranteed to be no longer in use. Mark the
indexes as incomplete and corrupted, so that other
@@ -4414,6 +4417,7 @@ row_merge_create_index(
dict_index_t* index;
ulint n_fields = index_def->n_fields;
ulint i;
+ ulint n_add_vcol = 0;
DBUG_ENTER("row_merge_create_index");
@@ -4438,7 +4442,7 @@ row_merge_create_index(
ut_ad(ifield->col_no >= table->n_v_def);
name = add_v->v_col_name[
ifield->col_no - table->n_v_def];
- index->has_new_v_col = true;
+ n_add_vcol++;
} else {
name = dict_table_get_v_col_name(
table, ifield->col_no);
@@ -4450,6 +4454,10 @@ row_merge_create_index(
dict_mem_index_add_field(index, name, ifield->prefix_len);
}
+ if (n_add_vcol) {
+ index->assign_new_v_col(n_add_vcol);
+ }
+
DBUG_RETURN(index);
}
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index d299f948d7c..19e981ee30f 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -729,7 +729,7 @@ row_purge_skip_uncommitted_virtual_index(
not support LOCK=NONE when adding an index on newly
added virtual column.*/
while (index != NULL && dict_index_has_virtual(index)
- && !index->is_committed() && index->has_new_v_col) {
+ && !index->is_committed() && index->has_new_v_col()) {
index = dict_table_get_next_index(index);
}
}
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 1bdb3727263..87814fa6c69 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2020, MariaDB Corporation.
+Copyright (c) 2017, 2021, 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