List:Commits« Previous MessageNext Message »
From:Tomas Ulin Date:October 28 2008 10:27am
Subject:bzr push into mysql-5.1 branch (tomas.ulin:2695 to 2707) Bug#37491
View as plain text  
 2707 Frazer Clement	2008-10-22
      Bug# 37491 :  ndbapi-examples build broken by the new library linking changes
      
      This patch fixes issues with building the ndbapi_examples in a source 
      distribution of MySQLD.
      
      There may still be issues with building out of the box of non source 
      distributions. 
modified:
  storage/ndb/ndbapi-examples/mgmapi_logevent/Makefile
  storage/ndb/ndbapi-examples/mgmapi_logevent2/Makefile
  storage/ndb/ndbapi-examples/ndbapi_async/Makefile
  storage/ndb/ndbapi-examples/ndbapi_async1/Makefile
  storage/ndb/ndbapi-examples/ndbapi_blob/Makefile
  storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/Makefile
  storage/ndb/ndbapi-examples/ndbapi_event/Makefile
  storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/Makefile
  storage/ndb/ndbapi-examples/ndbapi_retries/Makefile
  storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/Makefile
  storage/ndb/ndbapi-examples/ndbapi_scan/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple_dual/Makefile
  storage/ndb/ndbapi-examples/ndbapi_simple_index/Makefile

 2706 Frazer Clement	2008-10-21
      Bug#39295 cluster table with TEXT column cannot be cached in query cache
      
      Read of Text column resulted in lock upgrade to read/shared.
      Since rows are disk based, TUP-order scan is chosen
      
      TUP and TUX ordered scans with locks have unwanted side-effect of 
      incrementing fragment commit_count when locks are freed.
      
      This results in query cache invalidation.
      
      Fix is to remove unwanted fragment commit_count increment for TUP + TUX 
      ordered scans.
modified:
  mysql-test/suite/ndb/r/ndb_cache.result
  mysql-test/suite/ndb/t/ndb_cache.test
  mysql-test/suite/ndb/t/ndb_cache2.test
  storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp

 2705 Jonas Oreland	2008-10-21
      ndb - bug#28496
modified:
  storage/ndb/src/ndbapi/ndberror.c

 2704 Jonas Oreland	2008-10-21
      ndb - enable directio on solaris
modified:
  configure.in
  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp

 2703 Jonas Oreland	2008-10-21
      ndb - bug#34638 - O_SYNC incorrectly got disabled if os didnt have O_DIRECT (solaris)
modified:
  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp

 2702 Jonas Oreland	2008-10-21
      ndb - bug#40205
        O_DIRECT disabled for backups
modified:
  storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp

 2701 mysqldev	2008-10-21
      bump up version
modified:
  configure.in

 2700 Tomas Ulin	2008-10-17
      Bug#32656 bug fix corrections
modified:
  sql/ha_ndbcluster.cc

 2699 Frazer Clement	2008-10-16
      Add retries to testBasicAsynch
      
      Remove spurious failures in autotest.
      
      Recommit now that merge to 6.4 possible
modified:
  storage/ndb/test/include/HugoAsynchTransactions.hpp
  storage/ndb/test/src/HugoAsynchTransactions.cpp

 2698 Jonas Oreland	2008-10-16 [merge]
      merge with 62
modified:
  sql/ha_ndbcluster.cc

 2697 Jonas Oreland	2008-10-16
      ndb - flexAsync - add summary at end, and fix warnings
modified:
  storage/ndb/test/ndbapi/flexAsynch.cpp

 2696 Tomas Ulin	2008-10-16 [merge]
      merge
modified:
  sql/ha_ndbcluster.cc

 2695 Tomas Ulin	2008-10-15 [merge]
      merge
modified:
  sql/ha_ndbcluster.cc
  sql/ha_ndbcluster.h

=== modified file 'configure.in'
--- a/configure.in	2008-09-01 12:28:57 +0000
+++ b/configure.in	2008-10-21 12:52:50 +0000
@@ -10,12 +10,12 @@ AC_CANONICAL_SYSTEM
 #
 # When changing major version number please also check switch statement
 # in mysqlbinlog::check_master_version().
-AM_INIT_AUTOMAKE(mysql, 5.1.28-ndb-6.2.16)
+AM_INIT_AUTOMAKE(mysql, 5.1.28-ndb-6.2.17)
 AM_CONFIG_HEADER([include/config.h:config.h.in])
 
 NDB_VERSION_MAJOR=6
 NDB_VERSION_MINOR=2
-NDB_VERSION_BUILD=16
+NDB_VERSION_BUILD=17
 NDB_VERSION_STATUS="-RC"
 
 PROTOCOL_VERSION=10
@@ -2058,7 +2058,7 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bs
   sighold sigset sigthreadmask port_create sleep \
   snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \
   strtol strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr \
-  posix_fallocate backtrace backtrace_symbols backtrace_symbols_fd)
+  posix_fallocate backtrace backtrace_symbols backtrace_symbols_fd directio)
 
 #
 #

=== modified file 'mysql-test/suite/funcs_1/r/ndb_trig_1011ext.result'
--- a/mysql-test/suite/funcs_1/r/ndb_trig_1011ext.result	2008-06-02 19:57:11 +0000
+++ b/mysql-test/suite/funcs_1/r/ndb_trig_1011ext.result	2008-10-13 07:01:21 +0000
@@ -363,7 +363,7 @@ create table t4 (f4 tinyint) engine = <e
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
-  `f1` int(11) default NULL
+  `f1` int(11) DEFAULT NULL
 ) ENGINE=<engine_to_be_used> DEFAULT CHARSET=latin1
 insert into t1 values (1);
 create trigger tr1 after insert on t1
@@ -375,7 +375,7 @@ for each row insert into t4 (f4) values 
 set autocommit=0;
 start transaction;
 insert into t1 values (1);
-ERROR 22003: Out of range value adjusted for column 'f4' at row 1
+ERROR 22003: Out of range value for column 'f4' at row 1
 commit;
 select * from t1 order by f1;
 f1

=== modified file 'mysql-test/suite/funcs_1/t/disabled.def'
--- a/mysql-test/suite/funcs_1/t/disabled.def	2008-06-18 17:23:55 +0000
+++ b/mysql-test/suite/funcs_1/t/disabled.def	2008-10-15 12:24:10 +0000
@@ -10,4 +10,3 @@
 #
 ##############################################################################
 
-ndb_trig_1011ext:  Bug#32656 NDB: Duplicate key error aborts transaction in handler. Doesn't talk back to SQL
\ No newline at end of file

=== modified file 'mysql-test/suite/ndb/r/ndb_cache.result'
--- a/mysql-test/suite/ndb/r/ndb_cache.result	2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_cache.result	2008-10-21 22:53:32 +0000
@@ -188,4 +188,183 @@ drop table t1;
 show status like "Qcache_queries_in_cache";
 Variable_name	Value
 Qcache_queries_in_cache	0
+reset query cache;
+flush status;
+create table t1 (a int primary key,
+b text,
+c int,
+key(c))
+engine=ndb;
+insert into t1 values (1,'Alexandra', 1), (2,'Palace', 2);
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	0
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	0
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	0
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 order by a;
+a	b	c
+1	Alexandra	1
+2	Palace	2
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	1
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	1
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	0
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 order by a;
+a	b	c
+1	Alexandra	1
+2	Palace	2
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	1
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	1
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	1
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 force index(c) where c < 2 order by c;
+a	b	c
+1	Alexandra	1
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	2
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	2
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	1
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 force index(c) where c < 2 order by c;
+a	b	c
+1	Alexandra	1
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	2
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	2
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	2
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+drop table t1;
+CREATE LOGFILE GROUP lfg
+ADD UNDOFILE 'myundo.log'
+INITIAL_SIZE 16M
+UNDO_BUFFER_SIZE = 1M
+ENGINE=NDB;
+CREATE TABLESPACE tbsp
+ADD DATAFILE 'mydatafile.fil'
+USE LOGFILE GROUP lfg
+INITIAL_SIZE 12M
+ENGINE=NDB;
+create table t1 (a int primary key,
+b text,
+c int,
+key(c))
+storage disk tablespace tbsp engine ndb;
+insert into t1 values (1,'Alexandra', 1), (2,'Palace', 2);
+reset query cache;
+flush status;
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	0
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	0
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	0
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 order by a;
+a	b	c
+1	Alexandra	1
+2	Palace	2
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	1
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	1
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	0
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 order by a;
+a	b	c
+1	Alexandra	1
+2	Palace	2
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	1
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	1
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	1
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 force index (c) where c < 2 order by c;
+a	b	c
+1	Alexandra	1
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	2
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	2
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	1
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+select * from t1 force index (c) where c < 2 order by c;
+a	b	c
+1	Alexandra	1
+show status like "Qcache_queries_in_cache";
+Variable_name	Value
+Qcache_queries_in_cache	2
+show status like "Qcache_inserts";
+Variable_name	Value
+Qcache_inserts	2
+show status like "Qcache_hits";
+Variable_name	Value
+Qcache_hits	2
+show status like "Qcache_not_cached";
+Variable_name	Value
+Qcache_not_cached	0
+drop table t1;
+alter tablespace tbsp drop datafile 'mydatafile.fil' engine ndb;
+drop tablespace tbsp engine ndb;
+drop logfile group lfg engine ndb;
 SET GLOBAL query_cache_size=0;

