summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-02-20 22:42:18 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2019-02-20 22:42:18 +0200
commit9f1d752f41b8e441d16d9d0777a80154fb281dd8 (patch)
tree38fbed58a9f565a81e7237ca3f4e48a3e3c6d7de
parent662a8373a05c3e63ed9e30858e838d8ed4d4ddd5 (diff)
downloadmariadb-git-10.4-MDEV-17805.tar.gz
WIP MDEV-17805: Remove InnoDB cache for temporary tables10.4-MDEV-17805
The intention is to link dict_table_t to TABLE_SHARE. FIXME: Implement ha_innobase::delete_table() for temporary tables. FIXME: Implement rollback of ha_innobase::create() for temporary tables. FIXME: Currently, DBUG_ASSERT(s) fails in ha_innobase::open() because we fail to pass the InnoDB_share from ha_innobase::create(). This seems to happen for any ALTER TABLE that uses ALGORITHM=COPY (Old note from December, maybe not true any more:) An assignment to TABLE_SHARE::ha_share would not work either, because create() and open() will use different TABLE_SHARE.
-rw-r--r--storage/innobase/dict/dict0crea.cc2
-rw-r--r--storage/innobase/dict/dict0dict.cc34
-rw-r--r--storage/innobase/handler/ha_innodb.cc204
-rw-r--r--storage/innobase/handler/ha_innodb.h4
-rw-r--r--storage/innobase/include/dict0dict.h17
5 files changed, 175 insertions, 86 deletions
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index d8b9bcdaf39..35f3e810db4 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -2065,7 +2065,7 @@ dict_foreigns_has_s_base_col(
{
dict_foreign_t* foreign;
- if (table->s_cols == NULL) {
+ if (!table || !table->s_cols) {
return (false);
}
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 7664bc2064d..ef40df5569b 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1099,7 +1099,6 @@ dict_init(void)
dict_sys->table_hash = hash_create(hash_size);
dict_sys->table_id_hash = hash_create(hash_size);
- dict_sys->temp_id_hash = hash_create(hash_size);
rw_lock_create(dict_operation_lock_key,
dict_operation_lock, SYNC_DICT_OPERATION);
@@ -1263,6 +1262,7 @@ void dict_table_t::add_to_cache()
{
ut_ad(dict_lru_validate());
ut_ad(mutex_own(&dict_sys->mutex));
+ ut_ad(!is_temporary());
cached = TRUE;
@@ -1288,25 +1288,24 @@ void dict_table_t::add_to_cache()
this);
/* Look for a table with the same id: error if such exists */
- hash_table_t* id_hash = is_temporary()
- ? dict_sys->temp_id_hash : dict_sys->table_id_hash;
const ulint id_fold = ut_fold_ull(id);
{
dict_table_t* table2;
- HASH_SEARCH(id_hash, id_hash, id_fold,
+ HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
dict_table_t*, table2, ut_ad(table2->cached),
table2->id == id);
ut_a(table2 == NULL);
#ifdef UNIV_DEBUG
/* Look for the same table pointer with a different id */
- HASH_SEARCH_ALL(id_hash, id_hash,
+ HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
dict_table_t*, table2, ut_ad(table2->cached),
table2 == this);
ut_ad(table2 == NULL);
#endif /* UNIV_DEBUG */
- HASH_INSERT(dict_table_t, id_hash, id_hash, id_fold, this);
+ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
+ id_fold, this);
}
if (can_be_evicted) {
@@ -1977,6 +1976,7 @@ void dict_table_remove_from_cache(dict_table_t* table, bool lru, bool keep)
dict_index_t* index;
ut_ad(table);
+ ut_ad(!table->is_temporary());
ut_ad(dict_lru_validate());
ut_a(table->get_ref_count() == 0);
ut_a(table->n_rec_locks == 0);
@@ -2012,10 +2012,9 @@ void dict_table_remove_from_cache(dict_table_t* table, bool lru, bool keep)
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
ut_fold_string(table->name.m_name), table);
- hash_table_t* id_hash = table->is_temporary()
- ? dict_sys->temp_id_hash : dict_sys->table_id_hash;
const ulint id_fold = ut_fold_ull(table->id);
- HASH_DELETE(dict_table_t, id_hash, id_hash, id_fold, table);
+ HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
+ id_fold, table);
/* Remove table from LRU or non-LRU list. */
if (table->can_be_evicted) {
@@ -4499,7 +4498,7 @@ loop:
error = dict_create_add_foreigns_to_dictionary(
local_fk_set, table, trx);
- if (error == DB_SUCCESS) {
+ if (error == DB_SUCCESS && table) {
table->foreign_set.insert(local_fk_set.begin(),
local_fk_set.end());
@@ -6486,8 +6485,7 @@ dict_fs2utf8(
}
/** Resize the hash tables besed on the current buffer pool size. */
-void
-dict_resize()
+void dict_resize()
{
dict_table_t* table;
@@ -6496,13 +6494,11 @@ dict_resize()
/* all table entries are in table_LRU and table_non_LRU lists */
hash_table_free(dict_sys->table_hash);
hash_table_free(dict_sys->table_id_hash);
- hash_table_free(dict_sys->temp_id_hash);
const ulint hash_size = buf_pool_get_curr_size()
/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE);
dict_sys->table_hash = hash_create(hash_size);
dict_sys->table_id_hash = hash_create(hash_size);
- dict_sys->temp_id_hash = hash_create(hash_size);
for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table;
table = UT_LIST_GET_NEXT(table_LRU, table)) {
@@ -6512,23 +6508,20 @@ dict_resize()
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash,
fold, table);
-
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
id_fold, table);
}
for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU); table;
table = UT_LIST_GET_NEXT(table_LRU, table)) {
+ ut_ad(!table->is_temporary());
ulint fold = ut_fold_string(table->name.m_name);
ulint id_fold = ut_fold_ull(table->id);
HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash,
fold, table);
-
- hash_table_t* id_hash = table->is_temporary()
- ? dict_sys->temp_id_hash : dict_sys->table_id_hash;
-
- HASH_INSERT(dict_table_t, id_hash, id_hash, id_fold, table);
+ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
+ id_fold, table);
}
mutex_exit(&dict_sys->mutex);
@@ -6572,7 +6565,6 @@ dict_close(void)
/* The elements are the same instance as in dict_sys->table_hash,
therefore we don't delete the individual elements. */
hash_table_free(dict_sys->table_id_hash);
- hash_table_free(dict_sys->temp_id_hash);
mutex_exit(&dict_sys->mutex);
mutex_free(&dict_sys->mutex);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index f9e18f25e82..344e8335f9b 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -258,6 +258,66 @@ is_partition(
return strstr(file_name, table_name_t::part_suffix);
}
+struct get_temporary_table_arg
+{
+ table_id_t id;
+ dict_table_t* table;
+};
+
+static handlerton* innobase_hton;
+
+class InnoDB_share : public Handler_share
+{
+public:
+ /** Temporary table associated with the handle, or NULL */
+ dict_table_t* const temp_table;
+
+ InnoDB_share(dict_table_t* table)
+ : Handler_share(), temp_table(table)
+ {
+ DBUG_ASSERT(temp_table->is_temporary());
+ DBUG_ASSERT(temp_table->id >= DICT_HDR_FIRST_ID);
+ }
+ ~InnoDB_share() {}
+
+ /** Look up a temporary table.
+ @param t lookup request
+ @return whether the table was found */
+ inline bool get_temporary_table(get_temporary_table_arg* t) const
+ {
+ DBUG_ASSERT(!t->table);
+ if (!temp_table || temp_table->id != t->id) {
+ return false;
+ }
+ DBUG_ASSERT(temp_table->is_temporary());
+ temp_table->acquire();
+ t->table = temp_table;
+ return true;
+ }
+};
+
+static int get_temporary_table_callback(TABLE_SHARE *share, void *arg)
+{
+ if (share->db_type() != innobase_hton) {
+ return false;
+ }
+
+ auto s = static_cast<const InnoDB_share*>(share->ha_share);
+
+ return s && s->get_temporary_table(
+ static_cast<get_temporary_table_arg*>(arg));
+}
+
+dict_table_t* dict_sys_t::get_temporary_table(table_id_t id)
+{
+ DBUG_ENTER("dict_sys_t::get_temporary_table");
+ DBUG_ASSERT(id >= DICT_HDR_FIRST_ID);
+ get_temporary_table_arg t = { id, NULL };
+ thd_iterate_temporary_tables(current_thd,
+ get_temporary_table_callback, &t);
+ DBUG_RETURN(t.table);
+}
+
/** Signal to shut down InnoDB (NULL if shutdown was signaled, or if
running in innodb_read_only mode, srv_read_only_mode) */
std::atomic <st_my_thread_var *> srv_running;
@@ -4142,7 +4202,7 @@ static int innodb_init_params()
static int innodb_init(void* p)
{
DBUG_ENTER("innodb_init");
- handlerton* innobase_hton= static_cast<handlerton*>(p);
+ innobase_hton= static_cast<handlerton*>(p);
innodb_hton_ptr = innobase_hton;
innobase_hton->state = SHOW_OPTION_YES;
@@ -6129,6 +6189,17 @@ ha_innobase::open(const char* name, int, uint)
ignore_err = DICT_ERR_IGNORE_FK_NOKEY;
}
+ if (table_share->tmp_table != NO_TMP_TABLE) {
+ lock_shared_ha_data();
+ auto* s = static_cast<InnoDB_share*>(get_ha_share_ptr());
+ unlock_shared_ha_data();
+ DBUG_ASSERT(s);
+ DBUG_ASSERT(s->temp_table);
+ DBUG_ASSERT(s->temp_table->is_temporary());
+ ib_table = s->temp_table;
+ goto got_table;
+ }
+
ib_table = open_dict_table(name, norm_name, is_part, ignore_err);
if (NULL == ib_table) {
@@ -6141,36 +6212,38 @@ no_such_table:
set_my_errno(ENOENT);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+ } else {
+ size_t n_fields = omits_virtual_cols(*table_share)
+ ? table_share->stored_fields : table_share->fields;
+ size_t n_cols = dict_table_get_n_user_cols(ib_table)
+ + dict_table_get_n_v_cols(ib_table)
+ - !!DICT_TF2_FLAG_IS_SET(ib_table,
+ DICT_TF2_FTS_HAS_DOC_ID);
+
+ if (UNIV_UNLIKELY(n_cols != n_fields)) {
+ ib::warn() << "Table " << norm_name << " contains "
+ << n_cols << " user"
+ " defined columns in InnoDB, but " << n_fields
+ << " columns in MariaDB. Please check"
+ " INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and "
+ REFMAN "innodb-troubleshooting.html for "
+ "how to resolve the issue.";
+
+ /* Mark this table as corrupted, so the drop table
+ or force recovery can still use it, but not others. */
+ ib_table->file_unreadable = true;
+ ib_table->corrupted = true;
+ dict_table_close(ib_table, FALSE, FALSE);
+ goto no_such_table;
+ }
}
+got_table:
if (!ib_table->not_redundant()) {
m_int_table_flags |= HA_EXTENDED_TYPES_CONVERSION;
cached_table_flags |= HA_EXTENDED_TYPES_CONVERSION;
}
- size_t n_fields = omits_virtual_cols(*table_share)
- ? table_share->stored_fields : table_share->fields;
- size_t n_cols = dict_table_get_n_user_cols(ib_table)
- + dict_table_get_n_v_cols(ib_table)
- - !!DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID);
-
- if (UNIV_UNLIKELY(n_cols != n_fields)) {
- ib::warn() << "Table " << norm_name << " contains "
- << n_cols << " user"
- " defined columns in InnoDB, but " << n_fields
- << " columns in MariaDB. Please check"
- " INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and " REFMAN
- "innodb-troubleshooting.html for how to resolve the"
- " issue.";
-
- /* Mark this table as corrupted, so the drop table
- or force recovery can still use it, but not others. */
- ib_table->file_unreadable = true;
- ib_table->corrupted = true;
- dict_table_close(ib_table, FALSE, FALSE);
- goto no_such_table;
- }
-
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
/* No point to init any statistics if tablespace is still encrypted. */
@@ -11134,7 +11207,6 @@ err_col:
!= REC_FORMAT_COMPRESSED);
table->space_id = SRV_TMP_SPACE_ID;
table->space = fil_system.temp_space;
- table->add_to_cache();
} else {
if (err == DB_SUCCESS) {
err = row_create_table_for_mysql(
@@ -12370,6 +12442,8 @@ int create_table_info_t::create_table(bool create_fk)
DBUG_ASSERT(m_drop_before_rollback
== !(m_flags2 & DICT_TF2_TEMPORARY));
+ DBUG_ASSERT((m_flags2 & DICT_TF2_TEMPORARY)
+ == m_table->is_temporary());
/* Create the keys */
@@ -12531,14 +12605,32 @@ int create_table_info_t::create_table(bool create_fk)
int
create_table_info_t::create_table_update_dict()
{
- dict_table_t* innobase_table;
DBUG_ENTER("create_table_update_dict");
+ DBUG_ASSERT(m_table);
+
+ if (m_flags2 & DICT_TF2_TEMPORARY) {
+ DBUG_ASSERT(m_table->is_temporary());
+ DBUG_ASSERT(!m_table->fts);
+ DBUG_ASSERT(!m_table->fts_doc_id_index);
+ if (m_form->found_next_number_field) {
+ ut_ad(!innobase_is_v_fld(
+ m_form->found_next_number_field));
+ m_table->autoinc = m_create_info->auto_increment_value;
+ if (m_table->autoinc == 0) {
+ m_table->autoinc = 1;
+ }
+ }
+ innobase_parse_hint_from_comment(m_thd, m_table, m_form->s);
+ DBUG_RETURN(0);
+ }
- innobase_table = dict_table_open_on_name(
- m_table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
+ dict_table_t* innobase_table = dict_table_open_on_name(
+ m_table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
DBUG_ASSERT(innobase_table != 0);
+ DBUG_ASSERT(!innobase_table->is_temporary());
+
if (innobase_table->fts != NULL) {
if (innobase_table->fts_doc_id_index == NULL) {
innobase_table->fts_doc_id_index
@@ -12586,26 +12678,19 @@ create_table_info_t::create_table_update_dict()
dict_table_autoinc_lock(innobase_table);
dict_table_autoinc_initialize(innobase_table, autoinc);
- if (innobase_table->is_temporary()) {
- /* AUTO_INCREMENT is not persistent for
- TEMPORARY TABLE. Temporary tables are never
- evicted. Keep the counter in memory only. */
- } else {
- const unsigned col_no = innodb_col_no(ai);
-
- innobase_table->persistent_autoinc = 1
- + dict_table_get_nth_col_pos(
- innobase_table, col_no, NULL);
-
- /* Persist the "last used" value, which
- typically is AUTO_INCREMENT - 1.
- In btr_create(), the value 0 was already written. */
- if (--autoinc) {
- btr_write_autoinc(
- dict_table_get_first_index(
- innobase_table),
- autoinc);
- }
+ const unsigned col_no = innodb_col_no(ai);
+
+ innobase_table->persistent_autoinc = 1
+ + dict_table_get_nth_col_pos(innobase_table, col_no,
+ NULL);
+
+ /* Persist the "last used" value, which
+ typically is AUTO_INCREMENT - 1.
+ In btr_create(), the value 0 was already written. */
+ if (--autoinc) {
+ btr_write_autoinc(
+ dict_table_get_first_index(innobase_table),
+ autoinc);
}
dict_table_autoinc_unlock(innobase_table);
@@ -12627,6 +12712,18 @@ create_table_info_t::allocate_trx()
m_trx->ddl = true;
}
+/** @return temporary table
+@retval NULL if not a temporary table */
+inline dict_table_t* create_table_info_t::temp_table() const
+{
+ if (!(m_flags2 & DICT_TF2_TEMPORARY)) {
+ return NULL;
+ }
+
+ DBUG_ASSERT(!m_table || m_table->is_temporary());
+ return m_table;
+}
+
/** Create a new table to an InnoDB database.
@param[in] name Table name, format: "db/table_name".
@param[in] form Table format; columns and index information.
@@ -12714,6 +12811,17 @@ ha_innobase::create(
error = info.create_table_update_dict();
+ if (error) {
+ } else if (dict_table_t* t = info.temp_table()) {
+ DBUG_ASSERT(!get_ha_share_ptr());
+ set_ha_share_ptr(new InnoDB_share(t));
+ if (!get_ha_share_ptr()) {
+ //FIXME: drop_table
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ DBUG_RETURN(0);
+ }
+
/* Tell the InnoDB server that there might be work for
utility threads: */
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index bdef141ed1c..4677563c599 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -714,6 +714,10 @@ public:
const char* table_name() const
{ return(m_table_name); }
+ /** @return temporary table
+ @retval NULL if not a temporary table */
+ inline dict_table_t* temp_table() const;
+
/** @return whether the table needs to be dropped on rollback */
bool drop_before_rollback() const { return m_drop_before_rollback; }
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 202d56365b7..4aa65ad3287 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -1541,8 +1541,6 @@ struct dict_sys_t{
on name */
/** hash table of persistent table IDs */
hash_table_t* table_id_hash;
- /** hash table of temporary table IDs */
- hash_table_t* temp_id_hash;
dict_table_t* sys_tables; /*!< SYS_TABLES table */
dict_table_t* sys_columns; /*!< SYS_COLUMNS table */
dict_table_t* sys_indexes; /*!< SYS_INDEXES table */
@@ -1567,20 +1565,7 @@ struct dict_sys_t{
@return temporary table
@retval NULL if the table does not exist
(should only happen during the rollback of CREATE...SELECT) */
- dict_table_t* get_temporary_table(table_id_t id)
- {
- ut_ad(mutex_own(&mutex));
- dict_table_t* table;
- ulint fold = ut_fold_ull(id);
- HASH_SEARCH(id_hash, temp_id_hash, fold, dict_table_t*, table,
- ut_ad(table->cached), table->id == id);
- if (UNIV_LIKELY(table != NULL)) {
- DBUG_ASSERT(table->is_temporary());
- DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID);
- table->acquire();
- }
- return table;
- }
+ dict_table_t* get_temporary_table(table_id_t id);
/** Look up a persistent table.
@param id table ID