/* Copyright (c) 2015, 2024, Oracle and/or its affiliates. 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 designed to work 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 hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. 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 DD_CACHE__OBJECT_REGISTRY_INCLUDED #define DD_CACHE__OBJECT_REGISTRY_INCLUDED #include #include // unique_ptr #include "local_multi_map.h" // Local_multi_map #include "sql/dd/types/abstract_table.h" // Abstract_table #include "sql/dd/types/charset.h" // Charset #include "sql/dd/types/collation.h" // Collation #include "sql/dd/types/column_statistics.h" // Column_statistics #include "sql/dd/types/event.h" // Event #include "sql/dd/types/resource_group.h" // Resource_group #include "sql/dd/types/routine.h" // Routine #include "sql/dd/types/schema.h" // Schema #include "sql/dd/types/spatial_reference_system.h" // Spatial_reference_system #include "sql/dd/types/tablespace.h" // Tablespace namespace dd { namespace cache { /** Object registry containing several maps. The registry is mainly a collection of maps for each type supported. The functions dispatch to the appropriate map based on the key and object type parameter. There is no support for locking or thread synchronization. The object registry is kind of the single threaded version of the shared dictionary cache. The object registry is intended to be used as a thread local record of which objects have been used. The individual maps containing DD object pointers are allocated on demand to avoid excessive performance overhead during object instantiation. */ class Object_registry { private: template struct Type_selector {}; // Dummy type to use for // selecting map instance. std::unique_ptr> m_abstract_table_map; std::unique_ptr> m_charset_map; std::unique_ptr> m_collation_map; std::unique_ptr> m_column_statistics_map; std::unique_ptr> m_event_map; std::unique_ptr> m_resource_group_map; std::unique_ptr> m_routine_map; std::unique_ptr> m_schema_map; std::unique_ptr> m_spatial_reference_system_map; std::unique_ptr> m_tablespace_map; // Not inlined because it is big, and because it takes a lot of time // for the compiler to instantiate. Defined in dd.cc, along the similar // create_object() instantiations. template void create_map(std::unique_ptr *map); /** Create a map instance unless it exists already. */ template T *create_map_if_needed(std::unique_ptr *map) { if (*map == nullptr) create_map(map); return map->get(); } /** Overloaded functions to use for selecting map instance based on a key type. Const and non-const variants. The non-const variants will create the map unless it exists. */ Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_abstract_table_map); } const Local_multi_map *m_map( Type_selector) const { return m_abstract_table_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_charset_map); } const Local_multi_map *m_map(Type_selector) const { return m_charset_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_collation_map); } const Local_multi_map *m_map(Type_selector) const { return m_collation_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_column_statistics_map); } const Local_multi_map *m_map( Type_selector) const { return m_column_statistics_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_event_map); } const Local_multi_map *m_map(Type_selector) const { return m_event_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_resource_group_map); } const Local_multi_map *m_map( Type_selector) const { return m_resource_group_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_routine_map); } const Local_multi_map *m_map(Type_selector) const { return m_routine_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_schema_map); } const Local_multi_map *m_map(Type_selector) const { return m_schema_map.get(); } Local_multi_map *m_map( Type_selector) { return create_map_if_needed(&m_spatial_reference_system_map); } const Local_multi_map *m_map( Type_selector) const { return m_spatial_reference_system_map.get(); } Local_multi_map *m_map(Type_selector) { return create_map_if_needed(&m_tablespace_map); } const Local_multi_map *m_map(Type_selector) const { return m_tablespace_map.get(); } /** Template function to get a map instance. To support generic code, the map instances are available through template function instances. This allows looking up the appropriate instance based on the key type. We must use overloading to accomplish this (see above). Const and non-const variants. @note The non-const variant will create a map unless it exists already. The const variant will not create a map, and may thus return a nullptr. @tparam T Dictionary object type. @return The map handling objects of type T. */ template Local_multi_map *m_map() { return m_map(Type_selector()); } template const Local_multi_map *m_map() const { return m_map(Type_selector()); } public: /** Get an iterator to the beginning of the local reverse map. The reverse map is guaranteed to contain all elements, that why we use it for iteration. The other maps may not contain all elements since keys may be NULL. @tparam T Dictionary object type. @return Iterator to the beginning of the local reverse map. */ template typename Multi_map_base::Iterator begin() { return m_map()->begin(); } /** Get an iterator to one past the end of the local reverse map. The reverse map is guaranteed to contain all elements, that why we use it for iteration. The other maps may not contain all elements since keys may be NULL. @tparam T Dictionary object type. @return Iterator to one past the end of the local reverse map. */ template typename Multi_map_base::Iterator end() { return m_map()->end(); } /** Get the element corresponding to the given key. @note If the map does not exist, we may as well just set the object pointer to NULL right away since we know that the object will not exist either. @tparam K Key type. @tparam T Dictionary object type. @param key Key too lookup. @param [out] element Element, if present, otherwise, NULL. */ template void get(const K &key, Cache_element **element) const { const auto map = m_map(); if (map) map->get(key, element); else *element = nullptr; } /** Add a new element to the registry. @tparam T Dictionary object type. @param element Element to be added. */ template void put(Cache_element *element) { // If the map does not exist yet, the call to m_map() will // create it. m_map()->put(element); } /** Remove an element from the registry. @tparam T Dictionary object type. @param element Element to be removed. */ template void remove(Cache_element *element) { // There should be no need to create a map to remove an element. At the // same time, removing an element from a non-existing map means there // is an error in our bookkeeping. const auto map = m_map(); assert(map != nullptr); if (map) m_map()->remove(element); } /** Remove and delete all objects of a given type from the registry. @tparam T Dictionary object type. */ template void erase() { // No need to create a map just to erase it. But in this case, // it's not necessarily an error in our bookkeeping, since this // is done as part of regular clean-up. const auto map = m_map(); if (map) m_map()->erase(); } /** Remove and delete all objects from the registry. */ void erase_all() { erase(); erase(); erase(); erase(); erase(); erase(); erase(); erase(); erase(); erase(); } /** Get the number of objects of a given type in the registry. @tparam T Dictionary object type. @return Number of objects. */ template size_t size() const { const auto map = m_map(); if (map) return map->size(); return 0; } /** Get the total number of objects in the registry. @return Number of objects. */ size_t size_all() const { return size() + size() + size() + size() + size() + size() + size() + size() + size() + size(); } /** Debug dump of the object registry to stderr. @tparam T Dictionary object type. */ /* purecov: begin inspected */ template void dump() const { #ifndef NDEBUG const auto map = m_map(); if (map) map->dump(); #endif } /* purecov: end */ }; } // namespace cache } // namespace dd #endif // DD_CACHE__OBJECT_REGISTRY_INCLUDED