summaryrefslogtreecommitdiff
path: root/storage/perfschema/pfs_digest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema/pfs_digest.cc')
-rw-r--r--storage/perfschema/pfs_digest.cc206
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;