summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2020-06-10 13:47:29 +0200
committerVladislav Vaintroub <wlad@mariadb.com>2020-06-10 13:47:29 +0200
commitaf194ab5bd538567ef735cfc374ac328052105ed (patch)
tree2f1e453793615cc79cc59f53ce93af7e594a7bac
parentba4148698fa648aaf15aa3daea857edcdd0d52c8 (diff)
parentcc0205cf86220a2f2427336b34c19bbd66390038 (diff)
downloadmariadb-git-af194ab5bd538567ef735cfc374ac328052105ed.tar.gz
Merge branch 'bb-10.5-MDEV-22841' into 10.5
-rw-r--r--storage/innobase/include/ut0new.h109
-rw-r--r--storage/innobase/ut/ut0new.cc387
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