From 698d98bea0522c913ba67159673b8290805b1f33 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Apr 2007 17:59:52 -0400 Subject: Backport: B-g#24795: SHOW PROFILE implementation Don't use memory roots to store profiling information, because memory roots make freeing the data a no-op, and thus long-running processes with profiling turned on the whole time could eventually use all available memory. Instead, use regular heap allocation and deallocation calls to manage profiling data. Replace the leaky List usage with a similar- behaving structure named "Queue". sql/sql_profile.cc: Don't use C++ iterators on our simple Queue implementation. They're not implemented and we don't really need them. Rip out idea of swapping out the thd's mem_root. sql/sql_profile.h: Rip out idea of needing a mem_root. Implement a Queue that looks and behaves very similarly to memroot- using List. --- sql/sql_profile.h | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) (limited to 'sql/sql_profile.h') 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 @@ -83,6 +83,112 @@ class QUERY_PROFILE; 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 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. */ @@ -135,7 +241,7 @@ private: char *query_source; PROFILE_ENTRY profile_start; PROFILE_ENTRY *profile_end; - List entries; + Queue 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 history; + Queue history; query_id_t next_profile_id() { return(profile_id_counter++); } -- cgit v1.2.1