List:Commits« Previous MessageNext Message »
From:Jonas Oreland Date:December 6 2009 5:13pm
Subject:bzr commit into mysql-5.1-telco-7.0-spj branch (jonas:3014)
View as plain text  
#At file:///home/jonas/src/70-spj/ based on revid:jonas@stripped

 3014 Jonas Oreland	2009-12-06 [merge]
      ndb spj - merge 70-main

    added:
      mysql-test/suite/ndb/r/ndb_short_sigs.result
      mysql-test/suite/ndb/t/ndb_short_sigs.cnf
      mysql-test/suite/ndb/t/ndb_short_sigs.test
      storage/ndb/src/common/util/require.c
    modified:
      mysql-test/suite/ndb/r/ndb_restore.result
      mysql-test/suite/ndb/r/ndb_restore_options.result
      mysql-test/suite/ndb/t/ndb_restore.test
      mysql-test/suite/ndb/t/ndb_restore_options.test
      mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result
      mysql-test/suite/ndb_binlog/t/ndb_binlog_restore.test
      scripts/make_win_bin_dist
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster_connection.cc
      storage/ndb/include/kernel/kernel_config_parameters.h
      storage/ndb/include/kernel/signaldata/ConfigChange.hpp
      storage/ndb/include/kernel/signaldata/GetTabInfo.hpp
      storage/ndb/include/ndb_global.h
      storage/ndb/include/ndb_version.h.in
      storage/ndb/include/ndbapi/Ndb.hpp
      storage/ndb/include/ndbapi/NdbDictionary.hpp
      storage/ndb/include/ndbapi/NdbError.hpp
      storage/ndb/include/ndbapi/NdbOperation.hpp
      storage/ndb/include/util/NdbOut.hpp
      storage/ndb/src/common/debugger/EventLogger.cpp
      storage/ndb/src/common/util/BaseString.cpp
      storage/ndb/src/common/util/CMakeLists.txt
      storage/ndb/src/common/util/Makefile.am
      storage/ndb/src/common/util/NdbOut.cpp
      storage/ndb/src/cw/cpcd/CMakeLists.txt
      storage/ndb/src/cw/cpcd/Process.cpp
      storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp
      storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
      storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
      storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp
      storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp
      storage/ndb/src/kernel/blocks/pgman.cpp
      storage/ndb/src/kernel/blocks/pgman.hpp
      storage/ndb/src/kernel/vm/Configuration.cpp
      storage/ndb/src/kernel/vm/DynArr256.cpp
      storage/ndb/src/kernel/vm/SimulatedBlock.cpp
      storage/ndb/src/kernel/vm/SimulatedBlock.hpp
      storage/ndb/src/kernel/vm/mt.cpp
      storage/ndb/src/mgmapi/mgmapi.cpp
      storage/ndb/src/mgmsrv/CMakeLists.txt
      storage/ndb/src/mgmsrv/Config.cpp
      storage/ndb/src/mgmsrv/Config.hpp
      storage/ndb/src/mgmsrv/ConfigInfo.cpp
      storage/ndb/src/mgmsrv/ConfigManager.cpp
      storage/ndb/src/mgmsrv/InitConfigFileParser.cpp
      storage/ndb/src/mgmsrv/MgmtSrvr.cpp
      storage/ndb/src/mgmsrv/MgmtSrvr.hpp
      storage/ndb/src/mgmsrv/main.cpp
      storage/ndb/src/mgmsrv/testConfig.cpp
      storage/ndb/src/ndbapi/Ndb.cpp
      storage/ndb/src/ndbapi/NdbDictionary.cpp
      storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp
      storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp
      storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
      storage/ndb/src/ndbapi/NdbImpl.hpp
      storage/ndb/src/ndbapi/NdbOperationDefine.cpp
      storage/ndb/src/ndbapi/NdbOperationExec.cpp
      storage/ndb/src/ndbapi/NdbOperationSearch.cpp
      storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp
      storage/ndb/src/ndbapi/NdbScanOperation.cpp
      storage/ndb/src/ndbapi/Ndbinit.cpp
      storage/ndb/src/ndbapi/TransporterFacade.hpp
      storage/ndb/src/ndbapi/ndb_cluster_connection.cpp
      storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp
      storage/ndb/src/ndbapi/ndberror.c
      storage/ndb/test/include/NDBT_Test.hpp
      storage/ndb/test/ndbapi/slow_select.cpp
      storage/ndb/test/ndbapi/testBlobs.cpp
      storage/ndb/test/ndbapi/testIndex.cpp
      storage/ndb/test/ndbapi/testLcp.cpp
      storage/ndb/test/ndbapi/testMgmd.cpp
      storage/ndb/test/ndbapi/testNdbinfo.cpp
      storage/ndb/test/ndbapi/testPartitioning.cpp
      storage/ndb/test/run-test/CMakeLists.txt
      storage/ndb/test/run-test/atrt.hpp
      storage/ndb/test/run-test/daily-basic-tests.txt
      storage/ndb/test/run-test/daily-devel-tests.txt
      storage/ndb/test/run-test/main.cpp
      storage/ndb/test/src/CMakeLists.txt
      storage/ndb/test/src/Makefile.am
      storage/ndb/test/src/NDBT_Test.cpp
      storage/ndb/tools/ndbinfo_sql.cpp
      storage/ndb/tools/restore/Restore.cpp
      storage/ndb/tools/restore/Restore.hpp
      storage/ndb/tools/restore/consumer_printer.cpp
      storage/ndb/tools/restore/consumer_restore.cpp
      storage/ndb/tools/restore/consumer_restore.hpp
      storage/ndb/tools/restore/restore_main.cpp
=== modified file 'mysql-test/suite/ndb/r/ndb_restore.result'
--- a/mysql-test/suite/ndb/r/ndb_restore.result	2009-10-09 18:43:30 +0000
+++ b/mysql-test/suite/ndb/r/ndb_restore.result	2009-12-01 10:15:25 +0000
@@ -582,3 +582,21 @@ epoch
 select epoch > (1 << 32) from mysql.ndb_apply_status where server_id=0;
 epoch > (1 << 32)
 1
+create table t1 (a int not null primary key auto_increment, b int) auto_increment=200
+engine=ndb;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL AUTO_INCREMENT,
+  `b` int(11) DEFAULT NULL,
+  PRIMARY KEY (`a`)
+) ENGINE=ndbcluster AUTO_INCREMENT=200 DEFAULT CHARSET=latin1
+drop table t1;
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL AUTO_INCREMENT,
+  `b` int(11) DEFAULT NULL,
+  PRIMARY KEY (`a`)
+) ENGINE=ndbcluster AUTO_INCREMENT=200 DEFAULT CHARSET=latin1
+drop table t1;

=== modified file 'mysql-test/suite/ndb/r/ndb_restore_options.result'
--- a/mysql-test/suite/ndb/r/ndb_restore_options.result	2009-05-08 17:58:13 +0000
+++ b/mysql-test/suite/ndb/r/ndb_restore_options.result	2009-12-02 10:40:46 +0000
@@ -374,10 +374,12 @@ drop table db2.tab1, db2.tab2;
 *********************************
 Include db1, and include db2.tab1
 *********************************
-Should result in db2.tab1 only restored.
+Should result in all tables in db1 and db2.tab1 being restored.
 use db1;
 show tables;
 Tables_in_db1
+tab1
+tab2
 use db2;
 show tables;
 Tables_in_db2
@@ -394,7 +396,7 @@ a
 7
 8
 9
-drop table db2.tab1;
+drop table db1.tab1,db1.tab2,db2.tab1;
 ************************
 Include unknown database
 ************************
@@ -479,13 +481,14 @@ a	b	c	d
 7	Highlea	7	UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
 UUUUUUUUUUUUUUUUUUUUUUU
 drop table db1.tab1, db1.tab2;
 drop table db2.tab1, db2.tab2;
-*********************************************
-Check that last argument of each type is used
-*********************************************
-Should result in just db1.tab2 restored.
+************************************
+Check accumulative include arguments
+************************************
+Should result in both db1.tab1 and db1.tab2 restored.
 use db1;
 show tables;
 Tables_in_db1
+tab1
 tab2
 select * from tab2 order by a;
 a	b	c	d
@@ -499,6 +502,19 @@ a	b	c	d
 use db2;
 show tables;
 Tables_in_db2
-drop table db1.tab2;
+drop table db1.tab1, db1.tab2;
+************************************
+Check accumulative exclude arguments
+************************************
+Should result in both db2.tab1 and db2.tab2 restored.
+use db1;
+show tables;
+Tables_in_db1
+use db2;
+show tables;
+Tables_in_db2
+tab1
+tab2
+drop table db2.tab1, db2.tab2;
 drop database db1;
 drop database db2;

=== added file 'mysql-test/suite/ndb/r/ndb_short_sigs.result'
--- a/mysql-test/suite/ndb/r/ndb_short_sigs.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/r/ndb_short_sigs.result	2009-11-18 11:05:02 +0000
@@ -0,0 +1,105 @@
+create table t1 (
+th int primary key, 
+un int, 
+de int, 
+rb varchar(1000), 
+al longtext, 
+key(de),
+unique(rb)) 
+engine=ndb;
+insert into t1 values (1, 1, 1, repeat('O', 1000), repeat('L', 60000));
+insert into t1 values (2, 2, 2, repeat('W',  999), repeat('B', 60001));
+insert into t1 values (3, 3, 3, repeat('P',  998), repeat('P', 60002));
+insert into t1 values (4, 4, 4, repeat('Q',  997), repeat('E', 60003));
+insert into t1 values (5, 5, 5, repeat('E',  996), repeat('A', 60004));
+select th, un, de, length(rb), length(al) 
+from t1 
+where th in (2,4) 
+order by th;
+th	un	de	length(rb)	length(al)
+2	2	2	999	60001
+4	4	4	997	60003
+select th, un, de, length(rb), length(al) 
+from t1 
+where rb 
+in (repeat('O', 1000), repeat('Q', 997))
+order by th;
+th	un	de	length(rb)	length(al)
+1	1	1	1000	60000
+4	4	4	997	60003
+select th, un, de, length(rb), length(al)
+from t1
+where de between 3 and 5
+order by th;
+th	un	de	length(rb)	length(al)
+3	3	3	998	60002
+4	4	4	997	60003
+5	5	5	996	60004
+select th, un, de, length(rb), length(al) 
+from t1 
+order by th;
+th	un	de	length(rb)	length(al)
+1	1	1	1000	60000
+2	2	2	999	60001
+3	3	3	998	60002
+4	4	4	997	60003
+5	5	5	996	60004
+update t1 
+set un=6, de=6, rb= repeat('S', 995), al = repeat('O', 60005)
+where th = 1;
+update t1
+set un=7, de=7, al = repeat('F', 60006)
+where rb = repeat('W', 999);
+update t1
+set un= un + 5, rb = repeat('U', 1000 - un), al = repeat('U', 60000 + un)
+where de >= 3 and de <= 5;
+select th, un, de, length(rb), length(al) 
+from t1 
+order by th;
+th	un	de	length(rb)	length(al)
+1	6	6	995	60005
+2	7	7	999	60006
+3	8	3	992	60008
+4	9	4	991	60009
+5	10	5	990	60010
+alter table t1 add column extra varchar(2000);
+Warnings:
+Warning	1478	Converted FIXED field to DYNAMIC to enable on-line ADD COLUMN
+update t1 set extra = repeat(rb, 2);
+select th, un, de, length(rb), length(al), length(extra)
+from t1 
+order by th;
+th	un	de	length(rb)	length(al)	length(extra)
+1	6	6	995	60005	1990
+2	7	7	999	60006	1998
+3	8	3	992	60008	1984
+4	9	4	991	60009	1982
+5	10	5	990	60010	1980
+select th, un, de, length(rb), length(al), length(extra)
+from t1
+where extra in (
+repeat('U', 2000),
+repeat('U', 1998),
+repeat('U', 1996),
+repeat('U', 1994),
+repeat('U', 1992),
+repeat('U', 1990),
+repeat('U', 1988),
+repeat('U', 1986),
+repeat('U', 1984),
+repeat('U', 1982),
+repeat('U', 1980),
+repeat('U', 1978),
+repeat('U', 1976),
+repeat('U', 1974),
+repeat('U', 1972),
+repeat('U', 1970),
+repeat('U', 1968),
+repeat('U', 1966),
+repeat('U', 1964))
+order by th;
+th	un	de	length(rb)	length(al)	length(extra)
+3	8	3	992	60008	1984
+4	9	4	991	60009	1982
+5	10	5	990	60010	1980
+drop table t1;

=== modified file 'mysql-test/suite/ndb/t/ndb_restore.test'
--- a/mysql-test/suite/ndb/t/ndb_restore.test	2009-10-11 12:04:37 +0000
+++ b/mysql-test/suite/ndb/t/ndb_restore.test	2009-12-01 10:15:25 +0000
@@ -497,3 +497,16 @@ select epoch > (1 << 32) from mysql.ndb_
 #
 --exec $NDB_RESTORE --print_log -b 1 -n 1 $MYSQL_TEST_DIR/std_data/ndb_backup50 >> $NDB_TOOLS_OUTPUT
 
+#
+# Bug#48005 ndb backup / restore does not restore the auto_increment
+#
+create table t1 (a int not null primary key auto_increment, b int) auto_increment=200
+engine=ndb;
+show create table t1;
+--source include/ndb_backup.inc
+drop table t1;
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -m -r --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
+show create table t1;
+drop table t1;
+

=== modified file 'mysql-test/suite/ndb/t/ndb_restore_options.test'
--- a/mysql-test/suite/ndb/t/ndb_restore_options.test	2009-04-09 15:25:11 +0000
+++ b/mysql-test/suite/ndb/t/ndb_restore_options.test	2009-12-02 13:54:07 +0000
@@ -163,9 +163,8 @@ drop table db1.tab2, db2.tab1;
 --echo *********************************
 
 --echo Should result in only db1.tab1 being restored
---exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --include-tables db1.tab1 --exclude-databases db1 >> $NDB_TOOLS_OUTPUT
---exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id --include-tables db1.tab1 --exclude-databases db1 >> $NDB_TOOLS_OUTPUT
-
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --exclude-databases db1 --include-tables db1.tab1 >> $NDB_TOOLS_OUTPUT
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id  --exclude-databases db1 --include-tables db1.tab1>> $NDB_TOOLS_OUTPUT
 
 use db1;
 show tables;
@@ -181,9 +180,8 @@ drop table db1.tab1;
 --echo Exclude db1.tab1, but include db1
 --echo *********************************
 --echo Should result in only db1.tab2 being restored
---exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --exclude-tables db1.tab1 --include-databases db1 >> $NDB_TOOLS_OUTPUT
---exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id --exclude-tables db1.tab1 --include-databases db1 >> $NDB_TOOLS_OUTPUT
-
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id  --include-databases db1 --exclude-tables db1.tab1 >> $NDB_TOOLS_OUTPUT
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id  --include-databases db1 --exclude_tables db1.tab1 >> $NDB_TOOLS_OUTPUT
 
 use db1;
 show tables;
@@ -234,19 +232,20 @@ drop table db2.tab1, db2.tab2;
 --echo *********************************
 --echo Include db1, and include db2.tab1
 --echo *********************************
---echo Should result in db2.tab1 only restored.
+--echo Should result in all tables in db1 and db2.tab1 being restored.
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --include-databases db1 --include-tables db2.tab1 >> $NDB_TOOLS_OUTPUT
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id --include-databases db1 --include-tables db2.tab1 >> $NDB_TOOLS_OUTPUT
 
 
 use db1;
+--sorted_result
 show tables;
 use db2;
 show tables;
 # checksum table tab1;
 select * from tab1 order by a;
 
-drop table db2.tab1;
+drop table db1.tab1,db1.tab2,db2.tab1;
 
 
 --echo ************************
@@ -285,14 +284,15 @@ select * from tab2 order by a;
 drop table db1.tab1, db1.tab2;
 drop table db2.tab1, db2.tab2;
 
---echo *********************************************
---echo Check that last argument of each type is used
---echo *********************************************
---echo Should result in just db1.tab2 restored.
+--echo ************************************
+--echo Check accumulative include arguments
+--echo ************************************
+--echo Should result in both db1.tab1 and db1.tab2 restored.
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --include-tables db1.tab1 --include-tables db1.tab2 >> $NDB_TOOLS_OUTPUT
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id --include-tables db1.tab1 --include-tables db1.tab2 >> $NDB_TOOLS_OUTPUT
 
 use db1;
+--sorted_result
 show tables;
 # checksum table tab2;
 select * from tab2 order by a;
@@ -300,8 +300,22 @@ select * from tab2 order by a;
 use db2;
 show tables;
 
-drop table db1.tab2;
+drop table db1.tab1, db1.tab2;
+
+--echo ************************************
+--echo Check accumulative exclude arguments
+--echo ************************************
+--echo Should result in both db2.tab1 and db2.tab2 restored.
+--exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r -m  $NDB_BACKUPS-$the_backup_id --exclude-tables db1.tab1 --exclude-tables db1.tab2 >> $NDB_TOOLS_OUTPUT
+--exec $NDB_RESTORE  --no-defaults -b $the_backup_id -n 2 -r     $NDB_BACKUPS-$the_backup_id --exclude-tables db1.tab1 --exclude-tables db1.tab2 >> $NDB_TOOLS_OUTPUT
 
+use db1;
+show tables;
+use db2;
+--sorted_result
+show tables;
+
+drop table db2.tab1, db2.tab2;
 
 drop database db1;
 drop database db2;

=== added file 'mysql-test/suite/ndb/t/ndb_short_sigs.cnf'
--- a/mysql-test/suite/ndb/t/ndb_short_sigs.cnf	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_short_sigs.cnf	2009-11-18 11:05:02 +0000
@@ -0,0 +1,9 @@
+#
+# Config used when testing short NdbApi request handling
+# functionality
+#
+!include suite/ndb/my.cnf
+
+[ENV]
+# Activate short signal requests
+NDB_FORCE_SHORT_REQUESTS=Y

=== added file 'mysql-test/suite/ndb/t/ndb_short_sigs.test'
--- a/mysql-test/suite/ndb/t/ndb_short_sigs.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_short_sigs.test	2009-11-18 11:05:02 +0000
@@ -0,0 +1,102 @@
+-- source include/have_ndb.inc
+
+
+# Create table with unique key, ordered index + blob
+
+create table t1 (
+        th int primary key, 
+        un int, 
+        de int, 
+        rb varchar(1000), 
+        al longtext, 
+        key(de),
+        unique(rb)) 
+        engine=ndb;
+
+insert into t1 values (1, 1, 1, repeat('O', 1000), repeat('L', 60000));
+insert into t1 values (2, 2, 2, repeat('W',  999), repeat('B', 60001));
+insert into t1 values (3, 3, 3, repeat('P',  998), repeat('P', 60002));
+insert into t1 values (4, 4, 4, repeat('Q',  997), repeat('E', 60003));
+insert into t1 values (5, 5, 5, repeat('E',  996), repeat('A', 60004));
+
+# Pk lookup
+select th, un, de, length(rb), length(al) 
+        from t1 
+        where th in (2,4) 
+        order by th;
+
+# Uk lookup
+select th, un, de, length(rb), length(al) 
+        from t1 
+        where rb 
+        in (repeat('O', 1000), repeat('Q', 997))
+        order by th;
+
+# Secondary Index scan
+select th, un, de, length(rb), length(al)
+        from t1
+        where de between 3 and 5
+        order by th;
+
+# Table scan
+select th, un, de, length(rb), length(al) 
+        from t1 
+        order by th;
+
+# Update via Pk
+update t1 
+        set un=6, de=6, rb= repeat('S', 995), al = repeat('O', 60005)
+        where th = 1;
+
+# Update via Uk
+update t1
+        set un=7, de=7, al = repeat('F', 60006)
+        where rb = repeat('W', 999);
+
+# Update via Index Scan
+update t1
+        set un= un + 5, rb = repeat('U', 1000 - un), al = repeat('U', 60000 + un)
+        where de >= 3 and de <= 5;
+
+# Table scan
+select th, un, de, length(rb), length(al) 
+        from t1 
+        order by th;
+
+# Online alter table
+alter table t1 add column extra varchar(2000);
+
+# Table scanning update
+update t1 set extra = repeat(rb, 2);
+
+# Table scan
+select th, un, de, length(rb), length(al), length(extra)
+        from t1 
+        order by th;
+
+# Table scan with large pushed filter
+select th, un, de, length(rb), length(al), length(extra)
+        from t1
+        where extra in (
+        repeat('U', 2000),
+        repeat('U', 1998),
+        repeat('U', 1996),
+        repeat('U', 1994),
+        repeat('U', 1992),
+        repeat('U', 1990),
+        repeat('U', 1988),
+        repeat('U', 1986),
+        repeat('U', 1984),
+        repeat('U', 1982),
+        repeat('U', 1980),
+        repeat('U', 1978),
+        repeat('U', 1976),
+        repeat('U', 1974),
+        repeat('U', 1972),
+        repeat('U', 1970),
+        repeat('U', 1968),
+        repeat('U', 1966),
+        repeat('U', 1964))
+        order by th;
+
+drop table t1;

=== modified file 'mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result'
--- a/mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result	2009-02-01 21:05:19 +0000
+++ b/mysql-test/suite/ndb_binlog/r/ndb_binlog_restore.result	2009-12-04 17:15:03 +0000
@@ -5,40 +5,35 @@ drop table if exists t1;
 create table t1 (a int key, b int) engine ndb;
 insert into t1 values (1,1);
 #
-# extra table to be used to ensure data has arrived to binlog
-create table t2 (a int key, b int) engine ndb;
-#
 # reset and restore schema
 drop table t1;
 reset master;
 show tables;
 Tables_in_test
-t2
 t1
 #
 # restore and _no_ binlog
 #
-# check the binlog, should be empty
-# extra insert (not logged) to ensure data has arrived to binlog
-set SQL_LOG_BIN=0;
-insert into t2 values (1,1);
+# check the binlog, should be empty apart from our marker
+# create dummy table to wait for to ensure Binlog contains any previous events
+create table binlogmarker (a int) engine=ndb;
 show binlog events from <binlog_start>;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+mysqld-bin.000001	#	Query	1	#	use `test`; create table binlogmarker (a int) engine=ndb
 #
 # reset and restore schema again
+drop table binlogmarker;
 drop table t1;
 reset master;
 show tables;
 Tables_in_test
-t2
 t1
 #
-# restore and  binlog should now happen
+# restore and  binlog should now happen as well as the marker
 #
 # check the binlog, should contain data
-# extra insert (not logged) to ensure data has arrived to binlog
-set SQL_LOG_BIN=0;
-insert into t2 values (2,2);
+# create dummy table to wait for to ensure Binlog contains any previous events
+create table binlogmarker (a int) engine=ndb;
 show binlog events from <binlog_start>;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 mysqld-bin.000001	#	Query	1	#	BEGIN
@@ -47,7 +42,8 @@ mysqld-bin.000001	#	Table_map	1	#	table_
 mysqld-bin.000001	#	Write_rows	1	#	table_id: #
 mysqld-bin.000001	#	Write_rows	1	#	table_id: # flags: STMT_END_F
 mysqld-bin.000001	#	Query	1	#	COMMIT
-drop table t1, t2;
+mysqld-bin.000001	#	Query	1	#	use `test`; create table binlogmarker (a int) engine=ndb
+drop table binlogmarker, t1;
 #
 # Now more complex using "BANK schema" including restore of log
 #

=== modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_restore.test'
--- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_restore.test	2008-10-22 10:12:53 +0000
+++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_restore.test	2009-12-04 17:27:44 +0000
@@ -17,10 +17,6 @@ insert into t1 values (1,1);
 --enable_query_log
 
 --echo #
---echo # extra table to be used to ensure data has arrived to binlog
-create table t2 (a int key, b int) engine ndb;
-
---echo #
 --echo # reset and restore schema
 drop table t1;
 reset master;
@@ -33,32 +29,39 @@ show tables;
 --exec $NDB_RESTORE --no-defaults --no-binlog -b $the_backup_id -n 2 -r --print --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
 
 --echo #
---echo # check the binlog, should be empty
---echo # extra insert (not logged) to ensure data has arrived to binlog
-set SQL_LOG_BIN=0;
-insert into t2 values (1,1);
+--echo # check the binlog, should be empty apart from our marker
+--echo # create dummy table to wait for to ensure Binlog contains any previous events
+
+create table binlogmarker (a int) engine=ndb;
+let $wait_binlog_event= binlogmarker;
+--source include/wait_for_binlog_event.inc
+
 --source include/show_binlog_events2.inc
 
 --echo #
 --echo # reset and restore schema again
+drop table binlogmarker;
 drop table t1;
 reset master;
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -m --print --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
 show tables;
 
 --echo #
---echo # restore and  binlog should now happen
+--echo # restore and  binlog should now happen as well as the marker
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 1 -r --print --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
 --exec $NDB_RESTORE --no-defaults -b $the_backup_id -n 2 -r --print --print_meta $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT
 
 --echo #
 --echo # check the binlog, should contain data
---echo # extra insert (not logged) to ensure data has arrived to binlog
-set SQL_LOG_BIN=0;
-insert into t2 values (2,2);
+--echo # create dummy table to wait for to ensure Binlog contains any previous events
+
+create table binlogmarker (a int) engine=ndb;
+let $wait_binlog_event= binlogmarker;
+--source include/wait_for_binlog_event.inc
+
 --source include/show_binlog_events2.inc
 
-drop table t1, t2;
+drop table binlogmarker, t1;
 
 
 

=== modified file 'scripts/make_win_bin_dist'
--- a/scripts/make_win_bin_dist	2009-10-01 07:16:52 +0000
+++ b/scripts/make_win_bin_dist	2009-11-17 16:30:37 +0000
@@ -340,7 +340,7 @@ fi
 mkdir $DESTDIR/mysql-test
 cp mysql-test/mysql-test-run.pl $DESTDIR/mysql-test/
 cp mysql-test/README $DESTDIR/mysql-test/