=== modified file 'mysql-test/suite/ndb/r/ndb_insert.result'
--- a/mysql-test/suite/ndb/r/ndb_insert.result	2008-09-19 09:14:38 +0000
+++ b/mysql-test/suite/ndb/r/ndb_insert.result	2008-10-15 12:24:10 +0000
@@ -440,8 +440,7 @@ INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 ERROR 23000: Can't write; duplicate key in table 't1'
-commit;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+rollback;
 select * from t1 where pk1=1;
 pk1	b	c
 1	1	1
@@ -477,8 +476,14 @@ INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 ERROR 23000: Can't write; duplicate key in table 't1'
+SHOW WARNINGS;
+Level	Code	Message
+Error	1296	Got error 630 'Tuple already existed when attempting to insert' from NDB
+Error	1022	Can't write; duplicate key in table 't1'
+Warning	1615	Storage engine NDB does not support rollback for this statement. Transaction rolled back and must be restarted
 SELECT * FROM t1 WHERE pk1=10;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+pk1	b	c
+10	10	10
 rollback;
 select * from t1 where pk1=1;
 pk1	b	c
@@ -498,11 +503,12 @@ INSERT INTO t1 VALUES 
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 ERROR 23000: Can't write; duplicate key in table 't1'
 SELECT * FROM t1 WHERE pk1=10;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+pk1	b	c
+10	10	10
 SELECT * FROM t1 WHERE pk1=10;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+pk1	b	c
+10	10	10
 commit;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
 select * from t1 where pk1=1;
 pk1	b	c
 1	1	1
@@ -521,7 +527,6 @@ INSERT INTO t1 VALUES 
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 ERROR 23000: Can't write; duplicate key in table 't1'
 INSERT INTO t1 values (4000, 40, 44);
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
 rollback;
 select * from t1 where pk1=1;
 pk1	b	c

=== modified file 'mysql-test/suite/ndb/r/ndb_single_user.result'
--- a/mysql-test/suite/ndb/r/ndb_single_user.result	2007-10-26 20:40:48 +0000
+++ b/mysql-test/suite/ndb/r/ndb_single_user.result	2008-10-15 12:24:10 +0000
@@ -111,8 +111,7 @@ update t1 set b=b+100 where a=3;
 COMMIT;
 update t1 set b=b+100 where a=4;
 ERROR HY000: Got error 299 'Operation not allowed or aborted due to single user mode' from NDBCLUSTER
-COMMIT;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+ROLLBACK;
 create table t2 (a int) engine myisam;
 alter table t2 add column (b int);
 drop table t2;

=== modified file 'mysql-test/suite/ndb/t/ndb_cache.test'
--- a/mysql-test/suite/ndb/t/ndb_cache.test	2007-07-04 20:38:53 +0000
+++ b/mysql-test/suite/ndb/t/ndb_cache.test	2008-10-21 22:53:32 +0000
@@ -117,6 +117,132 @@ drop table t1;
 
 show status like "Qcache_queries_in_cache";
 
+# End of 4.1 tests
+
+# Bug#39295 cluster table with TEXT column cannot be cached in query cache
+# Disk table scans and Ordered index scans with locks were resulting
+# in the table's commit_count being incremented, making the query cache
+# ineffective 
+
+reset query cache;
+flush status;
+
+create table t1 (a int primary key,
+                 b text,
+                 c int,
+                 key(c))
+                 engine=ndb;
+
+insert into t1 values (1,'Alexandra', 1), (2,'Palace', 2);
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Normal, ACC sourced scan #1, should insert in cache
+select * from t1 order by a;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Normal, ACC sourced scan #2, should hit in cache
+select * from t1 order by a;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# TUX sourced scan #1, should insert in cache
+select * from t1 force index(c) where c < 2 order by c;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# TUX sourced scan #2, should hit in cache
+select * from t1 force index(c) where c < 2 order by c;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+drop table t1;
+
+
+# Now test with TUP-sourced scan with DD
+CREATE LOGFILE GROUP lfg
+ADD UNDOFILE 'myundo.log'
+INITIAL_SIZE 16M
+UNDO_BUFFER_SIZE = 1M
+ENGINE=NDB;
+
+CREATE TABLESPACE tbsp
+ADD DATAFILE 'mydatafile.fil'
+USE LOGFILE GROUP lfg
+INITIAL_SIZE 12M
+ENGINE=NDB;
+
+create table t1 (a int primary key,
+                 b text,
+                 c int,
+                 key(c))
+                 storage disk tablespace tbsp engine ndb;
+
+insert into t1 values (1,'Alexandra', 1), (2,'Palace', 2);
+
+reset query cache;
+flush status;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Normal, TUP sourced scan #1, should insert in cache
+select * from t1 order by a;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# Normal, TUP sourced scan #2, should hit in cache
+select * from t1 order by a;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# TUX sourced scan #1 should insert in cache
+select * from t1 force index (c) where c < 2 order by c;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+# TUX sourced scan #2 should hit in cache
+select * from t1 force index (c) where c < 2 order by c;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+show status like "Qcache_not_cached";
+
+drop table t1;
+alter tablespace tbsp drop datafile 'mydatafile.fil' engine ndb;
+drop tablespace tbsp engine ndb;
+drop logfile group lfg engine ndb;
+
+# end of tests for bug#39395
+
 SET GLOBAL query_cache_size=0;
 
-# End of 4.1 tests
+

=== modified file 'mysql-test/suite/ndb/t/ndb_cache2.test'
--- a/mysql-test/suite/ndb/t/ndb_cache2.test	2007-07-04 20:38:53 +0000
+++ b/mysql-test/suite/ndb/t/ndb_cache2.test	2008-10-21 22:53:32 +0000
@@ -63,6 +63,9 @@ show status like "Qcache_hits";
 
 # Update the table and make sure the correct data is returned
 update t1 set a1=3 where pk=1;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
+
 select * from t1;
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -70,6 +73,9 @@ show status like "Qcache_hits";
 # Insert a new record and make sure the correct data is returned
 insert into t1 value (2, 7, 8, 'Second row');
 insert into t1 value (4, 5, 6, 'Fourth row');
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
+
 select * from t1 order by pk desc;
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -87,6 +93,8 @@ show status like "Qcache_hits";
 
 # Delete from the table
 delete from t1 where c1='Fourth row';
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 select * from t1 where b1=3;
 show status like "Qcache_hits";
@@ -101,6 +109,9 @@ show status like "Qcache_hits";
 
 # Update the table and switch to other connection
 update t1 set a1=4 where b1=3;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
+
 connect (con2,localhost,root,,);
 connection con2;
 use test;
@@ -133,6 +144,8 @@ connection con1;
 flush status;
 begin;
 update t1 set a1=5 where pk=1;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -166,6 +179,8 @@ connection con1;
 flush status;
 begin;
 update t1 set a1=6 where pk=1;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -207,6 +222,8 @@ connection con1;
 flush status;
 begin;
 insert into t1 set pk=5, a1=6, b1=3, c1="New row";
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -245,6 +262,8 @@ connection con1;
 flush status;
 begin;
 delete from t1 where pk=2;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 show status like "Qcache_inserts";
 show status like "Qcache_hits";
@@ -287,6 +306,8 @@ update t2 set a2=9 where pk=1;
 update t3 set a3=9 where pk=1;
 update t4 set a4=9 where a4=2;
 update t5 set a5=9 where pk=1;
+# Sleep to give Qcache thread time to detect change
+--real_sleep 1
 show status like "Qcache_queries_in_cache";
 show status like "Qcache_inserts";
 show status like "Qcache_hits";

=== modified file 'mysql-test/suite/ndb/t/ndb_insert.test'
--- a/mysql-test/suite/ndb/t/ndb_insert.test	2008-09-19 09:14:38 +0000
+++ b/mysql-test/suite/ndb/t/ndb_insert.test	2008-10-15 12:24:10 +0000
@@ -465,8 +465,7 @@ INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 
---error 1296
-commit;
+rollback;
 
 select * from t1 where pk1=1;
 select * from t1 where pk1=10;
@@ -503,9 +502,13 @@ begin;
 INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
---error 1296
+# check that we get a warning that transaction has rolled back
+SHOW WARNINGS;
+
+# transaction has rolled back, no error
 SELECT * FROM t1 WHERE pk1=10;
 
+# transaction has rolled back, no error
 rollback;
 
 select * from t1 where pk1=1;
@@ -525,13 +528,13 @@ INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 
---error 1296
+# transaction has rolled back, no error
 SELECT * FROM t1 WHERE pk1=10;
 
---error 1296
+# transaction has rolled back, no error
 SELECT * FROM t1 WHERE pk1=10;
 
---error 1296
+# transaction has rolled back, no error
 commit;
 
 select * from t1 where pk1=1;
@@ -551,9 +554,10 @@ INSERT INTO t1 VALUES 
 (1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),
 (6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10);
 
