From: Marc Alff Date: March 31 2011 1:57pm Subject: bzr push into mysql-trunk-lock-order branch (marc.alff:3349 to 3350) List-Archive: http://lists.mysql.com/commits/134371 Message-Id: <201103311357.p2VDvg3A002842@acsmt358.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3350 Marc Alff 2011-03-31 Prototyping, mutex lock order added: sql/debug_lock_order.cc sql/debug_lock_order.h modified: .bzr-mysql/default.conf BUILD/SETUP.sh sql/CMakeLists.txt sql/mysqld.cc 3349 Magne Mahre 2011-03-30 [merge] Null merge === modified file '.bzr-mysql/default.conf' --- a/.bzr-mysql/default.conf 2011-03-30 07:34:34 +0000 +++ b/.bzr-mysql/default.conf 2011-03-31 13:55:55 +0000 @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@stripped" post_push_to = "commits@stripped" -tree_name = "mysql-trunk" +tree_name = "mysql-trunk-lock-order" === modified file 'BUILD/SETUP.sh' --- a/BUILD/SETUP.sh 2011-01-21 16:14:47 +0000 +++ b/BUILD/SETUP.sh 2011-03-31 13:55:55 +0000 @@ -207,7 +207,8 @@ if test -z "$CC" ; then fi if test -z "$CXX" ; then - CXX=gcc +# CXX=gcc + CXX=g++ fi # If ccache (a compiler cache which reduces build time) === modified file 'sql/CMakeLists.txt' --- a/sql/CMakeLists.txt 2011-02-02 08:30:13 +0000 +++ b/sql/CMakeLists.txt 2011-03-31 13:55:55 +0000 @@ -38,6 +38,8 @@ ENDIF() SET(SQL_SHARED_SOURCES datadict.cc + debug_lock_order.h + debug_lock_order.cc debug_sync.cc derror.cc des_key_file.cc === added file 'sql/debug_lock_order.cc' --- a/sql/debug_lock_order.cc 1970-01-01 00:00:00 +0000 +++ b/sql/debug_lock_order.cc 2011-03-31 13:55:55 +0000 @@ -0,0 +1,1879 @@ + +/* MySQL List implementation requires a MEM_ROOT in TLS */ +#include + +#include "mysqld.h" +#include "debug_lock_order.h" + +#define LO_MAX_THREAD_CLASS 100 +#define LO_MAX_MUTEX_CLASS 200 +#define LO_MAX_RWLOCK_CLASS 50 + +#define LO_MAX_QNAME_LENGTH 128 + +FILE *out_log= NULL; +FILE *out_dot= NULL; +FILE *out_txt= NULL; + +class LO_node; +class LO_arc; +class LO_graph; +class LO_lock; +class LO_thread_class; +class LO_thread; +class LO_mutex_class; +class LO_mutex; +class LO_mutex_locker; +class LO_mutex_lock; +class LO_rwlock_class; +class LO_rwlock; +class LO_rwlock_locker; +class LO_rwlock_lock; + +template +class LO_allocator +{ +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + LO_allocator() + {} + + LO_allocator(const LO_allocator&) + {} + + pointer allocate(size_type n, const void * = 0) + { + T* t = (T*) malloc(n * sizeof(T)); + return t; + } + + void deallocate(void* p, size_type) + { + if (p) + free(p); + } + + pointer address(reference x) const + { return &x; } + + const_pointer address(const_reference x) const + { return &x; } + + LO_allocator& operator=(const LO_allocator&) + { return *this; } + + void construct(pointer p, const T& val) + { new ((T*) p) T(val); } + + void destroy(pointer p) + { p->~T(); } + + size_type max_size() const + { return size_t(-1); } + + template + struct rebind + { + typedef LO_allocator other; + }; + + template + LO_allocator(const LO_allocator&) + {} + + template + LO_allocator& operator=(const LO_allocator&) + { return *this; } +}; + +template +inline bool +operator==(const LO_allocator<_T1>&, const LO_allocator<_T2>&) +{ return true; } + +template +inline bool +operator!=(const LO_allocator<_T1>&, const LO_allocator<_T2>&) +{ return false; } + +template class std::list >; +template class std::_List_base >; +typedef std::list > LO_mutex_lock_list; + +template class std::list >; +template class std::_List_base >; +typedef std::list > LO_rwlock_lock_list; + +template class std::list >; +template class std::_List_base >; +typedef std::list > LO_node_list; + +template class std::list >; +template class std::_List_base >; +typedef std::list > LO_arc_list; + +template class std::list >; +template class std::_List_base >; +typedef std::list > LO_authorised_arc_list; + +class LO_node +{ +public: + LO_node(const char *category, const char *name) + { + sprintf(m_qname, "%s/%s", category, name); + } + + virtual ~LO_node() + {} + + const char *get_qname() const + { return m_qname; } + + virtual int get_key() const = 0; + + void add_out(LO_arc *arc) + { m_arcs_out.push_front(arc); } + + void add_in (LO_arc *arc) + { m_arcs_in.push_front(arc); } + + const LO_arc_list& get_arcs_in() const + { return m_arcs_in; } + + const LO_arc_list& get_arcs_out() const + { return m_arcs_out; } + + LO_arc *find_edge_to(const LO_node *to) const; + +private: + char m_qname[LO_MAX_QNAME_LENGTH]; + LO_arc_list m_arcs_in; + LO_arc_list m_arcs_out; +}; + +class LO_arc +{ +public: + LO_arc(LO_node *from, LO_node *to, int flags) + : m_from(from), m_to(to), m_flags(flags) + {} + + ~LO_arc() + {} + + LO_node *get_from() const + { return m_from; } + + LO_node *get_to() const + { return m_to; } + + bool has_trace() const + { return m_flags & LO_FLAG_TRACE; } + + bool has_debug() const + { return m_flags & LO_FLAG_DEBUG; } + + bool has_loop() const + { return m_flags & LO_FLAG_LOOP; } + +private: + LO_node *m_from; + LO_node *m_to; + int m_flags; +}; + +LO_arc *LO_node::find_edge_to(const LO_node *to) const +{ + LO_arc_list::const_iterator it; + LO_arc *arc; + LO_node *n; + + DBUG_ASSERT(to != NULL); + + for (it= m_arcs_out.begin(); + it != m_arcs_out.end(); + it++) + { + arc= *it; + n= arc->get_to(); + DBUG_ASSERT(n != NULL); + if (strcmp(to->get_qname(), n->get_qname()) == 0) + return arc; + } + + return NULL; +} + + +class LO_graph +{ +public: + void check(const LO_lock *old_lock, + const LO_lock *new_lock); + + LO_node *find_node(const char *qname); + void add_node(LO_node *node); + + void add_arc(LO_authorised_arc *arc); + void add_arc(LO_node *from, LO_node *to, int flags); + void add_unresolved_arc(LO_authorised_arc *arc); + + bool find_path(LO_node *from, LO_node *to, LO_node_list& path); + + void dump_dot(); + void dump_txt(); + +private: + LO_node_list m_nodes; + LO_arc_list m_arcs; + LO_authorised_arc_list m_unresolved_arcs; +}; + +class LO_lock +{ +public: + LO_lock(const char *src_file, int src_line) + : m_locking_src_file(src_file), m_locking_src_line(src_line) + {} + + virtual const LO_node *get_node() const = 0; + + virtual ~LO_lock() + {} + + const char *get_locking_src_file() const + { return m_locking_src_file; } + + int get_locking_src_line() const + { return m_locking_src_line; } + +private: + const char *m_locking_src_file; + int m_locking_src_line; +}; + +void LO_graph::add_node(LO_node *node) +{ + m_nodes.push_front(node); + + LO_authorised_arc_list::iterator it; + LO_authorised_arc *unresolved_arc; + LO_node *n; + + for (it= m_unresolved_arcs.begin(); + it != m_unresolved_arcs.end(); + it++) + { + unresolved_arc= *it; + if (strcmp(unresolved_arc->m_from_name, node->get_qname()) == 0) + { + n= find_node(unresolved_arc->m_to_name); + if (n != NULL) + { + add_arc(node, n, unresolved_arc->m_flags); + m_unresolved_arcs.erase(it); + } + } + + if (strcmp(unresolved_arc->m_to_name, node->get_qname()) == 0) + { + n= find_node(unresolved_arc->m_from_name); + if (n != NULL) + { + add_arc(n, node, unresolved_arc->m_flags); + m_unresolved_arcs.erase(it); + } + } + } +} + +bool LO_graph::find_path(LO_node *from, LO_node *to, LO_node_list& path) +{ + LO_node_list sub_path; + const LO_arc_list& out_list= from->get_arcs_out(); + + LO_arc_list::const_iterator it; + LO_arc *arc; + LO_node *n; + + for (it= out_list.begin(); + it != out_list.end(); + it++) + { + arc= *it; + + if (! arc->has_loop()) + { + n= arc->get_to(); + + if (strcmp(n->get_qname(), to->get_qname()) == 0) + { + path.push_back(from); + path.push_back(to); + return true; + } + + if (find_path(n, to, sub_path)) + { + path= sub_path; + path.push_front(from); + return true; + } + } + } + + return false; +} + +void LO_graph::dump_dot() +{ + if (out_dot != NULL) + { + fprintf(out_dot, "# Automatically generated, do not edit\n"); + fprintf(out_dot, "# Process this file with:\n"); + fprintf(out_dot, "# neato -Tpng lock_order.dot > lock_order.png\n"); + fprintf(out_dot, "\n"); + fprintf(out_dot, "digraph LockOrder {\n"); + fprintf(out_dot, " graph [layout=dot rankdir=LR];\n"); + fprintf(out_dot, "\n"); + + LO_node_list::const_iterator node_it; + LO_node *n; + + for (node_it= m_nodes.begin(); + node_it != m_nodes.end(); + node_it++) + { + n= *node_it; + if ( (n->get_arcs_out().size() > 0) + || (n->get_arcs_in().size() > 0)) + { + fprintf(out_dot, + " node [label=\"%s\"] %d;\n", + n->get_qname(), + n->get_key()); + } + } + + fprintf(out_dot, "\n"); + + LO_arc_list::const_iterator arc_it; + LO_arc *a; + + for (arc_it= m_arcs.begin(); + arc_it != m_arcs.end(); + arc_it++) + { + a= *arc_it; + if (! a->has_loop()) + { + fprintf(out_dot, + " %d -> %d;\n", + a->get_from()->get_key(), + a->get_to()->get_key()); + } + else + { + /* + As far ar the layout is concerned, + a FROM -> TO back loop is printed as TO <- FROM, + so there are no loops seen during rendering. + */ + + fprintf(out_dot, + " %d:c -> %d:s [dir=back color=red arrowsize=2 penwidth=5];\n", + a->get_to()->get_key(), + a->get_from()->get_key()); + } + } + + fprintf(out_dot, "\n"); + fprintf(out_dot, " overlap=false\n"); + fprintf(out_dot, " label=\"Lock order enforced\"\n"); + fprintf(out_dot, "}\n"); + fclose(out_dot); + out_dot= NULL; + } +} + +void LO_graph::dump_txt() +{ + if (out_txt == NULL) + return; + + fprintf(out_txt, "# Automatically generated, do not edit\n"); + fprintf(out_txt, "\n"); + fprintf(out_txt, "total number of nodes: %d\n", (int) m_nodes.size()); + fprintf(out_txt, "total number of arcs: %d\n", (int) m_arcs.size()); + fprintf(out_txt, "\n"); + + LO_node_list::const_iterator node_it; + LO_node *n; + LO_arc_list::const_iterator arc_it; + LO_arc *a; + + for (node_it= m_nodes.begin(); + node_it != m_nodes.end(); + node_it++) + { + n= *node_it; + + fprintf(out_txt, "NODE: %s\n", n->get_qname()); + + const LO_arc_list& ali= n->get_arcs_in(); + if (ali.size() > 0) + { + fprintf(out_txt, " %d incoming arcs:\n", (int) ali.size()); + + for (arc_it= ali.begin(); + arc_it != ali.end(); + arc_it++) + { + a= *arc_it; + + fprintf(out_txt, " FROM: %s\n", + a->get_from()->get_qname()); + } + } + + const LO_arc_list& alo= n->get_arcs_out(); + if (alo.size() > 0) + { + fprintf(out_txt, " %d outgoing arcs:\n", (int) alo.size()); + + for (arc_it= alo.begin(); + arc_it != alo.end(); + arc_it++) + { + a= *arc_it; + + fprintf(out_txt, " TO: %s\n", + a->get_to()->get_qname()); + } + } + } + fclose(out_txt); + out_txt= NULL; +} + +LO_graph global_graph; + +class LO_thread_class +{ +public: + static LO_thread_class *find(int key); + + LO_thread_class(const char *category, const char *name); + ~LO_thread_class() + {} + + int get_key() const + { return m_key; } + +private: + static int m_counter; + static LO_thread_class *m_array[LO_MAX_THREAD_CLASS]; + + int m_key; + const char *m_category; + const char *m_name; +}; + +class LO_thread +{ +public: + LO_thread(const LO_thread_class *klass) + : m_class(klass) + {} + + ~LO_thread() + {} + + LO_mutex_locker* create_mutex_locker(LO_mutex *mutex); + LO_rwlock_locker* create_rwlock_locker(LO_rwlock *rwlock); + + void add_mutex_lock(LO_mutex *mutex, const char *src_file, int src_line); + void remove_mutex_lock(LO_mutex *mutex); + + void add_rwlock_lock(LO_rwlock *rwlock, const char *src_file, int src_line); + void remove_rwlock_lock(LO_rwlock *rwlock); + +private: + const LO_thread_class *m_class; + LO_mutex_lock_list m_mutex_locks; + LO_rwlock_lock_list m_rwlock_locks; +}; + +class LO_mutex_class : public LO_node +{ +public: + static LO_mutex_class *find_by_key(int key); + static LO_mutex_class *find_by_name(const char *name); + + LO_mutex_class(const char *category, const char *name); + virtual ~LO_mutex_class() + {} + + virtual int get_key() const + { return m_key; } + +private: + static int m_counter; + static LO_mutex_class *m_array[LO_MAX_MUTEX_CLASS]; + + int m_key; + char m_short_name[10]; +}; + +class LO_mutex +{ +public: + LO_mutex(const LO_mutex_class *klass) + : m_class(klass) + {} + + ~LO_mutex() + {} + + const LO_mutex_class *get_class() const + { return m_class; } + + void set_locked_by(const char *src_file, int src_line) + { + m_locking_src_file= src_file; + m_locking_src_line= src_line; + } + + void set_unlocked() + { + m_locking_src_file= "UNLOCKED"; + m_locking_src_line= 0; + } + + const char *get_locking_src_file() const + { return m_locking_src_file; } + + int get_locking_src_line() const + { return m_locking_src_line; } + +private: + const LO_mutex_class *m_class; + const char *m_locking_src_file; + int m_locking_src_line; +}; + +class LO_mutex_locker +{ +public: + LO_mutex_locker(LO_thread *thread, LO_mutex *mutex) + : m_thread(thread), m_mutex(mutex) + {} + + void start(const char *src_file, int src_line) + { + m_src_file= src_file; + m_src_line= src_line; + } + + void end() + { + m_thread->add_mutex_lock(m_mutex, m_src_file, m_src_line); + } + + ~LO_mutex_locker() + {} + + const char *get_src_file() const + { return m_src_file; } + + int get_src_line() const + { return m_src_line; } + +private: + LO_thread *m_thread; + LO_mutex *m_mutex; + const char *m_src_file; + int m_src_line; +}; + +class LO_mutex_lock : public LO_lock +{ +public: + LO_mutex_lock(LO_mutex *mutex, const char *src_file, int src_line) + : LO_lock(src_file, src_line), m_mutex(mutex) + {} + + virtual const LO_node *get_node() const + { + return m_mutex->get_class(); + } + + LO_mutex *get_mutex() + { return m_mutex; } + + ~LO_mutex_lock() + {} + +private: + LO_mutex *m_mutex; +}; + +class LO_rwlock_class : public LO_node +{ +public: + static LO_rwlock_class *find_by_key(int key); + static LO_rwlock_class *find_by_name(const char *name); + + LO_rwlock_class(const char *category, const char *name); + virtual ~LO_rwlock_class() + {} + + virtual int get_key() const + { return m_key; } + +private: + static int m_counter; + static LO_rwlock_class *m_array[LO_MAX_RWLOCK_CLASS]; + + int m_key; + char m_short_name[10]; +}; + +class LO_rwlock +{ +public: + LO_rwlock(const LO_rwlock_class *klass) + : m_class(klass) + {} + + ~LO_rwlock() + {} + + const LO_rwlock_class *get_class() const + { return m_class; } + + void set_locked_by(const char *src_file, int src_line) + { + m_locking_src_file= src_file; + m_locking_src_line= src_line; + } + + void set_unlocked() + { + m_locking_src_file= "UNLOCKED"; + m_locking_src_line= 0; + } + + const char *get_locking_src_file() const + { return m_locking_src_file; } + + int get_locking_src_line() const + { return m_locking_src_line; } + +private: + const LO_rwlock_class *m_class; + const char *m_locking_src_file; + int m_locking_src_line; +}; + +class LO_rwlock_locker +{ +public: + LO_rwlock_locker(LO_thread *thread, LO_rwlock *rwlock) + : m_thread(thread), m_rwlock(rwlock) + {} + + void start(const char *src_file, int src_line) + { + m_src_file= src_file; + m_src_line= src_line; + } + + void end() + { + DBUG_ASSERT(m_thread != NULL); + DBUG_ASSERT(m_rwlock != NULL); + m_thread->add_rwlock_lock(m_rwlock, m_src_file, m_src_line); + } + + ~LO_rwlock_locker() + {} + + const char *get_src_file() const + { return m_src_file; } + + int get_src_line() const + { return m_src_line; } + +private: + LO_thread *m_thread; + LO_rwlock *m_rwlock; + const char *m_src_file; + int m_src_line; +}; + +class LO_rwlock_lock : public LO_lock +{ +public: + LO_rwlock_lock(LO_rwlock *rwlock, const char *src_file, int src_line) + : LO_lock(src_file, src_line), m_rwlock(rwlock) + {} + + virtual const LO_node *get_node() const + { + return m_rwlock->get_class(); + } + + LO_rwlock *get_rwlock() + { return m_rwlock; } + + ~LO_rwlock_lock() + {} + +private: + LO_rwlock *m_rwlock; +}; + +void LO_graph::check(const LO_lock *old_lock, + const LO_lock *new_lock) +{ + DBUG_ASSERT(old_lock != NULL); + DBUG_ASSERT(new_lock != NULL); + + const LO_node *old_node= old_lock->get_node(); + const LO_node *new_node= new_lock->get_node(); + + DBUG_ASSERT(old_node != NULL); + DBUG_ASSERT(new_node != NULL); + + LO_arc *arc= old_node->find_edge_to(new_node); + + if (arc == NULL) + { + if (out_log != NULL) + { +#ifdef LATER + fprintf(out_log, + "Error: missing arc %s (%s:%d) -> %s (%s:%d)\n", + old_node->get_qname(), + old_lock->get_locking_src_file(), + old_lock->get_locking_src_line(), + new_node->get_qname(), + new_lock->get_locking_src_file(), + new_lock->get_locking_src_line()); +#endif + fprintf(out_log, + "Error: missing arc %s -> %s\n", + old_node->get_qname(), + new_node->get_qname()); + } + } + else + { + if (arc->has_trace() || arc->has_debug()) + { + if (out_log != NULL) + { + fprintf(out_log, + "Trace: using arc %s (%s:%d) -> %s (%s:%d)\n", + old_node->get_qname(), + old_lock->get_locking_src_file(), + old_lock->get_locking_src_line(), + new_node->get_qname(), + new_lock->get_locking_src_file(), + new_lock->get_locking_src_line()); + } + } + // DBUG_ASSERT(arc->has_debug() == false); + } +} + +void LO_graph::add_arc(LO_authorised_arc *arc) +{ + LO_node *from; + LO_node *to; + + from= find_node(arc->m_from_name); + to= find_node(arc->m_to_name); + + if ((from != NULL) && (to != NULL)) + add_arc(from, to, arc->m_flags); + else + add_unresolved_arc(arc); +} + +void LO_graph::add_arc(LO_node *from, LO_node *to, int flags) +{ + LO_node_list cycle; + bool is_loop= ((flags & LO_FLAG_LOOP) == LO_FLAG_LOOP); + if (find_path(to, from, cycle)) + { + if ((out_log != NULL) && ! is_loop) + { + fprintf(out_log, + "Error: Cycle dependency, %s -> %s\n", + from->get_qname(), to->get_qname()); + + LO_node_list::const_iterator it; + LO_node *node; + int link= 1; + + for (it= cycle.begin(); + it != cycle.end(); + it++, link++) + { + node= *it; + fprintf(out_log, "Cycle link %d: %s\n", link, node->get_qname()); + } + } + return; + } + +#ifdef LATER + if (out_log != NULL && is_loop) + { + fprintf(out_log, + "Error: Arc is not a loop %s -> %s\n", + from->get_qname(), to->get_qname()); + } +#endif + + const LO_arc_list& arcs_out= from->get_arcs_out(); + LO_arc_list::const_iterator it; + LO_arc *arc; + LO_node *n; + + for (it= arcs_out.begin(); + it != arcs_out.end(); + it++) + { + arc= *it; + n= arc->get_to(); + if (strcmp(to->get_qname(), n->get_qname()) == 0) + { + fprintf(out_log, + "Error: duplicate arc, %s -> %s\n", + from->get_qname(), to->get_qname()); + return; + } + } + + arc= new LO_arc(from, to, flags); + from->add_out(arc); + to->add_in(arc); + m_arcs.push_front(arc); +} + +void LO_graph::add_unresolved_arc(LO_authorised_arc *arc) +{ + m_unresolved_arcs.push_front(arc); +} + +LO_node *LO_graph::find_node(const char *qname) +{ + LO_node_list::const_iterator it; + LO_node *n; + + for (it= m_nodes.begin(); + it != m_nodes.end(); + it++) + { + n= *it; + if (strcmp(qname, n->get_qname()) == 0) + return n; + } + + return NULL; +} + +int LO_thread_class::m_counter= 0; + +LO_thread_class *LO_thread_class::m_array[LO_MAX_THREAD_CLASS]; + +LO_thread_class *LO_thread_class::find(int key) +{ + if (key == 0) + return NULL; + DBUG_ASSERT(key >= 1); + DBUG_ASSERT(key <= LO_MAX_THREAD_CLASS); + DBUG_ASSERT(m_array[key - 1] != NULL); + return m_array[key - 1]; +} + +LO_thread_class::LO_thread_class(const char *category, const char* name) +: m_category(category), m_name(name) +{ + m_counter++; + m_key= m_counter; + m_array[m_key - 1]= this; +} + +LO_mutex_locker *LO_thread::create_mutex_locker(LO_mutex *mutex) +{ + return new LO_mutex_locker(this, mutex); +} + +LO_rwlock_locker *LO_thread::create_rwlock_locker(LO_rwlock *rwlock) +{ + return new LO_rwlock_locker(this, rwlock); +} + +void LO_thread::add_mutex_lock(LO_mutex *mutex, + const char *src_file, int src_line) +{ + const LO_mutex_lock *old_lock; + LO_mutex_lock *new_lock; + new_lock= new LO_mutex_lock(mutex, src_file, src_line); + mutex->set_locked_by(src_file, src_line); + LO_mutex_lock_list::const_iterator it; + + for (it= m_mutex_locks.begin(); + it != m_mutex_locks.end(); + it++) + { + old_lock= *it; + global_graph.check(old_lock, new_lock); + } + + m_mutex_locks.push_front(new_lock); +} + +void LO_thread::remove_mutex_lock(LO_mutex *mutex) +{ + LO_mutex_lock *old_lock; + LO_mutex_lock_list::iterator it; + + for (it= m_mutex_locks.begin(); + it != m_mutex_locks.end(); + it++) + { + old_lock= *it; + if (old_lock->get_mutex() == mutex) + { + m_mutex_locks.erase(it); + delete old_lock; + break; + } + } + + mutex->set_unlocked(); +} + +void LO_thread::add_rwlock_lock(LO_rwlock *rwlock, + const char *src_file, int src_line) +{ +#ifdef LATER + const LO_rwlock_lock *old_lock; + LO_rwlock_lock *new_lock; + new_lock= new LO_rwlock_lock(rwlock, src_file, src_line); + rwlock->set_locked_by(src_file, src_line); + LO_rwlock_lock_list::const_iterator it; + + for (it= m_rwlock_locks.begin(); + it != m_rwlock_locks.end(); + it++) + { + old_lock= *it; + global_graph.check(old_lock, new_lock); + } + + m_rwlock_locks.push_front(new_lock); +#endif +} + +void LO_thread::remove_rwlock_lock(LO_rwlock *rwlock) +{ +#ifdef LATER + LO_rwlock_lock *old_lock; + LO_rwlock_lock_list::iterator it; + +// TODO + for (it= m_rwlock_locks.begin(); + it != m_rwlock_locks.end(); + it++) + { + old_lock= *it; + if (old_lock->get_rwlock() == rwlock) + { + m_rwlock_locks.erase(it); + delete old_lock; + break; + } + } + +// TODO + rwlock->set_unlocked(); +#endif +} + +int LO_mutex_class::m_counter= 0; + +LO_mutex_class *LO_mutex_class::m_array[LO_MAX_MUTEX_CLASS]; + +LO_mutex_class *LO_mutex_class::find_by_key(int key) +{ + if (key == 0) + return NULL; + DBUG_ASSERT(key >= 1); + DBUG_ASSERT(key <= LO_MAX_MUTEX_CLASS); + DBUG_ASSERT(m_array[key - 1] != NULL); + return m_array[key - 1]; +} + +LO_mutex_class::LO_mutex_class(const char *category, const char* name) +: LO_node(category, name) +{ + m_counter++; + m_key= m_counter; + m_array[m_key - 1]= this; +} + +int LO_rwlock_class::m_counter= 0; + +LO_rwlock_class *LO_rwlock_class::m_array[LO_MAX_RWLOCK_CLASS]; + +LO_rwlock_class *LO_rwlock_class::find_by_key(int key) +{ + if (key == 0) + return NULL; + DBUG_ASSERT(key >= 1); + DBUG_ASSERT(key <= LO_MAX_RWLOCK_CLASS); + DBUG_ASSERT(m_array[key - 1] != NULL); + return m_array[key - 1]; +} + +LO_rwlock_class::LO_rwlock_class(const char *category, const char* name) +: LO_node(category, name) +{ + m_counter++; + m_key= m_counter; + m_array[m_key - 1]= this; +} + +pthread_key(LO_thread*, THR_ENF); +bool THR_LO_initialized= false; + +pthread_mutex_t serialize; + +static void register_mutex_v1(const char *category, + PSI_mutex_info_v1 *info, + int count) +{ + LO_mutex_class *lo; + + pthread_mutex_lock(&serialize); + for (int i=0; i < count; i++, info++) + { + lo= new LO_mutex_class(category, info->m_name); + *info->m_key= lo->get_key(); + global_graph.add_node(lo); + } + pthread_mutex_unlock(&serialize); +} + +static void register_rwlock_v1(const char *category, + PSI_rwlock_info_v1 *info, + int count) +{ + LO_rwlock_class *lo; + + pthread_mutex_lock(&serialize); + for (int i=0; i < count; i++, info++) + { + lo= new LO_rwlock_class(category, info->m_name); + *info->m_key= lo->get_key(); + global_graph.add_node(lo); + } + pthread_mutex_unlock(&serialize); +} + +static void register_cond_v1(const char *category, + PSI_cond_info_v1 *info, + int count) +{ + pthread_mutex_lock(&serialize); + pthread_mutex_unlock(&serialize); +} + +static void register_thread_v1(const char *category, + PSI_thread_info_v1 *info, + int count) +{ + LO_thread_class *lo; + + pthread_mutex_lock(&serialize); + for (int i=0; i < count; i++, info++) + { + lo= new LO_thread_class(category, info->m_name); + *info->m_key= lo->get_key(); + } + pthread_mutex_unlock(&serialize); +} + +static void register_file_v1(const char *category, + PSI_file_info_v1 *info, + int count) +{ + pthread_mutex_lock(&serialize); + pthread_mutex_unlock(&serialize); +} + +static void register_stage_v1(const char *category, + PSI_stage_info_v1 **info_array, + int count) +{} + +static void register_statement_v1(const char *category, + PSI_statement_info_v1 *info, + int count) +{} + +static PSI_mutex* +init_mutex_v1(PSI_mutex_key key, const void *identity) +{ + LO_mutex *lo= NULL; + + pthread_mutex_lock(&serialize); + LO_mutex_class *klass= LO_mutex_class::find_by_key(key); + if (klass != NULL) + lo= new LO_mutex(klass); + pthread_mutex_unlock(&serialize); + return reinterpret_cast (lo); +} + +static void destroy_mutex_v1(PSI_mutex* mutex) +{ + pthread_mutex_lock(&serialize); + LO_mutex *lo= reinterpret_cast (mutex); + if (lo) + delete lo; + pthread_mutex_unlock(&serialize); +} + +static PSI_rwlock* +init_rwlock_v1(PSI_rwlock_key key, const void *identity) +{ + LO_rwlock *lo= NULL; + + pthread_mutex_lock(&serialize); + LO_rwlock_class *klass= LO_rwlock_class::find_by_key(key); + if (klass != NULL) + lo= new LO_rwlock(klass); + pthread_mutex_unlock(&serialize); + return reinterpret_cast (lo); +} + +static void destroy_rwlock_v1(PSI_rwlock* rwlock) +{ + pthread_mutex_lock(&serialize); + LO_rwlock *lo= reinterpret_cast (rwlock); + if (lo) + delete lo; + pthread_mutex_unlock(&serialize); +} + +static PSI_cond* +init_cond_v1(PSI_cond_key key, const void *identity) +{ + pthread_mutex_lock(&serialize); + pthread_mutex_unlock(&serialize); + return NULL; +} + +static void destroy_cond_v1(PSI_cond* cond) +{ + pthread_mutex_lock(&serialize); + pthread_mutex_unlock(&serialize); +} + +static PSI_table_share* +get_table_share_v1(my_bool temporary, TABLE_SHARE *share) +{ + return NULL; +} + +static void release_table_share_v1(PSI_table_share* share) +{ +} + +static void +drop_table_share_v1(const char *schema_name, int schema_name_length, + const char *table_name, int table_name_length) +{ +} + +static PSI_table* +open_table_v1(PSI_table_share *share, const void *identity) +{ + return NULL; +} + +static void close_table_v1(PSI_table *table) +{ +} + +static void create_file_v1(PSI_file_key key, const char *name, File file) +{ +} + +class LO_spawn_thread_arg +{ +public: + PSI_thread_key m_child_key; + void *(*m_user_start_routine)(void*); + void *m_user_arg; +}; + +void* lo_spawn_thread(void *arg) +{ + LO_spawn_thread_arg *typed_arg= (LO_spawn_thread_arg*) arg; + void *user_arg; + void *(*user_start_routine)(void*); + + LO_thread *lo; + + pthread_mutex_lock(&serialize); + /* First, attach instrumentation to this newly created pthread. */ + LO_thread_class *klass= LO_thread_class::find(typed_arg->m_child_key); + lo= new LO_thread(klass); + pthread_mutex_unlock(&serialize); + + my_pthread_setspecific_ptr(THR_ENF, lo); + + /* + Secondly, free the memory allocated in spawn_thread_v1(). + It is preferable to do this before invoking the user + routine, to avoid memory leaks at shutdown, in case + the server exits without waiting for this thread. + */ + user_start_routine= typed_arg->m_user_start_routine; + user_arg= typed_arg->m_user_arg; + delete typed_arg; + + /* Then, execute the user code for this thread. */ + (*user_start_routine)(user_arg); + + return NULL; +} + +static int spawn_thread_v1(PSI_thread_key key, + pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg) +{ + LO_spawn_thread_arg *psi_arg; + + /* psi_arg can not be global, and can not be a local variable. */ + psi_arg= new LO_spawn_thread_arg(); + if (unlikely(psi_arg == NULL)) + return EAGAIN; + + psi_arg->m_child_key= key; + psi_arg->m_user_start_routine= start_routine; + psi_arg->m_user_arg= arg; + + int result= pthread_create(thread, attr, lo_spawn_thread, psi_arg); + if (unlikely(result != 0)) + delete psi_arg; + return result; +} + +static PSI_thread* +new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id) +{ + LO_thread *lo; + + pthread_mutex_lock(&serialize); + LO_thread_class *klass= LO_thread_class::find(key); + lo= new LO_thread(klass); + pthread_mutex_unlock(&serialize); + + return reinterpret_cast (lo); +} + +static void set_thread_id_v1(PSI_thread *thread, unsigned long id) +{ +} + +static PSI_thread* +get_thread_v1(void) +{ + LO_thread *lo= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + return reinterpret_cast (lo); +} + +static void set_thread_user_v1(const char *user, int user_len) +{} + +static void set_thread_user_host_v1(const char *user, int user_len, + const char *host, int host_len) +{} + +static void set_thread_db_v1(const char* db, int db_len) +{} + +static void set_thread_command_v1(int command) +{} + +static void set_thread_start_time_v1(time_t start_time) +{} + +static void set_thread_state_v1(const char* state) +{} + +static void set_thread_info_v1(const char* info, int info_len) +{} + + +static void set_thread_v1(PSI_thread* thread) +{ + LO_thread *lo= reinterpret_cast (thread); + my_pthread_setspecific_ptr(THR_ENF, lo); +} + +static void delete_current_thread_v1(void) +{ + pthread_mutex_lock(&serialize); + LO_thread *thread= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + if (thread != NULL) + { + my_pthread_setspecific_ptr(THR_ENF, NULL); + delete thread; + } + pthread_mutex_unlock(&serialize); +} + +static void delete_thread_v1(PSI_thread *thread) +{ + pthread_mutex_lock(&serialize); + LO_thread *lo= reinterpret_cast (thread); + if (lo != NULL) + delete lo; + pthread_mutex_unlock(&serialize); +} + +static PSI_mutex_locker* +get_thread_mutex_locker_v1(PSI_mutex_locker_state *state, + PSI_mutex *mutex, PSI_mutex_operation op) +{ + LO_mutex *lo_mutex= reinterpret_cast (mutex); + DBUG_ASSERT(lo_mutex != NULL); + LO_thread *lo_thread= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + LO_mutex_locker *lo_locker= NULL; + + if (lo_thread != NULL) + { + pthread_mutex_lock(&serialize); + lo_locker= lo_thread->create_mutex_locker(lo_mutex); + pthread_mutex_unlock(&serialize); + } + + return reinterpret_cast (lo_locker); +} + +static PSI_rwlock_locker* +get_thread_rwlock_locker_v1(PSI_rwlock_locker_state *state, + PSI_rwlock *rwlock, PSI_rwlock_operation op) +{ + LO_rwlock *lo_rwlock= reinterpret_cast (rwlock); + DBUG_ASSERT(lo_rwlock != NULL); + LO_thread *lo_thread= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + LO_rwlock_locker *lo_locker= NULL; + + if (lo_thread != NULL) + { + pthread_mutex_lock(&serialize); + lo_locker= lo_thread->create_rwlock_locker(lo_rwlock); + pthread_mutex_unlock(&serialize); + } + + return reinterpret_cast (lo_locker); +} + +static PSI_cond_locker* +get_thread_cond_locker_v1(PSI_cond_locker_state *state, + PSI_cond *cond, PSI_mutex *mutex, + PSI_cond_operation op) +{ + return NULL; +} + +static PSI_table_locker* +get_thread_table_io_locker_v1(PSI_table_locker_state *state, + PSI_table *table, PSI_table_io_operation op, uint index) +{ + return NULL; +} + +static PSI_table_locker* +get_thread_table_lock_locker_v1(PSI_table_locker_state *state, + PSI_table *table, PSI_table_lock_operation op, ulong op_flags) +{ + return NULL; +} + +static PSI_file_locker* +get_thread_file_name_locker_v1(PSI_file_locker_state *state, + PSI_file_key key, + PSI_file_operation op, + const char *name, const void *identity) +{ + return NULL; +} + +static PSI_file_locker* +get_thread_file_stream_locker_v1(PSI_file_locker_state *state, + PSI_file *file, PSI_file_operation op) +{ + return NULL; +} + +static PSI_file_locker* +get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, + File file, PSI_file_operation op) +{ + return NULL; +} + +static void unlock_mutex_v1(PSI_mutex *mutex) +{ + LO_thread *lo_thread= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + LO_mutex *lo_mutex= reinterpret_cast (mutex); + DBUG_ASSERT(lo_mutex != NULL); + + if (lo_thread) + { + pthread_mutex_lock(&serialize); + lo_thread->remove_mutex_lock(lo_mutex); + pthread_mutex_unlock(&serialize); + } +} + +static void unlock_rwlock_v1(PSI_rwlock *rwlock) +{ + LO_thread *lo_thread= my_pthread_getspecific_ptr(LO_thread*, THR_ENF); + LO_rwlock *lo_rwlock= reinterpret_cast (rwlock); + DBUG_ASSERT(lo_rwlock != NULL); + + if (lo_thread) + { + pthread_mutex_lock(&serialize); + lo_thread->remove_rwlock_lock(lo_rwlock); + pthread_mutex_unlock(&serialize); + } +} + +static void signal_cond_v1(PSI_cond* cond) +{ +} + +static void broadcast_cond_v1(PSI_cond* cond) +{ +} + +static void start_mutex_wait_v1(PSI_mutex_locker* locker, + const char *src_file, uint src_line) +{ + LO_mutex_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->start(src_file, src_line); + pthread_mutex_unlock(&serialize); +} + +static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) +{ + LO_mutex_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->end(); + delete lo_locker; + pthread_mutex_unlock(&serialize); +} + +static void start_rwlock_rdwait_v1(PSI_rwlock_locker* locker, + const char *src_file, uint src_line) +{ + LO_rwlock_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->start(src_file, src_line); + pthread_mutex_unlock(&serialize); +} + +static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) +{ + LO_rwlock_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->end(); + delete lo_locker; + pthread_mutex_unlock(&serialize); +} + +static void start_rwlock_wrwait_v1(PSI_rwlock_locker* locker, + const char *src_file, uint src_line) +{ + LO_rwlock_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->start(src_file, src_line); + pthread_mutex_unlock(&serialize); +} + +static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) +{ + LO_rwlock_locker *lo_locker= reinterpret_cast (locker); + DBUG_ASSERT(lo_locker != NULL); + + pthread_mutex_lock(&serialize); + lo_locker->end(); + delete lo_locker; + pthread_mutex_unlock(&serialize); +} + +static void start_cond_wait_v1(PSI_cond_locker* locker, + const char *src_file, uint src_line) +{ +} + +static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) +{ +} + +static void start_table_io_wait_v1(PSI_table_locker* locker, + const char *src_file, uint src_line) +{ +} + +static void end_table_io_wait_v1(PSI_table_locker* locker) +{ +} + +static void start_table_lock_wait_v1(PSI_table_locker* locker, + const char *src_file, uint src_line) +{ +} + +static void end_table_lock_wait_v1(PSI_table_locker* locker) +{ +} + +static void start_file_wait_v1(PSI_file_locker *locker, + size_t count, + const char *src_file, + uint src_line); + +static void end_file_wait_v1(PSI_file_locker *locker, + size_t count); + +static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line) +{ +} + +static void end_stage_v1() +{ +} + +static PSI_statement_locker* +get_thread_statement_locker_v1(PSI_statement_locker_state *state, + PSI_statement_key key) +{ + return NULL; +} + +static PSI_statement_locker* +refine_statement_v1(PSI_statement_locker *locker, + PSI_statement_key key) +{ + return NULL; +} + +static void start_statement_v1(PSI_statement_locker *locker, + const char *db, uint db_len, + const char *src_file, uint src_line) +{ +} + +static void set_statement_text_v1(PSI_statement_locker *locker, + const char *text, uint text_len) +{ +} + +static void set_statement_lock_time_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void set_statement_rows_sent_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void set_statement_rows_examined_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_select_full_join_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_select_full_range_join_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_select_range_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_select_range_check_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_select_scan_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_sort_range_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_sort_rows_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void inc_statement_sort_scan_v1(PSI_statement_locker *locker, + ulonglong count) +{} + +static void set_statement_no_index_used_v1(PSI_statement_locker *locker) +{} + +static void set_statement_no_good_index_used_v1(PSI_statement_locker *locker) +{} + +static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) +{} + + +static PSI_file* start_file_open_wait_v1(PSI_file_locker *locker, + const char *src_file, + uint src_line) +{ + return NULL; +} + +static void end_file_open_wait_v1(PSI_file_locker *locker) +{ +} + +static void end_file_open_wait_and_bind_to_descriptor_v1 + (PSI_file_locker *locker, File file) +{ +} + +static void start_file_wait_v1(PSI_file_locker *locker, + size_t count, + const char *src_file, + uint src_line) +{ +} + +static void end_file_wait_v1(PSI_file_locker *locker, + size_t count) +{ +} + +PSI_v1 LO_v1= +{ + register_mutex_v1, + register_rwlock_v1, + register_cond_v1, + register_thread_v1, + register_file_v1, + register_stage_v1, + register_statement_v1, + init_mutex_v1, + destroy_mutex_v1, + init_rwlock_v1, + destroy_rwlock_v1, + init_cond_v1, + destroy_cond_v1, + get_table_share_v1, + release_table_share_v1, + drop_table_share_v1, + open_table_v1, + close_table_v1, + create_file_v1, + spawn_thread_v1, + new_thread_v1, + set_thread_id_v1, + get_thread_v1, + set_thread_user_v1, + set_thread_user_host_v1, + set_thread_db_v1, + set_thread_command_v1, + set_thread_start_time_v1, + set_thread_state_v1, + set_thread_info_v1, + set_thread_v1, + delete_current_thread_v1, + delete_thread_v1, + get_thread_mutex_locker_v1, + get_thread_rwlock_locker_v1, + get_thread_cond_locker_v1, + get_thread_table_io_locker_v1, + get_thread_table_lock_locker_v1, + get_thread_file_name_locker_v1, + get_thread_file_stream_locker_v1, + get_thread_file_descriptor_locker_v1, + unlock_mutex_v1, + unlock_rwlock_v1, + signal_cond_v1, + broadcast_cond_v1, + start_mutex_wait_v1, + end_mutex_wait_v1, + start_rwlock_rdwait_v1, + end_rwlock_rdwait_v1, + start_rwlock_wrwait_v1, + end_rwlock_wrwait_v1, + start_cond_wait_v1, + end_cond_wait_v1, + start_table_io_wait_v1, + end_table_io_wait_v1, + start_table_lock_wait_v1, + end_table_lock_wait_v1, + start_file_open_wait_v1, + end_file_open_wait_v1, + end_file_open_wait_and_bind_to_descriptor_v1, + start_file_wait_v1, + end_file_wait_v1, + start_stage_v1, + end_stage_v1, + get_thread_statement_locker_v1, + refine_statement_v1, + start_statement_v1, + set_statement_text_v1, + set_statement_lock_time_v1, + set_statement_rows_sent_v1, + set_statement_rows_examined_v1, + inc_statement_created_tmp_disk_tables_v1, + inc_statement_created_tmp_tables_v1, + inc_statement_select_full_join_v1, + inc_statement_select_full_range_join_v1, + inc_statement_select_range_v1, + inc_statement_select_range_check_v1, + inc_statement_select_scan_v1, + inc_statement_sort_merge_passes_v1, + inc_statement_sort_range_v1, + inc_statement_sort_rows_v1, + inc_statement_sort_scan_v1, + set_statement_no_index_used_v1, + set_statement_no_good_index_used_v1, + end_statement_v1 +}; + +static void* get_interface(int version) +{ + switch (version) + { + case PSI_VERSION_1: + return &LO_v1; + default: + return NULL; + } +} + +struct PSI_bootstrap LO_bootstrap= +{ + get_interface +}; + +PSI_bootstrap *LO_init() +{ + if (pthread_key_create(&THR_ENF, NULL)) + return NULL; + + THR_LO_initialized= true; + pthread_mutex_init(&serialize, NULL); + + out_log= fopen("lock_order.log", "a"); + if (out_log != NULL) + { + fprintf(out_log, "-- begin lock order\n"); + } + out_dot= fopen("lock_order.dot", "w"); + out_txt= fopen("lock_order.txt", "w"); + return &LO_bootstrap; +} + +void LO_add_authorised_arcs(struct LO_authorised_arc *arcs) +{ + LO_authorised_arc *arc= arcs; + + while (arc->m_from_name != NULL) + { + global_graph.add_arc(arc); + arc++; + } +} + +void LO_dump_dot() +{ + global_graph.dump_dot(); + global_graph.dump_txt(); +} + +void LO_cleanup() +{ +#ifdef LATER + if (THR_LO_initialized) + { + pthread_mutex_destroy(&serialize); + pthread_key_delete(THR_ENF); + THR_LO_initialized= false; + } +#endif + + if (out_log != NULL) + { + fprintf(out_log, "-- end lock order\n"); + fclose(out_log); + out_log= NULL; + } + + if (out_dot != NULL) + { + fclose(out_dot); + out_dot= NULL; + } + + if (out_txt != NULL) + { + fclose(out_txt); + out_txt= NULL; + } +} + === added file 'sql/debug_lock_order.h' --- a/sql/debug_lock_order.h 1970-01-01 00:00:00 +0000 +++ b/sql/debug_lock_order.h 2011-03-31 13:55:55 +0000 @@ -0,0 +1,27 @@ + +#ifndef DEBUG_LOCK_ORDER_H +#define DEBUG_LOCK_ORDER_H + +struct PSI_bootstrap; + +struct LO_authorised_arc +{ + const char *m_from_name; + const char *m_to_name; + int m_flags; +}; + +#define LO_FLAG_TRACE 1 +#define LO_FLAG_DEBUG 2 +#define LO_FLAG_LOOP 4 + +PSI_bootstrap *LO_init(); + +void LO_add_authorised_arcs(struct LO_authorised_arc *arcs); + +void LO_dump_dot(); + +void LO_cleanup(); + +#endif + === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2011-03-29 08:01:07 +0000 +++ b/sql/mysqld.cc 2011-03-31 13:55:55 +0000 @@ -68,6 +68,441 @@ #include "debug_sync.h" #include "sql_callback.h" +#ifdef HAVE_PSI_INTERFACE +#ifndef EMBEDDED_LIBRARY +#define WITH_LOCK_ORDER +#undef WITH_PERFSCHEMA_STORAGE_ENGINE +#endif +#endif + +#ifdef WITH_LOCK_ORDER +#include "debug_lock_order.h" +static LO_authorised_arc debug_lock_order_arcs[]= +{ + {"innodb/autoinc_mutex", "innodb/thr_local_mutex", 0}, + {"innodb/autoinc_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/autoinc_mutex", "innodb/mutex_list_mutex", 0}, + {"innodb/autoinc_mutex", "innodb/os_mutex", 0}, + + {"innodb/buf_pool_mutex", "innodb/mutex_list_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/os_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/rw_lock_list_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/ut_list_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/buf_pool_mutex", "innodb/buf_pool_zip_mutex", 0}, + + {"innodb/buf_pool_zip_mutex", "innodb/flush_list_mutex", 0}, + + {"innodb/dict_foreign_err_mutex", "sql/THD::LOCK_thd_data", 0}, // ??? + + {"innodb/dict_sys_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/ibuf_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/mutex_list_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/os_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/recv_sys_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/rw_lock_list_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/thr_local_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/lock_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/rseg_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/trx_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/trx_undo_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/purge_sys_bh_mutex", 0}, + {"innodb/dict_sys_mutex", "sql/LOCK_global_system_variables", 0}, // ??? + {"innodb/dict_sys_mutex", "innodb/autoinc_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/buf_pool_zip_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/srv_sys_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/trx_doublewrite_mutex", 0}, + {"innodb/dict_sys_mutex", "innodb/dict_foreign_err_mutex", 0}, + {"innodb/dict_sys_mutex", "sql/LOCK_error_log", 0}, + + {"innodb/fil_system_mutex", "innodb/os_mutex", 0}, + {"innodb/fil_system_mutex", "innodb/rw_lock_list_mutex", 0}, + + {"innodb/file_format_max_mutex", "innodb/log_sys_mutex", 0}, + + {"innodb/ibuf_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/ibuf_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/ibuf_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/ibuf_mutex", "innodb/os_mutex", 0}, + {"innodb/ibuf_mutex", "innodb/recv_sys_mutex", 0}, + {"innodb/ibuf_mutex", "innodb/thr_local_mutex", 0}, + + {"innodb/ibuf_bitmap_mutex", "innodb/thr_local_mutex", 0}, + + {"innodb/lock_mutex", "innodb/trx_mutex", 0}, + {"innodb/lock_mutex", "sql/THD::LOCK_thd_data", 0}, + + {"innodb/lock_wait_mutex", "innodb/os_mutex", 0}, + {"innodb/lock_wait_mutex", "innodb/trx_mutex", 0}, + {"innodb/lock_wait_mutex", "innodb/lock_mutex", 0}, + + {"innodb/log_flush_order_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/log_flush_order_mutex", "innodb/os_mutex", 0}, + + {"innodb/log_sys_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/os_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/thr_local_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/rw_lock_list_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/mutex_list_mutex", 0}, + {"innodb/log_sys_mutex", "innodb/recv_sys_mutex", 0}, + + {"innodb/prepare_commit_mutex", "innodb/lock_mutex", 0}, + {"innodb/prepare_commit_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/prepare_commit_mutex", "innodb/rseg_mutex", 0}, + {"innodb/prepare_commit_mutex", "innodb/trx_mutex", 0}, + {"innodb/prepare_commit_mutex", "sql/LOG::LOCK_log", 0}, + {"innodb/prepare_commit_mutex", "sql/MYSQL_BIN_LOG::LOCK_prep_xids", 0}, + {"innodb/prepare_commit_mutex", "innodb/read_view_mutex", 0}, + + {"innodb/rseg_mutex", "innodb/thr_local_mutex", 0}, + {"innodb/rseg_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/rseg_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/rseg_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/rseg_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/rseg_mutex", "innodb/purge_sys_bh_mutex", 0}, + {"innodb/rseg_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/rseg_mutex", "innodb/os_mutex", 0}, + {"innodb/rseg_mutex", "innodb/buf_pool_zip_mutex", 0}, + + {"innodb/rw_lock_list_mutex", "innodb/os_mutex", 0}, + + {"innodb/srv_dict_tmpfile_mutex", "innodb/dict_sys_mutex", 0}, + + {"innodb/srv_innodb_monitor_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/buf_pool_zip_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/dict_foreign_err_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/ibuf_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/lock_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/mem_pool_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "innodb/os_mutex", 0}, + {"innodb/srv_innodb_monitor_mutex", "sql/THD::LOCK_thd_data", 0}, + + {"innodb/srv_monitor_file_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/dict_foreign_err_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/ibuf_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/lock_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/mem_pool_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/os_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "innodb/srv_innodb_monitor_mutex", 0}, + {"innodb/srv_monitor_file_mutex", "sql/THD::LOCK_thd_data", 0}, + + {"innodb/srv_sys_mutex", "innodb/thr_local_mutex", 0}, + + {"innodb/trx_doublewrite_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/trx_doublewrite_mutex", "innodb/os_mutex", 0}, + {"innodb/trx_doublewrite_mutex", "innodb/thr_local_mutex", 0}, + + {"innodb/trx_mutex", "innodb/mutex_list_mutex", 0}, + {"innodb/trx_mutex", "innodb/os_mutex", 0}, + + {"innodb/trx_undo_mutex", "innodb/buf_pool_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/fil_system_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/flush_list_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/log_flush_order_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/log_sys_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/rseg_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/thr_local_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/os_mutex", 0}, + {"innodb/trx_undo_mutex", "innodb/buf_pool_zip_mutex", 0}, + + {"myisam/MYISAM_SHARE::intern_lock", "mysys/KEY_CACHE::cache_lock", 0}, + {"myisam/MYISAM_SHARE::intern_lock", "sql/LOCK_error_log", 0}, + {"myisam/MYISAM_SHARE::intern_lock", "sql/THD::LOCK_thd_data", 0}, + + {"mysys/my_thread_var::mutex", "sql/LOCK_event_queue", 0}, + {"mysys/my_thread_var::mutex", "sql/DEBUG_SYNC::mutex", 0}, + {"mysys/my_thread_var::mutex", "mysys/THR_LOCK::mutex", 0}, + {"mysys/my_thread_var::mutex", "sql/LOCK_user_locks", 0}, + {"mysys/my_thread_var::mutex", "sql/MDL_wait::LOCK_wait_status", 0}, + + {"mysys/THR_LOCK_myisam", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"mysys/THR_LOCK_myisam", "mysys/KEY_CACHE::cache_lock", 0}, + {"mysys/THR_LOCK_myisam", "mysys/THR_LOCK_open", 0}, + {"mysys/THR_LOCK_myisam", "sql/LOCK_error_log", 0}, + + {"mysys/THR_LOCK::mutex", "csv/TINA_SHARE::mutex", 0}, + {"mysys/THR_LOCK::mutex", "sql/DEBUG_SYNC::mutex", 0}, + + {"mysys/THR_LOCK_charset", "mysys/THR_LOCK_open", 0}, + + {"csv/tina", "mysys/THR_LOCK_open", 0}, + + {"archive/ARCHIVE_SHARE::mutex", "mysys/THR_LOCK_open", 0}, + + {"archive/archive_mutex", "mysys/THR_LOCK_open", 0}, + + {"sql/Delayed_insert::mutex", "sql/LOCK_delayed_status", 0}, + {"sql/Delayed_insert::mutex", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"sql/Delayed_insert::mutex", "mysys/THR_LOCK::mutex", 0}, + {"sql/Delayed_insert::mutex", "mysys/THR_LOCK_myisam", 0}, + {"sql/Delayed_insert::mutex", "mysys/THR_LOCK_open", 0}, + {"sql/Delayed_insert::mutex", "mysys/THR_LOCK_threads", 0}, + {"sql/Delayed_insert::mutex", "sql/LOCK_plugin", 0}, + {"sql/Delayed_insert::mutex", "sql/TABLE_SHARE::LOCK_ha_data", 0}, + {"sql/Delayed_insert::mutex", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/Delayed_insert::mutex", "sql/MDL_map::mutex", 0}, + {"sql/Delayed_insert::mutex", "sql/MDL_wait::LOCK_wait_status", 0}, + + {"sql/LOCK_delayed_insert", "sql/Delayed_insert::mutex", 0}, + {"sql/LOCK_delayed_insert", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/LOCK_delayed_insert", "sql/LOCK_plugin", 0}, + {"sql/LOCK_delayed_insert", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_delayed_insert", "sql/LOCK_thread_count", 0}, + {"sql/LOCK_delayed_insert", "sql/LOCK_xid_cache", 0}, + {"sql/LOCK_delayed_insert", "sql/THD::LOCK_thd_data", 0}, + + {"sql/LOCK_delayed_create", "sql/Delayed_insert::mutex", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_delayed_insert", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_global_system_variables", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_plugin", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_thread_count", 0}, + {"sql/LOCK_delayed_create", "sql/THD::LOCK_thd_data", 0}, + {"sql/LOCK_delayed_create", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_delayed_create", "sql/LOCK_xid_cache", 0}, + + {"sql/Event_scheduler::LOCK_scheduler_state", "mysys/LOCK_alarm", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "mysys/my_thread_var::mutex", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_error_log", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_event_queue", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_global_system_variables", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_plugin", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_thread_count", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/LOCK_xid_cache", 0}, + {"sql/Event_scheduler::LOCK_scheduler_state", "sql/THD::LOCK_thd_data", 0}, + + {"sql/LOCK_error_messages", "mysys/THR_LOCK_open", 0}, + + {"sql/LOCK_des_key_file", "mysys/THR_LOCK_open", 0}, + + {"sql/LOCK_gdl", "mysys/THR_LOCK_open", 0}, + {"sql/LOCK_gdl", "mysys/THR_LOCK_myisam", 0}, + {"sql/LOCK_gdl", "sql/LOCK_plugin", 0}, + {"sql/LOCK_gdl", "innodb/dict_sys_mutex", 0}, + {"sql/LOCK_gdl", "innodb/lock_mutex", 0}, + {"sql/LOCK_gdl", "innodb/log_sys_mutex", 0}, + {"sql/LOCK_gdl", "innodb/mutex_list_mutex", 0}, + {"sql/LOCK_gdl", "innodb/os_mutex", 0}, + {"sql/LOCK_gdl", "innodb/srv_sys_mutex", 0}, + {"sql/LOCK_gdl", "innodb/trx_mutex", 0}, + + {"sql/LOCK_active_mi", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"sql/LOCK_active_mi", "mysys/THR_LOCK::mutex", 0}, + {"sql/LOCK_active_mi", "mysys/THR_LOCK_myisam", 0}, + {"sql/LOCK_active_mi", "mysys/THR_LOCK_open", 0}, + {"sql/LOCK_active_mi", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_open", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_plugin", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_thread_count", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_xid_cache", 0}, + {"sql/LOCK_active_mi", "sql/MDL_map::mutex", 0}, + {"sql/LOCK_active_mi", "sql/Master_info::data_lock", 0}, + {"sql/LOCK_active_mi", "sql/Relay_log_info::data_lock", 0}, + {"sql/LOCK_active_mi", "sql/TABLE_SHARE::LOCK_ha_data", 0}, + {"sql/LOCK_active_mi", "sql/THD::LOCK_thd_data", 0}, + {"sql/LOCK_active_mi", "mysys/THR_LOCK_charset", 0}, + {"sql/LOCK_active_mi", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/LOCK_active_mi", "sql/Master_info::run_lock", 0}, + {"sql/LOCK_active_mi", "sql/Relay_log_info::run_lock", 0}, + {"sql/LOCK_active_mi", "sql/Slave_reporting_capability::err_lock", 0}, + {"sql/LOCK_active_mi", "mysys/IO_CACHE::append_buffer_lock", 0}, + {"sql/LOCK_active_mi", "sql/LOG::LOCK_log", 0}, + {"sql/LOCK_active_mi", "mysys/LOCK_alarm", 0}, + {"sql/LOCK_active_mi", "mysys/my_thread_var::mutex", 0}, + {"sql/LOCK_active_mi", "sql/LOCK_error_log", 0}, + {"sql/LOCK_active_mi", "sql/MYSQL_RELAY_LOG::LOCK_index", 0}, + + {"sql/LOCK_event_queue", "sql/LOCK_error_log", 0}, + + {"sql/LOCK_global_system_variables", "sql/LOCK_plugin", 0}, + {"sql/LOCK_global_system_variables", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_global_system_variables", "sql/LOCK_thread_count", 0}, + {"sql/LOCK_global_system_variables", "sql/Query_cache::structure_guard_mutex", 0}, + {"sql/LOCK_global_system_variables", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/LOCK_global_system_variables", "mysys/LOCK_alarm", 0}, + {"sql/LOCK_global_system_variables", "sql/Relay_log_info::data_lock", 0}, + {"sql/LOCK_global_system_variables", "sql/Relay_log_info::run_lock", 0}, + {"sql/LOCK_global_system_variables", "sql/LOG::LOCK_log", 0}, + {"sql/LOCK_global_system_variables", "innodb/file_format_max_mutex", 0}, + {"sql/LOCK_global_system_variables", "innodb/log_sys_mutex", 0}, + + {"sql/LOCK_open", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"sql/LOCK_open", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/LOCK_open", "mysys/THR_LOCK_myisam", 0}, + {"sql/LOCK_open", "mysys/THR_LOCK_open", 0}, + {"sql/LOCK_open", "sql/LOCK_plugin", 0}, + {"sql/LOCK_open", "mysys/THR_LOCK_charset", 0}, + {"sql/LOCK_open", "sql/LOCK_error_log", 0}, + {"sql/LOCK_open", "sql/hash_filo::lock", 0}, + {"sql/LOCK_open", "csv/tina", 0}, + {"sql/LOCK_open", "example/example", 0}, + {"sql/LOCK_open", "innodb/dict_sys_mutex", 0}, + {"sql/LOCK_open", "innodb/innobase_share_mutex", 0}, + {"sql/LOCK_open", "mysys/THR_LOCK_heap", 0}, + {"sql/LOCK_open", "sql/MDL_wait::LOCK_wait_status", 0}, + {"sql/LOCK_open", "archive/archive_mutex", 0}, + {"sql/LOCK_open", "mysys/my_thread_var::mutex", 0}, + {"sql/LOCK_open", "blackhole/blackhole", 0}, + + {"sql/LOCK_plugin", "sql/LOCK_error_log", 0}, + {"sql/LOCK_plugin", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/LOCK_plugin", "mysys/THR_LOCK_open", 0}, + + {"sql/LOCK_status", "innodb/buf_pool_mutex", 0}, + {"sql/LOCK_status", "innodb/buf_pool_zip_mutex", 0}, + {"sql/LOCK_status", "innodb/flush_list_mutex", 0}, + {"sql/LOCK_status", "innodb/srv_innodb_monitor_mutex", 0}, + {"sql/LOCK_status", "sql/LOCK_active_mi", 0}, + {"sql/LOCK_status", "sql/LOCK_global_system_variables", 0}, + {"sql/LOCK_status", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_status", "sql/Relay_log_info::data_lock", 0}, + {"sql/LOCK_status", "sql/LOCK_thread_count", 0}, + {"sql/LOCK_status", "sql/LOG::LOCK_log", 0}, + {"sql/LOCK_status", "sql/Query_cache::structure_guard_mutex", 0}, + + {"sql/LOCK_thread_count", "sql/LOCK_plugin", 0}, + {"sql/LOCK_thread_count", "sql/LOCK_prepared_stmt_count", 0}, + {"sql/LOCK_thread_count", "sql/THD::LOCK_thd_data", 0}, + {"sql/LOCK_thread_count", "innodb/mutex_list_mutex", 0}, + {"sql/LOCK_thread_count", "innodb/os_mutex", 0}, + {"sql/LOCK_thread_count", "innodb/thr_local_mutex", 0}, + {"sql/LOCK_thread_count", "innodb/trx_mutex", 0}, + {"sql/LOCK_thread_count", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/LOCK_thread_count", "sql/LOCK_user_locks", 0}, + {"sql/LOCK_thread_count", "sql/LOCK_xid_cache", 0}, + {"sql/LOCK_thread_count", "sql/MDL_map::mutex", 0}, + {"sql/LOCK_thread_count", "mysys/my_thread_var::mutex", 0}, + {"sql/LOCK_thread_count", "sql/LOCK_event_queue", 0}, + {"sql/LOCK_thread_count", "mysys/THR_LOCK_open", 0}, + + {"sql/THD::LOCK_thd_data", "mysys/LOCK_alarm", 0}, + {"sql/THD::LOCK_thd_data", "sql/LOCK_error_log", 0}, + {"sql/THD::LOCK_thd_data", "sql/LOCK_event_queue", 0}, + {"sql/THD::LOCK_thd_data", "mysys/THR_LOCK::mutex", 0}, + {"sql/THD::LOCK_thd_data", "sql/DEBUG_SYNC::mutex", 0}, + {"sql/THD::LOCK_thd_data", "sql/LOCK_user_locks", 0}, + {"sql/THD::LOCK_thd_data", "sql/MDL_wait::LOCK_wait_status", 0}, + + {"sql/LOCK_uuid_generator", "sql/LOCK_thread_count", 0}, + + {"sql/Master_info::data_lock", "sql/Relay_log_info::data_lock", 0}, + {"sql/Master_info::data_lock", "mysys/IO_CACHE::append_buffer_lock", 0}, + {"sql/Master_info::data_lock", "mysys/THR_LOCK_open", 0}, + {"sql/Master_info::data_lock", "sql/LOG::LOCK_log", 0}, + {"sql/Master_info::data_lock", "sql/MYSQL_RELAY_LOG::LOCK_index", 0}, + + {"sql/Master_info::run_lock", "sql/Relay_log_info::run_lock", 0}, + {"sql/Master_info::run_lock", "sql/Slave_reporting_capability::err_lock", 0}, + + {"sql/Relay_log_info::run_lock", "sql/Slave_reporting_capability::err_lock", 0}, + {"sql/Relay_log_info::run_lock", "sql/Relay_log_info::data_lock", 0}, + + {"sql/MYSQL_BIN_LOG::LOCK_index", "mysys/THR_LOCK_open", 0}, + {"sql/MYSQL_BIN_LOG::LOCK_index", "sql/LOCK_thread_count", 0}, + + {"sql/MYSQL_RELAY_LOG::LOCK_index", "mysys/IO_CACHE::append_buffer_lock", 0}, + {"sql/MYSQL_RELAY_LOG::LOCK_index", "mysys/THR_LOCK_open", 0}, + {"sql/MYSQL_RELAY_LOG::LOCK_index", "sql/LOCK_thread_count", 0}, + {"sql/MYSQL_RELAY_LOG::LOCK_index", "sql/Relay_log_info::log_space_lock", 0}, + + {"sql/LOG::LOCK_log", "mysys/THR_LOCK_open", 0}, + {"sql/LOG::LOCK_log", "sql/LOCK_thread_count", 0}, + {"sql/LOG::LOCK_log", "sql/MYSQL_BIN_LOG::LOCK_index", 0}, + {"sql/LOG::LOCK_log", "mysys/IO_CACHE::append_buffer_lock", 0}, + {"sql/LOG::LOCK_log", "sql/LOCK_error_log", 0}, + {"sql/LOG::LOCK_log", "sql/MYSQL_BIN_LOG::LOCK_prep_xids", 0}, + {"sql/LOG::LOCK_log", "sql/MYSQL_RELAY_LOG::LOCK_index", 0}, + {"sql/LOG::LOCK_log", "sql/Relay_log_info::log_space_lock", 0}, + + {"sql/hash_filo::lock", "sql/LOCK_global_system_variables", 0}, + {"sql/hash_filo::lock", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/hash_filo::lock", "sql/LOCK_plugin", 0}, + {"sql/hash_filo::lock", "sql/LOCK_error_log", 0}, + {"sql/hash_filo::lock", "sql/LOG::LOCK_log", 0}, + + {"sql/tz_LOCK", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"sql/tz_LOCK", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/tz_LOCK", "mysys/THR_LOCK::mutex", 0}, + {"sql/tz_LOCK", "sql/LOCK_error_log", 0}, + {"sql/tz_LOCK", "sql/LOCK_open", 0}, + {"sql/tz_LOCK", "sql/MDL_map::mutex", 0}, + {"sql/tz_LOCK", "sql/THD::LOCK_thd_data", 0}, + + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "archive/ARCHIVE_SHARE::mutex", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "myisam/MYISAM_SHARE::intern_lock", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "mysys/THR_LOCK_open", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "mysys/KEY_CACHE::cache_lock", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "sql/LOCK_global_system_variables", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "sql/LOCK_plugin", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "sql/Query_cache::structure_guard_mutex", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "sql/TABLE_SHARE::LOCK_ha_data", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "innodb/autoinc_mutex", 0}, + {"sql/HA_DATA_PARTITION::LOCK_auto_inc", "sql/LOG::LOCK_log", 0}, + +/* + Error: Cycle dependency, mysys/my_thread_var::mutex -> sql/Delayed_insert::mutex + Cycle link 1: sql/Delayed_insert::mutex + Cycle link 2: sql/THD::LOCK_thd_data + Cycle link 3: mysys/my_thread_var::mutex +*/ + {"sql/Delayed_insert::mutex", "sql/THD::LOCK_thd_data", 0}, + {"sql/THD::LOCK_thd_data", "mysys/my_thread_var::mutex", 0}, + {"mysys/my_thread_var::mutex", "sql/Delayed_insert::mutex", LO_FLAG_LOOP}, + +/* + Error: Cycle dependency, sql/Delayed_insert::mutex -> sql/LOCK_open + Cycle link 1: sql/LOCK_open + Cycle link 2: sql/Delayed_insert::mutex +*/ + {"sql/Delayed_insert::mutex", "sql/LOCK_open", 0}, + {"sql/LOCK_open", "sql/Delayed_insert::mutex", LO_FLAG_LOOP}, + +/* + Error: Cycle dependency, sql/LOCK_active_mi -> sql/LOCK_global_system_variables + Cycle link 1: sql/LOCK_global_system_variables + Cycle link 2: sql/LOCK_active_mi +*/ + {"sql/LOCK_active_mi", "sql/LOCK_global_system_variables", 0}, + {"sql/LOCK_global_system_variables", "sql/LOCK_active_mi", LO_FLAG_LOOP}, + +/* + Error: Cycle dependency, sql/LOCK_open -> sql/LOCK_delayed_insert + Cycle link 1: sql/LOCK_delayed_insert + Cycle link 2: sql/Delayed_insert::mutex + Cycle link 3: sql/LOCK_open +*/ + {"sql/LOCK_open", "sql/LOCK_delayed_insert", LO_FLAG_LOOP}, + +/* + Error: Cycle dependency, mysys/my_thread_var::mutex -> sql/LOG::LOCK_log + Cycle link 1: sql/LOG::LOCK_log + Cycle link 2: sql/LOCK_thread_count + Cycle link 3: mysys/my_thread_var::mutex +*/ + {"mysys/my_thread_var::mutex", "sql/LOG::LOCK_log", LO_FLAG_LOOP}, + + {NULL, NULL, 0} +}; +#endif + #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #include "../storage/perfschema/pfs_server.h" #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ @@ -1423,6 +1858,11 @@ static void mysqld_exit(int exit_code) shutdown_performance_schema(); */ #endif + +#ifdef WITH_LOCK_ORDER + LO_cleanup(); +#endif + my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); exit(exit_code); /* purecov: inspected */ } @@ -4574,6 +5014,14 @@ int mysqld_main(int argc, char **argv) sys_var_init(); +#ifdef WITH_LOCK_ORDER + PSI_hook= LO_init(); + LO_add_authorised_arcs(&debug_lock_order_arcs[0]); + if (PSI_hook != NULL) + sql_print_information("Enforcer in use.\n"); + else + sql_print_error("No enforcer.\n"); +#else #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE /* The performance schema needs to be initialized as early as possible, @@ -4629,6 +5077,7 @@ int mysqld_main(int argc, char **argv) these two defines are kept separate. */ #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +#endif /* WITH_LOCK_ORDER */ #ifdef HAVE_PSI_INTERFACE /* @@ -4928,6 +5377,10 @@ int mysqld_main(int argc, char **argv) mysql_cond_signal(&COND_server_started); mysql_mutex_unlock(&LOCK_server_started); +#ifdef WITH_LOCK_ORDER + LO_dump_dot(); +#endif + #if defined(_WIN32) || defined(HAVE_SMEM) handle_connections_methods(); #else No bundle (reason: useless for push emails).