diff options
author | Vladislav Vaintroub <wlad@mariadb.com> | 2020-06-10 13:47:29 +0200 |
---|---|---|
committer | Vladislav Vaintroub <wlad@mariadb.com> | 2020-06-10 13:47:29 +0200 |
commit | af194ab5bd538567ef735cfc374ac328052105ed (patch) | |
tree | 2f1e453793615cc79cc59f53ce93af7e594a7bac | |
parent | ba4148698fa648aaf15aa3daea857edcdd0d52c8 (diff) | |
parent | cc0205cf86220a2f2427336b34c19bbd66390038 (diff) | |
download | mariadb-git-af194ab5bd538567ef735cfc374ac328052105ed.tar.gz |
Merge branch 'bb-10.5-MDEV-22841' into 10.5
-rw-r--r-- | storage/innobase/include/ut0new.h | 109 | ||||
-rw-r--r-- | storage/innobase/ut/ut0new.cc | 387 |
2 files changed, 309 insertions, 187 deletions
diff --git a/storage/innobase/include/ut0new.h b/storage/innobase/include/ut0new.h index c35808a56e2..354e6a485f7 100644 --- a/storage/innobase/include/ut0new.h +++ b/storage/innobase/include/ut0new.h @@ -178,13 +178,13 @@ ut_new_boot(); #ifdef UNIV_PFS_MEMORY -/** Retrieve a memory key (registered with PFS), given a portion of the file -name of the caller. -@param[in] file portion of the filename - basename without an extension -@return registered memory key or PSI_NOT_INSTRUMENTED if not found */ -PSI_memory_key -ut_new_get_key_by_file( - const char* file); +/** +Retrieve a memory key (registered with PFS), +given filename hash of the caller + +@param[in] filename_hash - FILENAME_HASH value of the caller +@return registered memory key or PSI_NOT_INSTRUMENTED */ +PSI_memory_key ut_new_get_key_by_file(uint32_t filename_hash); #endif /* UNIV_PFS_MEMORY */ @@ -293,7 +293,7 @@ public: ) { #ifdef UNIV_PFS_MEMORY - const PSI_memory_key other_key = other.get_mem_key(NULL); + const PSI_memory_key other_key = other.get_mem_key(0); m_key = (other_key != mem_key_std) ? other_key @@ -315,7 +315,7 @@ public: #endif /* UNIV_PFS_MEMORY */ } - pointer allocate(size_type n) { return allocate(n, NULL, NULL); } + pointer allocate(size_type n) { return allocate(n, NULL, 0); } /** Allocate a chunk of memory that can hold 'n_elements' objects of type 'T' and trace the allocation. @@ -333,9 +333,9 @@ public: allocate( size_type n_elements, const_pointer, - const char* + uint32_t #ifdef UNIV_PFS_MEMORY - file /*!< file name of the caller */ + filename_hash /* filename hash of the caller */ #endif , bool set_to_zero = false, @@ -397,7 +397,7 @@ public: #ifdef UNIV_PFS_MEMORY ut_new_pfx_t* pfx = static_cast<ut_new_pfx_t*>(ptr); - allocate_trace(total_bytes, file, pfx); + allocate_trace(total_bytes, filename_hash, pfx); return(reinterpret_cast<pointer>(pfx + 1)); #else @@ -479,7 +479,7 @@ public: reallocate( void* ptr, size_type n_elements, - const char* file) + uint32_t filename_hash) { if (n_elements == 0) { deallocate(static_cast<pointer>(ptr)); @@ -487,7 +487,7 @@ public: } if (ptr == NULL) { - return(allocate(n_elements, NULL, file, false, false)); + return(allocate(n_elements, NULL, filename_hash, false, false)); } if (n_elements > max_size()) { @@ -530,7 +530,7 @@ public: deallocate_trace(pfx_new); /* pfx_new is set here to describe the new block. */ - allocate_trace(total_bytes, file, pfx_new); + allocate_trace(total_bytes, filename_hash, pfx_new); return(reinterpret_cast<pointer>(pfx_new + 1)); } @@ -546,9 +546,10 @@ public: pointer new_array( size_type n_elements, - const char* file) + uint32_t filename_hash + ) { - T* p = allocate(n_elements, NULL, file, false, false); + T* p = allocate(n_elements, NULL, filename_hash, false, false); if (p == NULL) { return(NULL); @@ -634,7 +635,7 @@ public: if (pfx != NULL) { #ifdef UNIV_PFS_MEMORY - allocate_trace(n_bytes, NULL, pfx); + allocate_trace(n_bytes, 0, pfx); #endif /* UNIV_PFS_MEMORY */ pfx->m_size = n_bytes; } @@ -687,25 +688,16 @@ public: @return performance schema key */ PSI_memory_key get_mem_key( - const char* file) const + uint32_t filename_hash) const { if (m_key != PSI_NOT_INSTRUMENTED) { return(m_key); } - if (file == NULL) { + if (filename_hash == 0) { return(mem_key_std); } - - /* e.g. "btr0cur", derived from "/path/to/btr0cur.cc" */ - char keyname[FILENAME_MAX]; - const size_t len = ut_basename_noext(file, keyname, - sizeof(keyname)); - /* If sizeof(keyname) was not enough then the output would - be truncated, assert that this did not happen. */ - ut_a(len < sizeof(keyname)); - - const PSI_memory_key key = ut_new_get_key_by_file(keyname); + const PSI_memory_key key = ut_new_get_key_by_file(filename_hash); if (key != PSI_NOT_INSTRUMENTED) { return(key); @@ -747,16 +739,16 @@ private: corresponds to "file", that will be used (see ut_new_boot()) 4. Otherwise, the name associated with mem_key_other will be used. @param[in] size number of bytes that were allocated - @param[in] file file name of the caller or NULL if unknown + @param[in] filename_hash FILENAME_HASH of the caller @param[out] pfx placeholder to store the info which will be needed when freeing the memory */ void allocate_trace( size_t size, - const char* file, + const uint32_t filename_hash, ut_new_pfx_t* pfx) { - const PSI_memory_key key = get_mem_key(file); + const PSI_memory_key key = get_mem_key(filename_hash); pfx->m_key = PSI_MEMORY_CALL(memory_alloc)(key, size, & pfx->m_owner); pfx->m_size = size; @@ -806,6 +798,41 @@ operator!=( #ifdef UNIV_PFS_MEMORY +/* + constexpr trickery ahead. + + Retrieve the FILENAME_HASH = djb2(basename_noext(__FILE__)) at the compile time. + We use the number rather than __FILE__ because integers is better to deal with + (hashing, searching) that C style strings. +*/ + +static constexpr const char * basename_helper(const char* s, const char * last_slash) +{ + return + *s == '\0' ? last_slash : + *s == '/' || *s == '\\' ? basename_helper(s + 1, s + 1) : + basename_helper(s + 1, last_slash); +} + +static constexpr const char* ut_basename(const char *filename) +{ + return basename_helper(filename, filename); +} + +/** Compute djb2 hash for a string. Stop at '.' , or '\0' */ +constexpr uint32_t ut_filename_hash(const char* s, uint32_t h = 5381) +{ + return *s == 0 || *s == '.' ? h : + ut_filename_hash(s + 1, 33 * h + (uint8_t)*s); +} + +/* Force constexpr to be evaluated at compile time.*/ +#define FORCE_CONSTEXPR(expr)[&]() \ +{ static constexpr auto x = (expr); return x; }() + +#define FILENAME_HASH FORCE_CONSTEXPR(ut_filename_hash(ut_basename(__FILE__))) + + /** Allocate, trace the allocation and construct an object. Use this macro instead of 'new' within InnoDB. For example: instead of @@ -823,7 +850,7 @@ pointer must be passed to UT_DELETE() when no longer needed. object if the passed in pointer is NULL, e.g. if allocate() has failed to allocate memory and has returned NULL. */ \ ::new(ut_allocator<byte>(key).allocate( \ - sizeof expr, NULL, __FILE__, false, false)) expr + sizeof expr, NULL, FILENAME_HASH, false, false)) expr /** Allocate, trace the allocation and construct an object. Use this macro instead of 'new' within InnoDB and instead of UT_NEW() @@ -871,7 +898,7 @@ The returned pointer must be passed to UT_DELETE_ARRAY(). @param[in] key performance schema memory tracing key @return pointer to the first allocated object or NULL */ #define UT_NEW_ARRAY(type, n_elements, key) \ - ut_allocator<type>(key).new_array(n_elements, __FILE__) + ut_allocator<type>(key).new_array(n_elements, FILENAME_HASH) /** Allocate and account 'n_elements' objects of type 'type'. Use this macro to allocate memory within InnoDB instead of 'new[]' and @@ -902,7 +929,7 @@ ut_delete_array( #define ut_malloc(n_bytes, key) static_cast<void*>( \ ut_allocator<byte>(key).allocate( \ - n_bytes, NULL, __FILE__, false, false)) + n_bytes, NULL, FILENAME_HASH, false, false)) #define ut_malloc_dontdump(n_bytes, key) static_cast<void*>( \ ut_allocator<byte>(key).allocate_large( \ @@ -910,23 +937,23 @@ ut_delete_array( #define ut_zalloc(n_bytes, key) static_cast<void*>( \ ut_allocator<byte>(key).allocate( \ - n_bytes, NULL, __FILE__, true, false)) + n_bytes, NULL, FILENAME_HASH, true, false)) #define ut_malloc_nokey(n_bytes) static_cast<void*>( \ ut_allocator<byte>(PSI_NOT_INSTRUMENTED).allocate( \ - n_bytes, NULL, __FILE__, false, false)) + n_bytes, NULL, FILENAME_HASH, false, false)) #define ut_zalloc_nokey(n_bytes) static_cast<void*>( \ ut_allocator<byte>(PSI_NOT_INSTRUMENTED).allocate( \ - n_bytes, NULL, __FILE__, true, false)) + n_bytes, NULL, FILENAME_HASH, true, false)) #define ut_zalloc_nokey_nofatal(n_bytes) static_cast<void*>( \ ut_allocator<byte, false>(PSI_NOT_INSTRUMENTED).allocate( \ - n_bytes, NULL, __FILE__, true, false)) + n_bytes, NULL, FILENAME_HASH, true, false)) #define ut_realloc(ptr, n_bytes) static_cast<void*>( \ ut_allocator<byte>(PSI_NOT_INSTRUMENTED).reallocate( \ - ptr, n_bytes, __FILE__)) + ptr, n_bytes, FILENAME_HASH)) #define ut_free(ptr) ut_allocator<byte>(PSI_NOT_INSTRUMENTED).deallocate( \ reinterpret_cast<byte*>(ptr)) diff --git a/storage/innobase/ut/ut0new.cc b/storage/innobase/ut/ut0new.cc index d1d9e8452f1..057fe86bb08 100644 --- a/storage/innobase/ut/ut0new.cc +++ b/storage/innobase/ut/ut0new.cc @@ -25,7 +25,7 @@ Created May 26, 2014 Vasil Dimov *******************************************************/ #include "univ.i" - +#include <algorithm> /** Maximum number of retries to allocate memory. */ const size_t alloc_max_retries = 60; @@ -44,6 +44,175 @@ PSI_memory_key mem_key_row_merge_sort; PSI_memory_key mem_key_std; #ifdef UNIV_PFS_MEMORY +static const char* auto_event_names[] = +{ + "btr0btr", + "btr0bulk", + "btr0cur", + "btr0defragment", + "btr0pcur", + "btr0sea", + "btr0types", + "buf0buddy", + "buf0buf", + "buf0checksum", + "buf0dblwr", + "buf0dump", + "buf0flu", + "buf0lru", + "buf0rea", + "buf0types", + "data0data", + "data0type", + "data0types", + "db0err", + "dict0boot", + "dict0crea", + "dict0defrag_bg", + "dict0dict", + "dict0load", + "dict0mem", + "dict0pagecompress", + "dict0priv", + "dict0stats", + "dict0stats_bg", + "dict0types", + "dyn0buf", + "dyn0types", + "eval0eval", + "eval0proc", + "fil0crypt", + "fil0fil", + "fil0pagecompress", + "fsp0file", + "fsp0fsp", + "fsp0space", + "fsp0sysspace", + "fsp0types", + "fts0ast", + "fts0blex", + "fts0config", + "fts0fts", + "fts0opt", + "fts0pars", + "fts0plugin", + "fts0priv", + "fts0que", + "fts0sql", + "fts0tlex", + "fts0tokenize", + "fts0types", + "fts0vlc", + "fut0fut", + "fut0lst", + "gis0geo", + "gis0rtree", + "gis0sea", + "gis0type", + "ha0ha", + "ha0storage", + "ha_innodb", + "ha_prototypes", + "handler0alter", + "hash0hash", + "i_s", + "ib0mutex", + "ibuf0ibuf", + "ibuf0types", + "lexyy", + "lock0iter", + "lock0lock", + "lock0prdt", + "lock0priv", + "lock0types", + "lock0wait", + "log0crypt", + "log0log", + "log0recv", + "log0sync", + "log0types", + "mach0data", + "mem0mem", + "mtr0log", + "mtr0mtr", + "mtr0types", + "os0api", + "os0event", + "os0file", + "os0proc", + "os0thread", + "page0cur", + "page0page", + "page0types", + "page0zip", + "pars0grm", + "pars0lex", + "pars0opt", + "pars0pars", + "pars0sym", + "pars0types", + "que0que", + "que0types", + "read0read", + "read0types", + "rem0cmp", + "rem0rec", + "rem0types", + "row0ext", + "row0ftsort", + "row0import", + "row0ins", + "row0log", + "row0merge", + "row0mysql", + "row0purge", + "row0quiesce", + "row0row", + "row0sel", + "row0types", + "row0uins", + "row0umod", + "row0undo", + "row0upd", + "row0vers", + "srv0conc", + "srv0mon", + "srv0srv", + "srv0start", + "sync0arr", + "sync0debug", + "sync0policy", + "sync0rw", + "sync0sync", + "sync0types", + "trx0i_s", + "trx0purge", + "trx0rec", + "trx0roll", + "trx0rseg", + "trx0sys", + "trx0trx", + "trx0types", + "trx0undo", + "trx0xa", + "ut0byte", + "ut0counter", + "ut0crc32", + "ut0dbg", + "ut0list", + "ut0lst", + "ut0mem", + "ut0mutex", + "ut0new", + "ut0pool", + "ut0rbt", + "ut0rnd", + "ut0sort", + "ut0stage", + "ut0ut", + "ut0vec", + "ut0wqueue" +}; /** Auxiliary array of performance schema 'PSI_memory_info'. Each allocation appears in @@ -59,163 +228,89 @@ the list below: Keep this list alphabetically sorted. */ static PSI_memory_info pfs_info[] = { #ifdef BTR_CUR_HASH_ADAPT - {&mem_key_ahi, "adaptive hash index", 0}, + {&mem_key_ahi, "adaptive hash index", 0}, #endif /* BTR_CUR_HASH_ADAPT */ - {&mem_key_buf_buf_pool, "buf_buf_pool", 0}, - {&mem_key_dict_stats_bg_recalc_pool_t, "dict_stats_bg_recalc_pool_t", 0}, - {&mem_key_dict_stats_index_map_t, "dict_stats_index_map_t", 0}, - {&mem_key_dict_stats_n_diff_on_level, "dict_stats_n_diff_on_level", 0}, - {&mem_key_other, "other", 0}, - {&mem_key_row_log_buf, "row_log_buf", 0}, - {&mem_key_row_merge_sort, "row_merge_sort", 0}, - {&mem_key_std, "std", 0}, + {&mem_key_buf_buf_pool, "buf_buf_pool", 0}, + {&mem_key_dict_stats_bg_recalc_pool_t, "dict_stats_bg_recalc_pool_t", 0}, + {&mem_key_dict_stats_index_map_t, "dict_stats_index_map_t", 0}, + {&mem_key_dict_stats_n_diff_on_level, "dict_stats_n_diff_on_level", 0}, + {&mem_key_other, "other", 0}, + {&mem_key_row_log_buf, "row_log_buf", 0}, + {&mem_key_row_merge_sort, "row_merge_sort", 0}, + {&mem_key_std, "std", 0}, }; -/** Map used for default performance schema keys, based on file name of the -caller. The key is the file name of the caller and the value is a pointer -to a PSI_memory_key variable to be passed to performance schema methods. -We use ut_strcmp_functor because by default std::map will compare the pointers -themselves (cont char*) and not do strcmp(). */ -typedef std::map<const char*, PSI_memory_key*, ut_strcmp_functor> - mem_keys_auto_t; - -/** Map of filename/pfskey, used for tracing allocations that have not -provided a manually created pfs key. This map is only ever modified (bulk -insert) at startup in a single-threaded environment by ut_new_boot(). -Later it is only read (only std::map::find() is called) from multithreaded -environment, thus it is not protected by any latch. */ -static mem_keys_auto_t mem_keys_auto; - -#endif /* UNIV_PFS_MEMORY */ +static const int NKEYS = static_cast<int>UT_ARR_SIZE(auto_event_names); +std::pair<uint32_t, PSI_memory_key> search_array[NKEYS]; /** Setup the internal objects needed for UT_NEW() to operate. This must be called before the first call to UT_NEW(). */ -void -ut_new_boot() +void ut_new_boot() { -#ifdef UNIV_PFS_MEMORY - static const char* auto_event_names[] = { - /* Keep this list alphabetically sorted. */ - "btr0btr", - "btr0bulk", - "btr0cur", - "btr0pcur", - "btr0sea", - "buf0buf", - "buf0dblwr", - "buf0dump", - "buf0flu", - "buf0lru", - "dict0dict", - "dict0mem", - "dict0stats", - "dict0stats_bg", - "eval0eval", - "fil0fil", - "fsp0file", - "fsp0space", - "fsp0sysspace", - "fts0ast", - "fts0config", - "fts0fts", - "fts0opt", - "fts0pars", - "fts0que", - "fts0sql", - "gis0sea", - "ha0ha", - "ha_innodb", - "handler0alter", - "hash0hash", - "i_s", - "ibuf0ibuf", - "lexyy", - "lock0lock", - "log0log", - "log0recv", - "mem0mem", - "os0event", - "os0file", - "page0cur", - "page0zip", - "pars0lex", - "read0read", - "rem0rec", - "row0ftsort", - "row0import", - "row0log", - "row0merge", - "row0mysql", - "row0sel", - "srv0conc", - "srv0srv", - "srv0start", - "sync0arr", - "sync0debug", - "sync0rw", - "sync0types", - "trx0i_s", - "trx0purge", - "trx0roll", - "trx0rseg", - "trx0sys", - "trx0trx", - "trx0undo", - "ut0list", - "ut0mem", - "ut0mutex", - "ut0pool", - "ut0rbt", - "ut0wqueue", - }; - static const size_t n_auto = UT_ARR_SIZE(auto_event_names); - static PSI_memory_key auto_event_keys[n_auto]; - static PSI_memory_info pfs_info_auto[n_auto]; - - for (size_t i = 0; i < n_auto; i++) { - - const std::pair<mem_keys_auto_t::iterator, bool> ret - MY_ATTRIBUTE((unused)) - = mem_keys_auto.insert( - mem_keys_auto_t::value_type(auto_event_names[i], - &auto_event_keys[i])); - - /* ret.second is true if new element has been inserted */ - ut_a(ret.second); - - /* e.g. "btr0btr" */ - pfs_info_auto[i].m_name = auto_event_names[i]; - - /* a pointer to the pfs key */ - pfs_info_auto[i].m_key = &auto_event_keys[i]; - - pfs_info_auto[i].m_flags = 0; - } - - PSI_MEMORY_CALL(register_memory)("innodb", pfs_info, static_cast<int>( - UT_ARR_SIZE(pfs_info))); - PSI_MEMORY_CALL(register_memory)("innodb", pfs_info_auto, - static_cast<int>(n_auto)); -#endif /* UNIV_PFS_MEMORY */ + PSI_MEMORY_CALL(register_memory)("innodb", pfs_info, UT_ARR_SIZE(pfs_info)); + + static PSI_memory_key auto_event_keys[NKEYS]; + static PSI_memory_info pfs_info_auto[NKEYS]; + for (int i= 0; i < NKEYS; i++) + { + pfs_info_auto[i]= {&auto_event_keys[i], auto_event_names[i], 0}; + } + + PSI_MEMORY_CALL(register_memory)("innodb", pfs_info_auto,NKEYS); + + if (auto_event_keys[0] == PSI_NOT_INSTRUMENTED) + return; // PSI is off + + for (int i= 0; i < NKEYS; i++) + { + search_array[i]= {ut_filename_hash(auto_event_names[i]), auto_event_keys[i]}; + } + + std::sort(search_array, std::end(search_array)); + +#ifdef UNIV_DEBUG + /* assumption that hash value is not 0 in ut0new.h, get_mem_key() */ + ut_ad(search_array[0].first); + + /* Check for hash duplicates */ + for(int i= 0; i < NKEYS-1; i++) + { + if (search_array[i].first == search_array[i + 1].first) + { + // This can only happen if autoevent_names was updated + // previously, or the hash function changed + ib::fatal() << __FILE__ "Duplicates found in filename hashes"; + } + } +#endif } -#ifdef UNIV_PFS_MEMORY +/** Retrieve a memory key (registered with PFS), corresponding to source file hash. -/** Retrieve a memory key (registered with PFS), given a portion of the file -name of the caller. -@param[in] file portion of the filename - basename without an extension -@return registered memory key or PSI_NOT_INSTRUMENTED if not found */ -PSI_memory_key -ut_new_get_key_by_file( - const char* file) +@param[in] filename_hash - hash value (computed at compile time) of a ut_filename_hash + for a one of the auto_event_names. +@return registered memory key or PSI_NOT_INSTRUMENTED +*/ +PSI_memory_key ut_new_get_key_by_file(uint32_t filename_hash) { - mem_keys_auto_t::const_iterator el = mem_keys_auto.find(file); + if(search_array[0].second == PSI_NOT_INSTRUMENTED) + { + // PSI is off. + return PSI_NOT_INSTRUMENTED; + } + + std::pair<uint32, PSI_memory_key> e{ filename_hash, 0 }; + auto result= std::lower_bound(search_array, std::end(search_array), e); + if (result != std::end(search_array) && result->first == filename_hash) + return result->second; - if (el != mem_keys_auto.end()) { - return(*(el->second)); - } +#ifdef UNIV_DEBUG + ib::fatal() << __FILE__ " ut_new_get_key_by_file : hash not found"; +#endif - return(PSI_NOT_INSTRUMENTED); + return PSI_NOT_INSTRUMENTED; } -#endif /* UNIV_PFS_MEMORY */ +#else /* UNIV_PFS_MEMORY */ +void ut_new_boot(){} +#endif |