summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/sql_profile.cc111
-rw-r--r--sql/sql_profile.h111
2 files changed, 147 insertions, 75 deletions
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index 028363f167e..8ed3df9cd2e 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -175,11 +175,8 @@ void QUERY_PROFILE::set_query_source(char *query_source_arg,
QUERY_PROFILE::~QUERY_PROFILE()
{
- PROFILE_ENTRY *entry;
- List_iterator<PROFILE_ENTRY> it(entries);
- while ((entry= it++) != NULL)
- delete entry;
- entries.empty();
+ while (! entries.is_empty())
+ delete entries.pop();
if (query_source != NULL)
my_free(query_source, MYF(0));
@@ -191,7 +188,6 @@ void QUERY_PROFILE::status(const char *status_arg,
{
THD *thd= profiling->thd;
PROFILE_ENTRY *prof;
- MEM_ROOT *saved_mem_root;
DBUG_ENTER("QUERY_PROFILE::status");
/* Blank status. Just return, and thd->proc_info will be set blank later. */
@@ -210,22 +206,6 @@ void QUERY_PROFILE::status(const char *status_arg,
if (unlikely((thd->query_id != server_query_id) && !thd->spcont))
reset();
- /*
- In order to keep the profile information between queries (i.e. from
- SELECT to the following SHOW PROFILE command) the following code is
- necessary to keep the profile from getting freed automatically when
- mysqld cleans up after the query.
-
- The "entries" list allocates is memory from the current thd's mem_root.
- We substitute our mem_root temporarily so that we intercept those
- allocations into our own mem_root.
-
- The thd->mem_root structure is freed after each query is completed,
- so temporarily override it.
- */
- saved_mem_root= thd->mem_root;
- thd->mem_root= &profiling->mem_root;
-
if (function_arg && file_arg)
{
if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg,
@@ -238,9 +218,6 @@ void QUERY_PROFILE::status(const char *status_arg,
entries.push_back(prof);
}
- /* Restore mem_root */
- thd->mem_root= saved_mem_root;
-
DBUG_VOID_RETURN;
}
@@ -252,11 +229,8 @@ void QUERY_PROFILE::reset()
server_query_id= profiling->thd->query_id; /* despite name, is global */
profile_start.collect();
- PROFILE_ENTRY *entry;
- List_iterator<PROFILE_ENTRY> it(entries);
- while ((entry= it++) != NULL)
- delete entry;
- entries.empty();
+ while (! entries.is_empty())
+ delete entries.pop();
}
DBUG_VOID_RETURN;
}
@@ -344,10 +318,14 @@ bool QUERY_PROFILE::show(uint options)
struct rusage *last_rusage= &(profile_start.rusage);
#endif
- List_iterator<PROFILE_ENTRY> it(entries);
PROFILE_ENTRY *entry;
- while ((entry= it++) != NULL)
+ void *iterator;
+ for (iterator= entries.new_iterator();
+ iterator != NULL;
+ iterator= entries.iterator_next(iterator))
{
+ entry= entries.iterator_value(iterator);
+
#ifdef HAVE_GETRUSAGE
struct rusage *rusage= &(entry->rusage);
#endif
@@ -463,24 +441,15 @@ bool QUERY_PROFILE::show(uint options)
PROFILING::PROFILING()
:profile_id_counter(0), keeping(1), current(NULL), last(NULL)
{
- init_sql_alloc(&mem_root,
- PROFILE_ALLOC_BLOCK_SIZE,
- PROFILE_ALLOC_PREALLOC_SIZE);
}
PROFILING::~PROFILING()
{
- QUERY_PROFILE *prof;
-
- List_iterator<QUERY_PROFILE> it(history);
- while ((prof= it++) != NULL)
- delete prof;
- history.empty();
+ while (! history.is_empty())
+ delete history.pop();
if (current != NULL)
delete current;
-
- free_root(&mem_root, MYF(0));
}
void PROFILING::status_change(const char *status_arg,
@@ -505,7 +474,6 @@ void PROFILING::status_change(const char *status_arg,
void PROFILING::store()
{
- MEM_ROOT *saved_mem_root;
DBUG_ENTER("PROFILING::store");
/* Already stored */
@@ -517,22 +485,8 @@ void PROFILING::store()
}
while (history.elements > thd->variables.profiling_history_size)
- {
- QUERY_PROFILE *tmp= history.pop();
- delete tmp;
- }
-
- /*
- Switch out memory roots so that we're sure that we keep what we need
-
- The "history" list implementation allocates its memory in the current
- thd's mem_root. We substitute our mem_root temporarily so that we
- intercept those allocations into our own mem_root.
- */
+ delete history.pop();
- saved_mem_root= thd->mem_root;
- thd->mem_root= &mem_root;
-
if (current != NULL)
{
if (keeping &&
@@ -556,9 +510,6 @@ void PROFILING::store()
DBUG_ASSERT(current == NULL);
current= new QUERY_PROFILE(this, thd->query, thd->query_length);
- /* Restore memory root */
- thd->mem_root= saved_mem_root;
-
DBUG_VOID_RETURN;
}
@@ -598,9 +549,13 @@ bool PROFILING::show_profiles()
unit->set_limit(sel);
- List_iterator<QUERY_PROFILE> it(history);
- while ((prof= it++) != NULL)
+ void *iterator;
+ for (iterator= history.new_iterator();
+ iterator != NULL;
+ iterator= history.iterator_next(iterator))
{
+ prof= history.iterator_value(iterator);
+
String elapsed;
PROFILE_ENTRY *ps= &prof->profile_start;
@@ -651,9 +606,13 @@ bool PROFILING::show(uint options, uint profiling_query_id)
DBUG_ENTER("PROFILING::show");
QUERY_PROFILE *prof;
- List_iterator<QUERY_PROFILE> it(history);
- while ((prof= it++) != NULL)
+ void *iterator;
+ for (iterator= history.new_iterator();
+ iterator != NULL;
+ iterator= history.iterator_next(iterator))
{
+ prof= history.iterator_value(iterator);
+
if(prof->profiling_query_id == profiling_query_id)
DBUG_RETURN(prof->show(options));
}
@@ -681,11 +640,15 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item
TABLE *table= tables->table;
ulonglong row_number= 0;
- List_iterator<QUERY_PROFILE> query_it(history);
QUERY_PROFILE *query;
/* Go through each query in this thread's stored history... */
- while ((query= query_it++) != NULL)
+ void *history_iterator;
+ for (history_iterator= history.new_iterator();
+ history_iterator != NULL;
+ history_iterator= history.iterator_next(history_iterator))
{
+ query= history.iterator_value(history_iterator);
+
PROFILE_ENTRY *ps= &(query->profile_start);
double last_time= ps->time_usecs;
#ifdef HAVE_GETRUSAGE
@@ -699,16 +662,20 @@ int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item
*/
ulonglong seq;
- List_iterator<PROFILE_ENTRY> step_it(query->entries);
+ void *entry_iterator;
PROFILE_ENTRY *entry;
/* ...and for each query, go through all its state-change steps. */
- for (seq= 0, entry= step_it++;
- entry != NULL;
+ for (seq= 0, entry_iterator= query->entries.new_iterator();
+ entry_iterator != NULL;
+ entry_iterator= query->entries.iterator_next(entry_iterator),
#ifdef HAVE_GETRUSAGE
last_rusage= &(entry->rusage),
#endif
- seq++, last_time= entry->time_usecs, entry= step_it++, row_number++)
+ seq++, last_time= entry->time_usecs, row_number++)
{
+ entry= query->entries.iterator_value(entry_iterator);
+
+
/* Set default values for this row. */
restore_record(table, s->default_values);
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index 0b387f2a7cb..7913d037551 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -84,6 +84,112 @@ class PROFILING;
/**
+ Implements a persistent FIFO using server List method names. Not
+ thread-safe. Intended to be used on thread-local data only.
+*/
+template <class T> class Queue
+{
+private:
+
+ struct queue_item
+ {
+ T *payload;
+ struct queue_item *next, *previous;
+ };
+
+ struct queue_item *first, *last;
+
+public:
+ Queue()
+ {
+ elements= 0;
+ first= last= NULL;
+ }
+
+ void empty()
+ {
+ struct queue_item *i, *after_i;
+ for (i= first; i != NULL; i= after_i)
+ {
+ after_i= i->next;
+ my_free((char *) i, MYF(0));
+ }
+ elements= 0;
+ }
+
+ ulong elements; /* The count of items in the Queue */
+
+ void push_back(T *payload)
+ {
+ struct queue_item *new_item;
+
+ new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0));
+
+ new_item->payload= payload;
+
+ if (first == NULL)
+ first= new_item;
+ if (last != NULL)
+ {
+ DBUG_ASSERT(last->next == NULL);
+ last->next= new_item;
+ }
+ new_item->previous= last;
+ new_item->next= NULL;
+ last= new_item;
+
+ elements++;
+ }
+
+ T *pop()
+ {
+ struct queue_item *old_item= first;
+ T *ret= NULL;
+
+ if (first == NULL)
+ {
+ DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue"));
+ return NULL;
+ }
+
+ ret= old_item->payload;
+ if (first->next != NULL)
+ first->next->previous= NULL;
+ else
+ last= NULL;
+ first= first->next;
+
+ my_free((char *)old_item, MYF(0));
+ elements--;
+
+ return ret;
+ }
+
+ bool is_empty()
+ {
+ DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL)));
+ return (elements == 0);
+ }
+
+ void *new_iterator()
+ {
+ return first;
+ }
+
+ void *iterator_next(void *current)
+ {
+ return ((struct queue_item *) current)->next;
+ }
+
+ T *iterator_value(void *current)
+ {
+ return ((struct queue_item *) current)->payload;
+ }
+
+};
+
+
+/**
A single entry in a single profile.
*/
class PROFILE_ENTRY
@@ -135,7 +241,7 @@ private:
char *query_source;
PROFILE_ENTRY profile_start;
PROFILE_ENTRY *profile_end;
- List<PROFILE_ENTRY> entries;
+ Queue<PROFILE_ENTRY> entries;
QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg);
@@ -169,13 +275,12 @@ private:
Not the system query_id, but a counter unique to profiling.
*/
query_id_t profile_id_counter;
- MEM_ROOT mem_root;
THD *thd;
bool keeping;
QUERY_PROFILE *current;
QUERY_PROFILE *last;
- List<QUERY_PROFILE> history;
+ Queue<QUERY_PROFILE> history;
query_id_t next_profile_id() { return(profile_id_counter++); }