#At file:///Users/malff/BZR_TREE/mysql-trunk-lock-order/ based on revid:magne.mahre@stripped
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
=== 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 <list>
+
+#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 T>
+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<T>& 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 <class U>
+ struct rebind
+ {
+ typedef LO_allocator<U> other;
+ };
+
+ template <class U>
+ LO_allocator(const LO_allocator<U>&)
+ {}
+
+ template <class U>
+ LO_allocator& operator=(const LO_allocator<U>&)
+ { return *this; }
+};
+
+template<typename _T1, typename _T2>
+inline bool
+operator==(const LO_allocator<_T1>&, const LO_allocator<_T2>&)
+{ return true; }
+
+template<typename _T1, typename _T2>
+inline bool
+operator!=(const LO_allocator<_T1>&, const LO_allocator<_T2>&)
+{ return false; }
+
+template class std::list<LO_mutex_lock*, LO_allocator<LO_mutex_lock*> >;
+template class std::_List_base<LO_mutex_lock*, LO_allocator<LO_mutex_lock*> >;
+typedef std::list<LO_mutex_lock*, LO_allocator<LO_mutex_lock*> > LO_mutex_lock_list;
+
+template class std::list<LO_rwlock_lock*, LO_allocator<LO_rwlock_lock*> >;
+template class std::_List_base<LO_rwlock_lock*, LO_allocator<LO_rwlock_lock*> >;
+typedef std::list<LO_rwlock_lock*, LO_allocator<LO_rwlock_lock*> > LO_rwlock_lock_list;
+
+template class std::list<LO_node*, LO_allocator<LO_node*> >;
+template class std::_List_base<LO_node*, LO_allocator<LO_node*> >;
+typedef std::list<LO_node*, LO_allocator<LO_node*> > LO_node_list;
+
+template class std::list<LO_arc*, LO_allocator<LO_arc*> >;
+template class std::_List_base<LO_arc*, LO_allocator<LO_arc*> >;
+typedef std::list<LO_arc*, LO_allocator<LO_arc*> > LO_arc_list;
+
+template class std::list<LO_authorised_arc*, LO_allocator<LO_authorised_arc*> >;
+template class std::_List_base<LO_authorised_arc*, LO_allocator<LO_authorised_arc*> >;
+typedef std::list<LO_authorised_arc*, LO_allocator<LO_authorised_arc*> > 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<PSI_mutex*> (lo);
+}
+
+static void destroy_mutex_v1(PSI_mutex* mutex)
+{
+ pthread_mutex_lock(&serialize);
+ LO_mutex *lo= reinterpret_cast<LO_mutex*> (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<PSI_rwlock*> (lo);
+}
+
+static void destroy_rwlock_v1(PSI_rwlock* rwlock)
+{
+ pthread_mutex_lock(&serialize);
+ LO_rwlock *lo= reinterpret_cast<LO_rwlock*> (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<PSI_thread*> (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<PSI_thread*> (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<LO_thread*> (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<LO_thread*> (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<LO_mutex*> (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<PSI_mutex_locker*> (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<LO_rwlock*> (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<PSI_rwlock_locker*> (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<LO_mutex*> (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<LO_rwlock*> (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<LO_mutex_locker*> (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<LO_mutex_locker*> (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<LO_rwlock_locker*> (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<LO_rwlock_locker*> (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<LO_rwlock_locker*> (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<LO_rwlock_locker*> (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
Attachment: [text/bzr-bundle] bzr/marc.alff@oracle.com-20110331135555-c1auokje8ag249e8.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-lock-order branch (marc.alff:3350) | Marc Alff | 31 Mar |