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#37491 | Tomas Ulin | 28 Oct |