List:Commits« Previous MessageNext Message »
From:Jan Wedvik Date:September 29 2011 1:12pm
Subject:bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (jan.wedvik:3567
to 3569)
View as plain text  
 3569 Jan Wedvik	2011-09-29
      Adding regression test for the following commit:
      
      "4562 Jan Wedvik 2011-09-29
      This patch will make the SPJ block fetch all rows for some non-root index scans
      in one batch rather than two.
      This will happen if the first batch reads from a subset of the fragments and
      receive few rows. The SPJ block will then
      try to read from the remaining fragments before finishing the batch.
      This is especially useful when doing bushy scans. If there are more branches in
      the bushy scan, then these will have to be
      repeated for each batch of the current scan."

    modified:
      mysql-test/suite/ndb/r/ndb_join_pushdown.result
      mysql-test/suite/ndb/t/ndb_join_pushdown.test
 3568 Jan Wedvik	2011-09-29 [merge]
      Merging from mysql-5.1-telco-7.0.

    added:
      storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp
      storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h
    modified:
      configure.in
      mysql-test/suite/ndb/my.cnf
      mysql-test/suite/ndb_binlog/my.cnf
      mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt
      mysql-test/suite/ndb_rpl/my.cnf
      mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf
      mysql-test/suite/ndb_team/my.cnf
      mysql-test/suite/rpl_ndb/my.cnf
      sql/ha_ndbcluster.cc
      storage/ndb/include/portlib/NdbMutex.h
      storage/ndb/ndb_configure.m4
      storage/ndb/src/common/debugger/signaldata/ScanTab.cpp
      storage/ndb/src/common/portlib/CMakeLists.txt
      storage/ndb/src/common/portlib/Makefile.am
      storage/ndb/src/common/portlib/NdbCondition.c
      storage/ndb/src/common/portlib/NdbMutex.c
      storage/ndb/src/common/portlib/NdbThread.c
      storage/ndb/src/common/util/ndb_init.cpp
      storage/ndb/src/kernel/SimBlockList.cpp
      storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
      storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
      storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp
      storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp
      storage/ndb/src/kernel/ndbd.cpp
      storage/ndb/src/kernel/vm/ArrayPool.hpp
      storage/ndb/src/kernel/vm/Configuration.cpp
      storage/ndb/src/kernel/vm/Emulator.cpp
      storage/ndb/src/kernel/vm/mt_thr_config.cpp
      storage/ndb/src/kernel/vm/mt_thr_config.hpp
      storage/ndb/src/mgmsrv/MgmtSrvr.cpp
      storage/ndb/src/ndbapi/NdbQueryBuilder.cpp
      storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp
      storage/ndb/src/ndbapi/ndberror.c
      storage/ndb/test/ndbapi/testNdbApi.cpp
      storage/ndb/test/ndbapi/testRestartGci.cpp
      storage/ndb/test/ndbapi/test_event.cpp
      storage/ndb/test/run-test/daily-basic-tests.txt
      storage/ndb/test/tools/hugoJoin.cpp
 3567 Ole John Aske	2011-09-28
      Fixed windows compiler warnings

    modified:
      sql/abstract_query_plan.cc
=== modified file 'configure.in'
--- a/configure.in	2011-09-21 08:53:48 +0000
+++ b/configure.in	2011-09-22 17:10:09 +0000
@@ -12,7 +12,7 @@ dnl
 dnl When changing the major version number please also check the switch
 dnl statement in mysqlbinlog::check_master_version().  You may also need
 dnl to update version.c in ndb.
-AC_INIT([MySQL Server], [5.1.56-ndb-7.0.27], [], [mysql])
+AC_INIT([MySQL Server], [5.1.56-ndb-7.0.28], [], [mysql])
 
 AC_CONFIG_SRCDIR([sql/mysqld.cc])
 AC_CANONICAL_SYSTEM

=== modified file 'mysql-test/suite/ndb/my.cnf'
--- a/mysql-test/suite/ndb/my.cnf	2011-04-17 18:25:41 +0000
+++ b/mysql-test/suite/ndb/my.cnf	2011-09-29 13:07:26 +0000
@@ -38,7 +38,7 @@ NodeId=255
 [mysqld]
 # Make all mysqlds use cluster
 ndbcluster
-ndb-wait-connected=20
+ndb-wait-connected=30
 ndb-wait-setup=120
 ndb-cluster-connection-pool=3
 ndb-extra-logging=99

=== modified file 'mysql-test/suite/ndb/r/ndb_join_pushdown.result'
--- a/mysql-test/suite/ndb/r/ndb_join_pushdown.result	2011-09-27 13:02:41 +0000
+++ b/mysql-test/suite/ndb/r/ndb_join_pushdown.result	2011-09-29 13:11:52 +0000
@@ -4792,6 +4792,20 @@ join t3 as x3 on x3.a=x2.c
 join t1 as x4 on x4.a=x0.d and x4.b=x3.b;
 count(*)
 4800
+explain select straight_join count(*) from t1 as x1  
+join t1 as x2 on x1.c=x2.a and x2.d=2
+join t3 as x3 on x1.d=x3.a;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	x1	ALL	NULL	NULL	NULL	NULL	4	Parent of 3 pushed join@1
+1	SIMPLE	x2	ref	PRIMARY	PRIMARY	4	test.x1.c	1	Child of 'x1' in pushed join@1; Using where with pushed condition
+1	SIMPLE	x3	ref	PRIMARY	PRIMARY	4	test.x1.d	1	Child of 'x1' in pushed join@1
+select straight_join count(*) from t1 as x1  
+join t1 as x2 on x1.c=x2.a and x2.d=2
+join t3 as x3 on x1.d=x3.a;
+count(*)
+300
+Local_range_scans
+4
 drop table t1;
 drop table t2;
 drop table t3;
@@ -5471,11 +5485,11 @@ and spj_counts_at_end.counter_name <> 'R
        and spj_counts_at_end.counter_name <> 'SCAN_BATCHES_RETURNED';
 counter_name	spj_counts_at_end.val - spj_counts_at_startup.val
 CONST_PRUNED_RANGE_SCANS_RECEIVED	6
-LOCAL_TABLE_SCANS_SENT	248
+LOCAL_TABLE_SCANS_SENT	250
 PRUNED_RANGE_SCANS_RECEIVED	25
 RANGE_SCANS_RECEIVED	728
 READS_RECEIVED	58
-TABLE_SCANS_RECEIVED	248
+TABLE_SCANS_RECEIVED	250
 drop table spj_counts_at_startup;
 drop table spj_counts_at_end;
 scan_count_derived
@@ -5485,9 +5499,9 @@ pruned_scan_count
 sorted_scan_count
 10
 pushed_queries_defined
-399
+401
 pushed_queries_dropped
 11
 pushed_queries_executed
-547
+548
 set ndb_join_pushdown = @save_ndb_join_pushdown;

=== modified file 'mysql-test/suite/ndb/t/ndb_join_pushdown.test'
--- a/mysql-test/suite/ndb/t/ndb_join_pushdown.test	2011-09-27 13:02:41 +0000
+++ b/mysql-test/suite/ndb/t/ndb_join_pushdown.test	2011-09-29 13:11:52 +0000
@@ -3323,6 +3323,28 @@ select straight_join count(*) from t1 as
    join t3 as x3 on x3.a=x2.c
    join t1 as x4 on x4.a=x0.d and x4.b=x3.b;
 
+# If the first batch of an index scan has low parallelism and returns few rows,
+# there is a mechanism that will try to query the remaining fragments within
+# the same batch. This is done in order to avoid repeating other branches of 
+# a bushy scan whenever possible. This is a test of that mechanism. Scan
+# of x2 should return only one row. Therefore we should be able to fetch
+# x2 in one batch and scan x3 only once.
+
+let $scan_rows = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name='LOCAL_RANGE_SCANS_SENT', Value, 1);
+
+explain select straight_join count(*) from t1 as x1  
+   join t1 as x2 on x1.c=x2.a and x2.d=2
+   join t3 as x3 on x1.d=x3.a;  
+
+select straight_join count(*) from t1 as x1  
+   join t1 as x2 on x1.c=x2.a and x2.d=2
+   join t3 as x3 on x1.d=x3.a;
+
+--disable_query_log
+--eval select sum(val) - $scan_rows as Local_range_scans from ndbinfo.counters where block_name='DBSPJ' and counter_name='LOCAL_RANGE_SCANS_SENT';
+--enable_query_log
+
+
 connection ddl;
 drop table t1;
 drop table t2;

=== modified file 'mysql-test/suite/ndb_binlog/my.cnf'
--- a/mysql-test/suite/ndb_binlog/my.cnf	2011-04-15 09:31:03 +0000
+++ b/mysql-test/suite/ndb_binlog/my.cnf	2011-09-22 14:43:45 +0000
@@ -11,7 +11,7 @@ ndbapi=,,,,,,,,,,,
 [mysqld]
 # Make all mysqlds use cluster
 ndbcluster
-ndb-wait-connected=20
+ndb-wait-connected=30
 ndb-wait-setup=120
 ndb-cluster-connection-pool=3
 ndb-extra-logging=99

=== modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt'
--- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt	2011-09-07 22:50:01 +0000
+++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_log_transaction_id-master.opt	2011-09-28 09:40:14 +0000
@@ -1 +1 @@
---ndb-log-transaction-id
+--ndb-log-transaction-id --log-bin-use-v1-row-events=false

=== modified file 'mysql-test/suite/ndb_rpl/my.cnf'
--- a/mysql-test/suite/ndb_rpl/my.cnf	2011-06-08 19:25:29 +0000
+++ b/mysql-test/suite/ndb_rpl/my.cnf	2011-09-22 14:43:45 +0000
@@ -21,7 +21,7 @@ ndbapi=,,,,
 [mysqld]
 # Make all mysqlds use cluster
 ndbcluster
-ndb-wait-connected=20
+ndb-wait-connected=30
 ndb-wait-setup=120
 ndb-cluster-connection-pool=3
 slave-allow-batching

=== modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf'
--- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf	2011-09-07 22:50:01 +0000
+++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch_trans.cnf	2011-09-28 09:40:14 +0000
@@ -11,10 +11,14 @@
 # Potential infinite loops are broken by both servers
 # on each cluster having the same server-id
 
+[cluster_config.slave]
+mysqld=,
+
 [mysqld]
 log-slave-updates
 ndb-log-apply-status
 ndb-log-transaction-id
+log-bin-use-v1-row-events=false
 
 [mysqld.1.1]
 server-id= 1

=== modified file 'mysql-test/suite/ndb_team/my.cnf'
--- a/mysql-test/suite/ndb_team/my.cnf	2011-06-08 19:25:29 +0000
+++ b/mysql-test/suite/ndb_team/my.cnf	2011-09-22 14:43:45 +0000
@@ -18,7 +18,7 @@ ndbapi=,,,,
 [mysqld]
 # Make all mysqlds use cluster
 ndbcluster
-ndb-wait-connected=20
+ndb-wait-connected=30
 ndb-wait-setup=120
 ndb-cluster-connection-pool=3
 loose-slave-allow-batching