---error 1296
+# transaction has rolled back, no error
 INSERT INTO t1 values (4000, 40, 44);
 
+# transaction has rolled back, no error
 rollback;
 
 select * from t1 where pk1=1;

=== modified file 'mysql-test/suite/ndb/t/ndb_single_user.test'
--- a/mysql-test/suite/ndb/t/ndb_single_user.test	2007-07-14 17:35:43 +0000
+++ b/mysql-test/suite/ndb/t/ndb_single_user.test	2008-10-15 12:24:10 +0000
@@ -150,8 +150,7 @@ COMMIT;
 --connection server2
 --error 1296
 update t1 set b=b+100 where a=4;
---error 1296
-COMMIT;
+ROLLBACK;
 
 # Bug #25275 SINGLE USER MODE prevents ALTER on non-ndb
 # tables for other mysqld nodes

=== modified file 'mysql-test/suite/ndb_team/r/ndb_autodiscover3.result'
--- a/mysql-test/suite/ndb_team/r/ndb_autodiscover3.result	2007-09-05 17:13:36 +0000
+++ b/mysql-test/suite/ndb_team/r/ndb_autodiscover3.result	2008-10-15 12:24:10 +0000
@@ -4,8 +4,7 @@ begin;
 insert into t1 values (1);
 insert into t1 values (2);
 ERROR HY000: Got temporary error 4025 'Node failure caused abort of transaction' from NDBCLUSTER
-commit;
-ERROR HY000: Got error 4350 'Transaction already aborted' from NDBCLUSTER
+rollback;
 drop table t1;
 create table t2 (a int, b int, primary key(a,b)) engine=ndbcluster;
 insert into t2 values (1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1);

=== modified file 'mysql-test/suite/ndb_team/t/ndb_autodiscover3.test'
--- a/mysql-test/suite/ndb_team/t/ndb_autodiscover3.test	2008-03-14 08:04:34 +0000
+++ b/mysql-test/suite/ndb_team/t/ndb_autodiscover3.test	2008-10-15 12:24:10 +0000
@@ -39,8 +39,7 @@ insert into t1 values (1);
 --connection server1
 --error 1297
 insert into t1 values (2);
