diff options
Diffstat (limited to 'storage/perfschema/pfs_digest.cc')
-rw-r--r-- | storage/perfschema/pfs_digest.cc | 206 |
1 files changed, 129 insertions, 77 deletions
diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc index 92c27b2e85f..6edcba4c013 100644 --- a/storage/perfschema/pfs_digest.cc +++ b/storage/perfschema/pfs_digest.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2012, Oracle 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 as published by @@ -30,6 +30,8 @@ #include "table_helper.h" #include "my_md5.h" #include "sql_lex.h" +#include "sql_get_diagnostics.h" +#include "sql_string.h" #include <string.h> /* Generated code */ @@ -58,7 +60,6 @@ ulong digest_max= 0; ulong digest_lost= 0; - /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ PFS_statements_digest_stat *statements_digest_stat_array= NULL; /** Consumer flag for table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. */ @@ -69,7 +70,7 @@ bool flag_statements_digest= true; */ volatile uint32 digest_index= 1; -static LF_HASH digest_hash; +LF_HASH digest_hash; static bool digest_hash_inited= false; /** @@ -123,8 +124,8 @@ static uchar *digest_hash_get_key(const uchar *entry, size_t *length, DBUG_ASSERT(typed_entry != NULL); digest= *typed_entry; DBUG_ASSERT(digest != NULL); - *length= PFS_MD5_SIZE; - result= digest->m_digest_hash.m_md5; + *length= sizeof (PFS_digest_key); + result= & digest->m_digest_key; return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); } C_MODE_END @@ -136,11 +137,12 @@ C_MODE_END */ int init_digest_hash(void) { - if (! digest_hash_inited) + if ((! digest_hash_inited) && (digest_max > 0)) { lf_hash_init(&digest_hash, sizeof(PFS_statements_digest_stat*), LF_HASH_UNIQUE, 0, 0, digest_hash_get_key, &my_charset_bin); + /* digest_hash.size= digest_max; */ digest_hash_inited= true; } return 0; @@ -167,8 +169,10 @@ static LF_PINS* get_digest_hash_pins(PFS_thread *thread) } PFS_statement_stat* -find_or_create_digest(PFS_thread* thread, - PSI_digest_storage* digest_storage) +find_or_create_digest(PFS_thread *thread, + PSI_digest_storage *digest_storage, + const char *schema_name, + uint schema_name_length) { if (statements_digest_stat_array == NULL) return NULL; @@ -180,13 +184,21 @@ find_or_create_digest(PFS_thread* thread, if (unlikely(pins == NULL)) return NULL; + /* + Note: the LF_HASH key is a block of memory, + make sure to clean unused bytes, + so that memcmp() can compare keys. + */ + PFS_digest_key hash_key; + memset(& hash_key, 0, sizeof(hash_key)); /* Compute MD5 Hash of the tokens received. */ - PFS_digest_hash md5; - compute_md5_hash((char *) md5.m_md5, + compute_md5_hash((char *) hash_key.m_md5, (char *) digest_storage->m_token_array, digest_storage->m_byte_count); - - unsigned char* hash_key= md5.m_md5; + /* Add the current schema to the key */ + hash_key.m_schema_name_length= schema_name_length; + if (schema_name_length > 0) + memcpy(hash_key.m_schema_name, schema_name, schema_name_length); int res; ulong safe_index; @@ -202,7 +214,7 @@ search: /* Lookup LF_HASH using this new key. */ entry= reinterpret_cast<PFS_statements_digest_stat**> (lf_hash_search(&digest_hash, pins, - hash_key, PFS_MD5_SIZE)); + &hash_key, sizeof(PFS_digest_key))); if (entry && (entry != MY_ERRPTR)) { @@ -244,7 +256,7 @@ search: pfs= &statements_digest_stat_array[safe_index]; /* Copy digest hash/LF Hash search key. */ - memcpy(pfs->m_digest_hash.m_md5, md5.m_md5, PFS_MD5_SIZE); + memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key)); /* Copy digest storage to statement_digest_stat_array so that it could be @@ -278,7 +290,7 @@ search: return NULL; } -void purge_digest(PFS_thread* thread, unsigned char* hash_key) +void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key) { LF_PINS *pins= get_digest_hash_pins(thread); if (unlikely(pins == NULL)) @@ -289,12 +301,12 @@ void purge_digest(PFS_thread* thread, unsigned char* hash_key) /* Lookup LF_HASH using this new key. */ entry= reinterpret_cast<PFS_statements_digest_stat**> (lf_hash_search(&digest_hash, pins, - hash_key, PFS_MD5_SIZE)); + hash_key, sizeof(PFS_digest_key))); if (entry && (entry != MY_ERRPTR)) - { + { lf_hash_delete(&digest_hash, pins, - hash_key, PFS_MD5_SIZE); + hash_key, sizeof(PFS_digest_key)); } lf_hash_search_unpin(pins); return; @@ -313,7 +325,7 @@ void PFS_statements_digest_stat::reset_index(PFS_thread *thread) /* Only remove entries that exists in the HASH index. */ if (m_digest_storage.m_byte_count > 0) { - purge_digest(thread, m_digest_hash.m_md5); + purge_digest(thread, & m_digest_key); } } @@ -347,98 +359,130 @@ void reset_esms_by_digest() */ void get_digest_text(char* digest_text, PSI_digest_storage* digest_storage) { + DBUG_ASSERT(digest_storage != NULL); bool truncated= false; int byte_count= digest_storage->m_byte_count; - int need_bytes; + int bytes_needed= 0; uint tok= 0; - char *id_string; - int id_length; int current_byte= 0; lex_token_string *tok_data; /* -4 is to make sure extra space for '...' and a '\0' at the end. */ - int available_bytes_to_write= COL_DIGEST_TEXT_SIZE - 4; + int bytes_available= COL_DIGEST_TEXT_SIZE - 4; + + /* Convert text to utf8 */ + const CHARSET_INFO *from_cs= get_charset(digest_storage->m_charset_number, MYF(0)); + const CHARSET_INFO *to_cs= &my_charset_utf8_bin; + + if (from_cs == NULL) + { + /* + Can happen, as we do dirty reads on digest_storage, + which can be written to in another thread. + */ + *digest_text= '\0'; + return; + } + + /* + Max converted size is number of characters * max multibyte length of the + target charset, which is 4 for UTF8. + */ + const uint max_converted_size= PSI_MAX_DIGEST_STORAGE_SIZE * 4; + char id_buffer[max_converted_size]; + char *id_string; + int id_length; + bool convert_text= !my_charset_same(from_cs, to_cs); DBUG_ASSERT(byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); while ((current_byte < byte_count) && - (available_bytes_to_write > 0) && - (! truncated)) + (bytes_available > 0) && + !truncated) { current_byte= read_token(digest_storage, current_byte, &tok); - tok_data= & lex_token_array[tok]; + tok_data= &lex_token_array[tok]; switch (tok) { /* All identifiers are printed with their name. */ case IDENT: - current_byte= read_identifier(digest_storage, current_byte, - & id_string, & id_length); - need_bytes= id_length + 1; /* <id> space */ - if (need_bytes <= available_bytes_to_write) + case IDENT_QUOTED: { - if (id_length > 0) + char *id_ptr; + int id_len; + uint err_cs= 0; + + /* Get the next identifier from the storage buffer. */ + current_byte= read_identifier(digest_storage, current_byte, + &id_ptr, &id_len); + if (convert_text) { - strncpy(digest_text, id_string, id_length); - digest_text+= id_length; + /* Verify that the converted text will fit. */ + if (to_cs->mbmaxlen*id_len > max_converted_size) + { + truncated= true; + break; + } + /* Convert identifier string into the storage character set. */ + id_length= my_convert(id_buffer, max_converted_size, to_cs, + id_ptr, id_len, from_cs, &err_cs); + id_string= id_buffer; } - *digest_text= ' '; - digest_text++; - available_bytes_to_write-= need_bytes; - } - else - { - truncated= true; - } - break; - case IDENT_QUOTED: - current_byte= read_identifier(digest_storage, current_byte, - & id_string, & id_length); - need_bytes= id_length + 3; /* quote <id> quote space */ - if (need_bytes <= available_bytes_to_write) - { - *digest_text= '`'; - digest_text++; - if (id_length > 0) + else { - strncpy(digest_text, id_string, id_length); - digest_text+= id_length; + id_string= id_ptr; + id_length= id_len; + } + + if (id_length == 0 || err_cs != 0) + { + truncated= true; + break; + } + /* Copy the converted identifier into the digest string. */ + bytes_needed= id_length + (tok == IDENT ? 1 : 3); + if (bytes_needed <= bytes_available) + { + if (tok == IDENT_QUOTED) + *digest_text++= '`'; + if (id_length > 0) + { + memcpy(digest_text, id_string, id_length); + digest_text+= id_length; + } + if (tok == IDENT_QUOTED) + *digest_text++= '`'; + *digest_text++= ' '; + bytes_available-= bytes_needed; + } + else + { + truncated= true; } - *digest_text= '`'; - digest_text++; - *digest_text= ' '; - digest_text++; - available_bytes_to_write-= need_bytes; - } - else - { - truncated= true; } break; /* Everything else is printed as is. */ default: /* - Make sure not to overflow digest_text buffer while writing - this token string. + Make sure not to overflow digest_text buffer. +1 is to make sure extra space for ' '. */ int tok_length= tok_data->m_token_length; - need_bytes= tok_length + 1; + bytes_needed= tok_length + 1; - if (need_bytes <= available_bytes_to_write) + if (bytes_needed <= bytes_available) { - strncpy(digest_text, - tok_data->m_token_string, - tok_length); + strncpy(digest_text, tok_data->m_token_string, tok_length); digest_text+= tok_length; - *digest_text= ' '; - digest_text++; - available_bytes_to_write-= need_bytes; + *digest_text++= ' '; + bytes_available-= bytes_needed; } else { truncated= true; } + break; } } @@ -524,7 +568,11 @@ PSI_digest_locker* pfs_digest_add_token_v1(PSI_digest_locker *locker, digest_storage= &state->m_digest_storage; - if (digest_storage->m_full) + /* + Stop collecting further tokens if digest storage is full or + if END token is received. + */ + if (digest_storage->m_full || token == END_OF_INPUT) return NULL; /* @@ -555,19 +603,23 @@ PSI_digest_locker* pfs_digest_add_token_v1(PSI_digest_locker *locker, TOK_PFS_GENERIC_VALUE := BIN_NUM | DECIMAL_NUM | ... | ULONGLONG_NUM */ token= TOK_PFS_GENERIC_VALUE; - + } + /* fall through */ + case NULL_SYM: + { if ((last_token2 == TOK_PFS_GENERIC_VALUE || - last_token2 == TOK_PFS_GENERIC_VALUE_LIST) && + last_token2 == TOK_PFS_GENERIC_VALUE_LIST || + last_token2 == NULL_SYM) && (last_token == ',')) { /* REDUCE: TOK_PFS_GENERIC_VALUE_LIST := - TOK_PFS_GENERIC_VALUE ',' TOK_PFS_GENERIC_VALUE + (TOK_PFS_GENERIC_VALUE|NULL_SYM) ',' (TOK_PFS_GENERIC_VALUE|NULL_SYM) REDUCE: TOK_PFS_GENERIC_VALUE_LIST := - TOK_PFS_GENERIC_VALUE_LIST ',' TOK_PFS_GENERIC_VALUE + TOK_PFS_GENERIC_VALUE_LIST ',' (TOK_PFS_GENERIC_VALUE|NULL_SYM) */ digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; token= TOK_PFS_GENERIC_VALUE_LIST; |