diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-02-20 22:42:18 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-02-20 22:42:18 +0200 |
commit | 9f1d752f41b8e441d16d9d0777a80154fb281dd8 (patch) | |
tree | 38fbed58a9f565a81e7237ca3f4e48a3e3c6d7de | |
parent | 662a8373a05c3e63ed9e30858e838d8ed4d4ddd5 (diff) | |
download | mariadb-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.cc | 2 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 34 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 204 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 4 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.h | 17 |
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 |