-cp -R mysql-test/{t,r,include,suite,std_data,lib} $DESTDIR/mysql-test/
+cp -R mysql-test/{t,r,include,suite,std_data,lib,collections} $DESTDIR/mysql-test/
 
 # Note that this will not copy "extra" if a soft link
 if [ -d mysql-test/extra ] ; then

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2009-12-04 18:23:46 +0000
+++ b/sql/ha_ndbcluster.cc	2009-12-06 17:12:40 +0000
@@ -1961,7 +1961,7 @@ void ha_ndbcluster::release_blobs_buffer
   DBUG_ENTER("releaseBlobsBuffer");
   if (m_blobs_buffer_size > 0)
   {
-    DBUG_PRINT("info", ("Deleting blobs buffer, size %u", m_blobs_buffer_size));
+    DBUG_PRINT("info", ("Deleting blobs buffer, size %llu", m_blobs_buffer_size));
     my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
     m_blobs_buffer= 0;
     m_blobs_row_total_size= 0;
@@ -13581,6 +13581,7 @@ int ha_ndbcluster::alter_table_phase1(TH
     DBUG_PRINT("info", ("Failed to start schema transaction"));
     ERR_PRINT(dict->getNdbError());
     error= ndb_to_mysql_error(&dict->getNdbError());
+    table->file->print_error(error, MYF(0));
     goto err;
   }
 

=== modified file 'sql/ha_ndbcluster_connection.cc'
--- a/sql/ha_ndbcluster_connection.cc	2009-11-08 18:23:30 +0000
+++ b/sql/ha_ndbcluster_connection.cc	2009-11-17 15:57:14 +0000
@@ -72,7 +72,7 @@ int ndbcluster_connect(int (*connect_cal
     DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
                         opt_ndb_connectstring));
     my_errno= HA_ERR_OUT_OF_MEM;
-    goto ndbcluster_connect_error;
+    DBUG_RETURN(-1);
   }
   {
     char buf[128];
@@ -89,14 +89,14 @@ int ndbcluster_connect(int (*connect_cal
     sql_print_error("NDB: failed to allocate global ndb object");
     DBUG_PRINT("error", ("failed to create global ndb object"));
     my_errno= HA_ERR_OUT_OF_MEM;
-    goto ndbcluster_connect_error;
+    DBUG_RETURN(-1);
   }
   if (g_ndb->init() != 0)
   {
     DBUG_PRINT("error", ("%d  message: %s",
                          g_ndb->getNdbError().code,
                          g_ndb->getNdbError().message));
-    goto ndbcluster_connect_error;
+    DBUG_RETURN(-1);
   }
 
   /* Connect to management server */
@@ -110,7 +110,7 @@ int ndbcluster_connect(int (*connect_cal
       break;
     do_retry_sleep(100);
     if (abort_loop)
-      goto ndbcluster_connect_error;
+      DBUG_RETURN(-1);
   }
 
   {
@@ -131,7 +131,7 @@ int ndbcluster_connect(int (*connect_cal
                         i);
         DBUG_PRINT("error",("Ndb_cluster_connection[%u](%s)",
                             i, opt_ndb_connectstring));
-        goto ndbcluster_connect_error;
+        DBUG_RETURN(-1);
       }
       {
         char buf[128];
@@ -200,7 +200,7 @@ int ndbcluster_connect(int (*connect_cal
       {
         sql_print_error("NDB[%u]: failed to start connect thread", i);
         DBUG_PRINT("error", ("g_ndb_cluster_connection->start_connect_thread()"));
-        goto ndbcluster_connect_error;
+        DBUG_RETURN(-1);
       }
     }
 #ifndef DBUG_OFF
@@ -221,11 +221,9 @@ int ndbcluster_connect(int (*connect_cal
     sql_print_error("NDB: error (%u) %s",
                     g_ndb_cluster_connection->get_latest_error(),
                     g_ndb_cluster_connection->get_latest_error_msg());
-    goto ndbcluster_connect_error;
+    DBUG_RETURN(-1);
   }
   DBUG_RETURN(0);
-ndbcluster_connect_error:
-  DBUG_RETURN(-1);
 }
 
 void ndbcluster_disconnect(void)

=== modified file 'storage/ndb/include/kernel/kernel_config_parameters.h'
--- a/storage/ndb/include/kernel/kernel_config_parameters.h	2009-10-15 12:36:53 +0000
+++ b/storage/ndb/include/kernel/kernel_config_parameters.h	2009-12-04 12:45:23 +0000
@@ -36,7 +36,6 @@
 
 #define CFG_DIH_API_CONNECT   (PRIVATE_BASE + 15)
 #define CFG_DIH_FRAG_CONNECT  (PRIVATE_BASE + 17)
-#define CFG_DIH_MORE_NODES    (PRIVATE_BASE + 18)
 #define CFG_DIH_REPLICAS      (PRIVATE_BASE + 19)
 #define CFG_DIH_TABLE         (PRIVATE_BASE + 20)
 

=== modified file 'storage/ndb/include/kernel/signaldata/ConfigChange.hpp'
--- a/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	2009-09-25 07:57:29 +0000
+++ b/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	2009-11-17 18:13:29 +0000
@@ -204,11 +204,13 @@ class ConfigCheckReq  {
   friend class ConfigManager;
 
 public:
-  STATIC_CONST( SignalLength = 2 );
+  STATIC_CONST( SignalLengthBeforeChecksum = 2 );
+  STATIC_CONST( SignalLength = 3 );
 
 private:
   Uint32 state;
   Uint32 generation;
+  Uint32 checksum;
 };
 
 
@@ -246,7 +248,8 @@ class ConfigCheckRef  {
 
   enum ErrorCode {
     WrongState                 = 1,
-    WrongGeneration            = 2
+    WrongGeneration            = 2,
+    WrongChecksum              = 3
   };
 
   static const char* errorMessage(Uint32 error) {
@@ -255,6 +258,8 @@ class ConfigCheckRef  {
       return "Wrong state";
     case WrongGeneration:
       return "Wrong generation";
+    case WrongChecksum:
+      return "Wrong checksum";
 
     default:
       return "ConfigCheckRef, unknown error";

=== modified file 'storage/ndb/include/kernel/signaldata/GetTabInfo.hpp'
--- a/storage/ndb/include/kernel/signaldata/GetTabInfo.hpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/include/kernel/signaldata/GetTabInfo.hpp	2009-11-18 11:05:02 +0000
@@ -74,6 +74,9 @@ class GetTabInfoRef {
   friend bool printGET_TABINFO_REF(FILE *, const Uint32 *, Uint32, Uint16);    
 public:
   STATIC_CONST( SignalLength = 7 );
+  /* 6.3 <-> 7.0 upgrade code */
+  STATIC_CONST( OriginalSignalLength = 5 );
+  STATIC_CONST( OriginalErrorOffset = 4 );
 public:
   Uint32 senderData;
   Uint32 senderRef;

=== modified file 'storage/ndb/include/ndb_global.h'
--- a/storage/ndb/include/ndb_global.h	2009-10-09 14:12:17 +0000
+++ b/storage/ndb/include/ndb_global.h	2009-12-04 05:53:03 +0000
@@ -211,4 +211,34 @@ extern "C" {
 #define ASSERT_TYPE_HAS_CONSTRUCTOR(x)
 #endif
 
+/*
+ * require is like a normal assert, only it's always on (eg. in release)
+*/
+C_MODE_START
+// see below
+typedef int(*RequirePrinter)(const char *fmt, ...);
+void require_failed(int exitcode, RequirePrinter p,
+                    const char* expr, const char* file, int line);
+int ndbout_printer(const char * fmt, ...);
+C_MODE_END
+/*
+ *  this allows for an exit() call if exitcode is not zero
+ *  and takes a Printer to print the error
+*/
+#define require_exit_or_core_with_printer(v, exitcode, printer) \
+  do { if (likely(!(!(v)))) break;                                    \
+       require_failed((exitcode), (printer), #v, __FILE__, __LINE__); \
+  } while (0)
+
+/*
+ *  this allows for an exit() call if exitcode is not zero
+*/
+#define require_exit_or_core(v, exitcode) \
+       require_exit_or_core_with_printer((v), (exitcode), 0)
+
+/*
+ * this require is like a normal assert.  (only it's always on)
+*/
+#define require(v) require_exit_or_core_with_printer((v), 0, 0)
+
 #endif

=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in	2009-11-02 17:15:29 +0000
+++ b/storage/ndb/include/ndb_version.h.in	2009-12-02 16:01:50 +0000
@@ -102,11 +102,16 @@ Uint32 ndbGetOwnVersion();
 #define NDBD_MICRO_GCP_62 NDB_MAKE_VERSION(6,2,5)
 #define NDBD_MICRO_GCP_63 NDB_MAKE_VERSION(6,3,2)
 #define NDBD_RAW_LCP MAKE_VERSION(6,3,11)
+#define NDBD_LONG_TCKEYREQ NDB_MAKE_VERSION(6,4,0)
 #define NDBD_LONG_LQHKEYREQ MAKE_VERSION(6,4,0)
 #define NDBD_MAX_RECVBYTESIZE_32K MAKE_VERSION(6,3,18)
+#define NDBD_LONG_SCANTABREQ NDB_MAKE_VERSION(6,4,0)
 #define NDBD_LONG_SCANFRAGREQ MAKE_VERSION(6,4,0)
 #define NDBD_MT_LQH_VERSION MAKE_VERSION(6,4,0)
 
+#define NDBD_SCHEMA_TRANS_VERSION NDB_MAKE_VERSION(6,4,0)
+#define MGMD_MGMAPI_PROTOCOL_CHANGE NDB_MAKE_VERSION(6,4,0)
+
 
 static
 inline

=== modified file 'storage/ndb/include/ndbapi/Ndb.hpp'
--- a/storage/ndb/include/ndbapi/Ndb.hpp	2009-08-26 08:33:16 +0000
+++ b/storage/ndb/include/ndbapi/Ndb.hpp	2009-12-06 17:12:40 +0000
@@ -1626,6 +1626,18 @@ public:
    */
   const NdbError & getNdbError(int errorCode);
 
+  /**
+   * Get a string containing any extra error details in the supplied
+   * buffer
+   * Where there is extra detail available a ptr to the start of
+   * the supplied buffer will be returned.
+   * If the extra detail string is longer than the passed buffer 
+   * then it will be truncated to fit.
+   * Where there is no extra detail, NULL will be returned.
+   */
+  const char* getNdbErrorDetail(const NdbError& err, 
+                                char* buff, 
+                                Uint32 buffLen) const;
 
   /** @} *********************************************************************/
 

=== modified file 'storage/ndb/include/ndbapi/NdbDictionary.hpp'
--- a/storage/ndb/include/ndbapi/NdbDictionary.hpp	2009-10-07 02:56:19 +0000
+++ b/storage/ndb/include/ndbapi/NdbDictionary.hpp	2009-12-03 10:19:24 +0000
@@ -741,6 +741,11 @@ public:
     int getNoOfColumns() const;
     
     /**
+     * Get number of auto_increment columns in the table
+     */
+    int getNoOfAutoIncrementColumns() const;
+    
+    /**
      * Get number of primary keys in the table
      */
     int getNoOfPrimaryKeys() const;
@@ -2033,6 +2038,9 @@ public:
 #endif
     int listObjects(List & list,
 		    Object::Type type = Object::TypeUndefined) const;
+    int listObjects(List & list,
+                    Object::Type type,
+                    bool fullyQualified) const;
 
     /**
      * Get the latest error

=== modified file 'storage/ndb/include/ndbapi/NdbError.hpp'
--- a/storage/ndb/include/ndbapi/NdbError.hpp	2009-06-15 06:15:20 +0000
+++ b/storage/ndb/include/ndbapi/NdbError.hpp	2009-12-03 09:48:37 +0000
@@ -208,6 +208,7 @@ struct NdbError {
    */
   const char * message;
 
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
   /**
    * The detailed description.  This is extra information regarding the 
    * error which is not included in the error message.
@@ -215,6 +216,7 @@ struct NdbError {
    * @note Is NULL when no details specified
    */
   char * details;
+#endif
 
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
   NdbError(){

=== modified file 'storage/ndb/include/ndbapi/NdbOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbOperation.hpp	2009-10-21 12:51:50 +0000
+++ b/storage/ndb/include/ndbapi/NdbOperation.hpp	2009-12-06 17:12:40 +0000
@@ -36,6 +36,7 @@ class NdbBlob;
 class TcKeyReq;
 class NdbRecord;
 class NdbInterpretedCode;
+struct GenericSectionPtr;
 
 /**
  * @class NdbOperation
@@ -1207,8 +1208,8 @@ protected:
  * was sent, then the connection object is told about this situation.
  *****************************************************************************/
 
+  int    doSendKeyReq(int processorId, GenericSectionPtr* secs, Uint32 numSecs);
   int    doSend(int ProcessorId, Uint32 lastFlag);
-  int    doSendNdbRecord(int aNodeId);
   virtual int	 prepareSend(Uint32  TC_ConnectPtr,
                              Uint64  TransactionId,
 			     AbortOption);

=== modified file 'storage/ndb/include/util/NdbOut.hpp'
--- a/storage/ndb/include/util/NdbOut.hpp	2009-09-08 13:48:12 +0000
+++ b/storage/ndb/include/util/NdbOut.hpp	2009-12-03 05:53:33 +0000
@@ -120,6 +120,8 @@ inline NdbOut& dec(NdbOut& _NdbOut) {
 }
 extern "C"
 void ndbout_c(const char * fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+extern "C"
+void vndbout_c(const char * fmt, va_list ap);
 
 class FilteredNdbOut : public NdbOut {
 public:

=== modified file 'storage/ndb/src/common/debugger/EventLogger.cpp'
--- a/storage/ndb/src/common/debugger/EventLogger.cpp	2009-10-21 07:22:23 +0000
+++ b/storage/ndb/src/common/debugger/EventLogger.cpp	2009-11-30 10:45:52 +0000
@@ -1093,7 +1093,7 @@ const EventLoggerBase::EventRepLogLevelM
   ROW(GlobalCheckpointStarted, LogLevel::llCheckpoint,  9, Logger::LL_INFO ),
   ROW(GlobalCheckpointCompleted,LogLevel::llCheckpoint,10, Logger::LL_INFO ),
   ROW(LocalCheckpointStarted,  LogLevel::llCheckpoint,  7, Logger::LL_INFO ),
-  ROW(LocalCheckpointCompleted,LogLevel::llCheckpoint,  8, Logger::LL_INFO ),
+  ROW(LocalCheckpointCompleted,LogLevel::llCheckpoint,  7, Logger::LL_INFO ),
   ROW(LCPStoppedInCalcKeepGci, LogLevel::llCheckpoint,  0, Logger::LL_ALERT ),
   ROW(LCPFragmentCompleted,    LogLevel::llCheckpoint, 11, Logger::LL_INFO ),
   ROW(UndoLogBlocked,          LogLevel::llCheckpoint,  7, Logger::LL_INFO ),
@@ -1119,11 +1119,11 @@ const EventLoggerBase::EventRepLogLevelM
   ROW(LogFileInitCompStatus,   LogLevel::llStartUp,     7, Logger::LL_INFO),
   
   // NODERESTART
-  ROW(NR_CopyDict,             LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
-  ROW(NR_CopyDistr,            LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
-  ROW(NR_CopyFragsStarted,     LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+  ROW(NR_CopyDict,             LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+  ROW(NR_CopyDistr,            LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
+  ROW(NR_CopyFragsStarted,     LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
   ROW(NR_CopyFragDone,         LogLevel::llNodeRestart,10, Logger::LL_INFO ),
-  ROW(NR_CopyFragsCompleted,   LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
+  ROW(NR_CopyFragsCompleted,   LogLevel::llNodeRestart, 7, Logger::LL_INFO ),
 
   ROW(NodeFailCompleted,       LogLevel::llNodeRestart, 8, Logger::LL_ALERT),
   ROW(NODE_FAILREP,            LogLevel::llNodeRestart, 8, Logger::LL_ALERT),

=== modified file 'storage/ndb/src/common/util/BaseString.cpp'
--- a/storage/ndb/src/common/util/BaseString.cpp	2009-07-16 16:36:20 +0000
+++ b/storage/ndb/src/common/util/BaseString.cpp	2009-11-13 11:11:12 +0000
@@ -500,9 +500,10 @@ BaseString
 BaseString::getPrettyText(unsigned size, const Uint32 data[])
 {
   const char* delimiter = "";
-  unsigned i, found = 0, MAX_BITS = 8 * size;
+  unsigned found = 0;
+  const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
   BaseString to;
-  for (i = 0; i < MAX_BITS; i++)
+  for (unsigned i = 0; i < MAX_BITS; i++)
   {
     if (BitmaskImpl::get(size, data, i))
     {
@@ -521,9 +522,9 @@ BaseString
 BaseString::getPrettyTextShort(unsigned size, const Uint32 data[])
 {
   const char* delimiter = "";
-  unsigned i, MAX_BITS = 8 * size;
+  const unsigned MAX_BITS = sizeof(Uint32) * 8 * size;
   BaseString to;
-  for (i = 0; i < MAX_BITS; i++)
+  for (unsigned i = 0; i < MAX_BITS; i++)
   {
     if (BitmaskImpl::get(size, data, i))
     {

=== modified file 'storage/ndb/src/common/util/CMakeLists.txt'
--- a/storage/ndb/src/common/util/CMakeLists.txt	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/src/common/util/CMakeLists.txt	2009-12-03 05:53:33 +0000
@@ -53,6 +53,7 @@ ADD_LIBRARY(ndbgeneral STATIC
             ndb_opts.c
             basestring_vsnprintf.c
             Bitmask.cpp
+            require.c
 )
 TARGET_LINK_LIBRARIES(ndbgeneral zlib mysys ws2_32)
 
@@ -70,3 +71,7 @@ ADD_EXECUTABLE(Parser-t Parser.cpp)
 SET_TARGET_PROPERTIES(Parser-t
                       PROPERTIES COMPILE_FLAGS "-DTEST_PARSER")
 TARGET_LINK_LIBRARIES(Parser-t ndbgeneral)
+
+ADD_EXECUTABLE(require-test require.c)
+SET_TARGET_PROPERTIES(require-test
+                      PROPERTIES COMPILE_FLAGS "-DTEST")

=== modified file 'storage/ndb/src/common/util/Makefile.am'
--- a/storage/ndb/src/common/util/Makefile.am	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/src/common/util/Makefile.am	2009-12-03 05:53:33 +0000
@@ -28,7 +28,7 @@ libgeneral_la_SOURCES = \
             strdup.c \
             ConfigValues.cpp ndb_init.cpp basestring_vsnprintf.c \
             Bitmask.cpp \
-	    ndb_rand.c
+	    ndb_rand.c require.c
 
 INCLUDES_LOC = @ZLIB_INCLUDES@
 

=== modified file 'storage/ndb/src/common/util/NdbOut.cpp'
--- a/storage/ndb/src/common/util/NdbOut.cpp	2009-09-09 12:34:25 +0000
+++ b/storage/ndb/src/common/util/NdbOut.cpp	2009-12-04 05:53:03 +0000
@@ -136,17 +136,37 @@ NdbOut::println(const char * fmt, ...){
 
 extern "C"
 void 
-ndbout_c(const char * fmt, ...){
-  va_list ap;
+vndbout_c(const char * fmt, va_list ap){
   char buf[1000];
   
-  va_start(ap, fmt);
   if (fmt != 0)
+  {
     BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+  }
   ndbout << buf << endl;
+}
+
+extern "C"
+void
+ndbout_c(const char * fmt, ...){
+  va_list ap;
+
+  va_start(ap, fmt);
+  vndbout_c(fmt, ap);
+  va_end(ap);
+}
+
+extern "C" int ndbout_printer(const char * fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  vndbout_c(fmt, ap);
   va_end(ap);
+  return 1;
 }
 
+
 FilteredNdbOut::FilteredNdbOut(OutputStream & out, 
 			       int threshold, int level)
   : NdbOut(out) {

=== added file 'storage/ndb/src/common/util/require.c'
--- a/storage/ndb/src/common/util/require.c	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/util/require.c	2009-12-03 11:39:48 +0000
@@ -0,0 +1,32 @@
+#include <ndb_global.h>
+
+void require_failed(int exitcode, RequirePrinter printer,
+                    const char* expr, const char* file, int line)
+{
+#define FMT "%s:%d: require(%s) failed\n", file, line, expr
+  if (!printer)
+  {
+    fprintf(stderr, FMT);
+    fflush(stderr);
+  }
+  else
+  {
+    printer(FMT);
+  }
+#ifdef _WIN32
+  DebugBreak();
+#endif
+  if(exitcode)
+  {
+    exit(exitcode);
+  }
+  abort();
+}
+
+#ifdef TEST
+int main()
+{
+  require(1);
+  require(0);
+}
+#endif

=== modified file 'storage/ndb/src/cw/cpcd/CMakeLists.txt'
--- a/storage/ndb/src/cw/cpcd/CMakeLists.txt	2009-10-08 09:20:37 +0000
+++ b/storage/ndb/src/cw/cpcd/CMakeLists.txt	2009-11-16 05:21:53 +0000
@@ -39,3 +39,4 @@ ADD_EXECUTABLE(ndb_cpcd
         common.cpp
         main.cpp)
 
+INSTALL(TARGETS ndb_cpcd DESTINATION bin)

=== modified file 'storage/ndb/src/cw/cpcd/Process.cpp'
--- a/storage/ndb/src/cw/cpcd/Process.cpp	2009-11-13 04:58:24 +0000
+++ b/storage/ndb/src/cw/cpcd/Process.cpp	2009-11-16 05:22:47 +0000
@@ -471,6 +471,8 @@ CPCD::Process::do_exec() {
   CloseHandle(proc);
   if (!pid) {
     logger.critical("Couldn't get process ID");
+  } else {
+    logger.debug("new pid: %d\n", pid);
   }
 
   m_status = RUNNING;
@@ -642,38 +644,51 @@ static void get_processes(Pairs & pairs)
 */
 static int kill_tree(pid_t pid, Pairs & pairs)
 {
-  size_t i, j;
-  Vector<pid_t> parents;
+  size_t i, j, k, new_count;
+  Vector<pid_t> parents, new_parents;
 
   parents.push_back(pid);
-  for(i = 0; i < pairs.size(); i++)
+  do
   {
-    Vector<pid_t> new_parents;
-    for(j = 0; j < parents.size(); j++)
+    for(i = 0; i < pairs.size(); i++)
     {
-      if(pairs[i].parent == parents[j])
+      for(j = 0; j < parents.size(); j++)
       {
-        new_parents.push_back(pairs[i].child);
+        if(pairs[i].parent == parents[j])
+        {
+          bool already_a_parent = false;
+          for(size_t x = 0; x < parents.size(); x++)
+          {
+            if(parents[x] == pairs[i].child)
+            {
+              already_a_parent = true;
+              break;
+            }
+          }
+          if (!already_a_parent)
+          {
+            new_parents.push_back(pairs[i].child);
+          }
+        }
       }
     }
-    if(!new_parents.size())
-    {
-      break;
-    }
-    for(j = 0; j < new_parents.size(); j++)
+
+    new_count = new_parents.size();
+    for(k = 0; k < new_count; k++)
     {
-      parents.push_back(new_parents[j]);
+      parents.push_back(new_parents[k]);
     }
-  }
+    new_parents.clear();
+  } while(new_count);
 
   logger.debug("killing processes in order: ");
-  for(i = parents.size() - 1; i >= 0; i--)
+  for(long i = (long)parents.size() - 1; i >= 0; i--)
   {
     logger.debug(" %d", parents[i]);
   }
   logger.debug(".\n");
 
-  for(i = parents.size() - 1; i >= 0; i--)
+  for(long i = (long)parents.size() - 1; i >= 0; i--)
   {
     pid_t pid = parents[i];
     HANDLE proc = OpenProcess(PROCESS_TERMINATE, 0, pid);

=== modified file 'storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp'
--- a/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp	2009-11-02 17:15:29 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp	2009-12-04 12:45:23 +0000
@@ -69,6 +69,7 @@
 // Error Codes for Add Table
 // --------------------------------------
 #define ZREPLERROR1 306
+#define ZREPLERROR2 307
 
 // --------------------------------------
 // Crash Codes

=== modified file 'storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp	2009-11-05 21:14:04 +0000
+++ b/storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp	2009-12-04 12:45:23 +0000
@@ -7541,7 +7541,7 @@ void Dbdih::execDIADDTABREQ(Signal* sign
   }//if
   if (noFragments > cremainingfrags) {
     jam();
-    addtabrefuseLab(signal, connectPtr, ZREPLERROR1);
+    addtabrefuseLab(signal, connectPtr, ZREPLERROR2);
     return;
   }//if
   

=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2009-11-16 13:36:35 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2009-12-06 17:12:40 +0000
@@ -1183,12 +1183,12 @@ void Dblqh::execREAD_CONFIG_REQ(Signal* 
     if (!ndb_mgm_get_string_parameter(p, CFG_DB_INIT_REDO, &conf) && conf)
     {
       jam();
-      if (strcmp(conf, "sparse") == 0)
+      if (strcasecmp(conf, "sparse") == 0)
       {
         jam();
         m_use_om_init = 0;
       }
-      else if (strcmp(conf, "full") == 0)
+      else if (strcasecmp(conf, "full") == 0)
       {
         jam();
         m_use_om_init = 1;

=== modified file 'storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp'
--- a/storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp	2009-10-12 07:07:14 +0000
+++ b/storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp	2009-11-30 11:53:55 +0000
@@ -104,6 +104,8 @@ public:
    // Information for open, needed if the first open action fails.
   AsyncFile* file;
   Uint32 theTrace;
+
+  MemoryChannel<Request>::ListMember m_mem_channel;
 };
 
 NdbOut& operator <<(NdbOut&, const Request&);

=== modified file 'storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp'
--- a/storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp	2009-11-30 11:53:55 +0000
@@ -78,20 +78,26 @@ template <class T>
 class MemoryChannel
 {
 public:
-  // wl4391_todo. adds 4*.  could set per ndb version.  why 512 ?
-  MemoryChannel( int size= 4* 512);
-  virtual ~MemoryChannel( );
+  MemoryChannel();
+  virtual ~MemoryChannel();
 
-  void writeChannel( T *t);
-  void writeChannelNoSignal( T *t);
+  void writeChannel(T *t);
+  void writeChannelNoSignal(T *t);
   T* readChannel();
   T* tryReadChannel();
 
+  /**
+   * Should be made class using MemoryChannel
+   */
+  struct ListMember
+  {
+    T* m_next;
+  };
+
 private:
-  int theSize;
-  T **theChannel;
-  CircularIndex theWriteIndex;
-  CircularIndex theReadIndex;
+  Uint32 m_occupancy;
+  T* m_head; // First element in list (e.g will be read by readChannel)
+  T* m_tail;
   NdbMutex* theMutexPtr;
   NdbCondition* theConditionPtr;
 
@@ -103,18 +109,14 @@ template <class T>
 NdbOut& operator<<(NdbOut& out, const MemoryChannel<T> & chn)
 {
   NdbMutex_Lock(chn.theMutexPtr);
-  out << "[ theSize: " << chn.theSize
-      << " theReadIndex: " << (int)chn.theReadIndex 
-      << " theWriteIndex: " << (int)chn.theWriteIndex << " ]";
+  out << "[ occupancy: " << chn.m_occupancy
+      << " ]";
   NdbMutex_Unlock(chn.theMutexPtr);
   return out;
 }
 
-template <class T> MemoryChannel<T>::MemoryChannel( int size):
-        theSize(size),
-        theChannel(new T*[size] ),
-        theWriteIndex(0, size),
-        theReadIndex(0, size)
+template <class T> MemoryChannel<T>::MemoryChannel() :
+  m_occupancy(0), m_head(0), m_tail(0)
 {
   theMutexPtr = NdbMutex_Create();
   theConditionPtr = NdbCondition_Create();
@@ -124,55 +126,79 @@ template <class T> MemoryChannel<T>::~Me
 {
   NdbMutex_Destroy(theMutexPtr);
   NdbCondition_Destroy(theConditionPtr);
-  delete [] theChannel;
 }
 
 template <class T> void MemoryChannel<T>::writeChannel( T *t)
 {
-
-  NdbMutex_Lock(theMutexPtr);
-  if(full(theWriteIndex, theReadIndex) || theChannel == NULL) abort();
-  theChannel[theWriteIndex]= t;
-  ++theWriteIndex;
+  writeChannelNoSignal(t);
   NdbCondition_Signal(theConditionPtr);
-  NdbMutex_Unlock(theMutexPtr);
 }
 
 template <class T> void MemoryChannel<T>::writeChannelNoSignal( T *t)
 {
-
   NdbMutex_Lock(theMutexPtr);
-  if(full(theWriteIndex, theReadIndex) || theChannel == NULL) abort();
-  theChannel[theWriteIndex]= t;
-  ++theWriteIndex;
+  if (m_head == 0)
+  {
+    assert(m_occupancy == 0);
+    m_head = m_tail = t;
+  }
+  else
+  {
+    assert(m_tail != 0);
+    m_tail->m_mem_channel.m_next = t;
+    m_tail = t;
+  }
+  t->m_mem_channel.m_next = 0;
+  m_occupancy++;
   NdbMutex_Unlock(theMutexPtr);
 }
 
 template <class T> T* MemoryChannel<T>::readChannel()
 {
-  T* tmp;
-
   NdbMutex_Lock(theMutexPtr);
-  while ( empty(theWriteIndex, theReadIndex) )
+  while (m_head == 0)
   {
+    assert(m_occupancy == 0);
     NdbCondition_Wait(theConditionPtr,
-                        theMutexPtr);    
+                      theMutexPtr);    
   }
-        
-  tmp= theChannel[theReadIndex];
-  ++theReadIndex;
+  assert(m_occupancy > 0);
+  T* tmp = m_head;
+  if (m_head == m_tail)
+  {
+    assert(m_occupancy == 1);
+    m_head = m_tail = 0;
+  }
+  else
+  {
+    m_head = m_head->m_mem_channel.m_next;
+  }
+  m_occupancy--;
   NdbMutex_Unlock(theMutexPtr);
   return tmp;
 }
 
 template <class T> T* MemoryChannel<T>::tryReadChannel()
 {
-  T* tmp= 0;
   NdbMutex_Lock(theMutexPtr);
-  if ( !empty(theWriteIndex, theReadIndex) )
-  {     
-    tmp= theChannel[theReadIndex];
-    ++theReadIndex;
+  T* tmp = m_head;
+  if (m_head != 0)
+  {
+    assert(m_occupancy > 0);
+    if (m_head == m_tail)
+    {
+      assert(m_occupancy == 1);
+      m_head = m_tail = 0;
+    }
+    else
+    {
+      m_head = m_head->m_mem_channel.m_next;
+    }
+    m_occupancy--;
+  }
+  else
+  {
+    assert(m_occupancy == 0);
   }
   NdbMutex_Unlock(theMutexPtr);
   return tmp;

=== modified file 'storage/ndb/src/kernel/blocks/pgman.cpp'
--- a/storage/ndb/src/kernel/blocks/pgman.cpp	2009-10-09 11:15:22 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.cpp	2009-11-27 10:26:10 +0000
@@ -50,6 +50,10 @@ Pgman::Pgman(Block_context& ctx, Uint32 
   m_page_hashlist(m_page_entry_pool),
   m_page_stack(m_page_entry_pool),
   m_page_queue(m_page_entry_pool)
+#ifdef VM_TRACE
+  ,debugFlag(false)
+  ,debugSummaryFlag(false)
+#endif
 {
   BLOCK_CONSTRUCTOR(Pgman);
 
@@ -150,6 +154,7 @@ Pgman::execREAD_CONFIG_REQ(Signal* signa
     m_param.m_max_pages = page_cnt;
     m_page_entry_pool.setSize(m_param.m_lirs_stack_mult * page_cnt);
     m_param.m_max_hot_pages = (page_cnt * 9) / 10;
+    ndbrequire(m_param.m_max_hot_pages >= 1);
   }
 
   Pool_context pc;
@@ -177,9 +182,10 @@ Pgman::Param::Param() :
 
 Pgman::Stats::Stats() :
   m_num_pages(0),
+  m_num_hot_pages(0),
+  m_current_io_waits(0),
   m_page_hits(0),
-  m_page_faults(0),
-  m_current_io_waits(0)
+  m_page_faults(0)
 {
 }
 
@@ -313,10 +319,6 @@ Pgman::Page_entry::Page_entry(Uint32 fil
 Uint32
 Pgman::get_sublist_no(Page_state state)
 {
-  if (state == 0)
-  {
-    return ZNIL;
-  }
   if (state & Page_entry::REQUEST)
   {
     if (! (state & Page_entry::BOUND))
@@ -348,7 +350,11 @@ Pgman::get_sublist_no(Page_state state)
   if (state == Page_entry::ONSTACK) {
     return Page_entry::SL_IDLE;
   }
-  return Page_entry::SL_OTHER;
+  if (state != 0)
+  {
+    return Page_entry::SL_OTHER;
+  }
+  return ZNIL;
 }
 
 void
@@ -381,9 +387,26 @@ Pgman::set_page_state(Ptr<Page_entry> pt
       }
     }
     ptr.p->m_state = new_state;
+
+    bool old_hot = (old_state & Page_entry::HOT);
+    bool new_hot = (new_state & Page_entry::HOT);
+    if (! old_hot && new_hot)
+    {
+      jam();
+      m_stats.m_num_hot_pages++;
+    }
+    if (old_hot && ! new_hot)
+    {
+      jam();
+      ndbrequire(m_stats.m_num_hot_pages != 0);
+      m_stats.m_num_hot_pages--;
+    }
   }
 
   D(ptr << ": after");
+#ifdef VM_TRACE
+  verify_page_entry(ptr);
+#endif
   D("<set_page_state");
 }
 
@@ -641,8 +664,10 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
   Page_state state = ptr.p->m_state;
   ndbrequire(! (state & Page_entry::LOCKED));
 
-  // even non-LIRS cache pages are counted on l.h.s.
-  if (m_stats.m_num_pages >= m_param.m_max_hot_pages)
+  ndbrequire(m_stats.m_num_hot_pages <= m_param.m_max_hot_pages);
+
+  // LIRS kicks in when we have max hot pages
+  if (m_stats.m_num_hot_pages == m_param.m_max_hot_pages)
   {
     if (state & Page_entry::HOT)
     {
@@ -684,6 +709,12 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
       jam();
       pl_stack.add(ptr);
       state |= Page_entry::ONSTACK;
+      /*
+       * bug#48910.  Using hot page count (not total page count)
+       * guarantees that stack is not empty here.  Therefore the new
+       * entry (added to top) is not at bottom and need not be hot.
+       */
+      ndbrequire(pl_stack.hasPrev(ptr));
       if (state & Page_entry::ONQUEUE)
       {
         jam();
@@ -706,7 +737,8 @@ Pgman::lirs_reference(Ptr<Page_entry> pt
   }
   else
   {
-    D("hot: " << m_stats.m_num_pages << " of " << m_param.m_max_hot_pages);
+    D("filling up hot pages: " << m_stats.m_num_hot_pages << "/"
+                               << m_param.m_max_hot_pages);
     jam();
     if (state & Page_entry::ONSTACK)
     {
@@ -1005,11 +1037,11 @@ Pgman::process_callback(Signal* signal, 
 {
   D(ptr << " : process_callback");
   int max_count = 1;
-  Page_state state = ptr.p->m_state;
 
   while (! ptr.p->m_requests.isEmpty() && --max_count >= 0)
   {
     jam();
+    Page_state state = ptr.p->m_state;
     SimulatedBlock* b;
     Callback callback;
     {
@@ -1051,19 +1083,18 @@ Pgman::process_callback(Signal* signal, 
     }
     ndbrequire(state & Page_entry::BOUND);
     ndbrequire(state & Page_entry::MAPPED);
+
+    // make REQUEST state consistent before set_page_state()
+    if (ptr.p->m_requests.isEmpty())
+    {
+      jam();
+      state &= ~ Page_entry::REQUEST;
+    }
     
     // callback may re-enter PGMAN and change page state
     set_page_state(ptr, state);
     b->execute(signal, callback, ptr.p->m_real_page_i);
-    state = ptr.p->m_state;
   }
-  
-  if (ptr.p->m_requests.isEmpty())
-  {
-    jam();
-    state &= ~ Page_entry::REQUEST;
-  }
-  set_page_state(ptr, state);
   return true;
 }
 
@@ -1608,7 +1639,7 @@ Pgman::execFSWRITEREF(Signal* signal)
 // client methods
 
 int
-Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
+Pgman::get_page_no_lirs(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
 {
   jamEntry();
   Ptr<Page_request> tmp = { &page_req, RNIL};
@@ -1649,16 +1680,6 @@ Pgman::get_page(Signal* signal, Ptr<Page
     jam();
   }
 
-  // update LIRS
-  if (! (state & Page_entry::LOCKED) &&
-      ! (req_flags & Page_request::CORR_REQ))
-  {
-    jam();
-    set_page_state(ptr, state);
-    lirs_reference(ptr);
-    state = ptr.p->m_state;
-  }
-
   const Page_state LOCKED = Page_entry::LOCKED | Page_entry::MAPPED;
   if ((state & LOCKED) == LOCKED && 
       ! (req_flags & Page_request::UNLOCK_PAGE))
@@ -1746,14 +1767,43 @@ Pgman::get_page(Signal* signal, Ptr<Page
   ptr.p->m_busy_count += busy_count;
   ptr.p->m_dirty_count += !!(req_flags & DIRTY_FLAGS);
   set_page_state(ptr, state);
-  
-  do_busy_loop(signal, true);
 
   D(req_ptr);
   D("<get_page: queued");
   return 0;
 }
 
+int
+Pgman::get_page(Signal* signal, Ptr<Page_entry> ptr, Page_request page_req)
+{
+  int i = get_page_no_lirs(signal, ptr, page_req);
+  if (unlikely(i == -1))
+  {
+    jam();
+    return -1;
+  }
+
+  Uint32 req_flags = page_req.m_flags;
+  Page_state state = ptr.p->m_state;
+
+  // update LIRS
+  if (! (state & Page_entry::LOCKED) &&
+      ! (req_flags & Page_request::CORR_REQ))
+  {
+    jam();
+    lirs_reference(ptr);
+  }
+
+  // start processing if request was queued
+  if (i == 0)
+  {
+    jam();
+    do_busy_loop(signal, true);
+  }
+
+  return i;
+}
+
 void
 Pgman::update_lsn(Ptr<Page_entry> ptr, Uint32 block, Uint64 lsn)
 {
@@ -1910,9 +1960,6 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
   Page_state state = ptr.p->m_state;
   if (! (state & (Page_entry::PAGEIN | Page_entry::PAGEOUT)))
   {
-    ndbrequire(state & Page_entry::BOUND);
-    ndbrequire(state & Page_entry::MAPPED);
-
     if (state & Page_entry::ONSTACK)
     {
       jam();
@@ -1922,9 +1969,13 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
       if (at_bottom)
       {
         jam();
-        ndbassert(state & Page_entry::HOT);
         lirs_stack_prune();
       }
+      if (state & Page_entry::HOT)
+      {
+        jam();
+        state &= ~ Page_entry::HOT;
+      }
     }
 
     if (state & Page_entry::ONQUEUE)
@@ -1934,12 +1985,37 @@ Pgman::drop_page(Ptr<Page_entry> ptr)
       state &= ~ Page_entry::ONQUEUE;
     }
 
-    ndbassert(ptr.p->m_real_page_i != RNIL);
-    if (ptr.p->m_real_page_i != RNIL)
+    if (state & Page_entry::BUSY)
     {
       jam();
+      state &= ~ Page_entry::BUSY;
+    }
+
+    if (state & Page_entry::DIRTY)
+    {
+      jam();
+      state &= ~ Page_entry::DIRTY;
+    }
+
+    if (state & Page_entry::EMPTY)
+    {
+      jam();
+      state &= ~ Page_entry::EMPTY;
+    }
+
+    if (state & Page_entry::MAPPED)
+    {
+      jam();
+      state &= ~ Page_entry::MAPPED;
+    }
+
+    if (state & Page_entry::BOUND)
+    {
+      jam();
+      ndbrequire(ptr.p->m_real_page_i != RNIL);
       release_cache_page(ptr.p->m_real_page_i);
       ptr.p->m_real_page_i = RNIL;
+      state &= ~ Page_entry::BOUND;
     }
 
     set_page_state(ptr, state);
@@ -2152,6 +2228,8 @@ Page_cache_client::free_data_file(Signal
 void
 Pgman::verify_page_entry(Ptr<Page_entry> ptr)
 {
+  Page_stack& pl_stack = m_page_stack;
+
   Uint32 ptrI = ptr.i;
   Page_state state = ptr.p->m_state;
 
@@ -2174,6 +2252,10 @@ Pgman::verify_page_entry(Ptr<Page_entry>
   // hot entry must be on stack
   ndbrequire(! is_hot || on_stack || dump_page_lists(ptrI));
 
+  // stack bottom is hot
+  bool at_bottom = on_stack && ! pl_stack.hasPrev(ptr);
+  ndbrequire(! at_bottom || is_hot || dump_page_lists(ptrI));
+
   bool on_queue = state & Page_entry::ONQUEUE;
   // hot entry is not on queue
   ndbrequire(! is_hot || ! on_queue || dump_page_lists(ptrI));
@@ -2185,9 +2267,12 @@ Pgman::verify_page_entry(Ptr<Page_entry>
   // entries waiting to enter queue
   bool to_queue = ! is_locked && ! is_hot && ! is_bound && has_req;
 
-  // page is either LOCKED or under LIRS
+  // page is about to be released
+  bool to_release = (state == 0);
+
+  // page is either LOCKED or under LIRS or about to be released
   bool is_lirs = on_stack || to_queue || on_queue;
-  ndbrequire(is_locked == ! is_lirs || dump_page_lists(ptrI));
+  ndbrequire(to_release || is_locked == ! is_lirs || dump_page_lists(ptrI));
 
   bool pagein = state & Page_entry::PAGEIN;
   bool pageout = state & Page_entry::PAGEOUT;
@@ -2219,6 +2304,9 @@ Pgman::verify_page_entry(Ptr<Page_entry>
     break;
   case Page_entry::SL_OTHER:
     break;
+  case ZNIL:
+    ndbrequire(to_release || dump_page_lists(ptrI));
+    break;
   default:
     ndbrequire(false || dump_page_lists(ptrI));
     break;
@@ -2228,124 +2316,114 @@ Pgman::verify_page_entry(Ptr<Page_entry>
 void
 Pgman::verify_page_lists()
 {
+  const Stats& stats = m_stats;
+  const Param& param = m_param;
   Page_hashlist& pl_hash = m_page_hashlist;
   Page_stack& pl_stack = m_page_stack;
   Page_queue& pl_queue = m_page_queue;
   Ptr<Page_entry> ptr;
 
-  Uint32 stack_count = 0;
-  Uint32 queue_count = 0;
-  Uint32 queuewait_count = 0;
-  Uint32 locked_bound_count = 0;
+  Uint32 is_locked = 0;
+  Uint32 is_bound = 0;
+  Uint32 is_mapped = 0;
+  Uint32 is_hot = 0;
+  Uint32 on_stack = 0;
+  Uint32 on_queue = 0;
+  Uint32 to_queue = 0;
 
   Page_hashlist::Iterator iter;
   pl_hash.next(0, iter);
   while (iter.curr.i != RNIL)
   {
-    verify_page_entry(iter.curr);
+    ptr = iter.curr;
+    Page_state state = ptr.p->m_state;
+    // (state == 0) occurs only within a time-slice
+    ndbrequire(state != 0);
+    verify_page_entry(ptr);
 
-    Page_state state = iter.curr.p->m_state;
+    if (state & Page_entry::LOCKED)
+      is_locked++;
+    if (state & Page_entry::BOUND)
+      is_bound++;
+    if (state & Page_entry::MAPPED)
+      is_mapped++;
+    if (state & Page_entry::HOT)
+      is_hot++;
     if (state & Page_entry::ONSTACK)
-      stack_count++;
+      on_stack++;
     if (state & Page_entry::ONQUEUE)
-      queue_count++;
+      on_queue++;
     if (! (state & Page_entry::LOCKED) &&
         ! (state & Page_entry::HOT) &&
         (state & Page_entry::REQUEST) &&
         ! (state & Page_entry::BOUND))
-      queuewait_count++;
-    if (state & Page_entry::LOCKED &&
-        state & Page_entry::BOUND)
-      locked_bound_count++;
+      to_queue++;
     pl_hash.next(iter);
   }
 
-  ndbrequire(stack_count == pl_stack.count() || dump_page_lists());
-  ndbrequire(queue_count == pl_queue.count() || dump_page_lists());
-
-  Uint32 hot_count = 0;
-  Uint32 hot_bound_count = 0;
-  Uint32 cold_bound_count = 0;
-  Uint32 stack_request_count = 0;
-  Uint32 queue_request_count = 0;
-
-  Uint32 i1 = RNIL;
   for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
   {
-    ndbrequire(i1 != ptr.i);
-    i1 = ptr.i;
     Page_state state = ptr.p->m_state;
-    ndbrequire(state & Page_entry::ONSTACK || dump_page_lists());
+    ndbrequire(state & Page_entry::ONSTACK || dump_page_lists(ptr.i));
     if (! pl_stack.hasPrev(ptr))
-      ndbrequire(state & Page_entry::HOT || dump_page_lists());
-    if (state & Page_entry::HOT) {
-      hot_count++;
-      if (state & Page_entry::BOUND)
-        hot_bound_count++;
-    }
-    if (state & Page_entry::REQUEST)
-      stack_request_count++;
+      ndbrequire(state & Page_entry::HOT || dump_page_lists(ptr.i));
   }
 
-  Uint32 i2 = RNIL;
   for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
   {
-    ndbrequire(i2 != ptr.i);
-    i2 = ptr.i;
     Page_state state = ptr.p->m_state;
-    ndbrequire(state & Page_entry::ONQUEUE || dump_page_lists());
-    ndbrequire(state & Page_entry::BOUND || dump_page_lists());
-    cold_bound_count++;
-    if (state & Page_entry::REQUEST)
-      queue_request_count++;
+    ndbrequire(state & Page_entry::ONQUEUE || dump_page_lists(ptr.i));
+    ndbrequire(state & Page_entry::BOUND || dump_page_lists(ptr.i));
+    ndbrequire(! (state & Page_entry::HOT) || dump_page_lists(ptr.i));
   }
 
-  Uint32 tot_bound_count =
-    locked_bound_count + hot_bound_count + cold_bound_count;
-  ndbrequire(m_stats.m_num_pages == tot_bound_count || dump_page_lists());
+  ndbrequire(is_bound == stats.m_num_pages || dump_page_lists());
+  ndbrequire(is_hot == stats.m_num_hot_pages || dump_page_lists());
+  ndbrequire(on_stack == pl_stack.count() || dump_page_lists());
+  ndbrequire(on_queue == pl_queue.count() || dump_page_lists());
 
   Uint32 k;
   Uint32 entry_count = 0;
-
+  char sublist_info[200] = "";
   for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
   {
     const Page_sublist& pl = *m_page_sublist[k];
     for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
-    {
-      ndbrequire(get_sublist_no(ptr.p->m_state) == k || dump_page_lists());
-      entry_count++;
-    }
+      ndbrequire(get_sublist_no(ptr.p->m_state) == k || dump_page_lists(ptr.i));
+    entry_count += pl.count();
+    sprintf(sublist_info + strlen(sublist_info),
+            " %s:%u", get_sublist_name(k), pl.count());
   }
-
   ndbrequire(entry_count == pl_hash.count() || dump_page_lists());
 
+  Uint32 hit_pct = 0;
+  char hit_pct_str[20];
+  if (stats.m_page_hits + stats.m_page_faults != 0)
+    hit_pct = 10000 * stats.m_page_hits /
+              (stats.m_page_hits + stats.m_page_faults);
+  sprintf(hit_pct_str, "%u.%02u", hit_pct / 100, hit_pct % 100);
+
   D("loop"
-    << " stats=" << m_stats_loop_on
-    << " busy=" << m_busy_loop_on
-    << " cleanup=" << m_cleanup_loop_on
-    << " lcp=" << m_lcp_loop_on);
-
-  D("stat"
-    << " entry:" << pl_hash.count()
-    << " cache:" << m_stats.m_num_pages
-    << "(" << locked_bound_count << "L)"
+    << " stats:" << m_stats_loop_on
+    << " busy:" << m_busy_loop_on
+    << " cleanup:" << m_cleanup_loop_on
+    << " lcp:" << m_lcp_loop_on);
+
+  D("page"
+    << " entries:" << pl_hash.count()
+    << " pages:" << stats.m_num_pages << "/" << param.m_max_pages
+    << " mapped:" << is_mapped
+    << " hot:" << is_hot
+    << " io:" << stats.m_current_io_waits << "/" << param.m_max_io_waits
+    << " hit pct:" << hit_pct_str);
+
+  D("list"
+    << " locked:" << is_locked
     << " stack:" << pl_stack.count()
-    << " hot:" << hot_count
-    << " hot_bound:" << hot_bound_count
-    << " stack_request:" << stack_request_count
     << " queue:" << pl_queue.count()
-    << " queue_request:" << queue_request_count
-    << " queuewait:" << queuewait_count);
+    << " to queue:" << to_queue);
 
-  char countbuf[200];
-  countbuf[0] = 0;
-  for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
-  {
-    const Page_sublist& pl = *m_page_sublist[k];
-    sprintf(countbuf + strlen(countbuf), " %s:%u",
-            get_sublist_name(k), pl.count());
-  }
-  D("list" << countbuf);
+  D(sublist_info);
 }
 
 void
@@ -2368,54 +2446,35 @@ Pgman::dump_page_lists(Uint32 ptrI)
   // use debugOut directly
   debugOut << "PGMAN: page list dump" << endl;
   if (ptrI != RNIL)
-    debugOut << "PGMAN: error on PE [" << ptrI << "]" << endl;
+    debugOut << "PGMAN: error on PE [" << ptrI << "]" << "\n";
 
   Page_hashlist& pl_hash = m_page_hashlist;
   Page_stack& pl_stack = m_page_stack;
   Page_queue& pl_queue = m_page_queue;
   Ptr<Page_entry> ptr;
   Uint32 n;
-  char buf[40];
 
-  debugOut << "hash:" << endl;
-  Page_hashlist::Iterator iter;
-  pl_hash.next(0, iter);
-  n = 0;
-  while (iter.curr.i != RNIL)
-  {
-    sprintf(buf, "%03d", n++);
-    debugOut << buf << " " << iter.curr << endl;
-    pl_hash.next(iter);
-  }
-
-  debugOut << "stack:" << endl;
+  debugOut << "stack:" << "\n";
   n = 0;
   for (pl_stack.first(ptr); ptr.i != RNIL; pl_stack.next(ptr))
-  {
-    sprintf(buf, "%03d", n++);
-    debugOut << buf << " " << ptr << endl;
-  }
+    debugOut << n++ << " " << ptr << "\n";
 
-  debugOut << "queue:" << endl;
+  debugOut << "queue:" << "\n";
   n = 0;
   for (pl_queue.first(ptr); ptr.i != RNIL; pl_queue.next(ptr))
-  {
-    sprintf(buf, "%03d", n++);
-    debugOut << buf << " " << ptr << endl;
-  }
+    debugOut << n++ << " " << ptr << "\n";
 
   Uint32 k;
   for (k = 0; k < Page_entry::SUBLIST_COUNT; k++)
   {
-    debugOut << get_sublist_name(k) << ":" << endl;
+    debugOut << get_sublist_name(k) << ":" << "\n";
     const Page_sublist& pl = *m_page_sublist[k];
+    n = 0;
     for (pl.first(ptr); ptr.i != RNIL; pl.next(ptr))
-    {
-      sprintf(buf, "%03d", n++);
-    debugOut << buf << " " << ptr << endl;
-    }
+      debugOut << n++ << " " << ptr << "\n";
   }
 
+  debugOut.flushline();
   return false;
 }
 
@@ -2432,9 +2491,9 @@ Pgman::get_sublist_name(Uint32 list_no)
   case Page_entry::SL_MAP_IO:
     return "map_io";
   case Page_entry::SL_CALLBACK:
-    return "callback";
+    return "cb";
   case Page_entry::SL_CALLBACK_IO:
-    return "callback_io";
+    return "cb_io";
   case Page_entry::SL_BUSY:
     return "busy";
   case Page_entry::SL_LOCKED:
@@ -2580,6 +2639,15 @@ Pgman::execDUMP_STATE_ORD(Signal* signal
 {
   jamEntry();
   Page_hashlist& pl_hash = m_page_hashlist;
+#ifdef VM_TRACE
+  if (signal->theData[0] == 11000 && signal->getLength() == 2)
+  {
+    // has no effect currently
+    Uint32 flag = signal->theData[1];
+    debugFlag = flag & 1;
+    debugSummaryFlag = flag & 2;
+  }
+#endif
 
   if (signal->theData[0] == 11001)
   {

=== modified file 'storage/ndb/src/kernel/blocks/pgman.hpp'
--- a/storage/ndb/src/kernel/blocks/pgman.hpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/kernel/blocks/pgman.hpp	2009-11-27 09:22:07 +0000
@@ -54,7 +54,7 @@
  * Updating a resident cache page makes it "dirty".  A background
  * clean-up process makes dirty pages "clean" via "pageout" to disk.
  * Write ahead logging (WAL) of the page is done first i.e. UNDO log is
- * flushed up to the page log sequence number (LSN) by calling a TSMAN
+ * flushed up to the page log sequence number (LSN) by calling a LGMAN
  * method.  The reason for this is obvious but not relevant to PGMAN.
  *
  * A local check point (LCP) periodically performs a complete pageout of
@@ -420,9 +420,10 @@ private:
   struct Stats {
     Stats();
     Uint32 m_num_pages;         // current number of cache pages
-    Uint32 m_page_hits;
-    Uint32 m_page_faults;
+    Uint32 m_num_hot_pages;
     Uint32 m_current_io_waits;
+    Uint64 m_page_hits;
+    Uint64 m_page_faults;
   } m_stats;
 
   enum CallbackIndex {
@@ -495,6 +496,7 @@ private:
   void fswritereq(Signal*, Ptr<Page_entry>);
   void fswriteconf(Signal*, Ptr<Page_entry>);
 
+  int get_page_no_lirs(Signal*, Ptr<Page_entry>, Page_request page_req);
   int get_page(Signal*, Ptr<Page_entry>, Page_request page_req);
   void update_lsn(Ptr<Page_entry>, Uint32 block, Uint64 lsn);
   Uint32 create_data_file();
@@ -504,6 +506,8 @@ private:
   int drop_page(Ptr<Page_entry>);
   
 #ifdef VM_TRACE
+  bool debugFlag;        // not yet in use in 7.0
+  bool debugSummaryFlag; // loop summary to signal log even if ! debugFlag
   void verify_page_entry(Ptr<Page_entry> ptr);
   void verify_page_lists();
   void verify_all();

=== modified file 'storage/ndb/src/kernel/vm/Configuration.cpp'
--- a/storage/ndb/src/kernel/vm/Configuration.cpp	2009-11-09 13:29:20 +0000
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp	2009-12-04 12:45:23 +0000
@@ -788,23 +788,14 @@ Configuration::calcSizeAlt(ConfigValues 
     cfg.put(CFG_DIH_API_CONNECT, 
 	    2 * noOfTransactions);
     
-    Uint32 noFragPerTable= ((noOfDBNodes + NO_OF_FRAGS_PER_CHUNK - 1) >>
-                           LOG_NO_OF_FRAGS_PER_CHUNK) <<
-                           LOG_NO_OF_FRAGS_PER_CHUNK;
+    Uint32 noFragPerTable= (((noOfDBNodes * lqhInstances) + 
+                             NO_OF_FRAGS_PER_CHUNK - 1) >>
+                            LOG_NO_OF_FRAGS_PER_CHUNK) <<
+      LOG_NO_OF_FRAGS_PER_CHUNK;
 
     cfg.put(CFG_DIH_FRAG_CONNECT, 
 	    noFragPerTable *  noOfMetaTables);
     
-    int temp;
-    temp = noOfReplicas - 2;
-    if (temp < 0)
-      temp = 1;
-    else
-      temp++;
-    cfg.put(CFG_DIH_MORE_NODES, 
-	    temp * NO_OF_FRAG_PER_NODE *
-	    noOfMetaTables *  noOfDBNodes);
-
     cfg.put(CFG_DIH_REPLICAS, 
 	    NO_OF_FRAG_PER_NODE * noOfMetaTables *
 	    noOfDBNodes * noOfReplicas * lqhInstances);

=== modified file 'storage/ndb/src/kernel/vm/DynArr256.cpp'
--- a/storage/ndb/src/kernel/vm/DynArr256.cpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/kernel/vm/DynArr256.cpp	2009-12-04 05:53:03 +0000
@@ -47,7 +47,8 @@ struct DA256Page
   struct DA256Node m_nodes[30];
 };
 
-#define require(x) require_impl(x, __LINE__)
+#undef require
+#define require(x) require_exit_or_core_with_printer((x), 0, ndbout_printer)
 //#define DA256_USE_PX
 //#define DA256_USE_PREFETCH
 #define DA256_EXTRA_SAFE

=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.cpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2009-11-16 13:36:35 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.cpp	2009-12-06 17:12:40 +0000
@@ -335,6 +335,38 @@ SimulatedBlock::handle_invalid_fragmentI
 #endif
 }
 
+void
+SimulatedBlock::handle_out_of_longsignal_memory(Signal * signal) const
+{
+  ErrorReporter::handleError(NDBD_EXIT_OUT_OF_LONG_SIGNAL_MEMORY,
+			     "Out of LongMessageBuffer in sendSignal",
+			     "");
+}
+
+void
+SimulatedBlock::handle_send_failed(SendStatus ss, Signal * signal) const
+{
+  switch(ss){
+  case SEND_BUFFER_FULL:
+    ErrorReporter::handleError(NDBD_EXIT_GENERIC,
+                               "Out of SendBufferMemory in sendSignal", "");
+    break;
+  case SEND_MESSAGE_TOO_BIG:
+    ErrorReporter::handleError(NDBD_EXIT_NDBREQUIRE,
+                               "Message to big in sendSignal", "");
+    break;
+  case SEND_UNKNOWN_NODE:
+    ErrorReporter::handleError(NDBD_EXIT_NDBREQUIRE,
+                               "Unknown node in sendSignal", "");
+    break;
+  case SEND_OK:
+  case SEND_BLOCKED:
+  case SEND_DISCONNECTED:
+    break;
+  }
+  ndbrequire(false);
+}
+
 static void
 linkSegments(Uint32 head, Uint32 tail){
   
@@ -522,18 +554,13 @@ SimulatedBlock::sendSignal(BlockReferenc
                                                &signal->theData[0], recNode,
                                                (LinearSectionPtr*)0);
 #endif
-/*  if(!(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED)){
- *      ndbout << "Failed to send signal no " << gsn 
- *	     << " sender blockNumber=" << refToMain(sendBRef)
- *	     << " sender Nodeno=" << refToNode(sendBRef)
- *	     << " sender instanceNo=" << refToInstance(sendBRef) 
- *	     << " blockNumber=" << refToMain(ref)
- *	     << " Nodeno=" << refToNode(ref)
- *	     << " instanceNo=" << refToInstance(ref) << endl;
- *     ndbout.flushline();
- *   }
- */   
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
   }
   return;
 }
@@ -635,7 +662,12 @@ SimulatedBlock::sendSignal(NodeReceiverG
                                                (LinearSectionPtr*)0);
 #endif
 
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
   }
 
   return;
@@ -692,11 +724,17 @@ SimulatedBlock::sendSignal(BlockReferenc
     /**
      * We have to copy the data
      */
+    bool ok = true;
     Ptr<SectionSegment> segptr[3];
     for(Uint32 i = 0; i<noOfSections; i++){
-      ndbrequire(::import(SB_SP_ARG segptr[i], ptr[i].p, ptr[i].sz));
+      ok &= ::import(SB_SP_ARG segptr[i], ptr[i].p, ptr[i].sz);
       signal->theData[length+i] = segptr[i].i;
     }
+
+    if (unlikely(! ok))
+    {
+      handle_out_of_longsignal_memory(signal);
+    }
     
 #ifdef NDBD_MULTITHREADED
     if (jobBuffer == JBB)
@@ -743,7 +781,12 @@ SimulatedBlock::sendSignal(BlockReferenc
                                                ptr);
 #endif
 
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
   }
 
   signal->header.m_noOfSections = 0;
@@ -807,12 +850,18 @@ SimulatedBlock::sendSignal(NodeReceiverG
     /**
      * We have to copy the data
      */
+    bool ok = true;
     Ptr<SectionSegment> segptr[3];
     for(Uint32 i = 0; i<noOfSections; i++){
-      ndbrequire(::import(SB_SP_ARG segptr[i], ptr[i].p, ptr[i].sz));
+      ok &= ::import(SB_SP_ARG segptr[i], ptr[i].p, ptr[i].sz);
       signal->theData[length+i] = segptr[i].i;
     }
 
+    if (unlikely(! ok))
+    {
+      handle_out_of_longsignal_memory(signal);
+    }
+
 #ifdef NDBD_MULTITHREADED
     if (jobBuffer == JBB)
       sendlocal(m_threadId, &signal->header, signal->theData,
@@ -862,7 +911,12 @@ SimulatedBlock::sendSignal(NodeReceiverG
                                                ptr);
 #endif
 
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
   }
   
   signal->header.m_noOfSections = 0;
@@ -967,7 +1021,13 @@ SimulatedBlock::sendSignal(BlockReferenc
                                                sections->m_ptr);
 #endif
 
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
+
     ::releaseSections(SB_SP_ARG noOfSections, sections->m_ptr);
   }
 
@@ -1090,7 +1150,12 @@ SimulatedBlock::sendSignal(NodeReceiverG
                                                sections->m_ptr);
 #endif
 
-    ndbrequire(ss == SEND_OK || ss == SEND_BLOCKED || ss == SEND_DISCONNECTED);
+    if (unlikely(! (ss == SEND_OK ||
+                    ss == SEND_BLOCKED ||
+                    ss == SEND_DISCONNECTED)))
+    {
+      handle_send_failed(ss, signal);
+    }
   }
 
   if (release)
@@ -2679,8 +2744,9 @@ SimulatedBlock::sendFirstFragment(Fragme
   
   /* Store main signal data in a segment for sending later */
   Ptr<SectionSegment> tmp;
-  if(!import(tmp, &signal->theData[0], length)){
-    ndbrequire(false);
+  if(!import(tmp, &signal->theData[0], length))
+  {
+    handle_out_of_longsignal_memory(0);
     return false;
   }
   info.m_theDataSection.p = &tmp.p->theData[0];
@@ -3019,8 +3085,9 @@ SimulatedBlock::sendFirstFragment(Fragme
   info.m_callback.m_callbackFunction = 0;
 
   Ptr<SectionSegment> tmp;
-  if(!import(tmp, &signal->theData[0], length)){
-    ndbrequire(false);
+  if(unlikely(!import(tmp, &signal->theData[0], length)))
+  {
+    handle_out_of_longsignal_memory(0);
     return false;
   }
 
@@ -3739,7 +3806,10 @@ SimulatedBlock::sendRoutedSignal(RoutePa
     handle.m_ptr[2] = handle.m_ptr[1];
     handle.m_ptr[1] = handle.m_ptr[0];
     Ptr<SectionSegment> tmp;
-    ndbrequire(import(tmp, signal->theData, sigLen));
+    if (unlikely(! import(tmp, signal->theData, sigLen)))
+    {
+      handle_out_of_longsignal_memory(0);
+    }
     handle.m_ptr[0].p = tmp.p;
     handle.m_ptr[0].i = tmp.i;
     handle.m_ptr[0].sz = sigLen;

=== modified file 'storage/ndb/src/kernel/vm/SimulatedBlock.hpp'
--- a/storage/ndb/src/kernel/vm/SimulatedBlock.hpp	2009-11-10 09:50:28 +0000
+++ b/storage/ndb/src/kernel/vm/SimulatedBlock.hpp	2009-12-06 17:12:40 +0000
@@ -336,6 +336,8 @@ protected:
   void handle_lingering_sections_after_execute(Signal*) const;
   void handle_lingering_sections_after_execute(SectionHandle*) const;
   void handle_invalid_fragmentInfo(Signal*) const;
+  void handle_send_failed(SendStatus, Signal*) const;
+  void handle_out_of_longsignal_memory(Signal*) const;
 
   /**
    * Send routed signals (ONLY LOCALLY)

=== modified file 'storage/ndb/src/kernel/vm/mt.cpp'
--- a/storage/ndb/src/kernel/vm/mt.cpp	2009-11-02 18:03:43 +0000
+++ b/storage/ndb/src/kernel/vm/mt.cpp	2009-12-06 17:12:40 +0000
@@ -259,14 +259,6 @@ wakeup(struct thr_wait* wait)
 
 #endif
 
-static inline
-void
-require(bool x)
-{
-  if (unlikely(!(x)))
-    abort();
-}
-
 #ifdef NDB_HAVE_XCNG
 struct thr_spin_lock
 {

=== modified file 'storage/ndb/src/mgmapi/mgmapi.cpp'
--- a/storage/ndb/src/mgmapi/mgmapi.cpp	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp	2009-12-02 16:01:50 +0000
@@ -40,6 +40,7 @@
 
 #include <base64.h>
 
+//#define MGMAPI_LOG
 #define MGM_CMD(name, fun, desc) \
  { name, \
    0, \
@@ -1163,6 +1164,27 @@ ndb_mgm_stop2(NdbMgmHandle handle, int n
 
 extern "C"
 int
+ndb_mgm_obtain_mgmd_version(NdbMgmHandle handle)
+{
+  if (handle->mgmd_version_build == -1)
+  {
+    char verStr[64]; /* Long enough? */
+
+    if (!ndb_mgm_get_version(handle,
+                             &(handle->mgmd_version_major),
+                             &(handle->mgmd_version_minor),
+                             &(handle->mgmd_version_build),
+                             sizeof(verStr),
+                             verStr))
+    {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+extern "C"
+int
 ndb_mgm_stop3(NdbMgmHandle handle, int no_of_nodes, const int * node_list,
 	      int abort, int *disconnect)
 {
@@ -1184,19 +1206,11 @@ ndb_mgm_stop3(NdbMgmHandle handle, int n
 
   CHECK_CONNECTED(handle, -1);
 
-  if(handle->mgmd_version_build==-1)
+  if(ndb_mgm_obtain_mgmd_version(handle) == -1)
   {
-    char verstr[50];
-    if(!ndb_mgm_get_version(handle,
-                        &(handle->mgmd_version_major),
-                        &(handle->mgmd_version_minor),
-                        &(handle->mgmd_version_build),
-                        sizeof(verstr),
-                            verstr))
-    {
       return -1;
-    }
   }
+
   int use_v2= ((handle->mgmd_version_major==5)
     && (
         (handle->mgmd_version_minor==0 && handle->mgmd_version_build>=21)
@@ -2211,6 +2225,20 @@ ndb_mgm_start_backup3(NdbMgmHandle handl
 		     unsigned int input_backupId,
 		     unsigned int backuppoint) 
 {
+  /* Before we start the backup, first get the version of the
+   * management node we are connected to
+   */
+  if (ndb_mgm_obtain_mgmd_version(handle) == -1)
+  {
+    return -1;
+  }
+
+  Uint32 mgmdVersion = NDB_MAKE_VERSION(handle->mgmd_version_major,
+                                        handle->mgmd_version_minor,
+                                        handle->mgmd_version_build);
+  
+  bool sendBackupPoint = (mgmdVersion >= MGMD_MGMAPI_PROTOCOL_CHANGE);
+
   CHECK_HANDLE(handle, -1);
   SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_start_backup");
   const ParserRow<ParserDummy> start_backup_reply[] = {
@@ -2225,7 +2253,9 @@ ndb_mgm_start_backup3(NdbMgmHandle handl
   args.put("completed", wait_completed);
   if(input_backupId > 0)
     args.put("backupid", input_backupId);
-  args.put("backuppoint", backuppoint);
+  if (sendBackupPoint)
+    args.put("backuppoint", backuppoint);
+
   const Properties *reply;
   { // start backup can take some time, set timeout high
     int old_timeout= handle->timeout;
@@ -2308,13 +2338,30 @@ struct ndb_mgm_configuration *
 ndb_mgm_get_configuration2(NdbMgmHandle handle, unsigned int version,
                            enum ndb_mgm_node_type nodetype)
 {
+  /* Before we get the config, first get the version of the
+   * managment node we are connected to
+   */
+  if (ndb_mgm_obtain_mgmd_version(handle) == -1)
+  {
+    return NULL;
+  }
+
+  Uint32 mgmdVersion = NDB_MAKE_VERSION(handle->mgmd_version_major,
+                                        handle->mgmd_version_minor,
+                                        handle->mgmd_version_build);
+  
+  bool getConfigUsingNodetype = (mgmdVersion >= MGMD_MGMAPI_PROTOCOL_CHANGE); 
+
   CHECK_HANDLE(handle, 0);
   SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_configuration");
   CHECK_CONNECTED(handle, 0);
 
   Properties args;
   args.put("version", version);
-  args.put("nodetype", nodetype);
+  if (getConfigUsingNodetype)
+  {
+    args.put("nodetype", nodetype);
+  }
 
   const ParserRow<ParserDummy> reply[] = {
     MGM_CMD("get config reply", NULL, ""),

=== modified file 'storage/ndb/src/mgmsrv/CMakeLists.txt'
--- a/storage/ndb/src/mgmsrv/CMakeLists.txt	2009-11-13 04:50:47 +0000
+++ b/storage/ndb/src/mgmsrv/CMakeLists.txt	2009-11-17 18:13:57 +0000
@@ -45,3 +45,7 @@ ADD_EXECUTABLE(ndb_mgmd
 TARGET_LINK_LIBRARIES(ndb_mgmd ndbconf)
 
 INSTALL(TARGETS ndb_mgmd DESTINATION libexec)
+
+ADD_EXECUTABLE(MgmConfig-t
+               testConfig.cpp)
+TARGET_LINK_LIBRARIES(ndb_mgmd ndbconf)

=== modified file 'storage/ndb/src/mgmsrv/Config.cpp'
--- a/storage/ndb/src/mgmsrv/Config.cpp	2009-10-09 12:47:49 +0000
+++ b/storage/ndb/src/mgmsrv/Config.cpp	2009-12-03 05:53:33 +0000
@@ -24,12 +24,6 @@
 
 #include <HashMap.hpp>
 
-static void require(bool b)
-{
-  if (!b)
-    abort();
-}
-
 Config::Config(struct ndb_mgm_configuration *config_values) :
   m_configValues(config_values)
 {
@@ -824,3 +818,19 @@ Config::get_nodemask(NodeBitmask& mask,
   }
 }
 
+
+Uint32
+Config::checksum(void) const {
+  Uint32 chk;
+
+  UtilBuffer buf;
+  pack(buf);
+
+  // Checksum is the last 4 bytes in buffer
+  const char* chk_ptr = (const char*)buf.get_data();
+  chk_ptr += buf.length() - sizeof(Uint32);
+  chk = *(Uint32*) chk_ptr;
+
+  return chk;
+}
+

=== modified file 'storage/ndb/src/mgmsrv/Config.hpp'
--- a/storage/ndb/src/mgmsrv/Config.hpp	2009-09-25 07:57:29 +0000
+++ b/storage/ndb/src/mgmsrv/Config.hpp	2009-11-17 18:13:29 +0000
@@ -120,6 +120,14 @@ public:
   bool equal(const Config*, const unsigned* exclude = NULL) const;
 
   /*
+    Return the checksum of the config. The checksum can be used to compare
+    two configs without having the whole config available(for example on
+    a remote host). It can also be printed to log files for manual verification
+    that same config is used
+  */
+  Uint32 checksum(void) const;
+
+  /*
     Return bitmask of all defined nodes of a certain type
     returns all defined nodes by default.
    */

=== modified file 'storage/ndb/src/mgmsrv/ConfigInfo.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigInfo.cpp	2009-11-03 16:16:09 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp	2009-12-03 05:53:33 +0000
@@ -2789,21 +2789,8 @@ const int ConfigInfo::m_NoOfParams = siz
 /****************************************************************************
  * Ctor
  ****************************************************************************/
-static void
-_require(bool v, const char* expr, unsigned line)
-{
-  if(!v)
-  {
-    fprintf(stderr, "require(%s) failed at %s:%d\n",
-            expr, __FILE__, line);
-    fflush(stderr);
-    if (opt_core)
-      abort();
-    else
-      exit(-1);
-  }
-}
-#define require(x) _require(x, #x, __LINE__)
+#undef require
+#define require(x) require_exit_or_core(x, -1)
 
 ConfigInfo::ConfigInfo()
   : m_info(true), m_systemDefaults(true)
@@ -3860,21 +3847,21 @@ applyDefaultValues(InitConfigFileParser:
 	case ConfigInfo::CI_INT:
 	case ConfigInfo::CI_BOOL:{
 	  Uint32 val = 0;
-	  ::require(defaults->get(name, &val));
+	  require(defaults->get(name, &val));
 	  ctx.m_currentSection->put(name, val);
           DBUG_PRINT("info",("%s=%d #default",name,val));
 	  break;
 	}
 	case ConfigInfo::CI_INT64:{
 	  Uint64 val = 0;
-	  ::require(defaults->get(name, &val));
+	  require(defaults->get(name, &val));
 	  ctx.m_currentSection->put64(name, val);
           DBUG_PRINT("info",("%s=%lld #default",name,val));
 	  break;
 	}
 	case ConfigInfo::CI_STRING:{
 	  const char * val;
-	  ::require(defaults->get(name, &val));
+	  require(defaults->get(name, &val));
 	  ctx.m_currentSection->put(name, val);
           DBUG_PRINT("info",("%s=%s #default",name,val));
 	  break;
@@ -3890,20 +3877,20 @@ applyDefaultValues(InitConfigFileParser:
         case ConfigInfo::CI_INT:
         case ConfigInfo::CI_BOOL:{
           Uint32 val = 0;
-          ::require(ctx.m_currentSection->get(name, &val));
+          require(ctx.m_currentSection->get(name, &val));
           DBUG_PRINT("info",("%s=%d",name,val));
           break;
         }
         case ConfigInfo::CI_INT64:{
           Uint64 val = 0;
-          ::require(ctx.m_currentSection->get(name, &val));
+          require(ctx.m_currentSection->get(name, &val));
           DBUG_PRINT("info",("%s=%lld",name,val));
           break;
         }
         case ConfigInfo::CI_ENUM:
         case ConfigInfo::CI_STRING:{
           const char * val;
-          ::require(ctx.m_currentSection->get(name, &val));
+          require(ctx.m_currentSection->get(name, &val));
           DBUG_PRINT("info",("%s=%s",name,val));
           break;
         }
@@ -3939,11 +3926,11 @@ checkMandatory(InitConfigFileParser::Con
   Properties::Iterator it(ctx.m_currentInfo);
   for(const char * name = it.first(); name != NULL; name = it.next()){
     const Properties * info = NULL;
-    ::require(ctx.m_currentInfo->get(name, &info));
+    require(ctx.m_currentInfo->get(name, &info));
     Uint32 val;
     if(info->get("Mandatory", &val)){
       const char * fname;
-      ::require(info->get("Fname", &fname));
+      require(info->get("Fname", &fname));
       if(!ctx.m_currentSection->contains(fname)){
 	ctx.reportError("Mandatory parameter %s missing from section "
 			"[%s] starting at line: %d",
@@ -4444,24 +4431,24 @@ fixDepricated(InitConfigFileParser::Cont
     case PropertiesType_Uint32:{
       Uint32 val;
       require(tmp.get(name, &val));
-      ::require(ctx.m_currentSection->put(name, val));
+      require(ctx.m_currentSection->put(name, val));
       break;
     }
     case PropertiesType_char:{
       const char * val;
       require(tmp.get(name, &val));
-      ::require(ctx.m_currentSection->put(name, val));
+      require(ctx.m_currentSection->put(name, val));
       break;
     }
     case PropertiesType_Uint64:{
       Uint64 val;
       require(tmp.get(name, &val));
-      ::require(ctx.m_currentSection->put64(name, val));
+      require(ctx.m_currentSection->put64(name, val));
       break;
     }
     case PropertiesType_Properties:
     default:
-      ::require(false);
+      require(false);
     }
   }
   return true;

=== modified file 'storage/ndb/src/mgmsrv/ConfigManager.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigManager.cpp	2009-10-27 16:50:41 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigManager.cpp	2009-12-03 05:53:33 +0000
@@ -28,19 +28,6 @@
 #include <ndb_version.h>
 
 
-static void
-_require(bool v, const char* expr, const char* file, int line)
-{
-  if (unlikely(!v))
-  {
-    fprintf(stderr, "%s:%d: require('%s') failed\n",
-            file, line, expr);
-    fflush(stderr);
-    abort();
-  }
-}
-#define require(v)  _require((v), #v, __FILE__, __LINE__)
-
 extern "C" const char* opt_connect_str;
 
 ConfigManager::ConfigManager(const MgmtSrvr::MgmtOpts& opts,
@@ -1323,6 +1310,22 @@ ConfigManager::execCONFIG_CHANGE_REQ(Sig
 }
 
 
+static Uint32
+config_check_checksum(const Config* config)
+{
+  Config copy(config);
+
+  // Make constants of a few values in SYSTEM section that are
+  // not part of the  checksum used for "config check"
+  copy.setName("CHECKSUM");
+  copy.setPrimaryMgmNode(0);
+
+  Uint32 checksum = copy.checksum();
+
+  return checksum;
+}
+
+
 void
 ConfigManager::execCONFIG_CHECK_REQ(SignalSender& ss, SimpleSignal* sig)
 {
@@ -1337,12 +1340,24 @@ ConfigManager::execCONFIG_CHECK_REQ(Sign
 
   Uint32 generation = m_config->getGeneration();
 
-  g_eventLogger->debug("Got CONFIG_CHECK_REQ from node: %d. "   \
-                       "generation: %d, other_generation: %d, " \
-                       "our state: %d, other state: %d",
-                       nodeId, generation, other_generation,
-                       m_config_state, other_state);
+  // checksum
+  Uint32 checksum = config_check_checksum(m_config);
+  Uint32 other_checksum = req->checksum;
+  if (sig->header.theLength == ConfigCheckReq::SignalLengthBeforeChecksum)
+  {
+    // Other side uses old version without checksum, use our checksum to
+    // bypass the checks
+    g_eventLogger->debug("Other mgmd does not have checksum, using own");
+    other_checksum = checksum;
+  }
 
+  g_eventLogger->debug("Got CONFIG_CHECK_REQ from node: %d. "
+                       "Our generation: %d, other generation: %d, "
+                       "our state: %d, other state: %d, "
+                       "our checksum: 0x%.8x, other checksum: 0x%.8x",
+                       nodeId, generation, other_generation,
+                       m_config_state, other_state,
+                       checksum, other_checksum);
 
   switch (m_config_state)
   {
@@ -1376,6 +1391,17 @@ ConfigManager::execCONFIG_CHECK_REQ(Sign
                          m_config_state, other_state);
       return;
     }
+
+    if (other_checksum != checksum)
+    {
+      g_eventLogger->warning("Refusing other node, it has different "
+                             "checksum: 0x%.8x, expected: 0x%.8x",
+                             other_checksum, checksum);
+      sendConfigCheckRef(ss, from, ConfigCheckRef::WrongChecksum,
+                         generation, other_generation,
+                         m_config_state, other_state);
+      return;
+    }
     break;
 
   case CS_CONFIRMED:
@@ -1393,7 +1419,18 @@ ConfigManager::execCONFIG_CHECK_REQ(Sign
 
     if (other_generation == generation)
     {
-      ;// OK
+      // Same generation, make sure it has same checksum
+      if (other_checksum != checksum)
+      {
+        g_eventLogger->warning("Refusing other node, it has different "
+                               "checksum: 0x%.8x, expected: 0x%.8x",
+                               other_checksum, checksum);
+        sendConfigCheckRef(ss, from, ConfigCheckRef::WrongChecksum,
+                           generation, other_generation,
+                           m_config_state, other_state);
+        return;
+      }
+      // OK!
     }
     else if (other_generation < generation)
     {
@@ -1429,17 +1466,15 @@ ConfigManager::sendConfigCheckReq(Signal
     CAST_PTR(ConfigCheckReq, ssig.getDataPtrSend());
   req->state =        m_config_state;
   req->generation =   m_config->getGeneration();
+  req->checksum =     config_check_checksum(m_config);
 
-  BaseString buf("Sending CONFIG_CHECK_REQ to node(s) ");
-  unsigned i = 0;
-  while((i = to.find(i+1)) != NodeBitmask::NotFound)
-    buf.appfmt("%d ", i);
-  g_eventLogger->debug(buf);
+  g_eventLogger->debug("Sending CONFIG_CHECK_REQ to %s",
+                       BaseString::getPrettyText(to).c_str());
 
   require(m_waiting_for.isclear());
   m_waiting_for = ss.broadcastSignal(to, ssig, MGM_CONFIG_MAN,
-                                GSN_CONFIG_CHECK_REQ,
-                                ConfigCheckReq::SignalLength);
+                                     GSN_CONFIG_CHECK_REQ,
+                                     ConfigCheckReq::SignalLength);
 }
 
 static bool
@@ -1559,7 +1594,8 @@ ConfigManager::execCONFIG_CHECK_REF(Sign
                       m_config_state);
 
   assert(ref->generation != ref->expected_generation ||
-         ref->state != ref->expected_state);
+         ref->state != ref->expected_state ||
+         ref->error == ConfigCheckRef::WrongChecksum);
   if((Uint32)m_config_state != ref->state)
   {
     // The config state changed while this check was in the air
@@ -1638,6 +1674,15 @@ ConfigManager::execCONFIG_CHECK_REF(Sign
     break;
   }
 
+  if (ref->error == ConfigCheckRef::WrongChecksum &&
+      m_node_id < nodeId)
+  {
+    g_eventLogger->warning("Ignoring CONFIG_CHECK_REF for wrong checksum "
+                           "other node has higher node id and should "
+                           "shutdown");
+    return;
+  }
+
   g_eventLogger->error("Terminating");
   exit(1);
 }
@@ -1655,6 +1700,10 @@ ConfigManager::run()
 
   m_started.set(m_facade->ownId());
 
+  // exclude nowait-nodes from config change protcol
+  m_all_mgm.bitANDC(m_opts.nowait_nodes);
+  m_all_mgm.set(m_facade->ownId()); // Never exclude own node
+
   start_checkers();
 
   while (!is_stopped())

=== modified file 'storage/ndb/src/mgmsrv/InitConfigFileParser.cpp'
--- a/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp	2009-10-09 12:38:45 +0000
+++ b/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp	2009-12-03 05:53:33 +0000
@@ -30,8 +30,6 @@ extern EventLogger *g_eventLogger;
 const int MAX_LINE_LENGTH = 1024;  // Max length of line of text in config file
 static void trim(char *);
 
-static void require(bool v) { if(!v) abort();}
-
 //****************************************************************************
 //  Ctor / Dtor
 //****************************************************************************

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2009-12-03 05:53:33 +0000
@@ -77,18 +77,6 @@ int g_errorInsert;
 
 extern "C" my_bool opt_core;
 
-static void require(bool v)
-{
-  if(!v)
-  {
-    if (opt_core)
-      abort();
-    else
-      exit(-1);
-  }
-}
-
-
 void *
 MgmtSrvr::logLevelThread_C(void* m)
 {
@@ -2605,7 +2593,7 @@ MgmtSrvr::alloc_node_id_req(NodeId free_
   SimpleSignal ssig;
   AllocNodeIdReq* req = CAST_PTR(AllocNodeIdReq, ssig.getDataPtrSend());
   ssig.set(ss, TestOrd::TraceAPI, QMGR, GSN_ALLOC_NODEID_REQ,
-	   AllocNodeIdReq::SignalLength);
+           AllocNodeIdReq::SignalLength);
   
   req->senderRef = ss.getOwnRef();
   req->senderData = 19;
@@ -2661,7 +2649,9 @@ MgmtSrvr::alloc_node_id_req(NodeId free_
         if (ref->errorCode != AllocNodeIdRef::NotMaster)
         {
           /* sleep for a while (100ms) before retrying */
+          ss.unlock();
           NdbSleep_MilliSleep(100);  
+          ss.lock();
         }
         continue;
       }
@@ -2669,20 +2659,20 @@ MgmtSrvr::alloc_node_id_req(NodeId free_
     }
     case GSN_NF_COMPLETEREP:
     {
-      const NFCompleteRep * const rep =
-        CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
-#ifdef VM_TRACE
-      ndbout_c("Node %d fail completed", rep->failedNodeId);
-#endif
-      if (rep->failedNodeId == nodeId)
-      {
-	do_send = 1;
-        nodeId = 0;
-      }
       continue;
     }
     case GSN_NODE_FAILREP:{
-      // ignore NF_COMPLETEREP will come
+      /**
+       * ok to trap using NODE_FAILREP
+       *   as we don't really wait on anything interesting
+       */
+      const NodeFailRep * const rep =
+	CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
+      if (NdbNodeBitmask::get(rep->theNodes, nodeId))
+      {
+        do_send = 1;
+        nodeId = 0;
+      }
       continue;
     }
     case GSN_API_REGCONF:
@@ -2894,7 +2884,6 @@ MgmtSrvr::try_alloc(unsigned id, const c
       m_connect_address[id].s_addr= 0;
     }
   }
-  m_reserved_nodes.set(id);
   if (theFacade && id != theFacade->ownId())
   {
     /**
@@ -2980,12 +2969,21 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
       continue;
 
     const char *config_hostname= nodes_info[i].host.c_str();
+    /**
+     * set bit as reserved, release mutex, try-alloc reaquire mutex
+     * and clear bit if alloc failed
+     */
+    m_reserved_nodes.set(id);
+    NdbMutex_Unlock(m_node_id_mutex);
     if (!try_alloc(id, config_hostname, type, client_addr, timeout_ms))
     {
+      NdbMutex_Lock(m_node_id_mutex);
       // success
       *nodeId= id;
       DBUG_RETURN(true);
     }
+    NdbMutex_Lock(m_node_id_mutex);
+    m_reserved_nodes.clear(id);
   }
 
   /* now try the open nodes */
@@ -3001,12 +2999,21 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
     if (exact_nodes.get(id))
       continue;
 
+    /**
+     * set bit as reserved, release mutex, try-alloc reaquire mutex
+     * and clear bit if alloc failed
+     */
+    m_reserved_nodes.set(id);
+    NdbMutex_Unlock(m_node_id_mutex);
     if (!try_alloc(id, NULL, type, client_addr, timeout_ms))
     {
+      NdbMutex_Lock(m_node_id_mutex);
       // success
       *nodeId= id;
       DBUG_RETURN(true);
     }
+    NdbMutex_Lock(m_node_id_mutex);
+    m_reserved_nodes.clear(id);
   }
 
   /*
@@ -3315,9 +3322,15 @@ MgmtSrvr::Allocated_resources::Allocated
 
 MgmtSrvr::Allocated_resources::~Allocated_resources()
 {
-  Guard g(m_mgmsrv.m_node_id_mutex);
-  if (!m_reserved_nodes.isclear()) {
-    m_mgmsrv.m_reserved_nodes.bitANDC(m_reserved_nodes); 
+  if (!m_reserved_nodes.isclear())
+  {
+    /**
+     * No need to aquire mutex if we didn't have any reservation in
+     * our sesssion
+     */
+    Guard g(m_mgmsrv.m_node_id_mutex);
+    m_mgmsrv.m_reserved_nodes.bitANDC(m_reserved_nodes);
+
     // node has been reserved, force update signal to ndb nodes
     m_mgmsrv.updateStatus();
 

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2009-11-13 11:24:05 +0000
@@ -123,6 +123,7 @@ public:
     MgmtOpts() : configdir(MYSQLCLUSTERDIR) {};
     int reload;
     int initial;
+    NodeBitmask nowait_nodes;
   };
 
   MgmtSrvr(); // Not implemented

=== modified file 'storage/ndb/src/mgmsrv/main.cpp'
--- a/storage/ndb/src/mgmsrv/main.cpp	2009-09-25 07:27:49 +0000
+++ b/storage/ndb/src/mgmsrv/main.cpp	2009-11-13 11:24:05 +0000
@@ -85,6 +85,7 @@ bool g_RestartServer= false;
 static MgmtSrvr* mgm;
 static MgmtSrvr::MgmtOpts opts;
 static const char* opt_logname = "MgmtSrvr";
+static const char* opt_nowait_nodes = 0;
 
 static struct my_option my_long_options[] =
 {
@@ -142,6 +143,10 @@ static struct my_option my_long_options[
     "Name to use when logging messages for this node",
     (uchar**) &opt_logname, (uchar**) &opt_logname, 0,
     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+  { "nowait-nodes", 256,
+    "Nodes that will not be waited for during start",
+    (uchar**) &opt_nowait_nodes, (uchar**) &opt_nowait_nodes, 0,
+    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
 
@@ -221,6 +226,24 @@ static int mgmd_main(int argc, char** ar
     mgmd_exit(1);
   }
 
+
+  if (opt_nowait_nodes)
+  {
+    int res = opts.nowait_nodes.parseMask(opt_nowait_nodes);
+    if(res == -2 || (res > 0 && opts.nowait_nodes.get(0)))
+    {
+      g_eventLogger->error("Invalid nodeid specified in nowait-nodes: '%s'",
+                           opt_nowait_nodes);
+      mgmd_exit(1);
+    }
+    else if (res < 0)
+    {
+      g_eventLogger->error("Unable to parse nowait-nodes argument: '%s'",
+                           opt_nowait_nodes);
+      mgmd_exit(1);
+    }
+  }
+
   /**
      Install signal handler for SIGPIPE
      Done in TransporterFacade as well.. what about Configretriever?

=== modified file 'storage/ndb/src/mgmsrv/testConfig.cpp'
--- a/storage/ndb/src/mgmsrv/testConfig.cpp	2009-11-03 16:40:26 +0000
+++ b/storage/ndb/src/mgmsrv/testConfig.cpp	2009-11-17 18:13:29 +0000
@@ -260,6 +260,40 @@ print_restart_info(void)
   fprintf(stderr, "\n");
 }
 
+
+static void
+checksum_config(void)
+{
+  Config* c1=
+    create_config("[ndbd]", "NoOfReplicas=1",
+                  "[ndb_mgmd]", "HostName=localhost",
+                  "[mysqld]", NULL);
+  Config* c2=
+    create_config("[ndbd]", "NoOfReplicas=1",
+                  "[ndb_mgmd]", "HostName=localhost",
+                  "[mysqld]", "[mysqld]", NULL);
+
+  ndbout_c("== checksum tests ==");
+  Uint32 c1_check = c1->checksum();
+  Uint32 c2_check = c2->checksum();
+  ndbout_c("c1->checksum(): 0x%x", c1_check);
+  ndbout_c("c2->checksum(): 0x%x", c2_check);
+   // Different config should not have same checksum
+  CHECK(c1_check != c2_check);
+
+  // Same config should have same checksum
+  CHECK(c1_check == c1->checksum());
+
+  // Copied config should have same checksum
+  Config c1_copy(c1);
+  CHECK(c1_check == c1_copy.checksum());
+
+  ndbout_c("==================");
+
+  delete c1;
+  delete c2;
+}
+
 #include <NdbTap.hpp>
 
 TAPTEST(MgmConfig)
@@ -267,6 +301,7 @@ TAPTEST(MgmConfig)
   ndb_init();
   diff_config();
   CHECK(check_params());
+  checksum_config();
 #if 0
   print_restart_info();
 #endif

=== modified file 'storage/ndb/src/ndbapi/Ndb.cpp'
--- a/storage/ndb/src/ndbapi/Ndb.cpp	2009-09-30 07:59:42 +0000
+++ b/storage/ndb/src/ndbapi/Ndb.cpp	2009-12-03 18:19:36 +0000
@@ -2206,6 +2206,154 @@ Ndb::printState(const char* fmt, ...)
     theCompletedTransactionsArray[i]->printState();
   NdbMutex_Unlock(ndb_print_state_mutex);
 }
+
 #endif
 
+const char*
+Ndb::getNdbErrorDetail(const NdbError& err, char* buff, Uint32 buffLen) const
+{
+  DBUG_ENTER("Ndb::getNdbErrorDetail");
+  /* If err has non-null details member, prepare a string containing
+   * those details
+   */
+  if (!buff)
+    DBUG_RETURN(NULL);
+
+  if (err.details != NULL)
+  {
+    DBUG_PRINT("info", ("err.code is %u", err.code));
+    switch (err.code) {
+    case 893: /* Unique constraint violation */
+    {
+      /* err.details contains the violated Index's object id
+       * We'll map it to a name, then map the name to a 
+       * base table, schema and database, and put that in
+       * string form into the caller's buffer
+       */
+      UintPtr uip = (UintPtr) err.details;
+      Uint32 indexObjectId = (Uint32) (uip - (UintPtr(0)));
+      Uint32 primTableObjectId = ~ (Uint32) 0;
+      BaseString indexName;
+      
+      {
+        DBUG_PRINT("info", ("Index object id is %u", indexObjectId));
+        NdbDictionary::Dictionary::List allIndices;
+        int rc = theDictionary->listObjects(allIndices, 
+                                            NdbDictionary::Object::UniqueHashIndex,
+                                            false); // FullyQualified names
+        if (rc)
+        {
+          DBUG_PRINT("info", ("listObjects call 1 failed with rc %u", rc));
+          DBUG_RETURN(NULL);
+        }
+        
+        DBUG_PRINT("info", ("Retrieved details for %u indices", allIndices.count));
+        
+        for (unsigned i = 0; i < allIndices.count; i++)
+        {
+          if (allIndices.elements[i].id == indexObjectId)
+          {
+            /* Found the index in question
+             * Expect fully qualified name to be in the form :
+             * <db>/<schema>/<primTabId>/<IndexName>
+             */
+            Vector<BaseString> idxNameComponents;
+            BaseString idxName(allIndices.elements[i].name);
+            
+            Uint32 components = idxName.split(idxNameComponents,
+                                              &table_name_separator);
+            
+            assert(components == 4);
+            
+            primTableObjectId = atoi(idxNameComponents[2].c_str());
+            indexName = idxNameComponents[3];
+            
+            DBUG_PRINT("info", ("Found index name : %s, primary table id : %u",
+                                indexName.c_str(), primTableObjectId));
+            
+            break;
+          }
+        }
+      }
+
+      if (primTableObjectId != (~(Uint32) 0))
+      {
+        NdbDictionary::Dictionary::List allTables;
+        int rc = theDictionary->listObjects(allTables,
+                                            NdbDictionary::Object::UserTable,
+                                            false); // FullyQualified names
+        
+        if (rc)
+        {
+          DBUG_PRINT("info", ("listObjects call 2 failed with rc %u", rc));
+          DBUG_RETURN(NULL);
+        }
+
+        DBUG_PRINT("info", ("Retrieved details for %u tables", allTables.count));
+
+        for (Uint32 t = 0; t < allTables.count; t++)
+        {
+          
+          if (allTables.elements[t].id == primTableObjectId)
+          {
+            /* Found table, name should be in format :
+             * <db>/<schema>/<tablename>
+             */
+            Vector<BaseString> tabNameComponents;
+            BaseString tabName(allTables.elements[t].name);
+            
+            Uint32 components = tabName.split(tabNameComponents,
+                                              &table_name_separator);
+            assert (components == 3);
+            
+            /* Now we generate a string of the format
+             * <dbname>/<schemaname>/<tabname>/<idxname>
+             * which should be usable by end users
+             */
+            BaseString result;
+            result.assfmt("%s/%s/%s/%s",
+                          tabNameComponents[0].c_str(),
+                          tabNameComponents[1].c_str(),
+                          tabNameComponents[2].c_str(),
+                          indexName.c_str());
+            
+            DBUG_PRINT("info", ("Found full index details : %s",
+                                result.c_str()));
+            
+            memcpy(buff, result.c_str(), 
+                   MIN(buffLen, 
+                       (result.length() + 1)));
+            buff[buffLen] = 0;
+
+            DBUG_RETURN(buff);
+          }
+        }
+
+        /* Primary table not found!  
+         * Strange - perhaps it's been dropped?
+         */          
+        DBUG_PRINT("info", ("Table id %u not found", primTableObjectId));
+        DBUG_RETURN(NULL);
+      }
+      else
+      {
+        /* Index not found from id - strange.
+         * Perhaps it has been dropped?
+         */
+        DBUG_PRINT("info", ("Index id %u not found", indexObjectId));
+        DBUG_RETURN(NULL);
+      }
+    }
+    default:
+    {
+      /* Unhandled details type */
+    }
+    }
+  }
+  
+  DBUG_PRINT("info", ("No details string for this error"));
+  DBUG_RETURN(NULL);
+}
+
+
 

=== modified file 'storage/ndb/src/ndbapi/NdbDictionary.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionary.cpp	2009-10-07 02:56:19 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionary.cpp	2009-12-03 10:19:24 +0000
@@ -582,6 +582,11 @@ NdbDictionary::Table::getNoOfColumns() c
 }
 
 int
+NdbDictionary::Table::getNoOfAutoIncrementColumns() const {
+  return m_impl.m_noOfAutoIncColumns;
+}
+
+int
 NdbDictionary::Table::getNoOfPrimaryKeys() const {
   return m_impl.m_noOfKeys;
 }
@@ -2539,7 +2544,17 @@ NdbDictionary::Dictionary::listObjects(L
 int
 NdbDictionary::Dictionary::listObjects(List& list, Object::Type type) const
 {
-  return m_impl.listObjects(list, type);
+  // delegate to variant with FQ names param
+  return listObjects(list, type, 
+                     m_impl.m_ndb.usingFullyQualifiedNames());
+}
+
+int
+NdbDictionary::Dictionary::listObjects(List& list, Object::Type type,
+                                       bool fullyQualified) const
+{
+  return m_impl.listObjects(list, type, 
+                            fullyQualified);
 }
 
 int

=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2009-09-04 11:33:38 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2009-12-03 10:19:24 +0000
@@ -591,6 +591,7 @@ NdbTableImpl::init(){
   m_noOfDistributionKeys= 0;
   m_noOfBlobs= 0;
   m_replicaCount= 0;
+  m_noOfAutoIncColumns = 0;
   m_ndbrecord= 0;
   m_pkMask= 0;
   m_min_rows = 0;
@@ -872,6 +873,8 @@ NdbTableImpl::assign(const NdbTableImpl&
   m_noOfBlobs = org.m_noOfBlobs;
   m_replicaCount = org.m_replicaCount;
 
+  m_noOfAutoIncColumns = org.m_noOfAutoIncColumns;
+
   m_id = org.m_id;
   m_version = org.m_version;
   m_status = org.m_status;
@@ -921,6 +924,9 @@ NdbTableImpl::computeAggregates()
       m_noOfDiskColumns++;
     
     col->m_keyInfoPos = ~0;
+
+    if (col->m_autoIncrement)
+      m_noOfAutoIncColumns++;
   }
   if (m_noOfDistributionKeys == m_noOfKeys) {
     // all is none!
@@ -2432,7 +2438,17 @@ NdbDictInterface::execGET_TABINFO_REF(Nd
   const GetTabInfoRef* ref = CAST_CONSTPTR(GetTabInfoRef, 
 					   signal->getDataPtr());
   
-  m_error.code= ref->errorCode;
+  if (likely(signal->getLength() == GetTabInfoRef::SignalLength))
+  {
+    m_error.code= ref->errorCode;
+  }
+  else
+  {
+    /* 6.3 <-> 7.0 upgrade only */
+    assert (signal->getLength() == GetTabInfoRef::OriginalSignalLength);
+    m_error.code = (*(signal->getDataPtr() + 
+                      GetTabInfoRef::OriginalErrorOffset));
+  }
   m_waiter.signal(NO_WAIT);
 }
 
@@ -4713,7 +4729,18 @@ NdbDictInterface::execSUB_START_CONF(Ndb
   }
   }
 
-  m_sub_start_conf.m_buckets = subStartConf->bucketCount;
+  if (signal->getLength() == SubStartConf::SignalLength)
+  {
+    m_sub_start_conf.m_buckets = subStartConf->bucketCount;
+  }
+  else
+  {
+    /* 6.3 <-> 7.0 upgrade 
+     * 6.3 doesn't send required bucketCount.  
+     * ~0 indicates no bucketCount received
+     */
+    m_sub_start_conf.m_buckets = ~0;
+  }
   DBUG_PRINT("info",("subscriptionId=%d,subscriptionKey=%d,subscriberData=%d",
 		     subscriptionId,subscriptionKey,subscriberData));
   m_waiter.signal(NO_WAIT);
@@ -5071,7 +5098,9 @@ NdbDictionaryImpl::listEvents(List& list
  * List objects or indexes
  */
 int
-NdbDictionaryImpl::listObjects(List& list, NdbDictionary::Object::Type type)
+NdbDictionaryImpl::listObjects(List& list, 
+                               NdbDictionary::Object::Type type,
+                               bool fullyQualified)
 {
   int ret;
   List list1, list2;
@@ -5091,8 +5120,8 @@ NdbDictionaryImpl::listObjects(List& lis
   req.setTableType(getKernelConstant(type, objectTypeMapping, 0));
   req.setListNames(true);
   if (!list2.count)
-    return m_receiver.listObjects(list, req, m_ndb.usingFullyQualifiedNames());
-  ret = m_receiver.listObjects(list1, req, m_ndb.usingFullyQualifiedNames());
+    return m_receiver.listObjects(list, req, fullyQualified);
+  ret = m_receiver.listObjects(list1, req, fullyQualified);
   if (ret)
     return ret;
   list.count = list1.count + list2.count;
@@ -7758,6 +7787,13 @@ NdbDictionaryImpl::beginSchemaTrans()
     m_error.code = 4410;
     DBUG_RETURN(-1);
   }
+  if (!m_receiver.checkAllNodeVersionsMin(NDBD_SCHEMA_TRANS_VERSION))
+  {
+    /* Upgrade 6.3 -> 7.0 path */
+    /* Schema transaction not possible until upgrade complete */
+    m_error.code = 4411;
+    DBUG_RETURN(-1);
+  }
   // TODO real transId
   m_tx.m_transId = rand();
   m_tx.m_state = NdbDictInterface::Tx::Started;
@@ -7839,6 +7875,27 @@ committed:
   DBUG_RETURN(0);
 }
 
+bool
+NdbDictInterface::checkAllNodeVersionsMin(Uint32 minNdbVersion) const
+{
+  for (Uint32 nodeId = 1; nodeId < MAX_NODES; nodeId++)
+  {
+    if (m_transporter->getIsDbNode(nodeId) &&
+        m_transporter->getIsNodeSendable(nodeId) &&
+        (m_transporter->getNodeNdbVersion(nodeId) <
+         minNdbVersion))
+    {
+      /* At least 1 sendable data node has lower-than-min
+       * version
+       */
+      return false;
+    }
+  }
+  
+  return true;
+}
+
+
 int
 NdbDictInterface::beginSchemaTrans()
 {

=== modified file 'storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp	2009-09-04 11:33:38 +0000
+++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp	2009-12-03 10:19:24 +0000
@@ -201,6 +201,7 @@ public:
     if iterating over columns.
   */
   Vector<NdbColumnImpl *> m_columns;
+  Uint32 m_noOfAutoIncColumns;
   void computeAggregates();
   int buildColumnHash(); 
 
@@ -689,6 +690,8 @@ public:
   int endSchemaTrans(Uint32 flags);
   Tx & m_tx; // shared with NdbDictionaryImpl
 
+  bool checkAllNodeVersionsMin(Uint32 minNdbVersion) const;
+
   const NdbError &getNdbError() const;  
   NdbError & m_error;
 private:
@@ -824,7 +827,8 @@ public:
 
   int forceGCPWait();
 
-  int listObjects(List& list, NdbDictionary::Object::Type type);
+  int listObjects(List& list, NdbDictionary::Object::Type type, 
+                  bool fullyQualified);
   int listIndexes(List& list, Uint32 indexId);
 
   NdbTableImpl * getTableGlobal(const char * tableName);

=== modified file 'storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp'
--- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp	2009-08-06 13:51:18 +0000
+++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp	2009-11-18 13:13:34 +0000
@@ -616,6 +616,12 @@ NdbEventOperationImpl::execute_nolock()
                                                                    buckets);
   if (r == 0) 
   {
+    /* Pre-7.0 kernel nodes do not return the number of buckets
+     * Assume it's == theNoOfDBnodes as was the case in 6.3
+     */
+    if (buckets == ~ (Uint32)0)
+      buckets = m_ndb->theImpl->theNoOfDBnodes;
+
     m_ndb->theEventBuffer->set_total_buckets(buckets);
 
     if (theMainOp == NULL) {

=== modified file 'storage/ndb/src/ndbapi/NdbImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbImpl.hpp	2009-10-21 12:51:50 +0000
+++ b/storage/ndb/src/ndbapi/NdbImpl.hpp	2009-12-06 17:12:40 +0000
@@ -27,9 +27,9 @@
 #include <NdbReceiver.hpp>
 #include <NdbOperation.hpp>
 #include <kernel/ndb_limits.h>
-#include <NdbQueryOperationImpl.hpp>
 #include <NdbTick.h>
 
+#include "NdbQueryOperationImpl.hpp"
 #include "ndb_cluster_connection_impl.hpp"
 #include "NdbDictionaryImpl.hpp"
 #include "ObjectMap.hpp"
@@ -110,6 +110,14 @@ public:
     return;
   }
 
+  bool forceShortRequests;
+
+  static inline void setForceShortRequests(Ndb* ndb, bool val)
+  {
+    ndb->theImpl->forceShortRequests = val;
+  }
+
+
   BaseString m_systemPrefix; // Buffer for preformatted for <sys>/<def>/
 
   /**

=== modified file 'storage/ndb/src/ndbapi/NdbOperationDefine.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationDefine.cpp	2009-06-12 14:12:30 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationDefine.cpp	2009-12-06 17:12:40 +0000
@@ -699,6 +699,26 @@ NdbOperation::getBlobHandle(NdbTransacti
     return NULL;
   }
 
+  /* Check key fully defined for key operations */
+  switch (theStatus)
+  {
+  case TupleKeyDefined:
+  case GetValue:
+  case SetValue:
+  case FinalGetValue:
+  case ExecInterpretedValue:
+  case SetValueInterpreted:
+    /* All ok states to create a Blob Handle in */
+    break;
+  default:
+  {
+    /* Unexpected state to be obtaining Blob handle */
+    /* Invalid usage of blob attribute */
+    setErrorCodeAbort(4264);
+    return NULL;
+  }
+  }
+
   tBlob = theNdb->getNdbBlob();
   if (tBlob == NULL)
     return NULL;

=== modified file 'storage/ndb/src/ndbapi/NdbOperationExec.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2009-10-26 13:55:01 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2009-12-06 17:12:40 +0000
@@ -130,6 +130,128 @@ NdbOperation::setLastFlag(NdbApiSignal* 
   TcKeyReq::setExecuteFlag(req->requestInfo, lastFlag);
 }
 
+int
+NdbOperation::doSendKeyReq(int aNodeId, 
+                           GenericSectionPtr* secs, 
+                           Uint32 numSecs)
+{
+  /* Send a KeyRequest - could be TCKEYREQ or TCINDXREQ
+   *
+   * Normally we send a single long signal with 1 or 2
+   * sections containing KeyInfo and AttrInfo.
+   * For backwards compatibility and testing purposes 
+   * we can send signal trains instead.
+   */
+  NdbApiSignal* request = theTCREQ;
+  TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
+  Uint32 tcNodeVersion = tp->getNodeNdbVersion(aNodeId);
+  bool forceShort = false;
+  forceShort = theNdb->theImpl->forceShortRequests;
+  bool sendLong = ( tcNodeVersion >= NDBD_LONG_TCKEYREQ ) &&
+    ! forceShort;
+  
+  if (sendLong)
+  {
+    return tp->sendSignal(request, aNodeId, secs, numSecs);
+  }
+  else
+  {
+    /* Send signal as short request - either for backwards
+     * compatibility or testing
+     */
+    Uint32 sigCount = 1;
+    Uint32 keyInfoLen  = secs[0].sz;
+    Uint32 attrInfoLen = (numSecs == 2)?
+      secs[1].sz : 
+      0;
+    
+    Uint32 keyInfoInReq = MIN(keyInfoLen, TcKeyReq::MaxKeyInfo);
+    Uint32 attrInfoInReq = MIN(attrInfoLen, TcKeyReq::MaxAttrInfo);
+    TcKeyReq* tcKeyReq = (TcKeyReq*) request->getDataPtrSend();
+    Uint32 connectPtr = tcKeyReq->apiConnectPtr;
+    Uint32 transId1 = tcKeyReq->transId1;
+    Uint32 transId2 = tcKeyReq->transId2;
+    bool indexReq = (request->theVerId_signalNumber == GSN_TCINDXREQ);
+    
+    Uint32 reqLen = request->theLength;
+    
+    /* Set TCKEYREQ flags */
+    TcKeyReq::setKeyLength(tcKeyReq->requestInfo, keyInfoLen);
+    TcKeyReq::setAIInTcKeyReq(tcKeyReq->requestInfo , attrInfoInReq);
+    TcKeyReq::setAttrinfoLen(tcKeyReq->attrLen, attrInfoLen);
+    
+    Uint32* writePtr = request->getDataPtrSend() + reqLen;
+
+    GSIReader keyInfoReader(secs[0].sectionIter);
+    GSIReader attrInfoReader(secs[1].sectionIter);
+    
+    keyInfoReader.copyNWords(writePtr, keyInfoInReq);
+    writePtr += keyInfoInReq;
+    attrInfoReader.copyNWords(writePtr, attrInfoInReq);
+
+    reqLen += keyInfoInReq + attrInfoInReq;
+    assert( reqLen <= TcKeyReq::SignalLength );
+
+    request->setLength(reqLen);
+
+    if (tp->sendSignal(request, aNodeId) == -1)
+      return -1;
+    
+    keyInfoLen -= keyInfoInReq;
+    attrInfoLen -= attrInfoInReq;
+
+    if (keyInfoLen)
+    {
+      request->theVerId_signalNumber = indexReq ? 
+        GSN_INDXKEYINFO : GSN_KEYINFO;
+      KeyInfo* keyInfo = (KeyInfo*) request->getDataPtrSend();
+      keyInfo->connectPtr = connectPtr;
+      keyInfo->transId[0] = transId1;
+      keyInfo->transId[1] = transId2;
+
+      while(keyInfoLen)
+      {
+        Uint32 dataWords = MIN(keyInfoLen, KeyInfo::DataLength);
+
+        keyInfoReader.copyNWords(&keyInfo->keyData[0], dataWords);
+        request->setLength(KeyInfo::HeaderLength + dataWords);
+
+        if (tp->sendSignal(request, aNodeId) == -1)
+          return -1;
+
+        keyInfoLen-= dataWords;
+        sigCount++;
+      }
+    }
+
+    if (attrInfoLen)
+    {
+      request->theVerId_signalNumber = indexReq ? 
+        GSN_INDXATTRINFO : GSN_ATTRINFO;
+      AttrInfo* attrInfo = (AttrInfo*) request->getDataPtrSend();
+      attrInfo->connectPtr = connectPtr;
+      attrInfo->transId[0] = transId1;
+      attrInfo->transId[1] = transId2;
+
+      while(attrInfoLen)
+      {
+        Uint32 dataWords = MIN(attrInfoLen, AttrInfo::DataLength);
+
+        attrInfoReader.copyNWords(&attrInfo->attrData[0], dataWords);
+        request->setLength(AttrInfo::HeaderLength + dataWords);
+
+        if (tp->sendSignal(request, aNodeId) == -1)
+          return -1;
+
+        attrInfoLen-= dataWords;
+        sigCount++;
+      }
+    }
+    
+    return sigCount;
+  }
+}
+
 /******************************************************************************
 int doSend()
 
@@ -144,17 +266,40 @@ NdbOperation::doSend(int aNodeId, Uint32
 {
   assert(theTCREQ != NULL);
   setLastFlag(theTCREQ, lastFlag);
+  Uint32 numSecs= 1;
+  GenericSectionPtr secs[2];
 
   if (m_attribute_record != NULL)
   {
-    /* NdbRecord send - single long signal */
-    if (doSendNdbRecord(aNodeId) == -1 )
+    /*
+     * NdbRecord signal building code puts all KeyInfo and 
+     * AttrInfo into the KeyInfo and AttrInfo signal lists.
+     */
+    SignalSectionIterator keyInfoIter(theTCREQ->next());
+    SignalSectionIterator attrInfoIter(theFirstATTRINFO);
+    
+    /* KeyInfo - always present for TCKEY/INDXREQ*/
+    secs[0].sz= theTupKeyLen;
+    secs[0].sectionIter= &keyInfoIter;
+    
+    /* AttrInfo - not always needed (e.g. Delete) */
+    if (theTotalCurrAI_Len != 0)
+    {
+      secs[1].sz= theTotalCurrAI_Len;
+      secs[1].sectionIter= &attrInfoIter;
+      numSecs++;
+    }
+    
+    if (doSendKeyReq(aNodeId, &secs[0], numSecs) == -1)
       return -1;
   }
   else
   {
-    /* Old Api send - transform signal train to long sections */
-    TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
+    /* 
+     * Old Api signal building code puts first words of KeyInfo
+     * and AttrInfo into the initial request signal
+     * We use special iterators to extract this
+     */
 
     TcKeyReq* tcKeyReq= (TcKeyReq*) theTCREQ->getDataPtrSend();
     const Uint32 inlineKIOffset= Uint32(tcKeyReq->keyInfo - (Uint32*)tcKeyReq);
@@ -164,8 +309,6 @@ NdbOperation::doSend(int aNodeId, Uint32
     const Uint32 inlineAILength= MIN(TcKeyReq::MaxAttrInfo, 
                                      theTotalCurrAI_Len);
     
-    Uint32 numSecs= 1;
-    GenericSectionPtr secs[2];
     /* Create iterators which use the signal train to extract
      * long sections from the short signal trains
      */
@@ -190,7 +333,7 @@ NdbOperation::doSend(int aNodeId, Uint32
       numSecs++;
     }
 
-    if (tp->sendSignal(theTCREQ, aNodeId, &secs[0], numSecs) == -1)
+    if (doSendKeyReq(aNodeId, &secs[0], numSecs) == -1)
       return -1;
   }
 
@@ -204,37 +347,6 @@ NdbOperation::doSend(int aNodeId, Uint32
 }//NdbOperation::doSend()
 
 
-int
-NdbOperation::doSendNdbRecord(int aNodeId)
-{
- /*
-  * Send a long signal to the kernel.
-  * KeyInfo and AttrInfo for NdbRecord are always sent as
-  * separate sections, with none in the TCKEYREQ
-  */
-  TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
-
-  Uint32 numSecs= 1;
-  GenericSectionPtr secs[2];
-  SignalSectionIterator keyInfoIter(theTCREQ->next());
-  SignalSectionIterator attrInfoIter(theFirstATTRINFO);
-  
-  /* KeyInfo - always present for TCKEY/INDXREQ*/
-  secs[0].sz= theTupKeyLen;
-  secs[0].sectionIter= &keyInfoIter;
-
-  /* AttrInfo - not always needed (e.g. Delete) */
-  if (theTotalCurrAI_Len != 0)
-  {
-    secs[1].sz= theTotalCurrAI_Len;
-    secs[1].sectionIter= &attrInfoIter;
-    numSecs++;
-  }
-
-  return tp->sendSignal(theTCREQ, aNodeId, &secs[0], numSecs);
-}
-
-
 /***************************************************************************
 int prepareSend(Uint32 aTC_ConnectPtr,
                 Uint64 aTransactionId)

=== modified file 'storage/ndb/src/ndbapi/NdbOperationSearch.cpp'
--- a/storage/ndb/src/ndbapi/NdbOperationSearch.cpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/ndbapi/NdbOperationSearch.cpp	2009-11-27 14:47:24 +0000
@@ -474,7 +474,8 @@ NdbOperation::reorderKEYINFO()
 {
   Uint32 data[ NDB_MAX_KEYSIZE_IN_WORDS ];
   Uint32 size = NDB_MAX_KEYSIZE_IN_WORDS;
-  getKeyFromTCREQ(data, size);
+  int rc = getKeyFromTCREQ(data, size);
+  assert(rc == 0);
   Uint32 pos = 1;
   Uint32 k;
   for (k = 0; k < m_accessTable->m_noOfKeys; k++) {
@@ -506,7 +507,10 @@ NdbOperation::reorderKEYINFO()
 int
 NdbOperation::getKeyFromTCREQ(Uint32* data, Uint32 & size)
 {
-  assert(size >= theTupKeyLen && theTupKeyLen > 0);
+  /* Check that we can correctly return a valid key */
+  if ((size < theTupKeyLen) || (theTupKeyLen == 0))
+    return -1;
+  
   size = theTupKeyLen;
   unsigned pos = 0;
   while (pos < 8 && pos < size) {

=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2009-12-02 15:24:36 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2009-12-06 17:12:40 +0000
@@ -22,10 +22,10 @@
 #include "NdbQueryOperation.hpp"
 #include "NdbQueryBuilderImpl.hpp"
 #include "NdbIndexScanOperation.hpp"
-#include "NdbError.hpp"
-#include "ndb_limits.h"
-#include "Vector.hpp"
-#include "Bitmask.hpp"
+#include <NdbError.hpp>
+#include <ndb_limits.h>
+#include <Vector.hpp>
+#include <Bitmask.hpp>
 
 // Forward declarations
 class NdbTableImpl;

=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2009-12-02 15:24:36 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2009-12-06 17:12:40 +0000
@@ -2395,15 +2395,93 @@ NdbScanOperation::doSendScan(int aProces
   }
 
   TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
-  
-  /* Send Fragmented as SCAN_TABREQ can be large */
-  if (tp->sendFragmentedSignal(theSCAN_TABREQ, 
-                               aProcessorId, 
-                               &secs[0], 
-                               numSections) == -1)
+
+  Uint32 tcNodeVersion = tp->getNodeNdbVersion(aProcessorId);
+  bool forceShort = false;
+  forceShort = theNdb->theImpl->forceShortRequests;
+  bool sendLong = ( tcNodeVersion >= NDBD_LONG_SCANTABREQ) &&
+    ! forceShort;
+  
+  if (sendLong)
+  {
+    /* Send Fragmented as SCAN_TABREQ can be large */
+    if (tp->sendFragmentedSignal(theSCAN_TABREQ, 
+                                 aProcessorId, 
+                                 &secs[0], 
+                                 numSections) == -1)
+    {
+      setErrorCode(4002);
+      return -1;
+    }
+  }
+  else
   {
-    setErrorCode(4002);
-    return -1;
+    /* Send a 'short' SCANTABREQ - e.g. long SCANTABREQ
+     * with signalIds as first section, followed by
+     * AttrInfo and KeyInfo trains
+     */
+    Uint32 attrInfoLen = secs[1].sz;
+    Uint32 keyInfoLen = (numSections == 3)? secs[2].sz : 0;
+
+    ScanTabReq* scanTabReq = (ScanTabReq*) theSCAN_TABREQ->getDataPtrSend();
+    Uint32 connectPtr = scanTabReq->apiConnectPtr;
+    Uint32 transId1 = scanTabReq->transId1;
+    Uint32 transId2 = scanTabReq->transId2;
+
+    /* Modify ScanTabReq to carry length of keyinfo and attrinfo */
+    scanTabReq->attrLenKeyLen = (keyInfoLen << 16) | attrInfoLen;
+
+    /* Send with receiver Ids as first and only section */
+    if (tp->sendSignal(theSCAN_TABREQ, aProcessorId, &secs[0], 1) == -1)
+    {
+      setErrorCode(4002);
+      return -1;
+    }
+
+    if (keyInfoLen)
+    {
+      GSIReader keyInfoReader(secs[2].sectionIter);
+      theSCAN_TABREQ->theVerId_signalNumber = GSN_KEYINFO;
+      KeyInfo* keyInfo = (KeyInfo*) theSCAN_TABREQ->getDataPtrSend();
+      keyInfo->connectPtr = connectPtr;
+      keyInfo->transId[0] = transId1;
+      keyInfo->transId[1] = transId2;
+
+      while(keyInfoLen)
+      {
+        Uint32 dataWords = MIN(keyInfoLen, KeyInfo::DataLength);
+        keyInfoReader.copyNWords(&keyInfo->keyData[0], dataWords);
+        theSCAN_TABREQ->setLength(KeyInfo::HeaderLength + dataWords);
+
+        if (tp->sendSignal(theSCAN_TABREQ, aProcessorId) == -1)
+        {
+          setErrorCode(4002);
+          return -1;
+        }
+        keyInfoLen -= dataWords;
+      }
+    }
+
+    GSIReader attrInfoReader(secs[1].sectionIter);
+    theSCAN_TABREQ->theVerId_signalNumber = GSN_ATTRINFO;
+    AttrInfo* attrInfo = (AttrInfo*) theSCAN_TABREQ->getDataPtrSend();
+    attrInfo->connectPtr = connectPtr;
+    attrInfo->transId[0] = transId1;
+    attrInfo->transId[1] = transId2;
+    
+    while(attrInfoLen)
+    {
+      Uint32 dataWords = MIN(attrInfoLen, AttrInfo::DataLength);
+      attrInfoReader.copyNWords(&attrInfo->attrData[0], dataWords);
+      theSCAN_TABREQ->setLength(AttrInfo::HeaderLength + dataWords);
+
+      if (tp->sendSignal(theSCAN_TABREQ, aProcessorId) == -1)
+      {
+        setErrorCode(4002);
+        return -1;
+      }
+      attrInfoLen -= dataWords;
+    }
   }
 
   theStatus = WaitResponse;  

=== modified file 'storage/ndb/src/ndbapi/Ndbinit.cpp'
--- a/storage/ndb/src/ndbapi/Ndbinit.cpp	2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/ndbapi/Ndbinit.cpp	2009-11-18 11:05:02 +0000
@@ -219,6 +219,11 @@ NdbImpl::NdbImpl(Ndb_cluster_connection 
 
   m_systemPrefix.assfmt("%s%c%s%c", NDB_SYSTEM_DATABASE, table_name_separator,
 			NDB_SYSTEM_SCHEMA, table_name_separator);
+
+  forceShortRequests = false;
+  const char* f= getenv("NDB_FORCE_SHORT_REQUESTS");
+  if (f != 0 && *f != 0 && *f != '0' && *f != 'n' && *f != 'N')
+    forceShortRequests = true;
 }
 
 NdbImpl::~NdbImpl()

=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.hpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.hpp	2009-09-16 11:18:37 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.hpp	2009-12-06 17:12:40 +0000
@@ -95,6 +95,7 @@ public:
   bool   getIsNodeSendable(NodeId nodeId) const;
   Uint32 getNodeGrp(NodeId nodeId) const;
   Uint32 getNodeSequence(NodeId nodeId) const;
+  Uint32 getNodeNdbVersion(NodeId nodeId) const;
 
   // Is there space in sendBuffer to send messages
   bool   check_send_size(Uint32 node_id, Uint32 send_size);
@@ -439,6 +440,13 @@ TransporterFacade::getNodeSequence(NodeI
 
 inline
 Uint32
+TransporterFacade::getNodeNdbVersion(NodeId n) const
+{
+  return theClusterMgr->getNodeInfo(n).m_info.m_version;
+}
+
+inline
+Uint32
 TransporterFacade::get_scan_batch_size() const {
   return m_scan_batch_size;
 }
@@ -531,4 +539,57 @@ public :
   const Uint32* getNextWords(Uint32& sz);
 };
 
+/*
+ * GenericSectionIteratorReader
+ * Helper class to simplify reading data from 
+ * GenericSectionIterator implementations
+ */
+
+class GSIReader
+{
+private :
+  GenericSectionIterator* gsi;
+  const Uint32* chunkPtr;
+  Uint32 chunkRemain;
+public :
+  GSIReader(GenericSectionIterator* _gsi)
+  {
+    gsi = _gsi;
+    chunkPtr = NULL;
+    chunkRemain = 0;
+  }
+
+  void copyNWords(Uint32* dest, Uint32 n)
+  {
+    while (n)
+    {
+      if (chunkRemain == 0)
+      {
+        /* Get next contiguous stretch of words from
+         * the iterator
+         */
+        chunkPtr = gsi->getNextWords(chunkRemain);
+        if (!chunkRemain)
+          abort(); // Must have the words the caller asks for
+      }
+      else
+      {
+        /* Have some words from the iterator, copy some/
+         * all of them
+         */
+        Uint32 wordsToCopy = MIN(chunkRemain, n);
+        memcpy(dest, chunkPtr, wordsToCopy << 2);
+        chunkPtr += wordsToCopy;
+        chunkRemain -= wordsToCopy;
+
+        dest += wordsToCopy;
+        n -= wordsToCopy;
+      }
+    }
+  }
+};
+
+  
+
+
 #endif // TransporterFacade_H

=== modified file 'storage/ndb/src/ndbapi/ndb_cluster_connection.cpp'
--- a/storage/ndb/src/ndbapi/ndb_cluster_connection.cpp	2009-09-08 15:12:34 +0000
+++ b/storage/ndb/src/ndbapi/ndb_cluster_connection.cpp	2009-11-17 16:26:09 +0000
@@ -290,7 +290,6 @@ Ndb_cluster_connection_impl(const char *
   : Ndb_cluster_connection(*this),
     m_main_connection(main_connection),
     m_optimized_node_selection(1),
-    m_name(0),
     m_run_connect_thread(0),
     m_latest_trans_gci(0),
     m_first_ndb_object(0),
@@ -335,13 +334,6 @@ Ndb_cluster_connection_impl(const char *
       ("Could not initialize handle to management server: %s",
        m_config_retriever->getErrorString());
     printf("%s\n", get_latest_error_msg());
-    delete m_config_retriever;
-    m_config_retriever= 0;
-  }
-  if (m_name)
-  {
-    NdbMgmHandle h= m_config_retriever->get_mgmHandle();
-    ndb_mgm_set_name(h, m_name);
   }
   if (!m_main_connection)
   {
@@ -354,6 +346,11 @@ Ndb_cluster_connection_impl(const char *
     m_globalDictCache = 0;
     m_transporter_facade=
       new TransporterFacade(m_main_connection->m_impl.m_globalDictCache);
+
+    // The secondary connection can't use same nodeid, clear the nodeid
+    // in ConfigRetriver to avoid asking for the same nodeid again
+    m_config_retriever->setNodeId(0);
+
   }
 
   DBUG_VOID_RETURN;
@@ -395,8 +392,6 @@ Ndb_cluster_connection_impl::~Ndb_cluste
     ndb_print_state_mutex= NULL;
   }
 #endif
-  if (m_name)
-    free(m_name);
 
   NdbMutex_Lock(g_ndb_connection_mutex);
   if(--g_ndb_connection_count == 0)
@@ -483,14 +478,8 @@ Ndb_cluster_connection_impl::unlink_ndb_
 void
 Ndb_cluster_connection_impl::set_name(const char *name)
 {
-  if (m_name)
-    free(m_name);
-  m_name= strdup(name);
-  if (m_config_retriever && m_name)
-  {
-    NdbMgmHandle h= m_config_retriever->get_mgmHandle();
-    ndb_mgm_set_name(h, m_name);
-  }
+  NdbMgmHandle h= m_config_retriever->get_mgmHandle();
+  ndb_mgm_set_name(h, name);
 }
 
 int

=== modified file 'storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp'
--- a/storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp	2009-11-17 16:15:19 +0000
@@ -89,7 +89,6 @@ private:
   int (*m_connect_callback)(void);
 
   int m_optimized_node_selection;
-  char *m_name;
   int m_run_connect_thread;
   NdbMutex *m_event_add_drop_mutex;
   Uint64 m_latest_trans_gci;

=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c	2009-12-02 15:24:36 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c	2009-12-06 17:12:40 +0000
@@ -583,6 +583,7 @@ ErrorBundle ErrorCodes[] = {
   { 4401, DMEC, AE, "Only one schema operation per schema transaction" },
   { 4402, DMEC, AE, "No schema operation defined before calling execute" },
   { 4410, DMEC, AE, "Schema transaction is already started" },
+  { 4411, DMEC, AE, "Schema transaction not possible until upgrade complete" },
 
   { 4501, DMEC, AE, "Insert in hash table failed when getting table information from Ndb" },
   { 4502, DMEC, AE, "GetValue not allowed in Update operation" },

=== modified file 'storage/ndb/test/include/NDBT_Test.hpp'
--- a/storage/ndb/test/include/NDBT_Test.hpp	2009-09-16 12:40:24 +0000
+++ b/storage/ndb/test/include/NDBT_Test.hpp	2009-11-18 11:05:02 +0000
@@ -380,6 +380,8 @@ public:
   void setLogging(bool val);
   bool getLogging() const;
 
+  bool getForceShort() const;
+
   int createTables(Ndb_cluster_connection&) const;
   int dropTables(Ndb_cluster_connection&) const;
 
@@ -417,6 +419,7 @@ private:
   bool m_logging;
   NDBT_DriverType m_driverType;
   bool m_noddl;
+  bool m_forceShort;
 };
 
 

=== modified file 'storage/ndb/test/ndbapi/slow_select.cpp'
--- a/storage/ndb/test/ndbapi/slow_select.cpp	2009-09-25 13:11:39 +0000
+++ b/storage/ndb/test/ndbapi/slow_select.cpp	2009-12-04 05:53:03 +0000
@@ -22,8 +22,15 @@ static S_Scan g_scans[] = {
   { "subgenrestometamap", "metaid", 0, 0, 0, 0 }
 };
 
-#define require(x) if(!(x)) { ndbout << "LINE: " << __LINE__ << endl;abort(); }
-#define require2(o, x) if(!(x)) { ndbout << o->getNdbError() << endl; abort(); }
+#undef require
+#define require(x)     require_exit_or_core_with_printer((x), 0, ndbout_printer)
+#define require2(o, x) \
+    if(!(x))\
+    {\
+      ndbout << o->getNdbError() << endl;\
+      require_exit_or_core_with_printer(0, 0, ndbout_printer);\
+    }
+
 Uint32 g_affiliateid = 2;
 Uint32 g_formatids[] = { 8, 31, 76 };
 

=== modified file 'storage/ndb/test/ndbapi/testBlobs.cpp'
--- a/storage/ndb/test/ndbapi/testBlobs.cpp	2009-10-26 20:51:04 +0000
+++ b/storage/ndb/test/ndbapi/testBlobs.cpp	2009-11-27 14:47:24 +0000
@@ -4177,6 +4177,87 @@ bugtest_27370()
   return 0;
 }
 
+static int
+bugtest_28116()
+{
+  DBG("bug test 28116 - Crash in getBlobHandle() when called without full key");
+
+  if (g_opt.m_pk2chr.m_len == 0)
+  {
+    DBG("  ... skipped, requires multi-column primary key.");
+    return 0;
+  }
+
+  for (unsigned k = 0; k < g_opt.m_rows; k++) {
+    Tup& tup = g_tups[k];
+    CHK((g_con = g_ndb->startTransaction()) != 0);
+    CHK((g_opr = g_con->getNdbOperation(g_opt.m_tname)) != 0);
+    int reqType = urandom(4);
+    switch(reqType) {
+    case 0:
+    {
+      DBG("Read");
+      CHK(g_opr->readTuple() == 0);
+      break;
+    }
+    case 1:
+    {
+      DBG("Insert");
+      CHK(g_opr->insertTuple() == 0);
+      break;
+    }
+    case 2:
+    {
+      DBG("Update");
+      CHK(g_opr->updateTuple() == 0);
+      break;
+    }
+    case 3:
+    default:
+    {
+      DBG("Delete");
+      CHK(g_opr->deleteTuple() == 0);
+      break;
+    }
+    }
+    switch (urandom(3)) {
+    case 0:
+    {
+      DBG("  No keys");
+      break;
+    }
+    case 1:
+    {
+      DBG("  Pk1 only");
+      CHK(g_opr->equal("PK1", tup.m_pk1) == 0);
+      break;
+    }
+    case 2:
+    default:
+    {
+      DBG("  Pk2/3 only");
+      if (g_opt.m_pk2chr.m_len != 0)
+      {
+        CHK(g_opr->equal("PK2", tup.m_pk2) == 0);
+        CHK(g_opr->equal("PK3", tup.m_pk3) == 0);
+      }
+      break;
+    }
+    }
+    /* Deliberately no equal() on rest of primary key, to provoke error. */
+    CHK(g_opr->getBlobHandle("BL1") == 0);
+
+    /* 4264 - Invalid usage of Blob attribute */
+    CHK(g_con->getNdbError().code == 4264);
+    CHK(g_opr->getNdbError().code == 4264);
+
+    g_ndb->closeTransaction(g_con);
+    g_opr = 0;
+    g_con = 0;
+  }
+  return 0;
+}
+
 static struct {
   int m_bug;
   int (*m_test)();
@@ -4186,7 +4267,8 @@ static struct {
   { 27370, bugtest_27370 },
   { 36756, bugtest_36756 },
   { 45768, bugtest_45768 },
-  { 48040, bugtest_48040 }
+  { 48040, bugtest_48040 },
+  { 28116, bugtest_28116 }
 };
 
 NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535)

=== modified file 'storage/ndb/test/ndbapi/testIndex.cpp'
--- a/storage/ndb/test/ndbapi/testIndex.cpp	2009-08-07 12:02:25 +0000
+++ b/storage/ndb/test/ndbapi/testIndex.cpp	2009-12-03 16:40:09 +0000
@@ -31,6 +31,13 @@
   result = NDBT_FAILED; break;\
 } 
 
+#define CHECKRET(b) if (!(b)) { \
+  g_err << "ERR: "<< step->getName() \
+         << " failed on line " << __LINE__ << endl; \
+  abort(); /* Remove */                             \
+  return NDBT_FAILED;                             \
+} 
+
 
 struct Attrib {
   bool indexCreated;
@@ -767,6 +774,298 @@ int runInsertDelete(NDBT_Context* ctx, N
   
   return result;
 }
+
+int tryAddUniqueIndex(Ndb* pNdb,
+                      const NdbDictionary::Table* pTab,
+                      const char* idxName,
+                      HugoCalculator& calc,
+                      int& chosenCol)
+{
+  for(int c = 0; c < pTab->getNoOfColumns(); c++)
+  {
+    const NdbDictionary::Column* col = pTab->getColumn(c);
+    
+    if (!col->getPrimaryKey() &&
+        !calc.isUpdateCol(c) &&
+        !col->getNullable() &&
+        col->getStorageType() != NDB_STORAGETYPE_DISK)
+    {
+      chosenCol = c;
+      break;
+    }
+  }
+  
+  if (chosenCol == -1)
+  {
+    return 1;
+  }
+  
+
+  /* Create unique index on chosen column */
+
+  const char* colName = pTab->getColumn(chosenCol)->getName();
+  ndbout << "Creating unique index :" << idxName << " on ("
+         << colName << ")" << endl;
+
+  NdbDictionary::Index idxDef(idxName);
+  idxDef.setTable(pTab->getName());
+  idxDef.setType(NdbDictionary::Index::UniqueHashIndex);
+  
+  idxDef.addIndexColumn(colName);
+  idxDef.setStoredIndex(false);
+
+  if (pNdb->getDictionary()->createIndex(idxDef) != 0)
+  {
+    ndbout << "FAILED!" << endl;
+    const NdbError err = pNdb->getDictionary()->getNdbError();
+    ERR(err);
+    return -1;
+  }
+
+  return 0;
+}
+
+int tryInsertUniqueRecord(NDBT_Step* step,
+                          HugoOperations& hugoOps,
+                          int& recordNum)
+{
+  Ndb* pNdb = GETNDB(step);
+  do
+  {
+    CHECKRET(hugoOps.startTransaction(pNdb) == 0);
+    CHECKRET(hugoOps.pkInsertRecord(pNdb,
+                                    recordNum,
+                                    1,  // NumRecords 
+                                    0)  // UpdatesValue
+             == 0);
+    if (hugoOps.execute_Commit(pNdb) != 0)
+    {
+      NdbError err = hugoOps.getTransaction()->getNdbError();
+      hugoOps.closeTransaction(pNdb);
+      if (err.code == 839)
+      {
+        /* Unique constraint violation, try again with
+         * different record
+         */
+        recordNum++;
+        continue;
+      }
+      else
+      {
+        ERR(err);
+        return NDBT_FAILED;
+      }
+    }
+    
+    hugoOps.closeTransaction(pNdb);
+    break;
+  } while (true);
+
+  return NDBT_OK;
+}
+                     
+
+int runConstraintDetails(NDBT_Context* ctx, NDBT_Step* step)
+{
+  const NdbDictionary::Table* pTab = ctx->getTab();
+  Ndb* pNdb = GETNDB(step);
+
+  /* Steps in testcase
+   * 1) Choose a column to index - not pk or updates column
+   * 2) Insert a couple of unique rows
+   * 3) For a number of different batch sizes :
+   *    i)  Insert a row with a conflicting values
+   *    ii) Update an existing row with a conflicting value
+   *    Verify :
+   *    - The correct error is received
+   *    - The failing constraint is detected
+   *    - The error details string is as expected.
+   */
+  HugoCalculator calc(*pTab);
+
+  /* Choose column to add unique index to */
+
+  int chosenCol = -1;
+  const char* idxName = "constraintCheck";
+  
+  int rc = tryAddUniqueIndex(pNdb, pTab, idxName, calc, chosenCol);
+
+  if (rc)
+  {
+    if (rc == 1)
+    {
+      ndbout << "No suitable column in this table, skipping" << endl;
+      return NDBT_OK;
+    }
+    return NDBT_FAILED;
+  }
+
+  const NdbDictionary::Index* pIdx = 
+    pNdb->getDictionary()->getIndex(idxName, pTab->getName());
+  CHECKRET(pIdx != 0);
+
+
+  /* Now insert a couple of rows */
+
+  HugoOperations hugoOps(*pTab);
+  int firstRecordNum = 0;
+  CHECKRET(tryInsertUniqueRecord(step, hugoOps, firstRecordNum) == NDBT_OK);
+  int secondRecordNum = firstRecordNum + 1;
+  CHECKRET(tryInsertUniqueRecord(step, hugoOps, secondRecordNum) == NDBT_OK);
+
+
+  /* Now we'll attempt to insert/update records 
+   * in various sized batches and check the errors which 
+   * are returned
+   */
+
+  int maxBatchSize = 10;
+  int recordOffset = secondRecordNum + 1;
+  char buff[NDB_MAX_TUPLE_SIZE];
+  Uint32 real_len;
+  CHECKRET(calc.calcValue(firstRecordNum, chosenCol, 0, &buff[0], 
+                          pTab->getColumn(chosenCol)->getSizeInBytes(), 
+                          &real_len) != 0);
+  
+  for (int optype = 0; optype < 2; optype ++)
+  {
+    bool useInsert = (optype == 0);
+    ndbout << "Verifying constraint violation for " 
+           << (useInsert?"Insert":"Update")
+           << " operations" << endl;
+      
+    for (int batchSize = 1; batchSize <= maxBatchSize; batchSize++)
+    {
+      NdbTransaction* trans = pNdb->startTransaction();
+      CHECKRET(trans != 0);
+      
+      for (int rows = 0; rows < batchSize; rows ++)
+      {
+        int rowId = recordOffset + rows;
+        NdbOperation* op = trans->getNdbOperation(pTab);
+        CHECKRET(op != 0);
+        if (useInsert)
+        {
+          CHECKRET(op->insertTuple() == 0);
+          
+          CHECKRET(hugoOps.setValues(op, rowId, 0) == 0);
+          
+          /* Now override setValue for the indexed column to cause
+           * constraint violation
+           */
+          CHECKRET(op->setValue(chosenCol, &buff[0], real_len) == 0);
+        }
+        else
+        {
+          /* Update value of 'second' row to conflict with
+           * first
+           */
+          CHECKRET(op->updateTuple() == 0);
+          CHECKRET(hugoOps.equalForRow(op, secondRecordNum) == 0);
+          
+          CHECKRET(op->setValue(chosenCol, &buff[0], real_len) == 0);
+        }
+      }
+      
+      CHECKRET(trans->execute(Commit) == -1);
+      
+      NdbError err = trans->getNdbError();
+      
+      ERR(err);
+      
+      CHECKRET(err.code == 893);
+      
+      /* Ugliness - current NdbApi puts index schema object id
+       * as abs. value of char* in NdbError struct
+       */
+
+      int idxObjId = (int) ((UintPtr) err.details - UintPtr(0));
+      char detailsBuff[100];
+      const char* errIdxName = NULL;
+      
+      ndbout_c("Got details column val of %p and string of %s\n",
+               err.details, pNdb->getNdbErrorDetail(err, 
+                                                    &detailsBuff[0],
+                                                    100));
+      if (idxObjId == pIdx->getObjectId())
+      {
+        /* Insert / update failed on the constraint we added */
+        errIdxName = pIdx->getName();
+      }
+      else
+      {
+        /* We failed on a different constraint.
+         * Some NDBT tables already have constraints (e.g. I3)
+         * Check that the failing constraint contains our column
+         */
+        NdbDictionary::Dictionary::List tableIndices;
+        
+        CHECKRET(pNdb->getDictionary()->listIndexes(tableIndices,
+                                                    pTab->getName()) == 0);
+        
+        bool ok = false;
+        for (unsigned ind = 0; ind < tableIndices.count; ind ++)
+        {
+          if (tableIndices.elements[ind].id == (unsigned) idxObjId)
+          {
+            const char* otherIdxName = tableIndices.elements[ind].name;
+            ndbout << "Found other violated constraint : " << otherIdxName << endl;
+            const NdbDictionary::Index* otherIndex = 
+              pNdb->getDictionary()->getIndex(otherIdxName,
+                                              pTab->getName());
+            CHECKRET(otherIndex != NULL);
+            
+            for (unsigned col = 0; col < otherIndex->getNoOfColumns(); col++)
+            {
+              if (strcmp(otherIndex->getColumn(col)->getName(),
+                         pTab->getColumn(chosenCol)->getName()) == 0)
+              {
+                /* Found our column in the index */
+                ok = true;
+                errIdxName = otherIndex->getName();
+                break;
+              }
+            }
+            
+            if (ok)
+            {
+              ndbout << "  Constraint contains unique column " << endl;
+              break;
+            }
+            ndbout << "  Constraint does not contain unique col - fail" << endl;
+            CHECKRET(false);
+          }
+        }
+        
+        if (!ok)
+        {
+          ndbout << "Did not find violated constraint" << endl;
+          CHECKRET(false);
+        }
+      }
+
+      /* Finally verify the name returned is :
+       * <db>/<schema>/<table>/<index> 
+       */
+      BaseString expected;
+
+      expected.assfmt("%s/%s/%s/%s",
+                      pNdb->getDatabaseName(),
+                      pNdb->getSchemaName(),
+                      pTab->getName(),
+                      errIdxName);
+
+      CHECKRET(strcmp(expected.c_str(), &detailsBuff[0]) == 0);
+
+      ndbout << " OK " << endl;
+
+      trans->close();
+    }
+  }
+  
+  return NDBT_OK;
+}
+
 int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
   int records = ctx->getNumRecords();
   
@@ -2376,6 +2675,11 @@ TESTCASE("Bug46069", ""){
   STEPS(runBug46069_scandel, 2);
   FINALIZER(createPkIndex_Drop);
 }
+TESTCASE("ConstraintDetails",
+         "Test that the details part of the returned NdbError is as "
+         "expected"){
+  INITIALIZER(runConstraintDetails);
+}
 NDBT_TESTSUITE_END(testIndex);
 
 int main(int argc, const char** argv){

=== modified file 'storage/ndb/test/ndbapi/testLcp.cpp'
--- a/storage/ndb/test/ndbapi/testLcp.cpp	2009-09-25 13:38:00 +0000
+++ b/storage/ndb/test/ndbapi/testLcp.cpp	2009-12-03 05:53:33 +0000
@@ -64,8 +64,6 @@ static int commit();
 static int restart();
 static int validate();
 
-#define require(x) { bool b = x; if(!b){g_err << __LINE__ << endl; abort();}}
-
 int 
 main(int argc, char ** argv){
   ndb_init();

=== modified file 'storage/ndb/test/ndbapi/testMgmd.cpp'
--- a/storage/ndb/test/ndbapi/testMgmd.cpp	2009-10-06 12:17:23 +0000
+++ b/storage/ndb/test/ndbapi/testMgmd.cpp	2009-11-17 18:13:29 +0000
@@ -613,6 +613,176 @@ int runTestBug42015(NDBT_Context* ctx, N
 
 }
 
+int runTestNowaitNodes(NDBT_Context* ctx, NDBT_Step* step)
+{
+  MgmdProcessList mgmds;
+  NDBT_Workingdir wd("test_mgmd"); // temporary working directory
+
+  // Create config.ini
+  Properties config = ConfigFactory::create(2);
+  CHECK(ConfigFactory::write_config_ini(config,
+                                        path(wd.path(),
+                                             "config.ini",
+                                             NULL).c_str()));
+  // Start first ndb_mgmd
+  {
+    Mgmd* mgmd1 = new Mgmd(1);
+    CHECK(mgmd1->start_from_config_ini(wd.path(),
+                                    "--initial",
+                                       "--nowait-nodes=2",
+                                       NULL));
+    mgmds.push_back(mgmd1);
+
+    // Connect the ndb_mgmd
+    CHECK(mgmd1->connect(config));
+
+    // wait for confirmed config
+    CHECK(mgmd1->wait_confirmed_config());
+
+    // Check binary config file created
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_1_config.bin.1",
+                           NULL).c_str()));
+  }
+
+  // Start second ndb_mgmd
+  {
+    Mgmd* mgmd2 = new Mgmd(2);
+    CHECK(mgmd2->start_from_config_ini(wd.path(),
+                                       "--initial",
+                                       NULL));
+    mgmds.push_back(mgmd2);
+
+    // Connect the ndb_mgmd
+    CHECK(mgmd2->connect(config));
+
+    // wait for confirmed config
+    CHECK(mgmd2->wait_confirmed_config());
+
+    // Check binary config file created
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_2_config.bin.1",
+                           NULL).c_str()));
+
+  }
+
+  // Create new config.ini
+  g_err << "** Create config2.ini" << endl;
+  CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
+  CHECK(ConfigFactory::write_config_ini(config,
+                                        path(wd.path(),
+                                             "config2.ini",
+                                             NULL).c_str()));
+
+  g_err << "** Reload second mgmd from config2.ini" << endl;
+  {
+    Mgmd* mgmd2 = mgmds[1];
+    CHECK(mgmd2->stop());
+    // Start from config2.ini
+    CHECK(mgmd2->start_from_config_ini(wd.path(),
+                                       "-f config2.ini",
+                                       "--reload", NULL));
+    CHECK(mgmd2->connect(config));
+    CHECK(mgmd2->wait_confirmed_config());
+
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_1_config.bin.1",
+                           NULL).c_str()));
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_2_config.bin.1",
+                           NULL).c_str()));
+
+    // Both ndb_mgmd(s) should have reloaded and new binary config exist
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_1_config.bin.2",
+                           NULL).c_str()));
+    CHECK(file_exists(path(wd.path(),
+                           "ndb_2_config.bin.2",
+                           NULL).c_str()));
+  }
+
+  // Stop the ndb_mgmd(s)
+  for (unsigned i = 0; i < mgmds.size(); i++)
+    CHECK(mgmds[i]->stop());
+
+  return NDBT_OK;
+}
+
+
+int runTestNowaitNodes2(NDBT_Context* ctx, NDBT_Step* step)
+{
+  int ret;
+  NDBT_Workingdir wd("test_mgmd"); // temporary working directory
+
+  // Create config.ini
+  Properties config = ConfigFactory::create(2);
+  CHECK(ConfigFactory::write_config_ini(config,
+                                        path(wd.path(),
+                                             "config.ini",
+                                             NULL).c_str()));
+
+  g_err << "** Start mgmd1 from config.ini" << endl;
+  Mgmd* mgmd1 = new Mgmd(1);
+  CHECK(mgmd1->start_from_config_ini(wd.path(),
+                                     "--initial",
+                                     "--nowait-nodes=1-255",
+                                     NULL));
+  CHECK(mgmd1->connect(config));
+  CHECK(mgmd1->wait_confirmed_config());
+
+  // check config files exist
+  CHECK(file_exists(path(wd.path(),
+                         "ndb_1_config.bin.1",
+                         NULL).c_str()));
+
+  g_err << "** Create config2.ini" << endl;
+  CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
+  CHECK(ConfigFactory::write_config_ini(config,
+                                        path(wd.path(),
+                                             "config2.ini",
+                                             NULL).c_str()));
+
+  g_err << "** Start mgmd2 from config2.ini" << endl;
+  Mgmd* mgmd2 = new Mgmd(2);
+  CHECK(mgmd2->start_from_config_ini(wd.path(),
+                                     "-f config2.ini",
+                                     "--initial",
+                                     "--nowait-nodes=1-255",
+                                     NULL));
+  CHECK(mgmd2->wait(ret));
+  CHECK(ret == 1);
+
+  CHECK(mgmd1->stop());
+
+  g_err << "** Start mgmd2 again from config2.ini" << endl;
+  CHECK(mgmd2->start_from_config_ini(wd.path(),
+                                     "-f config2.ini",
+                                     "--initial",
+                                     "--nowait-nodes=1-255",
+                                     NULL));
+
+
+  CHECK(mgmd2->connect(config));
+  CHECK(mgmd2->wait_confirmed_config());
+
+  // check config files exist
+  CHECK(file_exists(path(wd.path(),
+                         "ndb_2_config.bin.1",
+                         NULL).c_str()));
+
+  g_err << "** Start mgmd1 from config.ini, mgmd2 should shutdown" << endl;
+  CHECK(mgmd1->start_from_config_ini(wd.path(),
+                                     "--initial",
+                                     "--nowait-nodes=1-255",
+                                     NULL));
+  CHECK(mgmd2->wait(ret));
+  CHECK(ret == 1);
+
+  CHECK(mgmd1->stop());
+
+  return NDBT_OK;
+}
+
 NDBT_TESTSUITE(testMgmd);
 DRIVER(DummyDriver); /* turn off use of NdbApi */
 
@@ -633,6 +803,19 @@ TESTCASE("Bug42015",
 {
   INITIALIZER(runTestBug42015);
 }
+TESTCASE("NowaitNodes",
+         "Test that one mgmd(of 2) can start alone with usage "
+         "of --nowait-nodes, then start the second mgmd and it should join")
+{
+  INITIALIZER(runTestNowaitNodes);
+}
+TESTCASE("NowaitNodes2",
+         "Test that one mgmd(of 2) can start alone with usage "
+         "of --nowait-nodes, then start the second mgmd from different "
+         "configuration and the one with lowest nodeid should shutdown")
+{
+  INITIALIZER(runTestNowaitNodes2);
+}
 
 NDBT_TESTSUITE_END(testMgmd);
 

=== modified file 'storage/ndb/test/ndbapi/testNdbinfo.cpp'
--- a/storage/ndb/test/ndbapi/testNdbinfo.cpp	2009-11-08 12:52:27 +0000
+++ b/storage/ndb/test/ndbapi/testNdbinfo.cpp	2009-11-17 16:55:50 +0000
@@ -20,6 +20,7 @@
 #include <NDBT_Test.hpp>
 #include "../../src/ndbapi/NdbInfo.hpp"
 
+#include <NdbRestarter.hpp>
 
 int runTestNdbInfo(NDBT_Context* ctx, NDBT_Step* step)
 {
@@ -121,10 +122,10 @@ int runScanAll(NDBT_Context* ctx, NDBT_S
         columnId++;
       // At least one column
       assert(columnId >= 1);
-
-      if(scanOp->execute() != 0)
+      int ret;
+      if((ret = scanOp->execute()) != 0)
       {
-        g_err << "scanOp->execute failed" << endl;
+        g_err << "scanOp->execute failed, ret: " << ret << endl;
         return NDBT_FAILED;
       }
 
@@ -143,6 +144,20 @@ int runScanAll(NDBT_Context* ctx, NDBT_S
   return NDBT_FAILED;
 }
 
+
+int runScanAllUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
+  int i = 0;
+  while (ctx->isTestStopped() == false) {
+    g_info << i << ": ";
+    if (runScanAll(ctx,  step) != NDBT_OK){
+      return NDBT_FAILED;
+    }
+    i++;
+  }
+  return NDBT_OK;
+}
+
+
 int runScanStop(NDBT_Context* ctx, NDBT_Step* step)
 {
   NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
@@ -372,6 +387,84 @@ int runTestTable(NDBT_Context* ctx, NDBT
   return NDBT_OK;
 }
 
+int runRestarter(NDBT_Context* ctx, NDBT_Step* step){
+  int result = NDBT_OK;
+  int loops = ctx->getNumLoops();
+  int sync_threads = ctx->getProperty("SyncThreads", (unsigned)0);
+  int sleep0 = ctx->getProperty("Sleep0", (unsigned)0);
+  int sleep1 = ctx->getProperty("Sleep1", (unsigned)0);
+  int randnode = ctx->getProperty("RandNode", (unsigned)0);
+  NdbRestarter restarter;
+  int i = 0;
+  int lastId = 0;
+
+  if (restarter.getNumDbNodes() < 2){
+    ctx->stopTest();
+    return NDBT_OK;
+  }
+
+  if(restarter.waitClusterStarted() != 0){
+    g_err << "Cluster failed to start" << endl;
+    return NDBT_FAILED;
+  }
+
+  loops *= (restarter.getNumDbNodes() > 2 ? 2 : restarter.getNumDbNodes());
+  if (loops < restarter.getNumDbNodes())
+    loops = restarter.getNumDbNodes();
+
+  while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
+
+    int id = lastId % restarter.getNumDbNodes();
+    if (randnode == 1)
+    {
+      id = rand() % restarter.getNumDbNodes();
+    }
+    int nodeId = restarter.getDbNodeId(id);
+    ndbout << "Restart node " << nodeId << 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 (sleep1)
+      NdbSleep_MilliSleep(sleep1);
+
+    if (restarter.startNodes(&nodeId, 1))
+    {
+      g_err << "Failed to start node" << endl;
+      result = NDBT_FAILED;
+      break;
+    }
+
+    if(restarter.waitClusterStarted() != 0){
+      g_err << "Cluster failed to start" << endl;
+      result = NDBT_FAILED;
+      break;
+    }
+
+    if (sleep0)
+      NdbSleep_MilliSleep(sleep0);
+
+    ctx->sync_up_and_wait("PauseThreads", sync_threads);
+
+    lastId++;
+    i++;
+  }
+
+  ctx->stopTest();
+
+  return result;
+}
+
+
 
 NDBT_TESTSUITE(testNdbinfo);
 TESTCASE("Ndbinfo",
@@ -399,6 +492,13 @@ TESTCASE("TestTable",
           "of rows which will depend on how many TUP blocks are configured"){
   STEP(runTestTable);
 }
+#if 0
+TESTCASE("NodeRestart", "Scan NdbInfo tables while restarting nodes"){
+  TC_PROPERTY("Sleep0", 29000); // Between restarts
+  STEP(runRestarter);
+  STEPS(runScanAllUntilStopped, 1);
+}
+#endif
 NDBT_TESTSUITE_END(testNdbinfo);
 
 

=== modified file 'storage/ndb/test/ndbapi/testPartitioning.cpp'
--- a/storage/ndb/test/ndbapi/testPartitioning.cpp	2009-05-27 15:21:45 +0000
+++ b/storage/ndb/test/ndbapi/testPartitioning.cpp	2009-11-17 13:10:09 +0000
@@ -814,7 +814,20 @@ load_dist_table(Ndb* pNdb, int records, 
     CHECKNOTNULL(trans->insertTuple(distRecord, buf, 
                                     NULL, &opts, sizeof(opts)), trans);
 
-    CHECK(trans->execute(NdbTransaction::Commit), trans);
+    if (trans->execute(NdbTransaction::Commit) != 0)
+    {
+      NdbError err = trans->getNdbError();
+      if (err.status == NdbError::TemporaryError)
+      {
+        ndbout << err << endl;
+        NdbSleep_MilliSleep(50);
+        r--; // just retry
+      }
+      else
+      {
+        CHECK(-1, trans);
+      }
+    }
     trans->close();
   }
 

=== modified file 'storage/ndb/test/run-test/CMakeLists.txt'
--- a/storage/ndb/test/run-test/CMakeLists.txt	2009-11-13 04:50:47 +0000
+++ b/storage/ndb/test/run-test/CMakeLists.txt	2009-11-16 05:21:53 +0000
@@ -36,6 +36,7 @@ ADD_EXECUTABLE(atrt main.cpp setup.cpp f
 
 INSTALL(TARGETS atrt DESTINATION bin)
 INSTALL(FILES
+               atrt-testBackup
                atrt-analyze-result.sh
                atrt-backtrace.sh
                atrt-gather-result.sh

=== modified file 'storage/ndb/test/run-test/atrt.hpp'
--- a/storage/ndb/test/run-test/atrt.hpp	2009-11-13 04:55:46 +0000
+++ b/storage/ndb/test/run-test/atrt.hpp	2009-12-03 05:53:33 +0000
@@ -125,7 +125,6 @@ struct atrt_testcase 
 
 extern Logger g_logger;
 
-void require(bool x);
 bool parse_args(int argc, char** argv);
 bool setup_config(atrt_config&, const char * mysqld);
 bool configure(atrt_config&, int setup);

=== modified file 'storage/ndb/test/run-test/daily-basic-tests.txt'
--- a/storage/ndb/test/run-test/daily-basic-tests.txt	2009-11-02 17:15:29 +0000
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt	2009-12-03 10:19:24 +0000
@@ -274,6 +274,10 @@ max-time: 2500
 cmd: testIndex
 args: -n BuildDuring T6 
 
+max-time: 2500
+cmd: testIndex
+args: -n BuildDuring_O T6 
+
 max-time: 600
 cmd: testIndex
 args: -n Bug46069 T1
@@ -1469,6 +1473,32 @@ cmd: testBasic
 args: -n DDInsertFailUpdateBatch
 
 max-time: 300
+cmd: testBlobs
+args: -skip hp -bug 28116
+
+max-time: 300
 cmd: testNdbApi
 args: -n FragmentedApiFailure T1
 
+# Series of short (signal train) request generation/handling tests
+# Start
+max-time: 500
+cmd: testBasic
+args: --forceshortreqs -n PkUpdate
+
+max-time: 300
+cmd: testIndex
+args: --forceshortreqs -n InsertDelete T2
+
+max-time: 2500
+cmd: testPartitioning
+args: --forceshortreqs
+
+# End of short (signal train) handling tests
+
+max-time: 300
+cmd: testIndex
+args: -n ConstraintDetails
+
+
+

=== modified file 'storage/ndb/test/run-test/daily-devel-tests.txt'
--- a/storage/ndb/test/run-test/daily-devel-tests.txt	2009-09-15 10:13:15 +0000
+++ b/storage/ndb/test/run-test/daily-devel-tests.txt	2009-11-30 10:45:52 +0000
@@ -112,10 +112,6 @@ args: -n NFNR3_O T6 T13 
 
 max-time: 2500
 cmd: testIndex
-args: -n BuildDuring_O T6 
-
-max-time: 2500
-cmd: testIndex
 args: -l 2 -n SR1_O T6 T13 
 
 # dict trans

=== modified file 'storage/ndb/test/run-test/main.cpp'
--- a/storage/ndb/test/run-test/main.cpp	2009-11-13 04:54:50 +0000
+++ b/storage/ndb/test/run-test/main.cpp	2009-12-03 05:53:33 +0000
@@ -1404,13 +1404,6 @@ started:
   return true;
 }
 
-void
-require(bool x)
-{
-  if (!x)
-    abort();
-}
-
 bool
 reset_config(atrt_config & config)
 {

=== modified file 'storage/ndb/test/src/CMakeLists.txt'
--- a/storage/ndb/test/src/CMakeLists.txt	2009-10-07 06:35:51 +0000
+++ b/storage/ndb/test/src/CMakeLists.txt	2009-11-18 11:05:02 +0000
@@ -17,7 +17,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
                     ${CMAKE_SOURCE_DIR}/storage/ndb/src/common/mgmcommon
                     ${CMAKE_SOURCE_DIR}/storage/ndb/include/mgmcommon
                     ${CMAKE_SOURCE_DIR}/storage/ndb/include/kernel
-                    ${CMAKE_SOURCE_DIR}/storage/ndb/src/mgmapi)
+                    ${CMAKE_SOURCE_DIR}/storage/ndb/src/mgmapi
+                    ${CMAKE_SOURCE_DIR}/storage/ndb/include/debugger)
 INCLUDE(${CMAKE_SOURCE_DIR}/storage/ndb/config/type_ndbapitest.cmake)
 
 ADD_LIBRARY(ndbNDBT STATIC

=== modified file 'storage/ndb/test/src/Makefile.am'
--- a/storage/ndb/test/src/Makefile.am	2009-09-16 12:53:49 +0000
+++ b/storage/ndb/test/src/Makefile.am	2009-11-18 11:05:02 +0000
@@ -30,7 +30,7 @@ libNDBT_a_SOURCES = \
 	CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp DbUtil.cpp \
 	SocketInputStream2.cpp NDBT_Find.cpp
 
-INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi -I$(top_srcdir)/include
+INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi -I$(top_srcdir)/include -I$(top_srcdir)/storage/ndb/include/debugger
 
 include $(top_srcdir)/storage/ndb/config/common.mk.am
 include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am

=== modified file 'storage/ndb/test/src/NDBT_Test.cpp'
--- a/storage/ndb/test/src/NDBT_Test.cpp	2009-11-11 18:04:01 +0000
+++ b/storage/ndb/test/src/NDBT_Test.cpp	2009-11-18 23:14:19 +0000
@@ -268,6 +268,7 @@ NDBT_Step::NDBT_Step(NDBT_TestCase* ptes
 {
 }
 
+#include <../../src/ndbapi/NdbImpl.hpp>
 
 int
 NDBT_Step::setUp(Ndb_cluster_connection& con){
@@ -282,6 +283,9 @@ NDBT_Step::setUp(Ndb_cluster_connection&
     m_ndb = new Ndb(&con, "TEST_DB" );
     m_ndb->init(1024);
 
+    NdbImpl::setForceShortRequests(m_ndb, 
+                                   m_ctx->suite->getForceShort());
+
     int result = m_ndb->waitUntilReady(300); // 5 minutes
     if (result != 0){
       g_err << "Ndb was not ready" << endl;
@@ -792,6 +796,7 @@ NDBT_TestSuite::NDBT_TestSuite(const cha
    temporaryTables = false;
    runonce = false;
    m_noddl = false;
+   m_forceShort = false;
 }
 
 
@@ -833,6 +838,10 @@ bool NDBT_TestSuite::getLogging() const 
   return m_logging;
 }
 
+bool NDBT_TestSuite::getForceShort() const {
+  return m_forceShort;
+}
+
 bool NDBT_TestSuite::timerIsOn(){
   return (timer != 0);
 }
@@ -927,6 +936,8 @@ NDBT_TestSuite::executeOneCtx(Ndb_cluste
     Ndb ndb(&con, "TEST_DB");
     ndb.init(1024);
 
+    NdbImpl::setForceShortRequests(&ndb, m_forceShort);
+
     int result = ndb.waitUntilReady(300); // 5 minutes
     if (result != 0){
       g_err << name <<": Ndb was not ready" << endl;
@@ -1276,6 +1287,7 @@ static int opt_seed = 0;
 static int opt_nologging = 0;
 static int opt_temporary = 0;
 static int opt_noddl = 0;
+static int opt_forceShort = 0;
 
 static struct my_option my_long_options[] =
 {
@@ -1316,6 +1328,9 @@ static struct my_option my_long_options[
   { "noddl", 0, "Don't create/drop tables as part of running tests",
     (uchar**) &opt_noddl, (uchar**) &opt_noddl, 0,
     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+  { "forceshortreqs", 0, "Use short signals for NdbApi requests",
+    (uchar**) &opt_forceShort, (uchar**) &opt_forceShort, 0,
+    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
 
@@ -1386,6 +1401,7 @@ int NDBT_TestSuite::execute(int argc, co
     setLogging(false);
   temporaryTables = opt_temporary;
   m_noddl = opt_noddl;
+  m_forceShort = opt_forceShort;
 
   if (opt_seed == 0)
   {

=== modified file 'storage/ndb/tools/ndbinfo_sql.cpp'
--- a/storage/ndb/tools/ndbinfo_sql.cpp	2009-11-12 21:25:49 +0000
+++ b/storage/ndb/tools/ndbinfo_sql.cpp	2009-11-13 13:43:02 +0000
@@ -98,8 +98,8 @@ struct view {
     "  WHEN 5 THEN \"FILE_BUFFERS\""
     "  WHEN 6 THEN \"TRANSPORTER_BUFFERS\""
     "  ELSE \"<unknown>\" "
-    " END AS resource_id, "
-    "reserved, used, max, high "
+    " END AS resource_name, "
+    "reserved, used, max "
     "FROM <NDBINFO_DB>.<TABLE_PREFIX>resources"
    },
    { "counters",
@@ -142,15 +142,15 @@ struct view {
     "FROM <NDBINFO_DB>.<TABLE_PREFIX>nodes"
    },
   { "memoryusage",
-    "SELECT node_id, \"DATA_MEMORY\" "
-    "used, max, high "
+    "SELECT node_id, \"DATA_MEMORY\", "
+    "used, max "
     "FROM <NDBINFO_DB>.<TABLE_PREFIX>resources "
-    "WHERE resource_id = \"DATA_MEMORY|\" "
+    "WHERE resource_id = 3 "
     "UNION "
-    "SELECT node_id, \"INDEX_MEMORY\" "
-    "used, total, high "
+    "SELECT node_id, \"INDEX_MEMORY\", "
+    "used, total "
     "FROM <NDBINFO_DB>.<TABLE_PREFIX>pools "
-    "WHERE pool_name = \"Index memory|\" "
+    "WHERE block_number = 248 AND pool_name = \"Index memory\" "
   }
 };
 

=== modified file 'storage/ndb/tools/restore/Restore.cpp'
--- a/storage/ndb/tools/restore/Restore.cpp	2009-09-08 12:10:53 +0000
+++ b/storage/ndb/tools/restore/Restore.cpp	2009-12-02 15:01:19 +0000
@@ -501,8 +501,12 @@ RestoreMetaData::markSysTables()
         strcmp(tableName, OLD_NDB_REP_DB "/def/" OLD_NDB_SCHEMA_TABLE) == 0 ||
         strcmp(tableName, NDB_REP_DB "/def/" NDB_APPLY_TABLE) == 0 ||
         strcmp(tableName, NDB_REP_DB "/def/" NDB_SCHEMA_TABLE)== 0 )
-
-      table->isSysTable = true;
+    {
+      table->m_isSysTable = true;
+      if (strcmp(tableName, "SYSTAB_0") == 0 ||
+          strcmp(tableName, "sys/def/SYSTAB_0") == 0)
+        table->m_isSYSTAB_0 = true;
+    }
   }
   for (i = 0; i < getNoOfTables(); i++) {
     TableS* blobTable = allTables[i];
@@ -517,8 +521,8 @@ RestoreMetaData::markSysTables()
       for (j = 0; j < getNoOfTables(); j++) {
         TableS* table = allTables[j];
         if (table->getTableId() == (Uint32) id1) {
-          if (table->isSysTable)
-            blobTable->isSysTable = true;
+          if (table->m_isSysTable)
+            blobTable->m_isSysTable = true;
           blobTable->m_main_table = table;
           blobTable->m_main_column_id = id2;
           break;
@@ -565,7 +569,16 @@ RestoreMetaData::fixBlobs()
           break;
         }
       }
-      assert(blobTable != NULL);
+      if (blobTable == NULL)
+      {
+        /* Corrupt backup, has main table, but no blob table */
+        err << "Table " << table->m_dictTable->getName()
+            << " has blob column " << j << " (" 
+            << c->m_name.c_str()
+            << ") with missing parts table in backup."
+            << endl;
+        return false;
+      }
       assert(blobTable->m_dictTable != NULL);
       NdbTableImpl& bt = NdbTableImpl::getImpl(*blobTable->m_dictTable);
       const char* colName = c->m_blobVersion == 1 ? "DATA" : "NDB$DATA";
@@ -662,7 +675,8 @@ TableS::TableS(Uint32 version, NdbTableI
   m_max_auto_val= 0;
   m_noOfRecords= 0;
   backupVersion = version;
-  isSysTable = false;
+  m_isSysTable = false;
+  m_isSYSTAB_0 = false;
   m_main_table = NULL;
   m_main_column_id = ~(Uint32)0;
   
@@ -1742,6 +1756,35 @@ void TableS::createAttr(NdbDictionary::C
   m_variableAttribs.push_back(d);
 } // TableS::createAttr
 
+bool
+TableS::get_auto_data(const TupleS & tuple, Uint32 * syskey, Uint64 * nextid) const
+{
+  /*
+    Read current (highest) auto_increment value for
+    a table. Currently there can only be one per table.
+    The values are stored in sustable SYSTAB_0 as
+    {SYSKEY,NEXTID} values where SYSKEY (32-bit) is
+    the table_id and NEXTID (64-bit) is the next auto_increment
+    value in the sequence (note though that sequences of
+    values can have been fetched and that are cached in NdbAPI).
+    SYSTAB_0 can contain other data so we need to check that
+    the found SYSKEY value is a valid table_id (< 0x10000000).
+   */
+  AttributeData * attr_data = tuple.getData(0);
+  const AttributeDesc * attr_desc = tuple.getDesc(0);
+  const AttributeS attr1 = {attr_desc, *attr_data};
+  memcpy(syskey ,attr1.Data.u_int32_value, sizeof(Uint32));
+  attr_data = tuple.getData(1);
+  attr_desc = tuple.getDesc(1);
+  const AttributeS attr2 = {attr_desc, *attr_data};
+  memcpy(nextid, attr2.Data.u_int64_value, sizeof(Uint64));
+  if (*syskey < 0x10000000)
+  {
+    return true;
+  }
+  return false;
+};
+
 Uint16 Twiddle16(Uint16 in)
 {
   Uint16 retVal = 0;

=== modified file 'storage/ndb/tools/restore/Restore.hpp'
--- a/storage/ndb/tools/restore/Restore.hpp	2009-08-18 13:21:50 +0000
+++ b/storage/ndb/tools/restore/Restore.hpp	2009-12-01 10:15:25 +0000
@@ -168,7 +168,9 @@ class TableS {
   AttributeDesc * m_auto_val_attrib;
   Uint64 m_max_auto_val;
 
-  bool isSysTable;
+  bool m_isSysTable;
+  bool m_isSYSTAB_0;
+
   TableS *m_main_table;
   Uint32 m_main_column_id;
   Uint32 m_local_id;
@@ -264,6 +266,9 @@ public:
     if(v > m_max_auto_val)
       m_max_auto_val= v;
   };
+
+  bool get_auto_data(const TupleS & tuple, Uint32 * syskey, Uint64 * nextid) const;
+
   /**
    * Get attribute descriptor
    */
@@ -276,14 +281,19 @@ public:
   }
 
   bool getSysTable() const {
-    return isSysTable;
+    return m_isSysTable;
   }
 
   const TableS *getMainTable() const {
     return m_main_table;
   }
 
-  TableS& operator=(TableS& org) ; 
+  TableS& operator=(TableS& org) ;
+
+  inline
+  const bool isSYSTAB_0() const {
+    return m_isSYSTAB_0;
+  } 
 }; // TableS;
 
 class RestoreLogIterator;
@@ -496,6 +506,8 @@ NdbOut& operator<<(NdbOut& ndbout, const
 NdbOut& operator<<(NdbOut& ndbout, const LogEntry&);
 NdbOut& operator<<(NdbOut& ndbout, const RestoreMetaData&);
 
+bool readSYSTAB_0(const TupleS & tup, Uint32 * syskey, Uint64 * nextid);
+
 #endif
 
 

=== modified file 'storage/ndb/tools/restore/consumer_printer.cpp'
--- a/storage/ndb/tools/restore/consumer_printer.cpp	2009-05-26 18:53:34 +0000
+++ b/storage/ndb/tools/restore/consumer_printer.cpp	2009-11-25 12:37:14 +0000
@@ -18,6 +18,7 @@
 
 #include "consumer_printer.hpp"
 extern FilteredNdbOut info;
+extern bool ga_dont_ignore_systab_0;
 extern NdbRecordPrintFormat g_ndbrecord_print_format;
 extern const char *tab_path;
 
@@ -44,6 +45,9 @@ BackupPrinter::tuple(const TupleS & tup,
       info.setLevel(254);
       info << tup.getTable()->getTableName() << "; ";
     }
+    const TableS * table = tup.getTable();
+    if ((!ga_dont_ignore_systab_0) &&  table->isSYSTAB_0())
+      return;
     m_ndbout << tup << g_ndbrecord_print_format.lines_terminated_by;  
   }
 }

=== modified file 'storage/ndb/tools/restore/consumer_restore.cpp'
--- a/storage/ndb/tools/restore/consumer_restore.cpp	2009-08-18 13:21:50 +0000
+++ b/storage/ndb/tools/restore/consumer_restore.cpp	2009-12-01 10:15:25 +0000
@@ -176,8 +176,15 @@ BackupRestore::get_table(const NdbDictio
 
   int cnt, id1, id2;
   char db[256], schema[256];
-  if((cnt = sscanf(tab->getName(), "%[^/]/%[^/]/NDB$BLOB_%d_%d", 
-		   db, schema, &id1, &id2)) == 4){
+  if (strcmp(tab->getName(), "SYSTAB_0") == 0 ||
+      strcmp(tab->getName(), "sys/def/SYSTAB_0") == 0) {
+    /*
+      Restore SYSTAB_0 to itself
+    */
+    m_cache.m_new_table = tab;
+  }
+  else if((cnt = sscanf(tab->getName(), "%[^/]/%[^/]/NDB$BLOB_%d_%d", 
+                        db, schema, &id1, &id2)) == 4){
     m_ndb->setDatabaseName(db);
     m_ndb->setSchemaName(schema);
     
@@ -1442,6 +1449,8 @@ BackupRestore::endOfTables(){
 
 void BackupRestore::tuple(const TupleS & tup, Uint32 fragmentId)
 {
+  const TableS * tab = tup.getTable();
+
   if (!m_restore) 
     return;
 
@@ -1458,12 +1467,19 @@ void BackupRestore::tuple(const TupleS &
   if (cb == 0)
     assert(false);
   
-  m_free_callback = cb->next;
   cb->retries = 0;
   cb->fragId = fragmentId;
   cb->tup = tup; // must do copy!
-  tuple_a(cb);
 
+  if (tab->isSYSTAB_0())
+  {
+    tuple_SYSTAB_0(cb, *tab);
+    return;
+  }
+
+  m_free_callback = cb->next;
+
+  tuple_a(cb);
 }
 
 void BackupRestore::tuple_a(restore_callback_t *cb)
@@ -1637,6 +1653,59 @@ void BackupRestore::tuple_a(restore_call
   exitHandler();
 }
 
+void BackupRestore::tuple_SYSTAB_0(restore_callback_t *cb,
+                                   const TableS & tab)
+{
+  const TupleS & tup = cb->tup;
+  Uint32 syskey;
+  Uint64 nextid;
+
+  if (tab.get_auto_data(tup, &syskey, &nextid))
+  {
+    /*
+      We found a valid auto_increment value in SYSTAB_0
+      where syskey is a table_id and nextid is next auto_increment
+      value.
+     */
+    if (restoreAutoIncrement(cb, syskey, nextid) ==  -1)
+      exitHandler();
+  }
+}
+
+int BackupRestore::restoreAutoIncrement(restore_callback_t *cb,
+                                        Uint32 tableId, Uint64 value)
+{
+  /*
+    Restore the auto_increment value found in SYSTAB_0 from
+    backup. First map the old table id to the new table while
+    also checking that it is an actual table will some auto_increment
+    column. Note that the SYSTAB_0 table in the backup can contain
+    stale information from dropped tables.
+   */
+  int result = 0;
+  const NdbDictionary::Table* tab = (tableId < m_new_tables.size())? m_new_tables[tableId] : NULL;
+  if (tab && tab->getNoOfAutoIncrementColumns() > 0)
+  {
+    /*
+      Write the auto_increment value back into SYSTAB_0.
+      This is done in a separate transaction and could possibly
+      fail, so we retry if a temporary error is received.
+     */
+    while (cb->retries < 10)
+    {
+      if ((result = m_ndb->setAutoIncrementValue(tab, value, false) == -1))
+      {
+        if (errorHandler(cb)) 
+        {
+          continue;
+        }
+      }
+      break;
+    }
+  }
+  return result;
+}
+
 void BackupRestore::cback(int result, restore_callback_t *cb)
 {
   m_transactions--;

=== modified file 'storage/ndb/tools/restore/consumer_restore.hpp'
--- a/storage/ndb/tools/restore/consumer_restore.hpp	2009-08-18 13:21:50 +0000
+++ b/storage/ndb/tools/restore/consumer_restore.hpp	2009-12-01 10:15:25 +0000
@@ -89,6 +89,9 @@ public:
   virtual void tuple(const TupleS &, Uint32 fragId);
   virtual void tuple_free();
   virtual void tuple_a(restore_callback_t *cb);
+  virtual void tuple_SYSTAB_0(restore_callback_t *cb, const TableS &);
+  virtual int restoreAutoIncrement(restore_callback_t *cb,
+                                    Uint32 tableId, Uint64 value);
   virtual void cback(int result, restore_callback_t *cb);
   virtual bool errorHandler(restore_callback_t *cb);
   virtual void exitHandler();

=== modified file 'storage/ndb/tools/restore/restore_main.cpp'
--- a/storage/ndb/tools/restore/restore_main.cpp	2009-08-18 13:21:50 +0000
+++ b/storage/ndb/tools/restore/restore_main.cpp	2009-12-02 13:54:07 +0000
@@ -37,7 +37,7 @@ static Uint32 g_tableCompabilityMask = 0
 static int ga_nodeId = 0;
 static int ga_nParallelism = 128;
 static int ga_backupId = 0;
-static bool ga_dont_ignore_systab_0 = false;
+bool ga_dont_ignore_systab_0 = false;
 static bool ga_no_upgrade = false;
 static bool ga_promote_attributes = false;
 static Vector<class BackupConsumer *> g_consumers;
@@ -64,6 +64,17 @@ Vector<BaseString> g_include_databases, 
 NdbRecordPrintFormat g_ndbrecord_print_format;
 unsigned int opt_no_binlog;
 
+class RestoreOption
+{
+public:
+  virtual ~RestoreOption() { }
+  int optid;
+  BaseString argument;
+};
+
+Vector<class RestoreOption *> g_include_exclude;
+static void save_include_exclude(int optid, char * argument);
+
 /**
  * print and restore flags
  */
@@ -183,7 +194,7 @@ static struct my_option my_long_options[
     (uchar**) &ga_backupPath, (uchar**) &ga_backupPath, 0,
     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
   { "dont_ignore_systab_0", 'f',
-    "Experimental. Do not ignore system table during restore.", 
+    "Do not ignore system table during --print-data.", 
     (uchar**) &ga_dont_ignore_systab_0, (uchar**) &ga_dont_ignore_systab_0, 0,
     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
   { "ndb-nodegroup-map", OPT_NDB_NODEGROUP_MAP,
@@ -419,6 +430,12 @@ get_one_option(int optid, const struct m
       exit(NDBT_ProgramExit(NDBT_WRONGARGS));
     }
     break;
+  case OPT_INCLUDE_DATABASES:
+  case OPT_EXCLUDE_DATABASES:
+  case OPT_INCLUDE_TABLES:
+  case OPT_EXCLUDE_TABLES:
+    save_include_exclude(optid, argument);
+    break;
   }
   return 0;
 }
@@ -733,7 +750,7 @@ clearConsumers()
 static inline bool
 checkSysTable(const TableS* table)
 {
-  return ga_dont_ignore_systab_0 || ! table->getSysTable();
+  return ! table->getSysTable();
 }
 
 static inline bool
@@ -757,8 +774,13 @@ isIndex(const TableS* table)
 }
 
 static inline bool
-isInList(BaseString &needle, Vector<BaseString> &lst)
+isSYSTAB_0(const TableS* table)
 {
+  return table->isSYSTAB_0();
+}
+
+static inline bool
+isInList(BaseString &needle, Vector<BaseString> &lst){
   unsigned int i= 0;
   for (i= 0; i < lst.size(); i++)
   {
@@ -783,6 +805,100 @@ getTableName(const TableS* table)
   return table_name;
 }
 
+static void save_include_exclude(int optid, char * argument)
+{
+  BaseString arg = argument;
+  Vector<BaseString> args;
+  arg.split(args, ",");
+  for (uint i = 0; i < args.size(); i++)
+  {
+    RestoreOption * option = new RestoreOption();
+    BaseString arg;
+    
+    option->optid = optid;
+    switch (optid) {
+    case OPT_INCLUDE_TABLES:
+    case OPT_EXCLUDE_TABLES:
+      if (makeInternalTableName(args[i], arg))
+      {
+        info << "`" << args[i] << "` is not a valid tablename!" << endl;
+        exit(NDBT_ProgramExit(NDBT_WRONGARGS));
+      }
+      break;
+    default:
+      arg = args[i];
+      break;
+    }
+    option->argument = arg;
+    g_include_exclude.push_back(option);
+  }
+}
+static bool check_include_exclude(BaseString database, BaseString table)
+{
+  const char * db = database.c_str();
+  const char * tbl = table.c_str();
+  bool do_include = true;
+
+  if (g_include_databases.size() != 0 ||
+      g_include_tables.size() != 0)
+  {
+    /*
+      User has explicitly specified what databases
+      and/or tables should be restored. If no match is
+      found then DON'T restore table.
+     */
+    do_include = false;
+  }
+  if (do_include &&
+      (g_exclude_databases.size() != 0 ||
+       g_exclude_tables.size() != 0))
+  {
+    /*
+      User has not explicitly specified what databases
+      and/or tables should be restored.
+      User has explicitly specified what databases
+      and/or tables should NOT be restored. If no match is
+      found then DO restore table.
+     */
+    do_include = true;
+  }
+
+  if (g_include_exclude.size() != 0)
+  {
+    /*
+      Scan include exclude arguments in reverse.
+      First matching include causes table to be restored.
+      first matching exclude causes table NOT to be restored.      
+     */
+    for(uint i = g_include_exclude.size(); i > 0; i--)
+    {
+      RestoreOption *option = g_include_exclude[i-1];
+      switch (option->optid) {
+      case OPT_INCLUDE_TABLES:
+        if (strcmp(tbl, option->argument.c_str()) == 0)
+          return true; // do include
+        break;
+      case OPT_EXCLUDE_TABLES:
+        if (strcmp(tbl, option->argument.c_str()) == 0)
+          return false; // don't include
+        break;
+      case OPT_INCLUDE_DATABASES:
+        if (strcmp(db, option->argument.c_str()) == 0)
+          return true; // do include
+        break;
+      case OPT_EXCLUDE_DATABASES:
+        if (strcmp(db, option->argument.c_str()) == 0)
+          return false; // don't include
+        break;
+      default:
+        continue;
+      }
+    }
+  }
+  
+  return do_include;
+}
+
 static inline bool
 checkDoRestore(const TableS* table)
 {
@@ -794,32 +910,16 @@ checkDoRestore(const TableS* table)
   idx = tbl.indexOf('/');
   db = tbl.substr(0, idx);
   
-  /* Included tables overrides
-   * Excluded tables which overrides
-   * Included databases which overrides
-   * Excluded databases.
-   * If any databases are included, then only
-   * included databases are restored.
-   * If any tables are included, then only
-   * included tables are restored.
+  /*
+    Include/exclude flags are evaluated right
+    to left, and first match overrides any other
+    matches. Non-overlapping arguments are accumulative.
+    If no include flags are specified this means all databases/tables
+    except any excluded are restored.
+    If include flags are specified than only those databases
+    or tables specified are restored.
    */
-
-  if (g_exclude_databases.size() != 0) {
-    if (isInList(db, g_exclude_databases))
-      ret = false;
-  }
-  if (g_include_databases.size() != 0) {
-    ret= isInList(db, g_include_databases);
-  }
-  
-  if (g_exclude_tables.size() != 0) {
-    if (isInList(tbl, g_exclude_tables))
-      ret = false;
-  }
-  if (g_include_tables.size() != 0) {
-    ret= isInList(tbl, g_include_tables);
-  }
-  
+  ret = check_include_exclude(db, tbl);
   return ret;
 }
 
@@ -1075,6 +1175,10 @@ main(int argc, char** argv)
     table_output.push_back(NULL);
     if (!checkDbAndTableName(table))
       continue;
+    if (isSYSTAB_0(table))
+    {
+      table_output[i]= ndbout.m_out;
+    }
     if (checkSysTable(table))
     {
       if (!tab_path || isBlobTable(table) || isIndex(table))
@@ -1345,3 +1449,4 @@ main(int argc, char** argv)
 
 template class Vector<BackupConsumer*>;
 template class Vector<OutputStream*>;
+template class Vector<RestoreOption *>;


Attachment: [text/bzr-bundle] bzr/jonas@mysql.com-20091206171240-t8a8bke0gcxxvdun.bundle
Thread
bzr commit into mysql-5.1-telco-7.0-spj branch (jonas:3014)Jonas Oreland6 Dec