/* Copyright (c) 2018, 2021, Alibaba and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL/PolarDB-X Engine hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL/PolarDB-X Engine. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SQL_OUTLINE_OUTLINE_INCLUDED #define SQL_OUTLINE_OUTLINE_INCLUDED #include #include "sql/outline/outline_common.h" #include "sql/outline/outline_table_common.h" struct TABLE_LIST; namespace im { /* Outline statistics */ struct Outline_stats { ulonglong hit; ulonglong overflow; public: Outline_stats() { hit = 0; overflow = 0; } void aggregate(const Outline_stats &stats) { hit += stats.hit; overflow += stats.overflow; } }; /** Outline object definition. */ class Outline { using Index_array = Prealloced_array; /* Separator of indexs in hint column */ static constexpr const char *INDEX_HINT_SEPARATOR = ","; public: explicit Outline(Outline_record *record) : m_id(record->id), m_schema(record->schema.str ? record->schema.str : ""), m_digest(record->digest.str), m_digest_text(record->digest_text.str ? record->digest_text.str : ""), m_type(record->type), m_scope(record->scope), m_state(record->state), m_pos(record->pos), m_hint(record->hint.str ? record->hint.str : ""), m_indexes(key_memory_outline), m_stats() { /* Build the index hint array if outline_type is INDEX */ build_index_hint(); } explicit Outline(const Outline &other) : m_id(other.m_id), m_schema(other.m_schema), m_digest(other.m_digest), m_digest_text(other.m_digest_text), m_type(other.m_type), m_scope(other.m_scope), m_state(other.m_state), m_pos(other.m_pos), m_hint(other.m_hint), m_indexes(key_memory_outline), m_stats() { build_index_hint(); } virtual ~Outline() { m_indexes.clear(); } Outline_type get_type() const { return m_type; } ulonglong get_pos() const { return m_pos; } const String_outline &get_digest() const { return m_digest; } const String_outline &get_digest_text() const { return m_digest_text; } const String_outline &get_schema() const { return m_schema; } const String_outline &get_hint() const { return m_hint; } ulonglong get_id() const { return m_id; } const Outline_stats &get_stats() const { return m_stats; } Outline_scope get_scope() const { return m_scope; } void inc_hit() { m_stats.hit++; } void inc_overflow() { m_stats.overflow++; } /** Evoke index hint instance, and add into list. @param[in] mem_root memory allocator @param[in/out] list container */ void evoke_index_hint(MEM_ROOT *mem_root, List *list); /** Evoke optimizer hint instance, and add into list. @param[in] mem_root memory allocator @param[in/out] list container */ void evoke_optimizer_hint(MEM_ROOT *mem_root, List *list); private: /** Build the index array by hint column in table. */ void build_index_hint(); private: ulonglong m_id; String_outline m_schema; String_outline m_digest; String_outline m_digest_text; Outline_type m_type; Outline_scope m_scope; Outline_state m_state; ulonglong m_pos; String_outline m_hint; /* Generated attributes */ Index_array m_indexes; /* All metrics */ private: Outline_stats m_stats; }; /* Outline show result structure */ struct Outline_show_result { ulonglong id; String_outline schema; String_outline digest; Outline_type type; Outline_scope scope; ulonglong pos; String_outline hint; Outline_stats stats; String_outline digest_text; public: explicit Outline_show_result(const Outline *outline) : id(outline->get_id()), schema(outline->get_schema()), digest(outline->get_digest()), type(outline->get_type()), scope(outline->get_scope()), pos(outline->get_pos()), hint(outline->get_hint()), stats(), digest_text(outline->get_digest_text()) { stats.aggregate(outline->get_stats()); } explicit Outline_show_result(const Outline_show_result &other) : id(other.id), schema(other.schema), digest(other.digest), type(other.type), scope(other.scope), pos(other.pos), hint(other.hint), stats(other.stats), digest_text(other.digest_text) {} void aggregate(const Outline *outline) { stats.aggregate(outline->get_stats()); } }; using Outline_show_result_container = malloc_unordered_map; struct Outline_preview_result { String_outline schema; String_outline digest; String_outline block_type; String_outline block_name; ulonglong block; String_outline hint_text; public: explicit Outline_preview_result(const char *schema_arg, const char *digest_arg, const char *block_type_arg, const char *block_name_arg, ulonglong block_arg, const char *hint_text_arg) : schema(schema_arg), digest(digest_arg), block_type(block_type_arg), block_name(block_name_arg), block(block_arg), hint_text(hint_text_arg) {} }; using Outline_preview_result_container = Malloc_outline_vector; /** Statement outlines. Outline array within statement. Statement outline structure: 1) schema, digest [outline key] 2) outline array */ class Statement_outline : public Disable_copy_base { public: using Outline_vector = Malloc_outline_vector; public: explicit Statement_outline(const char *schema, const char *digest) : m_schema(schema), m_digest(digest), m_outlines() {} /** Insert outline into statement_outline. @param[in] outline outline */ void insert(Outline *outline); /** Delete the outline from array by id; @param[in] outline id @retval affected rows */ size_t delete_by_id(ulonglong id); virtual ~Statement_outline(); const Outline_vector &outlines() const { return m_outlines; } private: String_outline m_schema; String_outline m_digest; Outline_vector m_outlines; }; typedef Statement_outline::Outline_vector Statement_outline_vector; /** System outline cache. Structure: Statement_outline map array; map structure: { [schema, digest] => Statement_outline} 1) statement index outline map[0] map[1] ... 2) statement optimizer outline map[m_partition] ... map[m_elements - 1] */ class System_outline { using Statement_outline_map = Pair_key_unordered_map; template using Container = Prealloced_array; /* Lock helper class */ class Lock_helper : public Disable_unnamed_object { public: explicit Lock_helper(mysql_rwlock_t *lock, bool exclusive) : m_locked(false), m_lock(lock) { if (exclusive) mysql_rwlock_wrlock(m_lock); else mysql_rwlock_rdlock(m_lock); m_locked = true; } void unlock() { mysql_rwlock_unlock(m_lock); m_locked = false; } ~Lock_helper() { if (m_locked) mysql_rwlock_unlock(m_lock); } private: bool m_locked; mysql_rwlock_t *m_lock; }; public: /* Index or optimizer */ enum class Category { CATEGORY_INDEX = 0, CATEGORY_OPTIMIZER, CATEGORY_COUNT }; public: explicit System_outline(size_t partition); virtual ~System_outline(); size_t get_partition() { return m_partition; } /** Fill the outlines into maps, clear all if force_clean is true. @param[in] records outline records container. @param[in] force_clean Whether clear all maps. */ void fill_records(Conf_records *records, bool force_clean); /** Find the outlines by schema and digest, and create hint add into TABLE_LIST or SELECT_LEX if found. @param[in] thd thread context @param[in/out] T TABLE_LISTS or SELECT_LEX list @param[in] schema schema name @param[in] digest statement digest */ template void find_and_fill_hints(THD *thd, T *all_objects, String_outline &schema, String_outline &digest); /** Delete the outline from all maps by id @param[in] outline id @retval affected rows */ size_t delete_outline(ulonglong id); /** Aggregate the outlines that has the same outline id within all partition maps. @param[out] container Result container */ void aggregate_outline(Outline_show_result_container *container); /* The system outline singleton instance */ static System_outline *m_system_outline; static System_outline *instance() { return m_system_outline; } private: /** Get the suitable position by thread id and category type @param[in] type Category type @param[in] thread id Thread id @retval position */ template size_t get_pos(ulonglong thread_id) { return (thread_id % m_partition) + (static_cast(type) * m_partition); } /** Get the begin position by category type There will be m_partition for every kind of category. */ size_t get_begin(Category type) { return static_cast(type) * m_partition; } /** Add the outling into m_maps at pos. @param[in] pos partition position @param[in] outline outline object @retval true Failure @retval false Success */ bool add_outline(size_t pos, const Outline *outline); /** Clear the statement outline objects from maps at pos. @param[in] pos partition position */ void clear(size_t pos); /** Find the statement outline by schema and digest. @param[in] pos position @param[in] schema schema name @param[in] digest statement digest */ Statement_outline *find(size_t pos, const String_outline &schema, const String_outline &digest) { typename Statement_outline_map::const_iterator it; it = m_maps[pos]->find(Statement_outline_map::key_type(schema, digest)); if (it == m_maps[pos]->end()) return nullptr; else return const_cast(it->second); } private: /* The number of partition */ size_t m_partition; /* The number of element. */ size_t m_elements; /* statement outline map's array */ Container m_maps; /* statement outline size's array */ Container m_sizes; /* locks array */ Container m_locks; }; typedef System_outline::Category Outline_category; /** Structure of two category containers */ struct Outline_group { std::vector index_outlines; std::vector optimizer_outlines; public: Outline_group() {} /** Classify the different hint type, and fill into vector. 1) One is index hint. 2) The other is optimizer hint. @param[in] records All kinds of outline */ void classify_hint(Conf_records *records); /** Destructor of two container Should destroy the outlines from allocate_outline_object(); */ ~Outline_group(); }; /* Struct within SELECT_LEX */ class Lex_optimizer_hint { public: ulonglong query_block; LEX_CSTRING hint; explicit Lex_optimizer_hint() { query_block = 0; hint = NULL_CSTR; } explicit Lex_optimizer_hint(ulonglong pos, char *hint_arg, size_t len) { query_block = pos; hint.str = hint_arg; hint.length = len; } }; } /*namespace im */ #endif