---error 1296
-commit;
+rollback;
 
 drop table t1;
 

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2008-10-14 14:06:02 +0000
+++ b/sql/ha_ndbcluster.cc	2008-10-17 07:45:33 +0000
@@ -4476,6 +4476,7 @@ int ha_ndbcluster::start_statement(THD *
   trans_register_ha(thd, FALSE, ndbcluster_hton);
   if (!thd_ndb->trans)
   {
+    DBUG_ASSERT(thd_ndb->changed_tables.is_empty() == TRUE);
     if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
       trans_register_ha(thd, TRUE, ndbcluster_hton);
     DBUG_PRINT("trans",("Starting transaction"));      
@@ -4635,9 +4636,11 @@ int ha_ndbcluster::external_lock(THD *th
     {
       DBUG_PRINT("info", ("Rows has changed"));
 
-      if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+      if (thd_ndb->trans &&
+          thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
       {
-        DBUG_PRINT("info", ("Add share to list of changed tables"));
+        DBUG_PRINT("info", ("Add share to list of changed tables, %p",
+                            m_share));
         /* NOTE push_back allocates memory using transactions mem_root! */
         thd_ndb->changed_tables.push_back(get_share(m_share),
                                           &thd->transaction.mem_root);
@@ -4828,6 +4831,8 @@ static int ndbcluster_commit(handlerton 
   List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
   while ((share= it++))
   {
+    DBUG_PRINT("info", ("Remove share to list of changed tables, %p",
+                        share));
     pthread_mutex_lock(&share->mutex);
     DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %lu",
                         share->table_name, (ulong) share->commit_count));
@@ -4854,16 +4859,36 @@ static int ndbcluster_rollback(handlerto
   NdbTransaction *trans= thd_ndb->trans;
 
   DBUG_ENTER("ndbcluster_rollback");
+  DBUG_PRINT("enter", ("all: %d", all));
+  PRINT_OPTION_FLAGS(thd);
   DBUG_ASSERT(ndb);
   thd_ndb->start_stmt_count= 0;
-  if (trans == NULL || (!all &&
-      thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+  if (trans == NULL)
   {
     /* Ignore end-of-statement until real rollback or commit is called */
+    DBUG_PRINT("info", ("trans == NULL"));
+    DBUG_RETURN(0);
+  }
+  if (!all && thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+  {
+    /*
+      Ignore end-of-statement until real rollback or commit is called
+      as ndb does not support rollback statement
+      - mark that rollback was unsuccessful, this will cause full rollback
+      of the transaction
+    */
     DBUG_PRINT("info", ("Rollback before start or end-of-statement only"));
+    mark_transaction_to_rollback(thd, 1);
+    /*
+      This warning is not useful in the slave sql thread.
+      The slave sql thread code will handle the full rollback.
+    */
+    if (!thd->slave_thread)
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_WARN_ENGINE_TRANSACTION_ROLLBACK,
+                          ER(ER_WARN_ENGINE_TRANSACTION_ROLLBACK), "NDB");
     DBUG_RETURN(0);
   }
-
   if (trans->execute(NdbTransaction::Rollback) != 0)
   {
     const NdbError err= trans->getNdbError();
@@ -4881,6 +4906,8 @@ static int ndbcluster_rollback(handlerto
   List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
   while ((share= it++))
   {
+    DBUG_PRINT("info", ("Remove share to list of changed tables, %p",
+                        share));
     free_share(&share);
   }
   thd_ndb->changed_tables.empty();
@@ -8768,7 +8795,8 @@ int ha_ndbcluster::update_stats(THD *thd
       DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
     }
     if (int err= ndb_get_table_statistics(thd, this, TRUE, ndb,
-                                          m_ndb_statistics_record, &stat))
+                                          m_ndb_statistics_record, &stat,
+                                          have_lock))
     {
       DBUG_RETURN(err);
     }

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2008-08-06 14:20:41 +0000
+++ b/sql/share/errmsg.txt	2008-10-15 12:24:10 +0000
@@ -6133,3 +6133,6 @@ ER_NEED_REPREPARE
 
 ER_DELAYED_NOT_SUPPORTED  
   eng "DELAYED option not supported for table '%-.192s'"
+
+ER_WARN_ENGINE_TRANSACTION_ROLLBACK
+  eng "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted"

=== modified file 'storage/ndb/ndbapi-examples/mgmapi_logevent/Makefile'
--- a/storage/ndb/ndbapi-examples/mgmapi_logevent/Makefile	2007-05-29 21:39:57 +0000
+++ b/storage/ndb/ndbapi-examples/mgmapi_logevent/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-	  -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/mgmapi  -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/mgmapi_logevent2/Makefile'
--- a/storage/ndb/ndbapi-examples/mgmapi_logevent2/Makefile	2007-05-30 18:29:14 +0000
+++ b/storage/ndb/ndbapi-examples/mgmapi_logevent2/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-	  -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/mgmapi  -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_async/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_async/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_async/Makefile	2008-10-22 10:38:54 +0000
@@ -9,16 +9,14 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
-	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
+	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
 
 clean:
 	rm -f *.o $(TARGET)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_async1/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_async1/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_async1/Makefile	2008-10-22 10:38:54 +0000
@@ -8,13 +8,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
 	$(CXX) $(CFLAGS) -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_blob/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_blob/Makefile	2007-03-26 08:40:57 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_blob/Makefile	2008-10-22 10:38:54 +0000
@@ -9,16 +9,14 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
-	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
+	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
 
 clean:
 	rm -f *.o $(TARGET)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/Makefile	2007-07-04 06:55:19 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_blob_ndbrecord/Makefile	2008-10-22 10:38:54 +0000
@@ -9,16 +9,14 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
-	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
+	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
 
 clean:
 	rm -f *.o $(TARGET)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_event/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_event/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_event/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS) Makefile
 	$(CXX) $(CFLAGS) $(DEBUG) -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi -I$(TOP_SRCDIR)/include $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/Makefile	2008-04-01 15:37:28 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_retries/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_retries/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_retries/Makefile	2008-10-22 10:38:54 +0000
@@ -8,13 +8,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
 	$(CXX) $(CFLAGS)  -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/Makefile	2007-07-04 06:55:19 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_s_i_ndbrecord/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_scan/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_scan/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_scan/Makefile	2008-10-22 10:38:54 +0000
@@ -9,16 +9,14 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
-	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/extra -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
+	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)
 
 clean:
 	rm -f *.o $(TARGET)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_simple/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_simple/Makefile	2006-09-01 13:14:50 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings  -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(TARGET).o: $(SRCS)
 	$(CXX) $(CFLAGS) -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_simple_dual/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_simple_dual/Makefile	2007-05-29 21:39:57 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_dual/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)/storage/ndb/include
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings  -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(TOP_SRCDIR)/include -I$(INCLUDE_DIR) -I$(INCLUDE_DIR)/ndbapi $(SRCS)

=== modified file 'storage/ndb/ndbapi-examples/ndbapi_simple_index/Makefile'
--- a/storage/ndb/ndbapi-examples/ndbapi_simple_index/Makefile	2007-05-29 21:39:57 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_simple_index/Makefile	2008-10-22 10:38:54 +0000
@@ -9,13 +9,11 @@ LFLAGS = -Wall
 TOP_SRCDIR = ../../../..
 INCLUDE_DIR = $(TOP_SRCDIR)
 LIB_DIR = -L$(TOP_SRCDIR)/storage/ndb/src/.libs \
-          -L$(TOP_SRCDIR)/libmysql_r/.libs \
-          -L$(TOP_SRCDIR)/zlib/.libs \
-          -L$(TOP_SRCDIR)/mysys -L$(TOP_SRCDIR)/strings
+          -L$(TOP_SRCDIR)/libmysql_r/.libs
 SYS_LIB = 
 
 $(TARGET): $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r -lmysys -lmystrings -lz $(SYS_LIB) -o $(TARGET)
+	$(CXX) $(CXXFLAGS) $(LFLAGS) $(LIB_DIR) $(OBJS) -lndbclient -lmysqlclient_r $(SYS_LIB) -o $(TARGET)
 
 $(OBJS): $(SRCS)
 	$(CXX) $(CFLAGS) -I$(INCLUDE_DIR)/include -I$(INCLUDE_DIR)/storage/ndb/include -I$(INCLUDE_DIR)/storage/ndb/include/ndbapi $(SRCS)

=== modified file 'storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp	2008-05-29 15:58:58 +0000
+++ b/storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp	2008-10-21 22:53:32 +0000
@@ -2329,7 +2329,9 @@ void Dbacc::execACC_COMMITREQ(Signal* si
   ndbassert(operationRecPtr.i == tmp);
   ndbassert(operationRecPtr.p == ptr);
   operationRecPtr.p->m_op_bits = Operationrec::OP_INITIAL;
-  if(Toperation != ZREAD){
+  if((Toperation != ZREAD) &&
+     (Toperation != ZSCAN_OP))
+  {
     fragrecptr.p->m_commit_count++;
     if (Toperation != ZINSERT) {
       if (Toperation != ZDELETE) {

=== modified file 'storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp'
--- a/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp	2007-08-27 18:58:49 +0000
+++ b/storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp	2008-10-21 12:52:50 +0000
@@ -270,7 +270,10 @@ AsyncFile::check_odirect_write(Uint32 fl
   }
   
   close(theFd);
-  theFd = ::open(theFileName.c_str(), new_flags, mode);
+  /**
+   * We need to (O_TRUNC) truncate the file since we've written a page to it...
+   */
+  theFd = ::open(theFileName.c_str(), new_flags | O_TRUNC, mode);
   if (theFd == -1)
     return errno;
 #endif
@@ -417,8 +420,8 @@ void AsyncFile::openReq(Request* request
     new_flags |= O_APPEND;
   }
 
-  if (flags & FsOpenReq::OM_DIRECT) 
 #ifdef O_DIRECT
+  if (flags & FsOpenReq::OM_DIRECT) 
   {
     new_flags |= O_DIRECT;
   }
@@ -468,6 +471,7 @@ void AsyncFile::openReq(Request* request
       return;
     }
     new_flags |= O_CREAT;
+    flags |= FsOpenReq::OM_CREATE;
   }
 
 no_odirect:
@@ -611,8 +615,15 @@ no_odirect:
     
     if (request->error)
       return;
+#elif defined HAVE_DIRECTIO && defined(DIRECTIO_ON)
+    if (directio(theFd, DIRECTIO_ON) == -1)
+    {
+      ndbout_c("%s Failed to set DIRECTIO_ON errno: %u",
+               theFileName.c_str(), errno);
+    }
 #endif
   }
+
 #ifdef VM_TRACE
   if (flags & FsOpenReq::OM_DIRECT)
   {

=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c	2008-09-19 21:49:00 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c	2008-10-21 13:00:33 +0000
@@ -409,8 +409,10 @@ ErrorBundle ErrorCodes[] = {
   { 906,  DMEC, SE, "Unsupported attribute type in index" },
   { 907,  DMEC, SE, "Unsupported character set in table or index" },
   { 908,  DMEC, IS, "Invalid ordered index tree node size" },
+  { 1224, HA_WRONG_CREATE_OPTION, SE, "Too many fragments" },
   { 1225, DMEC, SE, "Table not defined in local query handler" },
   { 1226, DMEC, SE, "Table is being dropped" },
+  { 1227, HA_WRONG_CREATE_OPTION, SE, "Invalid schema version" },
   { 1228, DMEC, SE, "Cannot use drop table for drop index" },
   { 1229, DMEC, SE, "Too long frm data supplied" },
   { 1231, DMEC, SE, "Invalid table or index to scan" },

=== modified file 'storage/ndb/test/include/HugoAsynchTransactions.hpp'
--- a/storage/ndb/test/include/HugoAsynchTransactions.hpp	2006-12-23 19:20:40 +0000
+++ b/storage/ndb/test/include/HugoAsynchTransactions.hpp	2008-10-16 10:39:24 +0000
@@ -45,27 +45,60 @@ public:
 			 int batch = 1,
 			 int trans = 1,
 			 int operations = 1);
-  void transactionCompleted();
-
-  long getTransactionsCompleted();
 
 private:  
   enum NDB_OPERATION {NO_INSERT, NO_UPDATE, NO_READ, NO_DELETE};
 
-  void allocTransactions(int trans);
+  long transactionsCompleted;
+
+  struct TransactionInfo
+  {
+    HugoAsynchTransactions* hugoP;
+    NdbConnection* transaction;
+    int startRecordId;
+    int numRecords;
+    int resultRowStartIndex;
+    int retries;
+    NDB_OPERATION opType;
+  };
+
+  TransactionInfo* transInfo;
+  Ndb* theNdb;
+
+  /* Work description */
+  int totalLoops;
+  int recordsPerLoop;
+  int maxOpsPerTrans;
+  NDB_OPERATION operationType;
+  ExecType execType;
+
+  /* Progress description */
+  int nextUnProcessedRecord;
+  int loopNum;
+  int totalCompletedRecords;
+  int maxUsedRetries;
+  bool finished;
+  int testResult;
+
+  void allocTransactions(int trans, int maxOpsPerTrans);
   void deallocTransactions();
 
-  int executeAsynchOperation(Ndb*,		      
-			     int records,
-			     int batch,
-			     int trans,
-			     int operations,
-			     NDB_OPERATION theOperation,
-			     ExecType theType = Commit);
+  int getNextWorkTask(int* startRecordId, int* numRecords);
 
-  long transactionsCompleted;
-  int numTransactions;
-  NdbConnection** transactions;
+  int defineUpdateOpsForTask(TransactionInfo* tInfo);
+  int defineTransactionForTask(TransactionInfo* tInfo, ExecType taskExecType);
+
+  int beginNewTask(TransactionInfo* tInfo);
+  static void callbackFunc(int result, NdbConnection* trans, void* anObject);
+  void callback(int result, NdbConnection* trans, TransactionInfo* tInfo);
+
+  int executeAsynchOperation(Ndb*,		      
+                             int records,
+                             int batch,
+                             int trans,
+                             int operations,
+                             NDB_OPERATION theOperation,
+                             ExecType theType = Commit);
 };
 
 

=== modified file 'storage/ndb/test/ndbapi/flexAsynch.cpp'
--- a/storage/ndb/test/ndbapi/flexAsynch.cpp	2008-10-01 09:24:07 +0000
+++ b/storage/ndb/test/ndbapi/flexAsynch.cpp	2008-10-16 10:24:36 +0000
@@ -29,6 +29,7 @@
 #include <NDBT_Error.hpp>
 
 #include <NdbTest.hpp>
+#include <NDBT_Stats.hpp>
 
 #define MAX_PARTS 4 
 #define MAX_SEEK 16 
@@ -125,10 +126,24 @@ static int                              
 #define STOP_TIMER timer.doStop();
 #define PRINT_TIMER(text, trans, opertrans) timer.printTransactionStatistics(text, trans, opertrans); }; 
 
+NDBT_Stats a_i, a_u, a_d, a_r;
+
+static
+void
+print(const char * name, NDBT_Stats& s)
+{
+  printf("%s average: %u/s min: %u/s max: %u/s stddev: %u%%\n",
+         name,
+         (unsigned)s.getMean(),
+         (unsigned)s.getMin(),
+         (unsigned)s.getMax(),
+         (unsigned)(100*s.getStddev() / s.getMean()));
+}
+
 static void 
 resetThreads(){
 
-  for (int i = 0; i < tNoOfThreads ; i++) {
+  for (unsigned i = 0; i < tNoOfThreads ; i++) {
     ThreadReady[i] = 0;
     ThreadStart[i] = stIdle;
   }//for
@@ -141,7 +156,7 @@ waitForThreads(void)
   do {
     cont = 0;
     NdbSleep_MilliSleep(20);
-    for (int i = 0; i < tNoOfThreads ; i++) {
+    for (unsigned i = 0; i < tNoOfThreads ; i++) {
       if (ThreadReady[i] == 0) {
         cont = 1;
       }//if
@@ -152,7 +167,7 @@ waitForThreads(void)
 static void 
 tellThreads(StartType what)
 {
-  for (int i = 0; i < tNoOfThreads ; i++) 
+  for (unsigned i = 0; i < tNoOfThreads ; i++) 
     ThreadStart[i] = what;
 }
 
@@ -162,8 +177,9 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
 {
   ndb_init();
   ThreadNdb*            pThreadData;
-  int                   tLoops=0, i;
+  int                   tLoops=0;
   int                   returnValue = NDBT_OK;
+  unsigned i;
 
   flexAsynchErrorData = new ErrorData;
   flexAsynchErrorData->resetErrorCounters();
@@ -287,6 +303,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
       START_TIMER;
       execute(stInsert);
       STOP_TIMER;
+      a_i.addObservation((1000*noOfTransacts * tNoOfOpsPerTrans) / timer.elapsedTime());
       PRINT_TIMER("insert", noOfTransacts, tNoOfOpsPerTrans);
 
       if (0 < failed) {
@@ -324,6 +341,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
       START_TIMER;
       execute(stRead);
       STOP_TIMER;
+      a_r.addObservation((1000 * noOfTransacts * tNoOfOpsPerTrans) / timer.elapsedTime());
       PRINT_TIMER("read", noOfTransacts, tNoOfOpsPerTrans);
 
       if (0 < failed) {
@@ -361,6 +379,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
       START_TIMER;
       execute(stUpdate);
       STOP_TIMER;
+      a_u.addObservation((1000 * noOfTransacts * tNoOfOpsPerTrans) / timer.elapsedTime());
       PRINT_TIMER("update", noOfTransacts, tNoOfOpsPerTrans) ;
 
       if (0 < failed) {
@@ -397,6 +416,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
       START_TIMER;
       execute(stRead);
       STOP_TIMER;
+      a_r.addObservation((1000 * noOfTransacts * tNoOfOpsPerTrans) / timer.elapsedTime());
       PRINT_TIMER("read", noOfTransacts, tNoOfOpsPerTrans);
 
       if (0 < failed) {
@@ -434,6 +454,7 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
       START_TIMER;
       execute(stDelete);
       STOP_TIMER;
+      a_d.addObservation((1000 * noOfTransacts * tNoOfOpsPerTrans) / timer.elapsedTime());
       PRINT_TIMER("delete", noOfTransacts, tNoOfOpsPerTrans);
 
       if (0 < failed) {
@@ -483,6 +504,11 @@ NDB_COMMAND(flexAsynch, "flexAsynch", "f
   //printing errorCounters
   flexAsynchErrorData->printErrorCounters(ndbout);
 
+  print("insert", a_i);
+  print("update", a_u);
+  print("delete", a_d);
+  print("read  ", a_r);
+
   return NDBT_ProgramExit(returnValue);
 }//main()
 
@@ -534,7 +560,7 @@ static 
 bool
 executeThread(ThreadNdb* pThread, 
 	      StartType aType, Ndb* aNdbObject, unsigned int threadBase) {
-  int i, j, k;
+  unsigned i, j, k;
   NdbConnection* tConArray[1024];
   unsigned int tBase;
   unsigned int tBase2;
@@ -593,7 +619,7 @@ executeThread(ThreadNdb* pThread, 
       // to execute all of them.
       //-------------------------------------------------------
       int Tcomp = aNdbObject->sendPollNdb(3000, 0, 0);
-      while (Tcomp < tNoOfParallelTrans) {
+      while (unsigned(Tcomp) < tNoOfParallelTrans) {
         int TlocalComp = aNdbObject->pollNdb(3000, 0);
         Tcomp += TlocalComp;
       }//while
@@ -617,7 +643,7 @@ getKey(Uint32 aBase, Uint32 anIndex) {
     Tkey32[1] = (Uint32)i;
     hash = md5_hash((Uint64*)&Tkey64, (Uint32)2);
     hash = (hash >> 6) & (MAX_PARTS - 1);
-    if (hash == tLocalPart) {
+    if (hash == unsigned(tLocalPart)) {
       Tfound = i;
       break;
     }//if
@@ -668,7 +694,7 @@ defineOperation(NdbConnection* localNdbC
   //-------------------------------------------------------
   attrValue[0] = threadBase;
   attrValue[1] = aIndex;
-  for (int k = 2; k < loopCountAttributes; k++) {
+  for (unsigned k = 2; k < loopCountAttributes; k++) {
     attrValue[k] = aIndex;
   }//for
   localNdbOperation = localNdbConnection->getNdbOperation(tableName[0]);        
@@ -764,7 +790,7 @@ defineNdbRecordOperation(ThreadNdb* pThr
   //-------------------------------------------------------
   if (aType != stRead && aType != stDelete)
   {
-    for (int k = 1; k < tNoOfAttributes; k++) {
+    for (unsigned k = 1; k < tNoOfAttributes; k++) {
       NdbDictionary::getOffset(g_record[0], k, offset);
       * (Uint32*)(record + offset) = aIndex;    
     }//for
@@ -884,7 +910,7 @@ createTables(Ndb* pMyNdb){
       if (check == -1 &&
           (!error_handler(MySchemaTransaction->getNdbError())))
         return -1;
-      for (int j = 1; j < tNoOfAttributes ; j++){
+      for (unsigned j = 1; j < tNoOfAttributes ; j++){
         check = MySchemaOp->createAttribute( (char*)attrName[j],
                                              NoKey,
                                              32,
@@ -910,7 +936,7 @@ createTables(Ndb* pMyNdb){
 	
 	int off = 0;
 	Vector<NdbDictionary::RecordSpecification> spec;
-	for (Uint32 j = 0; j<pTab->getNoOfColumns(); j++)
+	for (Uint32 j = 0; j<unsigned(pTab->getNoOfColumns()); j++)
 	{
 	  NdbDictionary::RecordSpecification r0;
 	  r0.column = pTab->getColumn(j);
@@ -939,17 +965,8 @@ bool error_handler(const NdbError & err)
   case NdbError::SchemaError:
     ndbout << endl << "Attempting to recover and continue now..." << endl ;
     return true;
-  }
-  return false ; // return false to abort
-}
-static
-bool error_handler(const char* error_string, int error_int) {
-  ndbout << error_string << endl ;
-  if ((4008 == error_int) ||
-      (721 == error_int) ||
-      (266 == error_int)){
-    ndbout << endl << "Attempting to recover and continue now..." << endl ;
-    return true ; // return true to retry
+  default:
+    break;
   }
   return false ; // return false to abort
 }
@@ -1088,7 +1105,7 @@ input_error(){
   
   ndbout_c("FLEXASYNCH");
   ndbout_c("   Perform benchmark of insert, update and delete transactions");
-  ndbout_c("");
+  ndbout_c(" ");
   ndbout_c("Arguments:");
   ndbout_c("   -t Number of threads to start, default 1");
   ndbout_c("   -p Number of parallel transactions per thread, default 32");

=== modified file 'storage/ndb/test/src/HugoAsynchTransactions.cpp'
--- a/storage/ndb/test/src/HugoAsynchTransactions.cpp	2007-04-12 09:43:56 +0000
+++ b/storage/ndb/test/src/HugoAsynchTransactions.cpp	2008-10-16 10:39:24 +0000
@@ -15,12 +15,24 @@
 
 #include <NdbSleep.h>
 #include <HugoAsynchTransactions.hpp>
+#include <random.h>
+
 
 HugoAsynchTransactions::HugoAsynchTransactions(const NdbDictionary::Table& _t)
   : HugoTransactions(_t),
     transactionsCompleted(0),
-    numTransactions(0),
-    transactions(NULL)
+    transInfo(NULL),
+    theNdb(NULL),
+    totalLoops(0),
+    recordsPerLoop(0),
+    operationType(NO_READ),
+    execType(Commit),
+    nextUnProcessedRecord(0),
+    loopNum(0),
+    totalCompletedRecords(0),
+    maxUsedRetries(0),
+    finished(false),
+    testResult(NDBT_OK)
 {
 }
 
@@ -28,58 +40,6 @@ HugoAsynchTransactions::~HugoAsynchTrans
   deallocTransactions();
 }
 
-void asynchCallback(int result, NdbConnection* pTrans, 
-		    void* anObject) {
-  HugoAsynchTransactions* pHugo = (HugoAsynchTransactions*) anObject;
-  
-  pHugo->transactionCompleted();
-
-  if (result == -1) {
-    const NdbError err = pTrans->getNdbError();
-    switch(err.status) {
-    case NdbError::Success:
-      ERR(err);
-      g_info << "ERROR: NdbError reports success when transcaction failed"
-	     << endl;
-      break;
-      
-    case NdbError::TemporaryError:      
-      ERR(err);
-      break;
-
-#if 0      
-    case 626: // Tuple did not exist
-      g_info << (unsigned int)pHugo->getTransactionsCompleted() << ": " 
-	     << err.code << " " << err.message << endl;
-      break;
-#endif
- 
-    case NdbError::UnknownResult:
-      ERR(err);
-      break;
-      
-    case NdbError::PermanentError:
-      switch (err.classification) {
-      case NdbError::ConstraintViolation:
-	// Tuple already existed, OK in this application, 
-	// but should be reported
-	g_info << (unsigned int)pHugo->getTransactionsCompleted() 
-	       << ": " << err.code << " " << err.message << endl;
-	break;
-      default:
-	ERR(err);
-	break;
-      }
-      break;
-    }
-  } else {// if (result == -1)
-    /*
-    ndbout << (unsigned int)pHugo->getTransactionsCompleted() << " completed" 
-	   << endl;
-    */
-  }
-}
-
 int
 HugoAsynchTransactions::loadTableAsynch(Ndb* pNdb, 
 				  int records,
@@ -88,23 +48,13 @@ HugoAsynchTransactions::loadTableAsynch(
 				  int operations){
 
   int result = executeAsynchOperation(pNdb, records, batch, trans, operations, 
-				      NO_INSERT);
+                                       NO_INSERT);
   g_info << (unsigned int)transactionsCompleted * operations 
 	 << "|- inserted..." << endl;
 
   return result;
 } 
 
-void
-HugoAsynchTransactions::transactionCompleted() {
-  transactionsCompleted++;
-}
-
-long
-HugoAsynchTransactions::getTransactionsCompleted() {
-  return transactionsCompleted;
-}
-
 int 
 HugoAsynchTransactions::pkDelRecordsAsynch(Ndb* pNdb, 
 				     int records,
@@ -115,8 +65,8 @@ HugoAsynchTransactions::pkDelRecordsAsyn
   g_info << "|- Deleting records asynchronous..." << endl;
 
   int result =  executeAsynchOperation(pNdb, records, batch, trans, 
-				       operations, 
-				       NO_DELETE);
+                                        operations, 
+                                        NO_DELETE);
   g_info << "|- " << (unsigned int)transactionsCompleted * operations 
 	 << " deleted..." << endl;
 
@@ -134,7 +84,7 @@ HugoAsynchTransactions::pkReadRecordsAsy
 
   allocRows(trans*operations);
   int result = executeAsynchOperation(pNdb, records, batch, trans, operations, 
-				      NO_READ);
+                                       NO_READ);
 
   g_info << "|- " << (unsigned int)transactionsCompleted * operations 
 	 << " read..."
@@ -154,332 +104,495 @@ HugoAsynchTransactions::pkUpdateRecordsA
 
   g_info << "|- Updating records asynchronous..." << endl;
 
-  int             check = 0;
-  int             cTrans = 0;
-  int             cReadRecords = 0;
-  int             cReadIndex = 0;
-  int             cRecords = 0;
-  int             cIndex = 0;
-
-  transactionsCompleted = 0;
-
   allocRows(trans*operations);
-  allocTransactions(trans);
-  int a, t, r;
-
-  for (int i = 0; i < batch; i++) { // For each batch
-    while (cRecords < records*batch) {
-      cTrans = 0;
-      cReadIndex = 0;
-      for (t = 0; t < trans; t++) { // For each transaction
-	transactions[t] = pNdb->startTransaction();
-	if (transactions[t] == NULL) {
-	  ERR(pNdb->getNdbError());
-	  return NDBT_FAILED;
-	}	
-	for (int k = 0; k < operations; k++) { // For each operation
-	  NdbOperation* pOp = transactions[t]->getNdbOperation(tab.getName());
-	  if (pOp == NULL) { 
-	    ERR(transactions[t]->getNdbError());
-	    pNdb->closeTransaction(transactions[t]);
-	    return NDBT_FAILED;
-	  }
-	  
-	  // Read
-	  // Define primary keys
-	  check = pOp->readTupleExclusive();
-          if (equalForRow(pOp, cReadRecords) != 0)
-          {
-            ERR(transactions[t]->getNdbError());
-            pNdb->closeTransaction(transactions[t]);
-            return NDBT_FAILED;
-	  }	    
-	  // Define attributes to read  
-	  for (a = 0; a < tab.getNoOfColumns(); a++) {
-	    if ((rows[cReadIndex]->attributeStore(a) = 
-		 pOp->getValue(tab.getColumn(a)->getName())) == 0) {
-	      ERR(transactions[t]->getNdbError());
-	      pNdb->closeTransaction(transactions[t]);
-	      return NDBT_FAILED;
-	    }
-	  }	    	  
-	  cReadIndex++;
-	  cReadRecords++;
-	  
-	} // For each operation
-	
-	// Let's prepare...
-	transactions[t]->executeAsynchPrepare(NoCommit, &asynchCallback, 
-					this);
-	cTrans++;
-
-	if (cReadRecords >= records) {
-	  // No more transactions needed
-	  break;
-	}      
-      } // For each transaction
-
-      // Wait for all outstanding transactions
-      pNdb->sendPollNdb(3000, 0, 0);
-
-      // Verify the data!
-      for (r = 0; r < trans*operations; r++) {
-	if (calc.verifyRowValues(rows[r]) != 0) {
-	  g_info << "|- Verify failed..." << endl;
-	  // Close all transactions
-	  for (int t = 0; t < cTrans; t++) {
-	    pNdb->closeTransaction(transactions[t]);
-	  }
-	  return NDBT_FAILED;
-	}
-      }	
-
-      // Update
-      cTrans = 0;
-      cIndex = 0;
-      for (t = 0; t < trans; t++) { // For each transaction
-	for (int k = 0; k < operations; k++) { // For each operation
-	  NdbOperation* pOp = transactions[t]->getNdbOperation(tab.getName());
-	  if (pOp == NULL) { 
-	    ERR(transactions[t]->getNdbError());
-	    pNdb->closeTransaction(transactions[t]);
-	    return NDBT_FAILED;
-	  }
-	  
-	  int updates = calc.getUpdatesValue(rows[cIndex]) + 1;
-
-	  check = pOp->updateTuple();
-	  if (check == -1) {
-	    ERR(transactions[t]->getNdbError());
-	    pNdb->closeTransaction(transactions[t]);
-	      return NDBT_FAILED;
-	  }
-
-	  // Set search condition for the record
-          if (equalForRow(pOp, cReadRecords) != 0)
-          {
-            ERR(transactions[t]->getNdbError());
-            pNdb->closeTransaction(transactions[t]);
-            return NDBT_FAILED;
-	  }	    
-
-	  // Update the record
-	  for (a = 0; a < tab.getNoOfColumns(); a++) {
-	    if (tab.getColumn(a)->getPrimaryKey() == false) {
-	      if (setValueForAttr(pOp, a, cRecords, updates) != 0) {
-		ERR(transactions[t]->getNdbError());
-		pNdb->closeTransaction(transactions[t]);
-		return NDBT_FAILED;
-	      }
-	    }
-	  }	  
-	  cIndex++;
-	  cRecords++;
-	  
-	} // For each operation
-	
-	// Let's prepare...
-	transactions[t]->executeAsynchPrepare(Commit, &asynchCallback, 
-					this);
-	cTrans++;
-
-	if (cRecords >= records) {
-	  // No more transactions needed
-	  break;
-	}      
-      } // For each transaction
-
-      // Wait for all outstanding transactions
-      pNdb->sendPollNdb(3000, 0, 0);
-
-      // Close all transactions
-      for (t = 0; t < cTrans; t++) {
-	pNdb->closeTransaction(transactions[t]);
-      }
+  int result = executeAsynchOperation(pNdb, records, batch, trans, operations,
+                                       NO_UPDATE);
+  
+  g_info << "|- " << (unsigned int)transactionsCompleted * operations 
+	 << " read..."
+	 << endl;
 
-    } // while (cRecords < records*batch)
+  deallocRows();
 
-  } // For each batch
+  return result;
+};
 
-  deallocTransactions();
-  deallocRows();
-  
-  g_info << "|- " << ((unsigned int)transactionsCompleted * operations)/2 
-	 << " updated..." << endl;
-  return NDBT_OK;
-}
 
 void 
-HugoAsynchTransactions::allocTransactions(int trans) {
-  if (transactions != NULL) {
+HugoAsynchTransactions::allocTransactions(int trans, int maxOpsPerTrans) {
+  if (transInfo != NULL) {
     deallocTransactions(); 
   }
-  numTransactions = trans;
-  transactions = new NdbConnection*[numTransactions];  
+  transInfo = new TransactionInfo[trans];
+  
+  /* Initialise transaction info array */
+  TransactionInfo init;
+  init.hugoP= this;
+  init.transaction= NULL;
+  init.startRecordId= 0;
+  init.numRecords= 0;
+  init.resultRowStartIndex= 0;
+  init.retries= 0;
+  init.opType= NO_READ;
+
+  for (int i=0; i < trans; i++)
+  {
+    transInfo[i]= init;
+    transInfo[i].resultRowStartIndex= (i * maxOpsPerTrans);
+  };
 }
 
 void 
 HugoAsynchTransactions::deallocTransactions() {
-  if (transactions != NULL){
-    delete[] transactions;
+  if (transInfo != NULL){
+    delete[] transInfo;
   }
-  transactions = NULL;
+  transInfo = NULL;
 }
 
-int 
-HugoAsynchTransactions::executeAsynchOperation(Ndb* pNdb,		      
-					 int records,
-					 int batch,
-					 int trans,
-					 int operations,
-					 NDB_OPERATION theOperation,
-					 ExecType theType) {
-
-  int             check = 0;
-  //  int             retryAttempt = 0;  // Not used at the moment
-  //  int             retryMax = 5;      // Not used at the moment
-  int             cTrans = 0;
-  int             cRecords = 0;
-  int             cIndex = 0;
-  int a,t,r;
-
-  transactionsCompleted = 0;
-  allocTransactions(trans);
-
-  for (int i = 0; i < batch; i++) { // For each batch
-    while (cRecords < records*batch) {
-      cTrans = 0;
-      cIndex = 0;
-      for (t = 0; t < trans; t++) { // For each transaction
-	transactions[t] = pNdb->startTransaction();
-	if (transactions[t] == NULL) {
-	  ERR(pNdb->getNdbError());
-	  return NDBT_FAILED;
-	}	
-	for (int k = 0; k < operations; k++) { // For each operation
-	  NdbOperation* pOp = transactions[t]->getNdbOperation(tab.getName());
-	  if (pOp == NULL) { 
-	    ERR(transactions[t]->getNdbError());
-	    pNdb->closeTransaction(transactions[t]);
-	    return NDBT_FAILED;
-	  }
-	  
-	  switch (theOperation) {
-	  case NO_INSERT: 
-	    // Insert
-	    check = pOp->insertTuple();
-	    if (check == -1) { 
-	      ERR(transactions[t]->getNdbError());
-	      pNdb->closeTransaction(transactions[t]);
-	      return NDBT_FAILED;
-	    }
-	    
-	    // Set a calculated value for each attribute in this table	 
-	    for (a = 0; a < tab.getNoOfColumns(); a++) {
-	      if (setValueForAttr(pOp, a, cRecords, 0 ) != 0) {	  
-		ERR(transactions[t]->getNdbError());
-		pNdb->closeTransaction(transactions[t]);	  
-		return NDBT_FAILED;
-	      }
-	    } // For each attribute
-	    break;
-	  case NO_UPDATE:
-	    // This is a special case and is handled in the calling client...
-	    break;
-	  break;
-	  case NO_READ:
-	    // Define primary keys
-	    check = pOp->readTuple();
-            if (equalForRow(pOp, cRecords) != 0)
-            {
-              ERR(transactions[t]->getNdbError());
-              pNdb->closeTransaction(transactions[t]);
-              return NDBT_FAILED;
-            }	    
-	    // Define attributes to read  
-	    for (a = 0; a < tab.getNoOfColumns(); a++) {
-	      if ((rows[cIndex]->attributeStore(a) = 
-		   pOp->getValue(tab.getColumn(a)->getName())) == 0) {
-		ERR(transactions[t]->getNdbError());
-		pNdb->closeTransaction(transactions[t]);
-		return NDBT_FAILED;
-	      }
-	    }	    	  
-	    break;
-	  case NO_DELETE:
-	    // Delete
-	    check = pOp->deleteTuple();
-	    if (check == -1) { 
-	      ERR(transactions[t]->getNdbError());
-	      pNdb->closeTransaction(transactions[t]);
-	      return NDBT_FAILED;
-	    }
-
-	    // Define primary keys
-            if (equalForRow(pOp, cRecords) != 0)
-            {
-              ERR(transactions[t]->getNdbError());
-              pNdb->closeTransaction(transactions[t]);
-              return NDBT_FAILED;
-            }    
-	    break;
-	  default:
-	    // Should not happen...
-	    pNdb->closeTransaction(transactions[t]);		
-	    return NDBT_FAILED;
-	  }
+int
+HugoAsynchTransactions::getNextWorkTask(int* startRecordId, int* numRecords)
+{
+  /* Get a start record id and # of records for the next work task
+   * We return a range of up to maxOpsPerTrans records
+   * If there are no unprocessed records remaining, we return -1
+   */
+  if (nextUnProcessedRecord == recordsPerLoop)
+  {
+    /* If we've completed all loops then stop.  Otherwise, loop around */
+    if ((loopNum + 1) == totalLoops)
+      return -1; // All work has been dispatched
+    else
+    {
+      loopNum++;
+      nextUnProcessedRecord= 0;
+    }
+  }
+
+  int availableRecords= recordsPerLoop- nextUnProcessedRecord;
+  int recordsInTask= (availableRecords < maxOpsPerTrans)?
+    availableRecords : maxOpsPerTrans;
+
+  *startRecordId= nextUnProcessedRecord;
+  *numRecords= recordsInTask;
+  
+  nextUnProcessedRecord+= recordsInTask;
+
+  return 0;
+}
+
+int
+HugoAsynchTransactions::defineUpdateOpsForTask(TransactionInfo* tInfo)
+{
+  int check= 0;
+  int a= 0;
+  
+  NdbTransaction* trans= tInfo->transaction;
+
+  if (trans == NULL) {
+    return -1;
+  }	
+
+  for (int recordId= tInfo->startRecordId; 
+       recordId < (tInfo->startRecordId + tInfo->numRecords); 
+       recordId++)
+  {
+    NdbOperation* pOp= trans->getNdbOperation(tab.getName());
+    if (pOp == NULL) { 
+      ERR(trans->getNdbError());
+      trans->close();
+      return -1;
+    }
+    
+    /* We assume that row values have already been read. */
+    int updateVal= calc.getUpdatesValue(rows[recordId]) + 1;
+    
+    check= pOp->updateTuple();
+    if (equalForRow(pOp, recordId) != 0)
+    {
+      ERR(trans->getNdbError());
+      trans->close();
+      return -1;
+    }
+    // Update the record
+    for (a = 0; a < tab.getNoOfColumns(); a++) {
+      if (tab.getColumn(a)->getPrimaryKey() == false) {
+        if (setValueForAttr(pOp, a, recordId, updateVal) != 0) {
+          ERR(trans->getNdbError());
+          trans->close();
+          return -1;
+        }
+      }
+    }
+  } // For recordId
 
-	  cIndex++;
-	  cRecords++;
+  return 0;
+}
 
-	} // For each operation
+int
+HugoAsynchTransactions::defineTransactionForTask(TransactionInfo* tInfo,
+                                                 ExecType taskExecType)
+{
+  int check= 0;
+  int a= 0;
+  NdbTransaction* trans= theNdb->startTransaction();
+  
+  if (trans == NULL) {
+    ERR(theNdb->getNdbError());
+    return -1;
+  }	
+
+  for (int recordId= tInfo->startRecordId; 
+       recordId < (tInfo->startRecordId + tInfo->numRecords); 
+       recordId++)
+  {
+    NdbOperation* pOp= trans->getNdbOperation(tab.getName());
+    if (pOp == NULL) { 
+      ERR(trans->getNdbError());
+      theNdb->closeTransaction(trans);
+      return -1;
+    }
     
-	// Let's prepare...
-	transactions[t]->executeAsynchPrepare(theType, &asynchCallback, 
-					this);
-	cTrans++;
-
-	if (cRecords >= records) {
-	  // No more transactions needed
-	  break;
-	}      
-      } // For each transaction
-
-      // Wait for all outstanding transactions
-      pNdb->sendPollNdb(3000, 0, 0);
-
-      // ugly... it's starts to resemble flexXXX ...:(
-      switch (theOperation) {
-      case NO_READ:
-	// Verify the data!
-	for (r = 0; r < trans*operations; r++) {
-	  if (calc.verifyRowValues(rows[r]) != 0) {
-	    g_info << "|- Verify failed..." << endl;
-	    // Close all transactions
-	    for (int t = 0; t < cTrans; t++) {
-	      pNdb->closeTransaction(transactions[t]);
-	    }
-	    return NDBT_FAILED;
-	  }
-	}	
-	break;
-      case NO_INSERT:
-      case NO_UPDATE:
-      case NO_DELETE:
-	break;
+    switch (tInfo->opType) {
+    case NO_INSERT: 
+      // Insert
+      check = pOp->insertTuple();
+      if (check == -1) { 
+        ERR(trans->getNdbError());
+        theNdb->closeTransaction(trans);
+        return -1;
       }
+      
+      // Set a calculated value for each attribute in this table	 
+      for (a = 0; a < tab.getNoOfColumns(); a++) {
+        if (setValueForAttr(pOp, a, recordId, 0 ) != 0) {	  
+          ERR(trans->getNdbError());
+          theNdb->closeTransaction(trans);	  
+          return -1;
+        }
+      } // For each attribute
+      break;
+    case NO_UPDATE:
+    {
+      g_err << "Attempt to define update transaction" << endl;
+      return -1;
+    }
+    case NO_READ:
+      // Define primary keys
+      check = pOp->readTuple();
+      if (equalForRow(pOp, recordId) != 0)
+      {
+        ERR(trans->getNdbError());
+        theNdb->closeTransaction(trans);
+        return -1;
+      }	    
+      // Define attributes to read  
+      for (a = 0; a < tab.getNoOfColumns(); a++) {
+        if ((rows[recordId]->attributeStore(a) = 
+             pOp->getValue(tab.getColumn(a)->getName())) == 0) {
+          ERR(trans->getNdbError());
+          theNdb->closeTransaction(trans);
+          return -1;
+        }
+      }	    	  
+      break;
+    case NO_DELETE:
+      // Delete
+      check = pOp->deleteTuple();
+      if (check == -1) { 
+        ERR(trans->getNdbError());
+        theNdb->closeTransaction(trans);
+        return -1;
+      }
+      
+      // Define primary keys
+      if (equalForRow(pOp, recordId) != 0)
+      {
+        ERR(trans->getNdbError());
+        theNdb->closeTransaction(trans);
+        return -1;
+      }    
+      break;
+    default:
+      // Should not happen...
+      theNdb->closeTransaction(trans);
+      return -1;
+    }
+  } // For recordId
+
+  tInfo->transaction= trans;
+
+  /* Now send it */
+  tInfo->transaction->executeAsynch(taskExecType,
+                                    &callbackFunc,
+                                    tInfo);
+
+  return 0;
+}
+
+int
+HugoAsynchTransactions::beginNewTask(TransactionInfo* tInfo)
+{
+  tInfo->transaction= NULL;
+  tInfo->startRecordId= 0;
+  tInfo->numRecords= 0;
+  tInfo->retries= 0;
+  
+  /* Adjust for update special case */
+  NDB_OPERATION realOpType= operationType;
+  ExecType realExecType= execType;
+  if (operationType == NO_UPDATE)
+  {
+    realOpType= NO_READ;
+    realExecType= NoCommit;
+  }
+  tInfo->opType= realOpType;
+
+  if (getNextWorkTask(&tInfo->startRecordId,
+                      &tInfo->numRecords) == 0)
+  {
+    /* Have a task to do */
+    if (defineTransactionForTask(tInfo, realExecType) != 0)
+    {
+      g_err << "Error defining new transaction" << endl;
+      return -1;
+    }
+
+    return 0;
+  }
+  else
+  {
+    /* No more work to do */
+    return 1;
+  }
+}
+
+void 
+HugoAsynchTransactions::callbackFunc(int result, 
+                                        NdbConnection* pTrans, 
+                                        void* anObject) {
+  /* Execute callback method on passed object */
+  HugoAsynchTransactions::TransactionInfo* tranInfo=
+    (HugoAsynchTransactions::TransactionInfo*) anObject;
+
+  tranInfo->hugoP->callback(result, pTrans, tranInfo);
+};
+
+
+void
+HugoAsynchTransactions::callback(int result, 
+                                 NdbConnection* pTrans,
+                                 TransactionInfo* tInfo)
+{
+  if (finished)
+    return; // No point continuing here
+
+  // Paranoia
+  if (pTrans != tInfo->transaction)
+  {
+    g_err << "Transactions not same in callback!" << endl;
+    finished= true;
+    testResult= NDBT_FAILED;
+    return;
+  }
 
-      // Close all transactions
-      for (t = 0; t < cTrans; t++) {
-	pNdb->closeTransaction(transactions[t]);
+  NdbError transErr= pTrans->getNdbError();
+
+  if (transErr.code == 0)
+  {
+    /* This transaction executed successfully, perform post-execution 
+     * steps
+     */
+    switch (tInfo->opType)
+    {
+    case NO_READ:
+      // Verify the data!
+      for (int recordId = tInfo->startRecordId; 
+           recordId < (tInfo->startRecordId + tInfo->numRecords); 
+           recordId++) 
+      {
+        if (calc.verifyRowValues(rows[recordId]) != 0) {
+          g_info << "|- Verify failed..." << endl;
+          // Close all transactions
+          finished= true;
+          testResult= NDBT_FAILED;
+          return;
+        }
+      }
+      
+      if (operationType == NO_UPDATE)
+      {
+        /* Read part of update completed, now define the update...*/
+        if (defineUpdateOpsForTask(tInfo) == 0)
+        {
+          tInfo->opType= NO_UPDATE;
+          tInfo->transaction->executeAsynch(Commit,
+                                            &callbackFunc,
+                                            tInfo);
+        }
+        else
+        {
+          g_err << "Error defining update operations in callback" << endl;
+          finished= true;
+          testResult= NDBT_FAILED;
+        }
+        
+        /* return to polling loop awaiting completion of updates...*/
+        return;
+      }
+      
+      break;
+    case NO_UPDATE:
+    case NO_INSERT:
+    case NO_DELETE:
+      break;
+    }
+    
+    /* Task completed successfully
+     * Now close the transaction, and start next task, if there is one 
+     */
+    pTrans->close();
+    transactionsCompleted ++;
+    totalCompletedRecords+= tInfo->numRecords;
+    
+    if (beginNewTask(tInfo) < 0)
+    {
+      finished= true;
+      testResult= NDBT_FAILED;
+    }
+  }
+  else
+  {
+    /* We have had some sort of issue with this transaction ... */
+    g_err << "Callback got error on task : " 
+          << tInfo->startRecordId << " to "
+          << tInfo->startRecordId + tInfo->numRecords << "  "
+          << transErr.code << ":" 
+          << transErr.message 
+          << ". Task type : " << tInfo->opType <<  endl;
+    
+    switch(transErr.status) {
+    case NdbError::TemporaryError:
+      
+      if (tInfo->retries < 10) // Support up to 10 retries
+      {
+        /* Retry original request */
+        tInfo->retries++;
+        tInfo->transaction->close();
+        
+        if (tInfo->retries > maxUsedRetries)
+          maxUsedRetries= tInfo->retries;
+        
+        /* Exponential backoff - note that this also delays callback
+         * handling for other outstanding transactions so in effect
+         * serialises processing
+         */
+        int multiplier= 1 << tInfo->retries;
+        int base= 200; // millis
+        int backoffMillis= multiplier*base + myRandom48(base);
+        
+        g_err << "  Error is temporary, retrying in "
+              << backoffMillis << " millis.  Retry number " 
+              << tInfo->retries << endl;
+        NdbSleep_MilliSleep(backoffMillis);
+        
+        /* If we failed somewhere in an update operation, redo from the start
+         * (including reads)
+         */
+        tInfo->opType= operationType;
+        ExecType taskExecType= execType;
+        if (operationType == NO_UPDATE)
+        {
+          tInfo->opType= NO_READ;
+          taskExecType= NoCommit;
+        }
+        
+        /* Define a new transction to perform the original task */
+        if (defineTransactionForTask(tInfo, taskExecType) != 0)
+        {
+          g_err << "Error defining retry transaction in callback" << endl;
+          finished= true;
+          testResult= NDBT_FAILED;
+        }
+        
+        break;
       }
 
-    } // while (cRecords < records*batch)
+      g_err << "Too many retries (" << tInfo->retries 
+            << ") failing." << endl;
+      // Fall through
+
+    default:
+      /* Non temporary error */
+      ERR(transErr);
+      g_err << "Status= " << transErr.status << " Failing test" << endl;
+      testResult= NDBT_FAILED;
+      finished= true;
+      break;
+    };
+  } // Successful execution
+} // callbackFunc
 
-  } // For each batch
+int 
+HugoAsynchTransactions::executeAsynchOperation(Ndb* pNdb,		      
+                                               int records,
+                                               int batch,
+                                               int trans,
+                                               int operations,
+                                               NDB_OPERATION theOperation,
+                                               ExecType theType) {
+  
+  /* We want to process 'records' records using at most 'trans' transactions,
+   * each with at most 'operations' operations.
+   * This is done 'batch' times.
+   * This procedure sets up the control state, and starts the first 'trans'
+   * transactions
+   * After that the execution completion callback code handles operation
+   * results, and initiating new transactions or retrying failed transactions
+   * as necessary.
+   * If there is a failure, the finished bool is set, which is detected in the
+   * polling loop below.
+   * If all of the requested records have been read, this is detected in the
+   * loop below
+   * Note that Update operations are a special case, comprising a read, executed
+   * with NoCommit, followed by an Update executed with Commit.
+   */
+
+  theNdb= pNdb;
+  totalLoops= batch;
+  loopNum= 0;
+  recordsPerLoop= records;
+  maxOpsPerTrans= operations;
+  operationType= theOperation;
+  execType= theType;
+  nextUnProcessedRecord= 0;
+  totalCompletedRecords= 0;
+  maxUsedRetries= 0;
+  finished= false;
+  testResult= NDBT_OK;
+
+  allocTransactions(trans, maxOpsPerTrans);
+
+  /* Start by defining all transactions */
+  int nextUndefinedTrans= 0;
+  while ((nextUndefinedTrans < trans) &&
+         (beginNewTask(&transInfo[nextUndefinedTrans++]) == 0))
+  { /* Empty */ };
+  
+  /* Poll for results, the transaction callback will handle results
+   * and initiate new operations as necessary, setting finished to
+   * true if there's a problem.
+   */
+  while (!finished)
+  {
+    pNdb->pollNdb(3000,0);
+    
+    if (totalCompletedRecords == (records * totalLoops))
+      finished = true;
+  };
 
   deallocTransactions();
+  theNdb= NULL;
 
-  return NDBT_OK;
-
+  return testResult;
 }

Thread
bzr push into mysql-5.1 branch (tomas.ulin:2695 to 2707) Bug#37491Tomas Ulin28 Oct