=== modified file 'mysql-test/suite/rpl_ndb/my.cnf'
--- a/mysql-test/suite/rpl_ndb/my.cnf	2011-06-08 19:25:29 +0000
+++ b/mysql-test/suite/rpl_ndb/my.cnf	2011-09-22 14:43:45 +0000
@@ -21,7 +21,7 @@ ndbapi=,,,,
 [mysqld]
 # Make all mysqlds use cluster
 ndbcluster
-ndb-wait-connected=20
+ndb-wait-connected=30
 ndb-wait-setup=120
 ndb-cluster-connection-pool=3
 slave-allow-batching

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2011-09-15 21:00:03 +0000
+++ b/sql/ha_ndbcluster.cc	2011-09-29 13:07:26 +0000
@@ -17955,7 +17955,7 @@ static MYSQL_SYSVAR_ULONG(
   "to cluster management and data nodes.",
   NULL,                              /* check func. */
   NULL,                              /* update func. */
-  0,                                 /* default */
+  30,                                /* default */
   0,                                 /* min */
   ONE_YEAR_IN_SECONDS,               /* max */
   0                                  /* block */
@@ -17970,7 +17970,7 @@ static MYSQL_SYSVAR_ULONG(
   "complete (0 = no wait)",
   NULL,                              /* check func. */
   NULL,                              /* update func. */
-  15,                                /* default */
+  30,                                /* default */
   0,                                 /* min */
   ONE_YEAR_IN_SECONDS,               /* max */
   0                                  /* block */

=== modified file 'storage/ndb/include/portlib/NdbMutex.h'
--- a/storage/ndb/include/portlib/NdbMutex.h	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/include/portlib/NdbMutex.h	2011-09-27 17:28:13 +0000
@@ -29,11 +29,12 @@ extern "C" {
 #else
 #include <pthread.h>
 #endif
-#ifndef NDB_MUTEX_STAT
+#if !defined NDB_MUTEX_STAT && !defined NDB_MUTEX_DEADLOCK_DETECTOR
 typedef pthread_mutex_t NdbMutex;
 #else
 typedef struct {
   pthread_mutex_t mutex;
+#ifdef NDB_MUTEX_STAT
   unsigned cnt_lock;
   unsigned cnt_lock_contention;
   unsigned cnt_trylock_ok;
@@ -46,6 +47,10 @@ typedef struct {
   unsigned long long max_hold_time_ns;
   unsigned long long lock_start_time_ns;
   char name[32];
+#endif
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  struct ndb_mutex_state * m_mutex_state;
+#endif
 } NdbMutex;
 #endif
 

=== modified file 'storage/ndb/ndb_configure.m4'
--- a/storage/ndb/ndb_configure.m4	2011-07-04 07:46:44 +0000
+++ b/storage/ndb/ndb_configure.m4	2011-09-29 13:07:26 +0000
@@ -2,7 +2,7 @@
 # Should be updated when creating a new NDB version
 NDB_VERSION_MAJOR=7
 NDB_VERSION_MINOR=0
-NDB_VERSION_BUILD=27
+NDB_VERSION_BUILD=28
 NDB_VERSION_STATUS=""
 
 dnl for build ndb docs

=== modified file 'storage/ndb/src/common/debugger/signaldata/ScanTab.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp	2011-07-09 11:16:31 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/ScanTab.cpp	2011-09-29 13:07:26 +0000
@@ -78,9 +78,9 @@ printSCANTABCONF(FILE * output, const Ui
   size_t op_count= requestInfo & (~ScanTabConf::EndOfData);
   if (op_count)
   {
-    fprintf(output, " Operation(s) [api tc rows len]:\n");
     if (len == ScanTabConf::SignalLength + 4 * op_count)
     {
+      fprintf(output, " Operation(s) [api tc rows len]:\n");
       ScanTabConf::OpData * op = (ScanTabConf::OpData*)
         (theData + ScanTabConf::SignalLength);
       for(size_t i = 0; i<op_count; i++)
@@ -91,9 +91,9 @@ printSCANTABCONF(FILE * output, const Ui
         op++;
       }
     }
-    else
+    else if (len == ScanTabConf::SignalLength + 3 * op_count)
     {
-      assert(len == ScanTabConf::SignalLength + 3 * op_count);
+      fprintf(output, " Operation(s) [api tc rows len]:\n");      
       for(size_t i = 0; i<op_count; i++)
       {
         ScanTabConf::OpData * op = (ScanTabConf::OpData*)
@@ -104,6 +104,12 @@ printSCANTABCONF(FILE * output, const Ui
                 ScanTabConf::getLength(op->rows));
       }
     }
+    else
+    {
+      // ScanTabConf::OpData stored in section 0 of signal.
+      assert(len == ScanTabConf::SignalLength);
+      fprintf(output, " Long signal. Cannot print operations.");
+    }
     fprintf(output, "\n");
   }
   return false;

=== modified file 'storage/ndb/src/common/portlib/CMakeLists.txt'
--- a/storage/ndb/src/common/portlib/CMakeLists.txt	2011-07-04 13:37:56 +0000
+++ b/storage/ndb/src/common/portlib/CMakeLists.txt	2011-09-27 17:28:13 +0000
@@ -27,7 +27,7 @@ ADD_CONVENIENCE_LIBRARY(ndbportlib
             NdbEnv.c NdbThread.c NdbHost.c NdbTCP.cpp
             NdbMem.c NdbConfig.c NdbTick.c NdbDir.cpp
             ndb_daemon.cc ${EXTRA_SRC}
-            NdbNuma.cpp)
+            NdbNuma.cpp NdbMutex_DeadlockDetector.cpp)
 TARGET_LINK_LIBRARIES(ndbportlib mysys ${LIBSOCKET})
 
 ADD_EXECUTABLE(NdbDir-t

=== modified file 'storage/ndb/src/common/portlib/Makefile.am'
--- a/storage/ndb/src/common/portlib/Makefile.am	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/src/common/portlib/Makefile.am	2011-09-27 17:28:13 +0000
@@ -21,7 +21,8 @@ libportlib_la_SOURCES = \
 	NdbCondition.c NdbMutex.c NdbTick.c \
 	NdbEnv.c NdbThread.c NdbHost.c NdbTCP.cpp	    \
 	ndb_daemon.cc NdbMem.c \
-	NdbConfig.c NdbDir.cpp ndb_socket.cpp
+	NdbConfig.c NdbDir.cpp ndb_socket.cpp \
+        NdbMutex_DeadlockDetector.cpp
 
 include $(top_srcdir)/storage/ndb/config/common.mk.am
 include $(top_srcdir)/storage/ndb/config/type_util.mk.am

=== modified file 'storage/ndb/src/common/portlib/NdbCondition.c'
--- a/storage/ndb/src/common/portlib/NdbCondition.c	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/src/common/portlib/NdbCondition.c	2011-09-28 10:04:03 +0000
@@ -27,6 +27,10 @@ static int init = 0;
 static int clock_id = CLOCK_REALTIME;
 #endif
 
+#if defined NDB_MUTEX_STAT || defined NDB_MUTEX_DEADLOCK_DETECTOR
+#define NDB_MUTEX_STRUCT
+#endif
+
 void
 NdbCondition_initialize(int need_monotonic)
 {
@@ -129,7 +133,7 @@ NdbCondition_Wait(struct NdbCondition* p
   if (p_cond == NULL || p_mutex == NULL)
     return 1;
   
-#ifdef NDB_MUTEX_STAT
+#ifdef NDB_MUTEX_STRUCT
   result = pthread_cond_wait(&p_cond->cond, &p_mutex->mutex);
 #else
   result = pthread_cond_wait(&p_cond->cond, p_mutex);
@@ -187,17 +191,23 @@ NdbCondition_WaitTimeoutAbs(struct NdbCo
                             const struct timespec * abstime)
 {
 #ifdef NDB_WIN
+  /**
+   * mysys windows wrapper of pthread_cond_timedwait
+   *   does not have a const argument for the timespec
+   */
   struct timespec tmp = *abstime;
-  abstime = &tmp;
+  struct timespec * waitarg = &tmp;
+#else
+  const struct timespec * waitarg = abstime;
 #endif
 
   if (p_cond == NULL || p_mutex == NULL)
     return 1;
 
-#ifdef NDB_MUTEX_STAT
-  return pthread_cond_timedwait(&p_cond->cond, &p_mutex->mutex, abstime);
+#ifdef NDB_MUTEX_STRUCT
+  return pthread_cond_timedwait(&p_cond->cond, &p_mutex->mutex, waitarg);
 #else
-  return pthread_cond_timedwait(&p_cond->cond, p_mutex, abstime);
+  return pthread_cond_timedwait(&p_cond->cond, p_mutex, waitarg);
 #endif
 }
 

=== modified file 'storage/ndb/src/common/portlib/NdbMutex.c'
--- a/storage/ndb/src/common/portlib/NdbMutex.c	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/src/common/portlib/NdbMutex.c	2011-09-27 17:28:13 +0000
@@ -21,10 +21,34 @@
 #include <NdbMutex.h>
 #include <NdbMem.h>
 
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+#include "NdbMutex_DeadlockDetector.h"
+#endif
+
 #ifdef NDB_MUTEX_STAT
 static FILE * statout = 0;
 #endif
 
+#if defined NDB_MUTEX_STAT || defined NDB_MUTEX_DEADLOCK_DETECTOR
+#define NDB_MUTEX_STRUCT
+#endif
+
+void
+NdbMutex_SysInit()
+{
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  NdbMutex_DeadlockDetectorInit();
+#endif
+}
+
+void
+NdbMutex_SysEnd()
+{
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  NdbMutex_DeadlockDetectorEnd();
+#endif
+}
+
 NdbMutex* NdbMutex_Create()
 {
   return NdbMutex_CreateWithName(0);
@@ -59,12 +83,15 @@ int NdbMutex_InitWithName(NdbMutex* pNdb
   int result;
   pthread_mutex_t * p;
   DBUG_ENTER("NdbMutex_Init");
+  (void)name;
 
-#ifdef NDB_MUTEX_STAT
+#ifdef NDB_MUTEX_STRUCT
   bzero(pNdbMutex, sizeof(NdbMutex));
+  p = &pNdbMutex->mutex;
+
+#ifdef NDB_MUTEX_STAT
   pNdbMutex->min_lock_wait_time_ns = ~(Uint64)0;
   pNdbMutex->min_hold_time_ns = ~(Uint64)0;
-  p = &pNdbMutex->mutex;
   if (name == 0)
   {
     snprintf(pNdbMutex->name, sizeof(pNdbMutex->name), "%p",
@@ -79,9 +106,10 @@ int NdbMutex_InitWithName(NdbMutex* pNdb
   {
     statout = stdout;
   }
+#endif
+
 #else
   p = pNdbMutex;
-  (void)name;
 #endif
 
 #if defined(VM_TRACE) && \
@@ -99,6 +127,13 @@ int NdbMutex_InitWithName(NdbMutex* pNdb
 #else
   result = pthread_mutex_init(p, 0);
 #endif
+
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  if (result == 0)
+  {
+    ndb_mutex_created(pNdbMutex);
+  }
+#endif
   DBUG_RETURN(result);
 }
 
@@ -109,7 +144,11 @@ int NdbMutex_Destroy(NdbMutex* p_mutex)
   if (p_mutex == NULL)
     return -1;
 
-#ifdef NDB_MUTEX_STAT
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  ndb_mutex_destoyed(p_mutex);
+#endif
+
+#ifdef NDB_MUTEX_STRUCT
   result = pthread_mutex_destroy(&p_mutex->mutex);
 #else
   result = pthread_mutex_destroy(p_mutex);
@@ -201,11 +240,17 @@ int NdbMutex_Lock(NdbMutex* p_mutex)
     p_mutex->cnt_lock++;
     p_mutex->lock_start_time_ns = stop;
   }
+#elif defined NDB_MUTEX_STRUCT
+  result = pthread_mutex_lock(&p_mutex->mutex);
 #else
   result = pthread_mutex_lock(p_mutex);
 #endif
   assert(result == 0);
 
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  ndb_mutex_locked(p_mutex);
+#endif
+
   return result;
 }
 
@@ -234,11 +279,17 @@ int NdbMutex_Unlock(NdbMutex* p_mutex)
       dumpstat(p_mutex);
     }
   }
+#elif defined NDB_MUTEX_STRUCT
+  result = pthread_mutex_unlock(&p_mutex->mutex);
 #else
   result = pthread_mutex_unlock(p_mutex);
 #endif
   assert(result == 0);
 
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  ndb_mutex_unlocked(p_mutex);
+#endif
+
   return result;
 }
 
@@ -261,11 +312,21 @@ int NdbMutex_Trylock(NdbMutex* p_mutex)
   {
     __sync_fetch_and_add(&p_mutex->cnt_trylock_nok, 1);
   }
+#elif defined NDB_MUTEX_STRUCT
+  result = pthread_mutex_trylock(&p_mutex->mutex);
 #else
   result = pthread_mutex_trylock(p_mutex);
 #endif
   assert(result == 0 || result == EBUSY);
 
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  if (result == 0)
+  {
+    ndb_mutex_try_locked(p_mutex);
+  }
+#endif
+
+
   return result;
 }
 

=== added file 'storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp'
--- a/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.cpp	2011-09-27 17:28:13 +0000
@@ -0,0 +1,422 @@
+/*
+   Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#include <NdbMutex.h>
+#include <NdbThread.h>
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+
+#include "NdbMutex_DeadlockDetector.h"
+
+#define NDB_THREAD_TLS_SELF NDB_THREAD_TLS_MAX
+
+static NdbMutex g_mutex_no_mutex; // We need a mutex to assign numbers to mutexes...
+static nmdd_mask g_mutex_no_mask = { 0, 0 };
+
+static unsigned alloc_mutex_no();
+static void release_mutex_no(unsigned no);
+
+static NdbMutex* get_element(struct nmdd_mutex_array *, unsigned i);
+static void add_mutex_to_array(struct nmdd_mutex_array *, NdbMutex*);
+static void remove_mutex_from_array(struct nmdd_mutex_array *, NdbMutex*);
+
+static void set_bit(struct nmdd_mask *, unsigned no);
+static void clear_bit(struct nmdd_mask* , unsigned no);
+static bool check_bit(const struct nmdd_mask* , unsigned no);
+
+static void release(struct nmdd_mutex_array *);
+static void release(struct nmdd_mask*);
+
+extern "C"
+void
+NdbMutex_DeadlockDetectorInit()
+{
+  NdbMutex_Init(&g_mutex_no_mutex);
+}
+
+extern "C"
+void
+NdbMutex_DeadlockDetectorEnd()
+{
+  release(&g_mutex_no_mask);
+}
+
+extern "C"
+void
+ndb_mutex_created(NdbMutex* p)
+{
+  p->m_mutex_state = (ndb_mutex_state*)malloc(sizeof(ndb_mutex_state));
+  bzero(p->m_mutex_state, sizeof(ndb_mutex_state));
+
+  /**
+   * Assign mutex no
+   */
+  p->m_mutex_state->m_no = alloc_mutex_no();
+}
+
+extern "C"
+void
+ndb_mutex_destoyed(NdbMutex* p)
+{
+  unsigned no = p->m_mutex_state->m_no;
+
+  /**
+   * In order to be able to reuse mutex_no,
+   *   we need to clear this no from all mutexes that has it in before map...
+   *   this is all mutexes in after map
+   */
+  for (unsigned i = 0; i<p->m_mutex_state->m_locked_after_list.m_used; i++)
+  {
+    NdbMutex * m = get_element(&p->m_mutex_state->m_locked_after_list, i);
+    assert(check_bit(&p->m_mutex_state->m_locked_after_mask, m->m_mutex_state->m_no));
+
+    /**
+     * And we need to lock it while doing this
+     */
+    NdbMutex_Lock(m);
+    assert(check_bit(&m->m_mutex_state->m_locked_before_mask, no));
+    clear_bit(&m->m_mutex_state->m_locked_before_mask, no);
+    remove_mutex_from_array(&m->m_mutex_state->m_locked_before_list, p);
+    NdbMutex_Unlock(m);
+  }
+
+  /**
+   * And we need to remove ourselfs from after list of mutexes in out before list
+   */
+  for (unsigned i = 0; i<p->m_mutex_state->m_locked_before_list.m_used; i++)
+  {
+    NdbMutex * m = get_element(&p->m_mutex_state->m_locked_before_list, i);
+    NdbMutex_Lock(m);
+    assert(check_bit(&m->m_mutex_state->m_locked_after_mask, no));
+    clear_bit(&m->m_mutex_state->m_locked_after_mask, no);
+    remove_mutex_from_array(&m->m_mutex_state->m_locked_after_list, p);
+    NdbMutex_Unlock(m);
+  }
+
+  release(&p->m_mutex_state->m_locked_before_mask);
+  release(&p->m_mutex_state->m_locked_before_list);
+  release(&p->m_mutex_state->m_locked_after_mask);
+  release(&p->m_mutex_state->m_locked_after_list);
+  release_mutex_no(no);
+}
+
+static
+ndb_mutex_thr_state*
+get_thr()
+{
+  void * p = NdbThread_GetTlsKey(NDB_THREAD_TLS_SELF);
+  return (ndb_mutex_thr_state*)p;
+}
+
+#define INC_SIZE 16
+
+static
+void
+add_lock_to_thread(ndb_mutex_thr_state * t, NdbMutex * m)
+{
+  add_mutex_to_array(&t->m_mutexes_locked, m);
+}
+
+static
+void
+add_lock_to_mutex_before_list(ndb_mutex_state * m1, NdbMutex * m2)
+{
+  assert(m1 != m2->m_mutex_state);
+  unsigned no = m2->m_mutex_state->m_no;
+  if (!check_bit(&m1->m_locked_before_mask, no))
+  {
+    set_bit(&m1->m_locked_before_mask, no);
+    add_mutex_to_array(&m1->m_locked_before_list, m2);
+  }
+}
+
+static
+void
+add_lock_to_mutex_after_list(ndb_mutex_state * m1, NdbMutex* m2)
+{
+  assert(m1 != m2->m_mutex_state);
+  unsigned no = m2->m_mutex_state->m_no;
+  if (!check_bit(&m1->m_locked_after_mask, no))
+  {
+    set_bit(&m1->m_locked_after_mask, no);
+    add_mutex_to_array(&m1->m_locked_after_list, m2);
+  }
+}
+
+extern "C"
+void
+ndb_mutex_locked(NdbMutex* p)
+{
+  ndb_mutex_state * m = p->m_mutex_state;
+  ndb_mutex_thr_state * thr = get_thr();
+  if (thr == 0)
+  {
+    /**
+     * These are threads not started with NdbThread_Create(...)
+     *   e.g mysql-server threads...ignore these for now
+     */
+    return;
+  }
+
+  for (unsigned i = 0; i < thr->m_mutexes_locked.m_used; i++)
+  {
+    /**
+     * We want to lock m
+     * Check that none of the mutex we curreny have locked
+     *   have m in their *before* list
+     */
+    NdbMutex * h = get_element(&thr->m_mutexes_locked, i);
+    if (check_bit(&h->m_mutex_state->m_locked_before_mask, m->m_no))
+    {
+      abort();
+    }
+
+    /**
+     * Add h to m's list of before-locks
+     */
+    add_lock_to_mutex_before_list(m, h);
+
+    /**
+     * Add m to h's list of after locks
+     */
+    add_lock_to_mutex_after_list(h->m_mutex_state, p);
+  }
+
+  add_lock_to_thread(thr, p);
+}
+
+extern "C"
+void
+ndb_mutex_unlocked(NdbMutex* m)
+{
+  ndb_mutex_thr_state * thr = get_thr();
+  if (thr == 0)
+  {
+    /**
+     * These are threads not started with NdbThread_Create(...)
+     *   e.g mysql-server threads...ignore these for now
+     */
+    return;
+  }
+  unsigned pos = thr->m_mutexes_locked.m_used;
+  assert(pos > 0);
+  assert(get_element(&thr->m_mutexes_locked, pos-1) == m);
+  thr->m_mutexes_locked.m_used --;
+}
+
+extern "C"
+void
+ndb_mutex_try_locked(NdbMutex* p)
+{
+
+}
+
+extern "C"
+void
+ndb_mutex_thread_init(struct ndb_mutex_thr_state* p)
+{
+  bzero(p, sizeof(* p));
+  NdbThread_SetTlsKey(NDB_THREAD_TLS_SELF, p);
+}
+
+extern "C"
+void
+ndb_mutex_thread_exit()
+{
+  ndb_mutex_thr_state * thr = get_thr();
+  if (thr == 0)
+  {
+    /**
+     * These are threads not started with NdbThread_Create(...)
+     *   e.g mysql-server threads...ignore these for now
+     */
+    return;
+  }
+  release(&thr->m_mutexes_locked);
+}
+
+/**
+ * util
+ */
+static
+void
+set_bit(nmdd_mask * mask, unsigned no)
+{
+  unsigned byte_no = no / 8;
+  unsigned bit_no = no & 7;
+  if (byte_no >= mask->m_len)
+  {
+    unsigned new_len = mask->m_len + INC_SIZE;
+    if (byte_no >= new_len)
+    {
+      new_len = byte_no + 1;
+    }
+    unsigned char * new_arr = (unsigned char*)malloc(new_len);
+    bzero(new_arr, new_len);
+    if (mask->m_len != 0)
+    {
+      memcpy(new_arr, mask->m_mask, mask->m_len);
+      free(mask->m_mask);
+    }
+    mask->m_len = new_len;
+    mask->m_mask = new_arr;
+  }
+
+  mask->m_mask[byte_no] |= (1 << bit_no);
+}
+
+static
+void
+clear_bit(nmdd_mask * mask, unsigned no)
+{
+  unsigned byte_no = no / 8;
+  unsigned bit_no = no & 7;
+  if (byte_no >= mask->m_len)
+  {
+    return;
+  }
+
+  mask->m_mask[byte_no] &= ~(unsigned char)(1 << bit_no);
+}
+
+static
+bool
+check_bit(const nmdd_mask * mask, unsigned no)
+{
+  unsigned byte_no = no / 8;
+  unsigned bit_no = no & 7;
+  if (byte_no >= mask->m_len)
+  {
+    return false;
+  }
+
+  return (mask->m_mask[byte_no] & (1 << bit_no)) != 0;
+}
+
+static
+void
+release(nmdd_mask * mask)
+{
+  if (mask->m_len != 0)
+  {
+    free(mask->m_mask);
+  }
+}
+
+static
+NdbMutex*
+get_element(nmdd_mutex_array* arr, unsigned i)
+{
+  assert(i < arr->m_used);
+  return arr->m_array[i];
+}
+
+static
+void
+add_mutex_to_array(nmdd_mutex_array* arr, NdbMutex* m)
+{
+  unsigned pos = arr->m_used;
+  if (arr->m_used == arr->m_array_len)
+  {
+    unsigned new_len = arr->m_array_len + INC_SIZE;
+    NdbMutex** new_arr = (NdbMutex**)malloc(new_len * sizeof(NdbMutex*));
+    if (arr->m_array_len != 0)
+    {
+      memcpy(new_arr, arr->m_array, arr->m_array_len * sizeof(NdbMutex*));
+      free(arr->m_array);
+    }
+    arr->m_array = new_arr;
+    arr->m_array_len = new_len;
+  }
+  for (unsigned i = 0; i<arr->m_used; i++)
+    assert(arr->m_array[i] != m);
+
+  arr->m_array[pos] = m;
+  arr->m_used++;
+}
+
+static
+void
+remove_mutex_from_array(nmdd_mutex_array* arr, NdbMutex* m)
+{
+  for (unsigned i = 0; i < arr->m_used; i++)
+  {
+    unsigned idx = arr->m_used - i - 1;
+    if (arr->m_array[idx] == m)
+    {
+      memmove(arr->m_array+idx,
+              arr->m_array + idx + 1,
+              i * sizeof(NdbMutex*));
+      arr->m_used--;
+      return;
+    }
+  }
+  assert(false);
+}
+
+static
+void
+release(nmdd_mutex_array* arr)
+{
+  if (arr->m_array_len)
+  {
+    free(arr->m_array);
+  }
+}
+
+static
+unsigned
+ff(unsigned char b)
+{
+  for (unsigned i = 0; i<8; i++)
+    if ((b & (1 << i)) == 0)
+      return i;
+  assert(false);
+}
+
+static
+unsigned
+alloc_mutex_no()
+{
+  Guard g(&g_mutex_no_mutex);
+  unsigned no = 0;
+
+  for (unsigned i = 0; i < g_mutex_no_mask.m_len; i++)
+  {
+    if (g_mutex_no_mask.m_mask[i] != 255)
+    {
+      no = (8 * i) + ff(g_mutex_no_mask.m_mask[i]);
+      goto found;
+    }
+  }
+
+  no = 8 * g_mutex_no_mask.m_len;
+found:
+  set_bit(&g_mutex_no_mask, no);
+  assert(check_bit(&g_mutex_no_mask, no));
+  return no;
+}
+
+static
+void
+release_mutex_no(unsigned no)
+{
+  Guard g(&g_mutex_no_mutex);
+  assert(check_bit(&g_mutex_no_mask, no));
+  clear_bit(&g_mutex_no_mask, no);
+}
+
+#endif

=== added file 'storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h'
--- a/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/portlib/NdbMutex_DeadlockDetector.h	2011-09-27 17:28:13 +0000
@@ -0,0 +1,73 @@
+/*
+   Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#ifndef NDB_MUTEX_DEADLOCK_DETECTOR_H
+#define NDB_MUTEX_DEADLOCK_DETECTOR_H
+
+#include <NdbMutex.h>
+
+struct nmdd_mask
+{
+  unsigned char * m_mask;
+  unsigned m_len;
+};
+
+struct nmdd_mutex_array
+{
+  NdbMutex ** m_array;
+  unsigned m_used;
+  unsigned m_array_len;
+};
+
+struct ndb_mutex_state
+{
+  struct nmdd_mask m_locked_before_mask; /* mutexes held when locking this mutex */
+  struct nmdd_mutex_array m_locked_before_list; /* mutexes held when locking this mutex */
+
+  struct nmdd_mutex_array m_locked_after_list; /* mutexes locked when holding this mutex*/
+  struct nmdd_mask m_locked_after_mask;        /* mask (for quick check) */
+
+  unsigned m_no; /* my mutex "id" (for access in masks) */
+};
+
+struct ndb_mutex_thr_state
+{
+  struct nmdd_mutex_array m_mutexes_locked;
+};
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+  void NdbMutex_DeadlockDetectorInit();
+  void NdbMutex_DeadlockDetectorEnd();
+
+  void ndb_mutex_created(NdbMutex*);
+  void ndb_mutex_destoyed(NdbMutex*);
+  void ndb_mutex_locked(NdbMutex*);
+  void ndb_mutex_unlocked(NdbMutex*);
+  void ndb_mutex_try_locked(NdbMutex*);
+
+  void ndb_mutex_thread_init(struct ndb_mutex_thr_state*);
+  void ndb_mutex_thread_exit();
+
+#ifdef	__cplusplus
+}
+#endif
+
+
+#endif

=== modified file 'storage/ndb/src/common/portlib/NdbThread.c'
--- a/storage/ndb/src/common/portlib/NdbThread.c	2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/common/portlib/NdbThread.c	2011-09-27 17:28:13 +0000
@@ -38,6 +38,10 @@
 #include <sys/procset.h>
 #endif
 
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+#include "NdbMutex_DeadlockDetector.h"
+#endif
+
 static int g_min_prio = 0;
 static int g_max_prio = 0;
 static int g_prio = 0;
@@ -65,6 +69,9 @@ struct NdbThread 
   char thread_name[16];
   NDB_THREAD_FUNC * func;
   void * object;
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  struct ndb_mutex_thr_state m_mutex_thr_state;
+#endif
 };
 
 #ifdef NDB_SHM_TRANSPORTER
@@ -141,6 +148,11 @@ ndb_thread_wrapper(void* _ss){
       void *ret;
       struct NdbThread * ss = (struct NdbThread *)_ss;
       settid(ss);
+
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+      ndb_mutex_thread_init(&ss->m_mutex_thr_state);
+#endif
+
       NdbMutex_Lock(g_ndb_thread_mutex);
       ss->inited = 1;
       NdbCondition_Signal(g_ndb_thread_condition);
@@ -154,6 +166,7 @@ ndb_thread_wrapper(void* _ss){
   }
 }
 
+static struct NdbThread* g_main_thread = 0;
 
 struct NdbThread*
 NdbThread_CreateObject(const char * name)
@@ -161,6 +174,15 @@ NdbThread_CreateObject(const char * name
   struct NdbThread* tmpThread;
   DBUG_ENTER("NdbThread_Create");
 
+  if (g_main_thread != 0)
+  {
+    if (name)
+    {
+      strnmov(g_main_thread->thread_name, name, sizeof(tmpThread->thread_name));
+    }
+    DBUG_RETURN(g_main_thread);
+  }
+
   tmpThread = (struct NdbThread*)NdbMem_Allocate(sizeof(struct NdbThread));
   if (tmpThread == NULL)
     DBUG_RETURN(NULL);
@@ -183,7 +205,12 @@ NdbThread_CreateObject(const char * name
   settid(tmpThread);
   tmpThread->inited = 1;
 
-  return tmpThread;
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  ndb_mutex_thread_init(&tmpThread->m_mutex_thr_state);
+#endif
+
+  g_main_thread = tmpThread;
+  DBUG_RETURN(tmpThread);
 }
 
 struct NdbThread*
@@ -239,7 +266,7 @@ NdbThread_Create(NDB_THREAD_FUNC *p_thre
   tmpThread->object= p_thread_arg;
 
   NdbMutex_Lock(g_ndb_thread_mutex);
-  result = pthread_create(&tmpThread->thread, 
+  result = pthread_create(&tmpThread->thread,
 			  &thread_attr,
   		          ndb_thread_wrapper,
   		          tmpThread);
@@ -250,7 +277,7 @@ NdbThread_Create(NDB_THREAD_FUNC *p_thre
   {
     NdbMem_Free((char *)tmpThread);
     NdbMutex_Unlock(g_ndb_thread_mutex);
-    return 0;
+    DBUG_RETURN(0);
   }
 
   if (thread_prio == NDB_THREAD_PRIO_HIGH && f_high_prio_set)
@@ -471,7 +498,11 @@ NdbThread_LockCPU(struct NdbThread* pThr
   return error_no;
 }
 
+#ifndef NDB_MUTEX_DEADLOCK_DETECTOR
 static pthread_key(void*, tls_keys[NDB_THREAD_TLS_MAX]);
+#else
+static pthread_key(void*, tls_keys[NDB_THREAD_TLS_MAX + 1]);
+#endif
 
 void *NdbThread_GetTlsKey(NDB_THREAD_TLS key)
 {
@@ -490,6 +521,10 @@ NdbThread_Init()
   g_ndb_thread_condition = NdbCondition_Create();
   pthread_key_create(&(tls_keys[NDB_THREAD_TLS_JAM]), NULL);
   pthread_key_create(&(tls_keys[NDB_THREAD_TLS_THREAD]), NULL);
+#ifdef NDB_MUTEX_DEADLOCK_DETECTOR
+  pthread_key_create(&(tls_keys[NDB_THREAD_TLS_MAX]), NULL);
+#endif
+  NdbThread_CreateObject(0);
   return 0;
 }
 

=== modified file 'storage/ndb/src/common/util/ndb_init.cpp'
--- a/storage/ndb/src/common/util/ndb_init.cpp	2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/common/util/ndb_init.cpp	2011-09-27 17:28:13 +0000
@@ -32,6 +32,8 @@ int g_ndb_init_need_monotonic = 0;
 
 static int ndb_init_called = 0;
 
+extern "C" void NdbMutex_SysInit();
+extern "C" void NdbMutex_SysEnd();
 extern "C" void NdbCondition_initialize(int need_monotonic);
 extern "C" void NdbTick_Init(int need_monotonic);
 extern "C" int NdbThread_Init();
@@ -45,6 +47,7 @@ void
 ndb_init_internal()
 {
   NdbOut_Init();
+  NdbMutex_SysInit();
   if (!g_ndb_connection_mutex)
     g_ndb_connection_mutex = NdbMutex_Create();
   if (!g_eventLogger)
@@ -88,7 +91,6 @@ ndb_init()
 void
 ndb_end_internal()
 {
-  NdbThread_End();
   if (g_ndb_connection_mutex) 
   {
     NdbMutex_Destroy(g_ndb_connection_mutex);
@@ -96,6 +98,9 @@ ndb_end_internal()
   }
   if (g_eventLogger)
     destroy_event_logger(&g_eventLogger);
+
+  NdbThread_End();
+  NdbMutex_SysEnd();
 }
 
 void

=== modified file 'storage/ndb/src/kernel/SimBlockList.cpp'
--- a/storage/ndb/src/kernel/SimBlockList.cpp	2011-08-29 10:15:59 +0000
+++ b/storage/ndb/src/kernel/SimBlockList.cpp	2011-09-29 13:07:26 +0000
@@ -49,6 +49,8 @@
 #include <BackupProxy.hpp>
 #include <RestoreProxy.hpp>
 #include <PgmanProxy.hpp>
+#include <DbtcProxy.hpp>
+#include <DbspjProxy.hpp>
 #include <mt.hpp>
 
 #ifndef VM_TRACE
@@ -128,7 +130,10 @@ SimBlockList::load(EmulatorData& data){
     theList[8]  = NEW_BLOCK(Dblqh)(ctx);
   else
     theList[8]  = NEW_BLOCK(DblqhProxy)(ctx);
-  theList[9]  = NEW_BLOCK(Dbtc)(ctx);
+  if (globalData.ndbMtTcThreads == 0)
+    theList[9]  = NEW_BLOCK(Dbtc)(ctx);
+  else
+    theList[9] = NEW_BLOCK(DbtcProxy)(ctx);
   if (!mtLqh)
     theList[10] = NEW_BLOCK(Dbtup)(ctx);
   else
@@ -151,18 +156,12 @@ SimBlockList::load(EmulatorData& data){
   else
     theList[18] = NEW_BLOCK(RestoreProxy)(ctx);
   theList[19] = NEW_BLOCK(Dbinfo)(ctx);
-  theList[20]  = NEW_BLOCK(Dbspj)(ctx);
+  if (globalData.ndbMtTcThreads == 0)
+    theList[20]  = NEW_BLOCK(Dbspj)(ctx);
+  else
+    theList[20]  = NEW_BLOCK(DbspjProxy)(ctx);
   assert(NO_OF_BLOCKS == 21);
 
-  if (globalData.isNdbMt) {
-    add_main_thr_map();
-    if (globalData.isNdbMtLqh) {
-      for (int i = 0; i < noOfBlocks; i++)
-        theList[i]->loadWorkers();
-    }
-    finalize_thr_map();
-  }
-
   // Check that all blocks could be created
   for (int i = 0; i < noOfBlocks; i++)
   {
@@ -172,6 +171,14 @@ SimBlockList::load(EmulatorData& data){
                 "Failed to create block", "");
     }
   }
+
+  if (globalData.isNdbMt)
+  {
+    add_main_thr_map();
+    for (int i = 0; i < noOfBlocks; i++)
+      theList[i]->loadWorkers();
+    finalize_thr_map();
+  }
 }
 
 void

=== modified file 'storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp	2011-09-15 21:00:03 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp	2011-09-29 13:07:26 +0000
@@ -9018,6 +9018,7 @@ void Dbdih::execDIGETNODESREQ(Signal* si
   TabRecordPtr tabPtr;
   tabPtr.i = req->tableId;
   Uint32 hashValue = req->hashValue;
+  Uint32 distr_key_indicator = req->distr_key_indicator;
   Uint32 ttabFileSize = ctabFileSize;
   Uint32 fragId, newFragId = RNIL;
   DiGetNodesConf * const conf = (DiGetNodesConf *)&signal->theData[0];
@@ -9042,7 +9043,7 @@ loop:
    * of distribution algorithm in use, hashValue
    * IS fragment id.
    */
-  if (req->distr_key_indicator)
+  if (distr_key_indicator)
   {
     fragId = hashValue;
     if (unlikely(fragId >= tabPtr.p->totalfragments))

=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2011-09-24 10:00:49 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2011-09-29 13:07:26 +0000
@@ -3865,7 +3865,8 @@ void Dblqh::sendLqhkeyconfTc(Signal* sig
   {
     lqhKeyConf->connectPtr = tcConnectptr.i;
     if (instance() == refToInstance(atcBlockref) &&
-        (Thostptr.i == 0 || Thostptr.i == getOwnNodeId()))
+        (Thostptr.i == 0 || Thostptr.i == getOwnNodeId()) &&
+        globalData.ndbMtTcThreads == 0)
     {
       /**
        * This EXECUTE_DIRECT is multi-thread safe, as we only get here

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2011-08-22 08:50:01 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2011-09-29 13:07:26 +0000
@@ -580,6 +580,8 @@ public:
     Uint32 m_fragCount;
     // The number of fragments that we scan in parallel.
     Uint32 m_parallelism;
+    // True if we are still receiving the first batch for this operation.
+    bool   m_firstBatch;
     /**
      * True if this is the first instantiation of this operation. A child
      * operation will be instantiated once for each batch of its parent.
@@ -1229,7 +1231,6 @@ private:
   void scanIndex_execSCAN_FRAGCONF(Signal*, Ptr<Request>, Ptr<TreeNode>, Ptr<ScanFragHandle>);
   void scanIndex_parent_row(Signal*,Ptr<Request>,Ptr<TreeNode>, const RowPtr&);
   void scanIndex_fixupBound(Ptr<ScanFragHandle> fragPtr, Uint32 ptrI, Uint32);
-  void scanIndex_send(Signal*,Ptr<Request>,Ptr<TreeNode>);
   void scanIndex_send(Signal* signal,
                       Ptr<Request> requestPtr,
                       Ptr<TreeNode> treeNodePtr,

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2011-09-16 14:37:13 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2011-09-29 13:07:26 +0000
@@ -280,16 +280,15 @@ Dbspj::execAPI_FAILREQ(Signal* signal)
 {
   jamEntry();
   Uint32 failedApiNode = signal->theData[0];
-  ndbrequire(signal->theData[1] == QMGR_REF); // As callback hard-codes QMGR
+  Uint32 ref = signal->theData[1];
 
   /**
    * We only need to care about lookups
    *   as SCAN's are aborted by DBTC
    */
-
   signal->theData[0] = failedApiNode;
   signal->theData[1] = reference();
-  sendSignal(QMGR_REF, GSN_API_FAILCONF, signal, 2, JBB);
+  sendSignal(ref, GSN_API_FAILCONF, signal, 2, JBB);
 }
 
 void
@@ -5024,6 +5023,7 @@ Dbspj::scanIndex_parent_batch_complete(S
   const ScanFragReq * org = (const ScanFragReq*)data.m_scanFragReq;
   ndbrequire(org->batch_size_rows > 0);
 
+  data.m_firstBatch = true;
   if (treeNodePtr.p->m_bits & TreeNode::T_SCAN_PARALLEL)
   {
     jam();
@@ -5172,6 +5172,9 @@ Dbspj::scanIndex_send(Signal* signal,
                       Uint32 bs_rows,
                       Uint32& batchRange)
 {
+  jam();
+  ndbassert(bs_bytes > 0);
+  ndbassert(bs_rows > 0);
   /**
    * if (m_bits & prunemask):
    * - Range keys sliced out to each ScanFragHandle
@@ -5452,6 +5455,9 @@ Dbspj::scanIndex_execSCAN_FRAGCONF(Signa
 
   if (data.m_frags_outstanding == 0)
   {
+    const bool isFirstBatch = data.m_firstBatch;
+    data.m_firstBatch = false;
+
     const ScanFragReq * const org
       = reinterpret_cast<const ScanFragReq*>(data.m_scanFragReq);
 
@@ -5487,24 +5493,78 @@ Dbspj::scanIndex_execSCAN_FRAGCONF(Signa
     {
       jam();
       ndbrequire((requestPtr.p->m_state & Request::RS_ABORTING) != 0);
+      checkBatchComplete(signal, requestPtr, 1);
+      return;
     }
-    else if (! (data.m_rows_received == data.m_rows_expecting))
+
+    if (isFirstBatch && data.m_frags_not_started > 0)
+    {
+      /**
+       * Check if we can expect to be able to fetch the entire result set by
+       * asking for more fragments within the same batch. This may improve 
+       * performance for bushy scans, as subsequent bushy branches must be
+       * re-executed for each batch of this scan.
+       */
+      
+      /**
+       * Find the maximal correlation value that we may have seen so far.
+       * Correlation value must be unique within batch and smaller than 
+       * org->batch_size_rows.
+       */
+      const Uint32 maxCorrVal = (data.m_totalRows) == 0 ? 0 :
+        org->batch_size_rows / data.m_parallelism * (data.m_parallelism - 1)
+        + data.m_totalRows;
+      
+      // Number of rows that we can still fetch in this batch.
+      const Int32 remainingRows 
+        = static_cast<Int32>(org->batch_size_rows - maxCorrVal);
+      
+      if (remainingRows >= data.m_frags_not_started &&
+          /**
+           * Check that (remaning row capacity)/(remaining fragments) is 
+           * greater or equal to (rows read so far)/(finished fragments).
+           */
+          remainingRows * static_cast<Int32>(data.m_parallelism) >=
+          static_cast<Int32>(data.m_totalRows * data.m_frags_not_started) &&
+          (org->batch_size_bytes - data.m_totalBytes) * data.m_parallelism >=
+          data.m_totalBytes * data.m_frags_not_started)
+      {
+        jam();
+        Uint32 batchRange = maxCorrVal;
+        DEBUG("::scanIndex_execSCAN_FRAGCONF() first batch was not full."
+              " Asking for new batches from " << data.m_frags_not_started <<
+              " fragments with " << 
+              remainingRows / data.m_frags_not_started 
+              <<" rows and " << 
+              (org->batch_size_bytes - data.m_totalBytes)
+              / data.m_frags_not_started 
+              << " bytes.");
+        scanIndex_send(signal,
+                       requestPtr,
+                       treeNodePtr,
+                       data.m_frags_not_started,
+                       (org->batch_size_bytes - data.m_totalBytes)
+                       / data.m_frags_not_started,
+                       remainingRows / data.m_frags_not_started,
+                       batchRange);
+        return;
+      }
+    }
+    
+    if (data.m_rows_received != data.m_rows_expecting)
     {
       jam();
       return;
     }
-    else
+    
+    if (treeNodePtr.p->m_bits & TreeNode::T_REPORT_BATCH_COMPLETE)
     {
-      if (treeNodePtr.p->m_bits & TreeNode::T_REPORT_BATCH_COMPLETE)
-      {
-        jam();
-        reportBatchComplete(signal, requestPtr, treeNodePtr);
-      }
+      jam();
+      reportBatchComplete(signal, requestPtr, treeNodePtr);
     }
 
     checkBatchComplete(signal, requestPtr, 1);
-    return;
-  }
+  } // if (data.m_frags_outstanding == 0)
 }
 
 void

=== modified file 'storage/ndb/src/kernel/ndbd.cpp'
--- a/storage/ndb/src/kernel/ndbd.cpp	2011-09-08 11:49:24 +0000
+++ b/storage/ndb/src/kernel/ndbd.cpp	2011-09-23 09:13:22 +0000
@@ -310,7 +310,9 @@ get_multithreaded_config(EmulatorData& e
     return 0;
 
   ndbout << "NDBMT: workers=" << globalData.ndbMtLqhWorkers
-         << " threads=" << globalData.ndbMtLqhThreads << endl;
+         << " threads=" << globalData.ndbMtLqhThreads
+         << " tc=" << globalData.ndbMtTcThreads
+         << endl;
 
   return 0;
 }

=== modified file 'storage/ndb/src/kernel/vm/ArrayPool.hpp'
--- a/storage/ndb/src/kernel/vm/ArrayPool.hpp	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/src/kernel/vm/ArrayPool.hpp	2011-09-27 06:44:06 +0000
@@ -1385,7 +1385,7 @@ UnsafeArrayPool<T>::getPtrForce(ConstPtr
 template <class T>
 class SafeArrayPool : public ArrayPool<T> {
 public:
-  SafeArrayPool(NdbMutex* mutex = 0);
+  SafeArrayPool();
   ~SafeArrayPool();
   int lock();
   int unlock();
@@ -1393,6 +1393,8 @@ public:
   void release(Uint32 i);
   void release(Ptr<T>&);
 
+  void setMutex(NdbMutex* mutex = 0);
+
 private:
   NdbMutex* m_mutex;
   bool m_mutex_owner;
@@ -1403,7 +1405,16 @@ private:
 
 template <class T>
 inline
-SafeArrayPool<T>::SafeArrayPool(NdbMutex* mutex)
+SafeArrayPool<T>::SafeArrayPool()
+{
+  m_mutex = 0;
+  m_mutex_owner = false;
+}
+
+template <class T>
+inline
+void
+SafeArrayPool<T>::setMutex(NdbMutex* mutex)
 {
   if (mutex != 0) {
     m_mutex = mutex;

=== modified file 'storage/ndb/src/kernel/vm/Configuration.cpp'
--- a/storage/ndb/src/kernel/vm/Configuration.cpp	2011-09-13 09:10:52 +0000
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp	2011-09-23 09:13:22 +0000
@@ -436,18 +436,21 @@ Configuration::setupConfiguration(){
                 m_thr_config.getErrorMessage());
     }
   }
-  if (thrconfigstring)
+  if (NdbIsMultiThreaded())
   {
-    ndbout_c("ThreadConfig: input: %s LockExecuteThreadToCPU: %s => parsed: %s",
-             thrconfigstring,
-             lockmask ? lockmask : "",
-             m_thr_config.getConfigString());
-  }
-  else
-  {
-    ndbout_c("ThreadConfig (old ndb_mgmd) LockExecuteThreadToCPU: %s => parsed: %s",
-             lockmask ? lockmask : "",
-             m_thr_config.getConfigString());
+    if (thrconfigstring)
+    {
+      ndbout_c("ThreadConfig: input: %s LockExecuteThreadToCPU: %s => parsed: %s",
+               thrconfigstring,
+               lockmask ? lockmask : "",
+               m_thr_config.getConfigString());
+    }
+    else
+    {
+      ndbout_c("ThreadConfig (old ndb_mgmd) LockExecuteThreadToCPU: %s => parsed: %s",
+               lockmask ? lockmask : "",
+               m_thr_config.getConfigString());
+    }
   }
 
   ConfigValues* cf = ConfigValuesFactory::extractCurrentSection(iter.m_config);
@@ -466,6 +469,7 @@ Configuration::setupConfiguration(){
     if (!globalData.isNdbMt)
       break;
 
+    globalData.ndbMtTcThreads = m_thr_config.getThreadCount(THRConfig::T_TC);
     globalData.isNdbMtLqh = true;
     {
       if (m_thr_config.getMtClassic())

=== modified file 'storage/ndb/src/kernel/vm/Emulator.cpp'
--- a/storage/ndb/src/kernel/vm/Emulator.cpp	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/src/kernel/vm/Emulator.cpp	2011-09-27 06:44:06 +0000
@@ -89,6 +89,7 @@ EmulatorData::create(){
   theSimBlockList  = new SimBlockList();
   m_socket_server  = new SocketServer();
   m_mem_manager    = new Ndbd_mem_manager();
+  globalData.m_global_page_pool.setMutex();
 
   if (theConfiguration == NULL ||
       theWatchDog == NULL ||

=== modified file 'storage/ndb/src/kernel/vm/mt_thr_config.cpp'
--- a/storage/ndb/src/kernel/vm/mt_thr_config.cpp	2011-09-04 08:52:42 +0000
+++ b/storage/ndb/src/kernel/vm/mt_thr_config.cpp	2011-09-23 09:13:22 +0000
@@ -32,7 +32,8 @@ static const struct THRConfig::Entries m
   { "ldm",   THRConfig::T_LDM,   1, MAX_NDBMT_LQH_THREADS },
   { "recv",  THRConfig::T_RECV,  1, 1 },
   { "rep",   THRConfig::T_REP,   1, 1 },
-  { "io",    THRConfig::T_IO,    1, 1 }
+  { "io",    THRConfig::T_IO,    1, 1 },
+  { "tc",    THRConfig::T_TC,    0, MAX_NDBMT_TC_THREADS }
 };
 
 static const struct THRConfig::Param m_params[] =
@@ -140,6 +141,7 @@ THRConfig::do_parse(unsigned MaxNoOfExec
     return do_bindings();
   }
 
+  Uint32 tcthreads = 0;
   Uint32 lqhthreads = 0;
   switch(MaxNoOfExecutionThreads){
   case 0:
@@ -171,6 +173,11 @@ THRConfig::do_parse(unsigned MaxNoOfExec
     add(T_LDM);
   }
 
+  for(Uint32 i = 0; i < tcthreads; i++)
+  {
+    add(T_TC);
+  }
+
   return do_bindings() || do_validate();
 }
 
@@ -283,6 +290,13 @@ THRConfig::do_bindings()
                         "LockExecuteThreadToCPU. Only %u specified "
                         " but %u was needed, this may cause contention.\n",
                         cnt, num_threads);
+
+      if (count_unbound(m_threads[T_TC]))
+      {
+        m_err_msg.assfmt("Too CPU specifed with LockExecuteThreadToCPU. "
+                         "This is not supported when using multiple TC threads");
+        return -1;
+      }
     }
 
     if (cnt >= num_threads)
@@ -867,7 +881,13 @@ THRConfig::do_parse(const char * ThreadC
       add((T_Type)i);
   }
 
-  return do_bindings() || do_validate();
+  int res = do_bindings();
+  if (res != 0)
+  {
+    return res;
+  }
+
+  return do_validate();
 }
 
 unsigned
@@ -916,6 +936,10 @@ THRConfigApplier::find_thread(const unsi
   {
     return &m_threads[T_MAIN][instanceNo];
   }
+  else if ((instanceNo = findBlock(DBTC, instancelist, cnt)) >= 0)
+  {
+    return &m_threads[T_TC][instanceNo - 1]; // remove proxy
+  }
   else if ((instanceNo = findBlock(DBLQH, instancelist, cnt)) >= 0)
   {
     return &m_threads[T_LDM][instanceNo - 1]; // remove proxy...
@@ -1014,6 +1038,8 @@ TAPTEST(mt_thr_config)
         "ldm={count=3,cpubind=1-2,5 },  ldm",
         "ldm={cpuset=1-3,count=3 },ldm",
         "main,ldm={},ldm",
+        "main,ldm={},ldm,tc",
+        "main,ldm={},ldm,tc,tc",
         0
       };
 
@@ -1026,6 +1052,7 @@ TAPTEST(mt_thr_config)
         "main={ keso=88, count=23},ldm,ldm",
         "main={ cpuset=1-3 }, ldm={cpuset=3-4}",
         "main={ cpuset=1-3 }, ldm={cpubind=2}",
+        "tc,tc,tc",
         0
       };
 
@@ -1065,45 +1092,71 @@ TAPTEST(mt_thr_config)
       /** threads, LockExecuteThreadToCPU, answer */
       "1-8",
       "ldm={count=4}",
+      "OK",
       "main={cpubind=1},ldm={cpubind=2},ldm={cpubind=3},ldm={cpubind=4},ldm={cpubind=5},recv={cpubind=6},rep={cpubind=7}",
 
       "1-5",
       "ldm={count=4}",
+      "OK",
       "main={cpubind=5},ldm={cpubind=1},ldm={cpubind=2},ldm={cpubind=3},ldm={cpubind=4},recv={cpubind=5},rep={cpubind=5}",
 
       "1-3",
       "ldm={count=4}",
+      "OK",
       "main={cpubind=1},ldm={cpubind=2},ldm={cpubind=3},ldm={cpubind=2},ldm={cpubind=3},recv={cpubind=1},rep={cpubind=1}",
 
       "1-4",
       "ldm={count=4}",
+      "OK",
       "main={cpubind=1},ldm={cpubind=2},ldm={cpubind=3},ldm={cpubind=4},ldm={cpubind=2},recv={cpubind=1},rep={cpubind=1}",
 
       "1-8",
       "ldm={count=4},io={cpubind=8}",
+      "OK",
       "main={cpubind=1},ldm={cpubind=2},ldm={cpubind=3},ldm={cpubind=4},ldm={cpubind=5},recv={cpubind=6},rep={cpubind=7},io={cpubind=8}",
 
       "1-8",
       "ldm={count=4,cpubind=1,4,5,6}",
+      "OK",
       "main={cpubind=2},ldm={cpubind=1},ldm={cpubind=4},ldm={cpubind=5},ldm={cpubind=6},recv={cpubind=3},rep={cpubind=7}",
 
+      "1-9",
+      "ldm={count=4,cpubind=1,4,5,6},tc,tc",
+      "OK",
+      "main={cpubind=2},ldm={cpubind=1},ldm={cpubind=4},ldm={cpubind=5},ldm={cpubind=6},recv={cpubind=3},rep={cpubind=7},tc={cpubind=8},tc={cpubind=9}",
+
+      "1-8",
+      "ldm={count=4,cpubind=1,4,5,6},tc",
+      "OK",
+      "main={cpubind=2},ldm={cpubind=1},ldm={cpubind=4},ldm={cpubind=5},ldm={cpubind=6},recv={cpubind=3},rep={cpubind=7},tc={cpubind=8}",
+
+      "1-8",
+      "ldm={count=4,cpubind=1,4,5,6},tc,tc",
+      "FAIL",
+      "Too CPU specifed with LockExecuteThreadToCPU. This is not supported when using multiple TC threads",
+
       // END
       0
     };
 
-    for (unsigned i = 0; t[i]; i+= 3)
+    for (unsigned i = 0; t[i]; i+= 4)
     {
       THRConfig tmp;
       tmp.setLockExecuteThreadToCPU(t[i+0]);
-      int res = tmp.do_parse(t[i+1]);
-      int ok = strcmp(tmp.getConfigString(), t[i+2]) == 0;
+      const int _res = tmp.do_parse(t[i+1]);
+      const int expect_res = strcmp(t[i+2], "OK") == 0 ? 0 : -1;
+      const int res = _res == expect_res ? 0 : -1;
+      int ok = expect_res == 0 ?
+        strcmp(tmp.getConfigString(), t[i+3]) == 0:
+        strcmp(tmp.getErrorMessage(), t[i+3]) == 0;
       printf("mask: %s conf: %s => %s(%s) - %s - %s\n",
              t[i+0],
              t[i+1],
-             res == 0 ? "OK" : "FAIL",
-             res == 0 ? "" : tmp.getErrorMessage(),
+             _res == 0 ? "OK" : "FAIL",
+             _res == 0 ? "" : tmp.getErrorMessage(),
              tmp.getConfigString(),
              ok == 1 ? "CORRECT" : "INCORRECT");
+
       OK(res == 0);
       OK(ok == 1);
     }

=== modified file 'storage/ndb/src/kernel/vm/mt_thr_config.hpp'
--- a/storage/ndb/src/kernel/vm/mt_thr_config.hpp	2011-09-02 17:24:52 +0000
+++ b/storage/ndb/src/kernel/vm/mt_thr_config.hpp	2011-09-23 09:13:22 +0000
@@ -43,8 +43,9 @@ public:
     T_RECV  = 2, /* CMVMI */
     T_REP   = 3, /* SUMA */
     T_IO    = 4, /* FS, SocketServer etc */
+    T_TC    = 5, /* TC+SPJ */
 
-    T_END  = 5
+    T_END  = 6
   };
 
   THRConfig();

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2011-09-19 14:10:19 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2011-09-27 07:35:34 +0000
@@ -528,8 +528,6 @@ MgmtSrvr::start()
 {
   DBUG_ENTER("MgmtSrvr::start");
 
-  Guard g(m_local_config_mutex);
-
   /* Start transporter */
   if(!start_transporter(m_local_config))
   {
@@ -3451,15 +3449,17 @@ MgmtSrvr::try_alloc_from_list(NodeId& no
   for (unsigned i = 0; i < nodes.size(); i++)
   {
     const unsigned id= nodes[i].id;
-    if (m_reserved_nodes.get(id))
+    if (theFacade->ext_isConnected(id))
     {
-      // Node is already reserved(locally in this node)
+      // Node is already reserved(connected via transporter)
       continue;
     }
 
-    if (theFacade->ext_isConnected(id))
+    NdbMutex_Lock(m_reserved_nodes_mutex);
+    if (m_reserved_nodes.get(id))
     {
-      // Node is already reserved(connected via transporter)
+      // Node is already reserved(locally in this node)
+      NdbMutex_Unlock(m_reserved_nodes_mutex);
       continue;
     }
 
@@ -3483,16 +3483,14 @@ MgmtSrvr::try_alloc_from_list(NodeId& no
           more than one thread asked for same nodeid) since it's
           now reserved in data node
         */
-        m_reserved_nodes.clear(id);
+        release_local_nodeid_reservation(id);
       }
 
-      NdbMutex_Lock(m_reserved_nodes_mutex);
       return true;
     }
 
     /* Release the local reservation */
-    m_reserved_nodes.clear(id);
-    NdbMutex_Lock(m_reserved_nodes_mutex);
+    release_local_nodeid_reservation(id);
 
     if (res < 0)
     {
@@ -3601,8 +3599,6 @@ MgmtSrvr::alloc_node_id_impl(NodeId& nod
     return false;
   }
 
-  Guard g(m_reserved_nodes_mutex);
-
   /* Check timeout of nodeid reservations for NDB */
   if (type == NDB_MGM_NODE_TYPE_NDB)
   {
@@ -3610,8 +3606,11 @@ MgmtSrvr::alloc_node_id_impl(NodeId& nod
     for (unsigned i = 0; i < nodes.size(); i++)
     {
       const NodeId ndb_nodeid = nodes[i].id;
-      if (!m_reserved_nodes.has_timedout(ndb_nodeid, now))
-        continue;
+      {
+        Guard g(m_reserved_nodes_mutex);
+        if (!m_reserved_nodes.has_timedout(ndb_nodeid, now))
+          continue;
+      }
 
       // Found a timedout reservation
       if (theFacade->ext_isConnected(ndb_nodeid))
@@ -3621,7 +3620,7 @@ MgmtSrvr::alloc_node_id_impl(NodeId& nod
                              "releasing it", ndb_nodeid);
 
       // Clear the reservation
-      m_reserved_nodes.clear(ndb_nodeid);
+      release_local_nodeid_reservation(ndb_nodeid);
     }
   }
 

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilder.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2011-09-14 12:19:37 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2011-09-29 13:07:26 +0000
@@ -343,7 +343,8 @@ NdbQueryDef::destroy() const
 void
 NdbQueryDef::print() const
 {
-  m_impl.getQueryOperation(0U).printTree(0, Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32>());
+  m_impl.getQueryOperation(0U)
+    .printTree(0, NdbQueryOperationDefImpl::SiblingMask());
 }
 
 /*************************************************************************
@@ -1188,7 +1189,8 @@ NdbQueryBuilderImpl::prepare()
   if (doPrintQueryTree)
   {
     ndbout << "Query tree:" << endl;
-    def->getQueryOperation(0U).printTree(0, Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32>());
+    def->getQueryOperation(0U)
+      .printTree(0, NdbQueryOperationDefImpl::SiblingMask());
   }
 
   return def;
@@ -2159,7 +2161,8 @@ NdbQueryOperationDefImpl::appendChildPro
  * that connect the tree nodes.
  */
 static void printMargin(Uint32 depth, 
-                        Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> hasMoreSiblingsMask, 
+                        NdbQueryOperationDefImpl::SiblingMask 
+                        hasMoreSiblingsMask, 
                         bool header)
 {
   if (depth > 0)
@@ -2193,11 +2196,10 @@ static void printMargin(Uint32 depth, 
 
 void 
 NdbQueryOperationDefImpl::printTree(Uint32 depth, 
-                                    Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> 
-                                    hasMoreSiblingsMask) const
+                                    SiblingMask hasMoreSiblingsMask) const
 {
   // Print vertical line leading down to this node.
-  Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> firstLineMask = hasMoreSiblingsMask;
+  SiblingMask firstLineMask = hasMoreSiblingsMask;
   firstLineMask.set(depth);
   printMargin(depth, firstLineMask, false);
   ndbout << endl;
@@ -2214,22 +2216,24 @@ NdbQueryOperationDefImpl::printTree(Uint
     printMargin(depth, hasMoreSiblingsMask, false);
     ndbout << " index: " << getIndex()->getName() << endl; 
   }
-  /* For each child but the last one, use a mask with an extra bit set to
-   * indicate that there are more siblings.
-   */
-  hasMoreSiblingsMask.set(depth+1);
+
   for (int childNo = 0; 
-       childNo < static_cast<int>(getNoOfChildOperations()) - 1; 
+       childNo < static_cast<int>(getNoOfChildOperations()); 
        childNo++)
   {
-    getChildOperation(childNo).printTree(depth+1, hasMoreSiblingsMask);
-  }
-  if (getNoOfChildOperations() > 0)
-  {
-    // The last child has no more siblings.
-    hasMoreSiblingsMask.clear(depth+1);
-    getChildOperation(getNoOfChildOperations() - 1)
-      .printTree(depth+1, hasMoreSiblingsMask);
+    if (childNo == 0)
+    {
+      /* For each child but the last one, use a mask with an extra bit set to
+       * indicate that there are more siblings.
+       */
+      hasMoreSiblingsMask.set(depth+1);
+    }
+    if (childNo == static_cast<int>(getNoOfChildOperations()) - 1)
+    {
+      // The last child has no more siblings.
+      hasMoreSiblingsMask.clear(depth+1);
+    }
+    getChildOperation(childNo).printTree(depth+1, hasMoreSiblingsMask); 
   }
 } // NdbQueryOperationDefImpl::printTree()
 

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2011-09-14 12:19:37 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2011-09-29 13:07:26 +0000
@@ -429,6 +429,12 @@ public:
   // Get type of query operation
   virtual NdbQueryOperationDef::Type getType() const = 0;
 
+  /**
+   * Used for telling if parent at depth n has more siblings. (In that case
+   * we need to draw a horisontal line leading to that sibling.)
+   */
+  typedef Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> SiblingMask;
+
   /** Print query tree graph to trace file (using recursion).
    * @param depth Number of ancestor nodes that this node has.
    * @param hasMoreSiblingsMask The n'th bit should be set if the n'th ancestor
@@ -436,7 +442,7 @@ public:
    */
   void printTree(
            Uint32 depth, 
-           Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> hasMoreSiblingsMask) const;
+           SiblingMask hasMoreSiblingsMask) const;
 
 protected:
   // QueryTree building:

=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c	2011-09-14 12:19:37 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c	2011-09-29 13:07:26 +0000
@@ -187,7 +187,7 @@ ErrorBundle ErrorCodes[] = {
   { 805,  DMEC, TR, "Out of attrinfo records in tuple manager" },
   { 830,  DMEC, TR, "Out of add fragment operation records" },
   { 873,  DMEC, TR, "Out of attrinfo records for scan in tuple manager" },
-  { 899,  DMEC, IE, "Internal error: rowid already allocated" },
+  { 899,  DMEC, TR, "Rowid already allocated" },
   { 1217, DMEC, TR, "Out of operation records in local data manager (increase MaxNoOfLocalOperations)" },
   { 1218, DMEC, TR, "Send Buffers overloaded in NDB kernel" },
   { 1220, DMEC, TR, "REDO log files overloaded (increase FragmentLogFileSize)" },

=== modified file 'storage/ndb/test/ndbapi/testNdbApi.cpp'
--- a/storage/ndb/test/ndbapi/testNdbApi.cpp	2011-09-19 12:08:00 +0000
+++ b/storage/ndb/test/ndbapi/testNdbApi.cpp	2011-09-29 06:48:39 +0000
@@ -4580,8 +4580,17 @@ public:
         m_id(id), m_res(res) {
       m_res.lock(m_id);
     }
-    ~Reserve(){
+
+    void unlock() {
       m_res.unlock(m_id);
+      m_id = 0;
+    }
+
+    ~Reserve(){
+      if (m_id)
+      {
+        m_res.unlock(m_id);
+      }
     }
   };
 };
@@ -4644,6 +4653,8 @@ int runNdbClusterConnect(NDBT_Context* c
 {
   const Uint32 api_nodes = ctx->getProperty("API_NODES");
   const Uint32 step_no = step->getStepNo();
+  const Uint32 timeout_after_first_alive = ctx->getProperty("TimeoutAfterFirst",
+                                                            30);
   if (step_no > api_nodes)
   {
     // Don't run with more threads than API node slots
@@ -4652,8 +4663,8 @@ int runNdbClusterConnect(NDBT_Context* c
 
   // Get connectstring from main connection
   char constr[256];
-  if(!ctx->m_cluster_connection.get_connectstring(constr,
-                                                  sizeof(constr)))
+  if (!ctx->m_cluster_connection.get_connectstring(constr,
+                                                   sizeof(constr)))
   {
     g_err << "Too short buffer for connectstring" << endl;
     return NDBT_FAILED;
@@ -4661,9 +4672,17 @@ int runNdbClusterConnect(NDBT_Context* c
 
   Uint32 l = 0;
   const Uint32 loops = ctx->getNumLoops();
-  while (l < loops)
+  while (l < loops && !ctx->isTestStopped())
   {
     g_info << "loop: " << l << endl;
+    if (ctx->getProperty("WAIT") > 0)
+    {
+      ndbout_c("thread %u waiting", step_no);
+      ctx->incProperty("WAITING");
+      while (ctx->getProperty("WAIT") > 0 && !ctx->isTestStopped())
+        NdbSleep_MilliSleep(10);
+      ndbout_c("thread %u waiting complete", step_no);
+    }
     Ndb_cluster_connection con(constr);
 
     const int retries = 12;
@@ -4679,11 +4698,12 @@ int runNdbClusterConnect(NDBT_Context* c
     NodeIdReservations::Reserve res(g_reservations, con.node_id());
 
     const int timeout = 30;
-    const int timeout_after_first_alive = 30;
-    if (con.wait_until_ready(timeout, timeout_after_first_alive) != 0)
+    int ret = con.wait_until_ready(timeout, timeout_after_first_alive);
+    if (! (ret == 0 || (timeout_after_first_alive == 0 && ret > 0)))
     {
       g_err << "Cluster connection was not ready, nodeid: "
             << con.node_id() << endl;
+      abort();
       return NDBT_FAILED;
     }
 
@@ -4699,12 +4719,153 @@ int runNdbClusterConnect(NDBT_Context* c
     NdbSleep_MilliSleep(10 + rand() % max_sleep);
 
     l++;
+    res.unlock(); // make sure it's called before ~Ndb_cluster_connection
+  }
+
+  ctx->incProperty("runNdbClusterConnect_FINISHED");
+
+  return NDBT_OK;
+}
+
+int
+runRestarts(NDBT_Context* ctx, NDBT_Step* step)
+{
+  int result = NDBT_OK;
+  Uint32 threads = ctx->getProperty("API_NODES", (unsigned)0);
+  Uint32 sr = ctx->getProperty("ClusterRestart", (unsigned)0);
+  Uint32 master = ctx->getProperty("Master", (unsigned)0);
+  Uint32 slow = ctx->getProperty("SlowNR", (unsigned)0);
+  NdbRestarter restarter;
+
+  if (restarter.waitClusterStarted() != 0)
+  {
+    g_err << "Cluster failed to start" << endl;
+    return NDBT_FAILED;
+  }
+
+  if (sr == 0 && restarter.getNumDbNodes() < 2)
+    return NDBT_OK;
+
+  while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads
+         && !ctx->isTestStopped())
+  {
+    ndbout_c("%u %u",
+             ctx->getProperty("runNdbClusterConnect_FINISHED"),
+             threads);
+    if (sr == 0)
+    {
+      int id = rand() % restarter.getNumDbNodes();
+      int nodeId = restarter.getDbNodeId(id);
+      if (master == 1)
+      {
+        nodeId = restarter.getMasterNodeId();
+      }
+      else if (master == 2)
+      {
+        nodeId = restarter.getRandomNotMasterNodeId(rand());
+      }
+      ndbout << "Restart node " << nodeId
+             << "(master: " << restarter.getMasterNodeId() << ")"
+             << endl;
+      if (restarter.restartOneDbNode(nodeId, false, true, true) != 0)
+      {
+        g_err << "Failed to restartNextDbNode" << endl;
+        result = NDBT_FAILED;
+        break;
+      }
+
+      if (restarter.waitNodesNoStart(&nodeId, 1))
+      {
+        g_err << "Failed to waitNodesNoStart" << endl;
+        result = NDBT_FAILED;
+        break;
+      }
+
+      if (slow)
+      {
+        /**
+         * Block starting node in sp4
+         */
+        int dump[] = { 71, 4 };
+        restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump));
+      }
+
+      if (restarter.startNodes(&nodeId, 1))
+      {
+        g_err << "Failed to start node" << endl;
+        result = NDBT_FAILED;
+        break;
+      }
+
+      if (slow)
+      {
+        Uint32 blockTime = 3 * 60 * 1000;
+        Uint64 end = NdbTick_CurrentMillisecond() + blockTime;
+        while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads
+               && !ctx->isTestStopped() &&
+               NdbTick_CurrentMillisecond() < end)
+        {
+          NdbSleep_MilliSleep(100);
+        }
+
+        // unblock
+        int dump[] = { 71 };
+        restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump));
+      }
+    }
+    else
+    {
+      ndbout << "Blocking threads" << endl;
+      ctx->setProperty("WAITING", Uint32(0));
+      ctx->setProperty("WAIT", 1);
+      while (ctx->getProperty("WAITING") <
+             (threads - ctx->getProperty("runNdbClusterConnect_FINISHED")) &&
+             !ctx->isTestStopped())
+      {
+        NdbSleep_MilliSleep(10);
+      }
+
+      ndbout << "Restart cluster" << endl;
+      if (restarter.restartAll2(Uint32(NdbRestarter::NRRF_NOSTART |
+                                       NdbRestarter::NRRF_ABORT)) != 0)
+      {
+        g_err << "Failed to restartAll" << endl;
+        result = NDBT_FAILED;
+        break;
+      }
+
+      ctx->setProperty("WAITING", Uint32(0));
+      ctx->setProperty("WAIT", Uint32(0));
+
+      ndbout << "Starting cluster" << endl;
+      restarter.startAll();
+    }
+
+    if (restarter.waitClusterStarted() != 0)
+    {
+      g_err << "Cluster failed to start" << endl;
+      result = NDBT_FAILED;
+      break;
+    }
+  }
+
+  return result;
+}
+
+int runCheckAllNodesStarted(NDBT_Context* ctx, NDBT_Step* step){
+  NdbRestarter restarter;
+
+  if (restarter.waitClusterStarted(1) != 0)
+  {
+    g_err << "All nodes was not started " << endl;
+    return NDBT_FAILED;
   }
 
   return NDBT_OK;
 }
 
 
+
 static bool
 check_connect_no_such_host()
 {
@@ -5040,7 +5201,50 @@ TESTCASE("NdbClusterConnectionConnect",
 {
   INITIALIZER(runNdbClusterConnectionConnect);
 }
-
+TESTCASE("NdbClusterConnectNR",
+         "Make sure that every Ndb_cluster_connection get a unique nodeid")
+{
+  TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
+  INITIALIZER(runNdbClusterConnectInit);
+  STEPS(runNdbClusterConnect, MAX_NODES);
+  STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
+}
+TESTCASE("NdbClusterConnectNR_master",
+         "Make sure that every Ndb_cluster_connection get a unique nodeid")
+{
+  TC_PROPERTY("Master", 1);
+  TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
+  INITIALIZER(runNdbClusterConnectInit);
+  STEPS(runNdbClusterConnect, MAX_NODES);
+  STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
+}
+TESTCASE("NdbClusterConnectNR_non_master",
+         "Make sure that every Ndb_cluster_connection get a unique nodeid")
+{
+  TC_PROPERTY("Master", 2);
+  TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
+  INITIALIZER(runNdbClusterConnectInit);
+  STEPS(runNdbClusterConnect, MAX_NODES);
+  STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
+}
+TESTCASE("NdbClusterConnectNR_slow",
+         "Make sure that every Ndb_cluster_connection get a unique nodeid")
+{
+  TC_PROPERTY("Master", 2);
+  TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
+  TC_PROPERTY("SlowNR", 1);
+  INITIALIZER(runNdbClusterConnectInit);
+  STEPS(runNdbClusterConnect, MAX_NODES);
+  STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
+}
+TESTCASE("NdbClusterConnectSR",
+         "Make sure that every Ndb_cluster_connection get a unique nodeid")
+{
+  TC_PROPERTY("ClusterRestart", (Uint32)1);
+  INITIALIZER(runNdbClusterConnectInit);
+  STEPS(runNdbClusterConnect, MAX_NODES);
+  STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
+}
 NDBT_TESTSUITE_END(testNdbApi);
 
 int main(int argc, const char** argv){

=== modified file 'storage/ndb/test/ndbapi/testRestartGci.cpp'
--- a/storage/ndb/test/ndbapi/testRestartGci.cpp	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/test/ndbapi/testRestartGci.cpp	2011-09-29 06:48:39 +0000
@@ -486,7 +486,7 @@ int runNodeInitialRestarts(NDBT_Context*
     int nodeId = restarter.getNode(NdbRestarter::NS_RANDOM);
     ndbout_c("Restarting node %u", nodeId);
 
-    if (restarter.restartOneDbNode(nodeId, NdbRestarter::NRRF_INITIAL) != 0)
+    if (restarter.restartOneDbNode2(nodeId, NdbRestarter::NRRF_INITIAL) != 0)
     {
       ndbout_c("Error restarting node");
       ctx->stopTest();
@@ -546,7 +546,7 @@ int runUpdateVerifyGCI(NDBT_Context* ctx
     CHECK(rowGci != NULL);
 
     /* Define an update op to set the next GCI */
-    CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, loopCount+1) == 0);
+    CHECK(hugoOps.pkUpdateRecord(pNdb, 0, 1, (int)(loopCount+1)) == 0);
 
     if (hugoOps.execute_Commit(pNdb) != 0)
     {

=== modified file 'storage/ndb/test/ndbapi/test_event.cpp'
--- a/storage/ndb/test/ndbapi/test_event.cpp	2011-06-30 15:59:25 +0000
+++ b/storage/ndb/test/ndbapi/test_event.cpp	2011-09-28 10:04:03 +0000
@@ -168,7 +168,7 @@ Uint32 setAnyValue(Ndb* ndb, NdbTransact
 {
   /* XOR 2 32bit words of transid together */
   Uint64 transId = trans->getTransactionId();
-  return transId ^ (transId >> 32);
+  return (Uint32)(transId ^ (transId >> 32));
 }
 
 bool checkAnyValueTransId(Uint64 transId, Uint32 anyValue)

=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt	2011-09-09 13:13:52 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt	2011-09-29 13:07:26 +0000
@@ -1753,3 +1753,24 @@ max-time: 500
 cmd: testAsynchMultiwait
 args: -n AsynchMultiwaitWakeup T1
 
+# alloc node id
+max-time: 500
+cmd: testNdbApi
+args: -n NdbClusterConnect T1
+
+max-time: 500
+cmd: testNdbApi
+args: -n NdbClusterConnectionConnect T1
+
+max-time: 500
+cmd: testNdbApi
+args: -n NdbClusterConnectNR_non_master T1
+
+max-time: 500
+cmd: testNdbApi
+args: -n NdbClusterConnectNR_slow T1
+
+max-time: 500
+cmd: testNdbApi
+args: -n NdbClusterConnectSR T1
+

=== modified file 'storage/ndb/test/tools/hugoJoin.cpp'
--- a/storage/ndb/test/tools/hugoJoin.cpp	2011-04-06 14:16:13 +0000
+++ b/storage/ndb/test/tools/hugoJoin.cpp	2011-09-28 09:54:05 +0000
@@ -192,7 +192,7 @@ int main(int argc, char** argv){
     }
     HugoQueryBuilder builder(&MyNdb, tables.getBase(), mask);
     builder.setJoinLevel(_depth);
-    const NdbQueryDef * q = builder.createQuery(&MyNdb);
+    const NdbQueryDef * q = builder.createQuery();
     if (_verbose >= 2)
     {
       q->print(); ndbout << endl;

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (jan.wedvik:3567to 3569) Jan Wedvik2 Oct