List:Commits« Previous MessageNext Message »
From:Marc Alff Date:March 31 2011 1:57pm
Subject:bzr push into mysql-trunk-lock-order branch (marc.alff:3349 to 3350)
View as plain text  
 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 <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

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-lock-order branch (marc.alff:3349 to 3350) Marc Alff31 Mar