summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/include/get_binlog_dump_thread_id.inc9
-rw-r--r--mysql-test/lib/mtr_process.pl5
-rwxr-xr-xmysql-test/mysql-test-run.pl25
-rw-r--r--mysql-test/mysql-test-run.sh12
-rw-r--r--mysql-test/r/func_time.result36
-rw-r--r--mysql-test/r/having.result33
-rw-r--r--mysql-test/r/innodb.result2
-rw-r--r--mysql-test/r/rpl_temporary.result14
-rw-r--r--mysql-test/r/type_bit.result9
-rw-r--r--mysql-test/r/type_bit_innodb.result9
-rw-r--r--mysql-test/r/view.result21
-rw-r--r--mysql-test/t/cast.test2
-rw-r--r--mysql-test/t/func_time.test18
-rw-r--r--mysql-test/t/having.test46
-rw-r--r--mysql-test/t/rpl_temporary.test27
-rw-r--r--mysql-test/t/type_bit.test12
-rw-r--r--mysql-test/t/type_bit_innodb.test12
-rw-r--r--mysql-test/t/view.test20
-rw-r--r--ndb/include/kernel/signaldata/CmRegSignalData.hpp29
-rw-r--r--ndb/include/kernel/signaldata/DumpStateOrd.hpp1
-rw-r--r--ndb/include/kernel/signaldata/FailRep.hpp16
-rw-r--r--ndb/include/kernel/signaldata/StopReq.hpp41
-rw-r--r--ndb/include/kernel/signaldata/WaitGCP.hpp7
-rw-r--r--ndb/include/mgmapi/ndb_logevent.h13
-rw-r--r--ndb/src/common/debugger/EventLogger.cpp85
-rw-r--r--ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp66
-rw-r--r--ndb/src/kernel/blocks/dbdih/DbdihInit.cpp1
-rw-r--r--ndb/src/kernel/blocks/dbdih/DbdihMain.cpp106
-rw-r--r--ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp11
-rw-r--r--ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp1
-rw-r--r--ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp372
-rw-r--r--ndb/src/kernel/blocks/qmgr/Qmgr.hpp54
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrInit.cpp10
-rw-r--r--ndb/src/kernel/blocks/qmgr/QmgrMain.cpp885
-rw-r--r--ndb/src/kernel/vm/Configuration.cpp45
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp232
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp213
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.hpp14
-rw-r--r--ndb/src/mgmsrv/Services.cpp48
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp7
-rw-r--r--ndb/src/ndbapi/NdbLinHash.hpp13
-rw-r--r--ndb/test/ndbapi/testNodeRestart.cpp214
-rw-r--r--ndb/test/run-test/daily-basic-tests.txt10
-rw-r--r--ndb/test/src/NdbRestarts.cpp3
-rw-r--r--sql/field.cc53
-rw-r--r--sql/field.h14
-rw-r--r--sql/ha_ndbcluster.cc2
-rw-r--r--sql/item.cc9
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_timefunc.cc2
-rw-r--r--sql/key.cc3
-rw-r--r--sql/log.cc6
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/sql_cache.cc5
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_cursor.cc3
-rw-r--r--sql/sql_repl.cc6
57 files changed, 2457 insertions, 465 deletions
diff --git a/mysql-test/include/get_binlog_dump_thread_id.inc b/mysql-test/include/get_binlog_dump_thread_id.inc
new file mode 100644
index 00000000000..830a88b5db6
--- /dev/null
+++ b/mysql-test/include/get_binlog_dump_thread_id.inc
@@ -0,0 +1,9 @@
+--exec $MYSQL test -e 'show processlist' | grep 'Binlog Dump' | cut -f1 > $MYSQLTEST_VARDIR/tmp/bl_dump_thread_id
+--disable_warnings
+drop table if exists t999;
+--enable_warnings
+create temporary table t999 (f int);
+--replace_result $MYSQLTEST_VARDIR "."
+eval LOAD DATA INFILE "$MYSQLTEST_VARDIR/tmp/bl_dump_thread_id" into table t999;
+let $id = `select f from t999`;
+drop table t999;
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index 86a4312e0c8..58652960e36 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -465,8 +465,7 @@ sub mtr_kill_leftovers () {
if ( kill(0, @pids) ) # Check if some left
{
- # FIXME maybe just mtr_warning() ?
- mtr_error("can't kill process(es) " . join(" ", @pids));
+ mtr_warning("can't kill process(es) " . join(" ", @pids));
}
}
}
@@ -479,7 +478,7 @@ sub mtr_kill_leftovers () {
{
if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
{
- mtr_error("can't kill old mysqld holding port $srv->{'port'}");
+ mtr_warning("can't kill old mysqld holding port $srv->{'port'}");
}
}
}
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index c57e6faba7b..a045441e046 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -312,6 +312,9 @@ our $opt_udiff;
our $opt_skip_ndbcluster;
our $opt_with_ndbcluster;
+our $opt_with_ndbcluster_only= 0; # dummy, ignored
+
+our $opt_with_openssl;
our $exe_ndb_mgm;
our $path_ndb_tools_dir;
@@ -572,6 +575,7 @@ sub command_line_setup () {
'force' => \$opt_force,
'with-ndbcluster' => \$opt_with_ndbcluster,
'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
+ 'with-ndbcluster-only' => \$opt_with_ndbcluster_only,
'do-test=s' => \$opt_do_test,
'suite=s' => \$opt_suite,
'skip-rpl' => \$opt_skip_rpl,
@@ -677,6 +681,11 @@ sub command_line_setup () {
print '#' x 78, "\n\n";
}
+ if ( $opt_with_ndbcluster_only )
+ {
+ print "# Option '--with-ndbcluster-only' is ignored in this release.\n";
+ }
+
foreach my $arg ( @ARGV )
{
if ( $arg =~ /^--skip-/ )
@@ -2933,11 +2942,6 @@ sub run_mysqltest ($) {
mtr_init_args(\$args);
- if ( $opt_valgrind_mysqltest )
- {
- valgrind_arguments($args, \$exe);
- }
-
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--silent");
mtr_add_arg($args, "-v");
@@ -3053,6 +3057,17 @@ sub run_mysqltest ($) {
# Add arguments that should not go into the MYSQL_TEST env var
# ----------------------------------------------------------------------
+ if ( $opt_valgrind_mysqltest )
+ {
+ # Prefix the Valgrind options to the argument list.
+ # We do this here, since we do not want to Valgrind the nested invocations
+ # of mysqltest; that would mess up the stderr output causing test failure.
+ my @args_saved = @$args;
+ mtr_init_args(\$args);
+ valgrind_arguments($args, \$exe);
+ mtr_add_arg($args, "%s", $_) for @args_saved;
+ }
+
mtr_add_arg($args, "--test-file");
mtr_add_arg($args, $tinfo->{'path'});
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 7c5a810bf73..d7e976f9d49 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -277,6 +277,7 @@ EXTRA_MYSQLSHOW_OPT=""
EXTRA_MYSQLBINLOG_OPT=""
USE_RUNNING_SERVER=0
USE_NDBCLUSTER=@USE_NDBCLUSTER@
+USE_NDBCLUSTER_ONLY=0
USE_RUNNING_NDBCLUSTER=""
USE_PURIFY=""
PURIFY_LOGS=""
@@ -315,6 +316,8 @@ STRESS_INIT_FILE=""
STRESS_TEST_FILE=""
STRESS_TEST=""
+$ECHO "Logging: $0 $*" # To ensure we see all arguments in the output, for the test analysis tool
+
while test $# -gt 0; do
case "$1" in
--embedded-server)
@@ -341,6 +344,10 @@ while test $# -gt 0; do
--extern) USE_RUNNING_SERVER=1 ;;
--with-ndbcluster)
USE_NDBCLUSTER="--ndbcluster" ;;
+ --with-ndbcluster-only)
+ USE_NDBCLUSTER="--ndbcluster"
+ USE_NDBCLUSTER_SLAVE="--ndbcluster"
+ USE_NDBCLUSTER_ONLY=1 ;;
--ndb-connectstring=*)
USE_NDBCLUSTER="--ndbcluster" ;
USE_RUNNING_NDBCLUSTER=`$ECHO "$1" | $SED -e "s;--ndb-connectstring=;;"` ;;
@@ -1654,6 +1661,11 @@ run_testcase ()
result_file="r/$tname.result"
echo $tname > $CURRENT_TEST
SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0 \& \( $tname : federated \) = 0`
+ NDBCLUSTER_TEST=`$EXPR \( $tname : '.*ndb.*' \) != 0`
+ if [ "x$USE_NDBCLUSTER_ONLY" = "x1" -a "x$NDBCLUSTER_TEST" != "x1" ] ; then
+ skip_test $tname
+ return
+ fi
if [ "$USE_MANAGER" = 1 ] ; then
many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)`
fi
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 64dafa132b4..5d40a0ed01f 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -360,6 +360,42 @@ extract(SECOND FROM "1999-01-02 10:11:12")
select extract(MONTH FROM "2001-02-00");
extract(MONTH FROM "2001-02-00")
2
+SELECT EXTRACT(QUARTER FROM '2004-01-15') AS quarter;
+quarter
+1
+SELECT EXTRACT(QUARTER FROM '2004-02-15') AS quarter;
+quarter
+1
+SELECT EXTRACT(QUARTER FROM '2004-03-15') AS quarter;
+quarter
+1
+SELECT EXTRACT(QUARTER FROM '2004-04-15') AS quarter;
+quarter
+2
+SELECT EXTRACT(QUARTER FROM '2004-05-15') AS quarter;
+quarter
+2
+SELECT EXTRACT(QUARTER FROM '2004-06-15') AS quarter;
+quarter
+2
+SELECT EXTRACT(QUARTER FROM '2004-07-15') AS quarter;
+quarter
+3
+SELECT EXTRACT(QUARTER FROM '2004-08-15') AS quarter;
+quarter
+3
+SELECT EXTRACT(QUARTER FROM '2004-09-15') AS quarter;
+quarter
+3
+SELECT EXTRACT(QUARTER FROM '2004-10-15') AS quarter;
+quarter
+4
+SELECT EXTRACT(QUARTER FROM '2004-11-15') AS quarter;
+quarter
+4
+SELECT EXTRACT(QUARTER FROM '2004-12-15') AS quarter;
+quarter
+4
SELECT "1900-01-01 00:00:00" + INTERVAL 2147483648 SECOND;
"1900-01-01 00:00:00" + INTERVAL 2147483648 SECOND
1968-01-20 03:14:08
diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result
index 225d5a475ff..fe918e4c3ff 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -359,3 +359,36 @@ group by s1 collate latin1_swedish_ci having s1 = 'y';
s1 count(s1)
y 1
drop table t1;
+DROP SCHEMA IF EXISTS HU;
+CREATE SCHEMA HU ;
+USE HU ;
+CREATE TABLE STAFF
+(EMPNUM CHAR(3) NOT NULL UNIQUE,
+EMPNAME CHAR(20),
+GRADE DECIMAL(4),
+CITY CHAR(15));
+CREATE TABLE PROJ
+(PNUM CHAR(3) NOT NULL UNIQUE,
+PNAME CHAR(20),
+PTYPE CHAR(6),
+BUDGET DECIMAL(9),
+CITY CHAR(15));
+INSERT INTO STAFF VALUES ('E1','Alice',12,'Deale');
+INSERT INTO STAFF VALUES ('E2','Betty',10,'Vienna');
+INSERT INTO STAFF VALUES ('E3','Carmen',13,'Vienna');
+INSERT INTO STAFF VALUES ('E4','Don',12,'Deale');
+INSERT INTO STAFF VALUES ('E5','Ed',13,'Akron');
+INSERT INTO PROJ VALUES ('P1','MXSS','Design',10000,'Deale');
+INSERT INTO PROJ VALUES ('P2','CALM','Code',30000,'Vienna');
+INSERT INTO PROJ VALUES ('P3','SDP','Test',30000,'Tampa');
+INSERT INTO PROJ VALUES ('P4','SDP','Design',20000,'Deale');
+INSERT INTO PROJ VALUES ('P5','IRM','Test',10000,'Vienna');
+INSERT INTO PROJ VALUES ('P6','PAYR','Design',50000,'Deale');
+SELECT EMPNUM, GRADE*1000
+FROM HU.STAFF WHERE GRADE * 1000 >
+ANY (SELECT SUM(BUDGET) FROM HU.PROJ
+GROUP BY CITY, PTYPE
+HAVING HU.PROJ.CITY = HU.STAFF.CITY);
+EMPNUM GRADE*1000
+E3 13000
+DROP SCHEMA HU;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index e8af68a6067..c5658d22eb6 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1821,7 +1821,7 @@ Variable_name Value
innodb_sync_spin_loops 20
show variables like "innodb_thread_concurrency";
Variable_name Value
-innodb_thread_concurrency 0
+innodb_thread_concurrency 8
set global innodb_thread_concurrency=1001;
show variables like "innodb_thread_concurrency";
Variable_name Value
diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result
index a76fb87a52b..12143561854 100644
--- a/mysql-test/r/rpl_temporary.result
+++ b/mysql-test/r/rpl_temporary.result
@@ -89,3 +89,17 @@ f
7
drop table t1,t2;
create temporary table t3 (f int);
+create temporary table t4 (f int);
+create table t5 (f int);
+drop table if exists t999;
+create temporary table t999 (f int);
+LOAD DATA INFILE "./tmp/bl_dump_thread_id" into table t999;
+drop table t999;
+insert into t4 values (1);
+kill `select id from information_schema.processlist where command='Binlog Dump'`;
+insert into t5 select * from t4;
+select * from t5 /* must be 1 after reconnection */;
+f
+1
+drop temporary table t4;
+drop table t5;
diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result
index c6f204e8452..2281ed44e3f 100644
--- a/mysql-test/r/type_bit.result
+++ b/mysql-test/r/type_bit.result
@@ -564,3 +564,12 @@ b1+0 sum(b1) sum(b2)
1 4 4
2 2 2
drop table t1, t2;
+create table t1 (a bit(7));
+insert into t1 values (0x60);
+select * from t1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t1 t1 a a 16 7 1 Y 0 0 63
+a
+`
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/r/type_bit_innodb.result b/mysql-test/r/type_bit_innodb.result
index 8d9c9756a33..1f6857277bd 100644
--- a/mysql-test/r/type_bit_innodb.result
+++ b/mysql-test/r/type_bit_innodb.result
@@ -402,3 +402,12 @@ t1 CREATE TABLE `t1` (
`b` bit(10) default NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1;
+create table t1 (a bit(7)) engine=innodb;
+insert into t1 values (0x60);
+select * from t1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t1 t1 a a 16 7 1 Y 0 0 63
+a
+`
+drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index f0fb35f1a2e..7519b8022f0 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -2579,3 +2579,24 @@ COUNT(*)
2
DROP VIEW v2;
DROP TABLE t1, t2;
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY,
+td date DEFAULT NULL, KEY idx(td));
+INSERT INTO t1 VALUES
+(1, '2005-01-01'), (2, '2005-01-02'), (3, '2005-01-02'),
+(4, '2005-01-03'), (5, '2005-01-04'), (6, '2005-01-05'),
+(7, '2005-01-05'), (8, '2005-01-05'), (9, '2005-01-06');
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM t1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04';
+id td
+2 2005-01-02
+3 2005-01-02
+4 2005-01-03
+5 2005-01-04
+SELECT * FROM v1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04';
+id td
+2 2005-01-02
+3 2005-01-02
+4 2005-01-03
+5 2005-01-04
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test
index 7e09f44397c..533da542855 100644
--- a/mysql-test/t/cast.test
+++ b/mysql-test/t/cast.test
@@ -171,6 +171,8 @@ select cast(1.0e+300 as signed int);
CREATE TABLE t1 (f1 double);
INSERT INTO t1 SET f1 = -1.0e+30 ;
INSERT INTO t1 SET f1 = +1.0e+30 ;
+# Expected result is +-1e+30, but Windows returns +-1e+030.
+--replace_result 1e+030 1e+30
SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1;
DROP TABLE t1;
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 3a2eea59bed..c98c1c94609 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -140,6 +140,24 @@ select extract(SECOND FROM "1999-01-02 10:11:12");
select extract(MONTH FROM "2001-02-00");
#
+# test EXTRACT QUARTER (Bug #18100)
+#
+
+SELECT EXTRACT(QUARTER FROM '2004-01-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-02-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-03-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-04-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-05-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-06-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-07-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-08-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-09-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-10-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-11-15') AS quarter;
+SELECT EXTRACT(QUARTER FROM '2004-12-15') AS quarter;
+
+
+#
# Test big intervals (Bug #3498)
#
SELECT "1900-01-01 00:00:00" + INTERVAL 2147483648 SECOND;
diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test
index 78628bef198..9b21e544657 100644
--- a/mysql-test/t/having.test
+++ b/mysql-test/t/having.test
@@ -347,3 +347,49 @@ group by s1 collate latin1_swedish_ci having s1 = 'y';
# MySQL returns: 1 row, with count(s1) = 1
drop table t1;
+
+
+#
+# Bug #15917: unexpected complain for a name in having clause
+# when the server is run on Windows or with --lower-case-table-names=1
+#
+
+--disable_warnings
+DROP SCHEMA IF EXISTS HU;
+--enable_warnings
+CREATE SCHEMA HU ;
+USE HU ;
+
+CREATE TABLE STAFF
+ (EMPNUM CHAR(3) NOT NULL UNIQUE,
+ EMPNAME CHAR(20),
+ GRADE DECIMAL(4),
+ CITY CHAR(15));
+
+CREATE TABLE PROJ
+ (PNUM CHAR(3) NOT NULL UNIQUE,
+ PNAME CHAR(20),
+ PTYPE CHAR(6),
+ BUDGET DECIMAL(9),
+ CITY CHAR(15));
+
+INSERT INTO STAFF VALUES ('E1','Alice',12,'Deale');
+INSERT INTO STAFF VALUES ('E2','Betty',10,'Vienna');
+INSERT INTO STAFF VALUES ('E3','Carmen',13,'Vienna');
+INSERT INTO STAFF VALUES ('E4','Don',12,'Deale');
+INSERT INTO STAFF VALUES ('E5','Ed',13,'Akron');
+
+INSERT INTO PROJ VALUES ('P1','MXSS','Design',10000,'Deale');
+INSERT INTO PROJ VALUES ('P2','CALM','Code',30000,'Vienna');
+INSERT INTO PROJ VALUES ('P3','SDP','Test',30000,'Tampa');
+INSERT INTO PROJ VALUES ('P4','SDP','Design',20000,'Deale');
+INSERT INTO PROJ VALUES ('P5','IRM','Test',10000,'Vienna');
+INSERT INTO PROJ VALUES ('P6','PAYR','Design',50000,'Deale');
+
+SELECT EMPNUM, GRADE*1000
+ FROM HU.STAFF WHERE GRADE * 1000 >
+ ANY (SELECT SUM(BUDGET) FROM HU.PROJ
+ GROUP BY CITY, PTYPE
+ HAVING HU.PROJ.CITY = HU.STAFF.CITY);
+
+DROP SCHEMA HU;
diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test
index fcb2391a9d8..2400eac76ba 100644
--- a/mysql-test/t/rpl_temporary.test
+++ b/mysql-test/t/rpl_temporary.test
@@ -129,6 +129,31 @@ drop table t1,t2;
create temporary table t3 (f int);
sync_with_master;
+#
+# Bug#17284 erroneous temp table cleanup on slave
+#
+
+connection master;
+create temporary table t4 (f int);
+create table t5 (f int);
+sync_with_master;
+# find dumper's $id
+source include/get_binlog_dump_thread_id.inc;
+insert into t4 values (1);
+# a hint how to do that in 5.1
+--replace_result $id "`select id from information_schema.processlist where command='Binlog Dump'`"
+eval kill $id; # to stimulate reconnection by slave w/o timeout
+insert into t5 select * from t4;
+save_master_pos;
+
+connection slave;
+sync_with_master;
+select * from t5 /* must be 1 after reconnection */;
+
+connection master;
+drop temporary table t4;
+drop table t5;
+
# The server will now close done
-# End of 4.1 tests
+# End of 5.0 tests
diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test
index 1f05a9574d6..e028dbc51d9 100644
--- a/mysql-test/t/type_bit.test
+++ b/mysql-test/t/type_bit.test
@@ -227,3 +227,15 @@ select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1;
select 1 from t1 join t2 on b1 = b2 group by b1 order by 1;
select b1+0,sum(b1), sum(b2) from t1 join t2 on b1 = b2 group by b1 order by 1;
drop table t1, t2;
+
+#
+# Bug #13601: Wrong field length reported for BIT fields
+#
+create table t1 (a bit(7));
+insert into t1 values (0x60);
+--enable_metadata
+select * from t1;
+--disable_metadata
+drop table t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/type_bit_innodb.test b/mysql-test/t/type_bit_innodb.test
index ec433f40a88..dbca69d67f0 100644
--- a/mysql-test/t/type_bit_innodb.test
+++ b/mysql-test/t/type_bit_innodb.test
@@ -133,3 +133,15 @@ show create table t1;
alter table t1 engine=innodb;
show create table t1;
drop table t1;
+
+#
+# Bug #13601: Wrong field length reported for BIT fields
+#
+create table t1 (a bit(7)) engine=innodb;
+insert into t1 values (0x60);
+--enable_metadata
+select * from t1;
+--disable_metadata
+drop table t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index afeb0dda729..7ef1f82dbd3 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2434,3 +2434,23 @@ SELECT COUNT(*) FROM t1 LEFT JOIN v2 ON t1.id=v2.id;
DROP VIEW v2;
DROP TABLE t1, t2;
+
+#
+# Bug #16069: VIEW does return the same results as underlying SELECT
+# with WHERE condition containing BETWEEN over dates
+
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY,
+ td date DEFAULT NULL, KEY idx(td));
+
+INSERT INTO t1 VALUES
+ (1, '2005-01-01'), (2, '2005-01-02'), (3, '2005-01-02'),
+ (4, '2005-01-03'), (5, '2005-01-04'), (6, '2005-01-05'),
+ (7, '2005-01-05'), (8, '2005-01-05'), (9, '2005-01-06');
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+SELECT * FROM t1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04';
+SELECT * FROM v1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04';
+
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/ndb/include/kernel/signaldata/CmRegSignalData.hpp b/ndb/include/kernel/signaldata/CmRegSignalData.hpp
index f33c991249f..ab51ed17bc3 100644
--- a/ndb/include/kernel/signaldata/CmRegSignalData.hpp
+++ b/ndb/include/kernel/signaldata/CmRegSignalData.hpp
@@ -30,12 +30,17 @@ class CmRegReq {
friend class Qmgr;
public:
- STATIC_CONST( SignalLength = 3 );
+ STATIC_CONST( SignalLength = 5 + NdbNodeBitmask::Size );
private:
Uint32 blockRef;
Uint32 nodeId;
- Uint32 version; // See ndb_version.h
+ Uint32 version; // See ndb_version.h
+
+ Uint32 start_type; // As specified by cmd-line or mgm, NodeState::StartType
+ Uint32 latest_gci; // 0 means no fs
+ Uint32 skip_nodes[NdbNodeBitmask::Size]; // Nodes that does not _need_
+ // to be part of restart
};
/**
@@ -59,8 +64,7 @@ private:
* The dynamic id that the node reciving this signal has
*/
Uint32 dynamicId;
-
- Uint32 allNdbNodes[NdbNodeBitmask::Size];
+ Uint32 allNdbNodes[NdbNodeBitmask::Size];
};
/**
@@ -73,7 +77,7 @@ class CmRegRef {
friend class Qmgr;
public:
- STATIC_CONST( SignalLength = 4 );
+ STATIC_CONST( SignalLength = 7 + NdbNodeBitmask::Size );
enum ErrorCode {
ZBUSY = 0, /* Only the president can send this */
@@ -85,14 +89,27 @@ public:
* as president. */
ZNOT_PRESIDENT = 5, /* We are not president */
ZNOT_DEAD = 6, /* We are not dead when we are starting */
- ZINCOMPATIBLE_VERSION = 7
+ ZINCOMPATIBLE_VERSION = 7,
+ ZINCOMPATIBLE_START_TYPE = 8
};
private:
Uint32 blockRef;
Uint32 nodeId;
Uint32 errorCode;
+ /**
+ * Applicable if ZELECTION
+ */
Uint32 presidentCandidate;
+ Uint32 candidate_latest_gci; // 0 means non
+
+ /**
+ * Data for sending node sending node
+ */
+ Uint32 latest_gci;
+ Uint32 start_type;
+ Uint32 skip_nodes[NdbNodeBitmask::Size]; // Nodes that does not _need_
+ // to be part of restart
};
class CmAdd {
diff --git a/ndb/include/kernel/signaldata/DumpStateOrd.hpp b/ndb/include/kernel/signaldata/DumpStateOrd.hpp
index b42b930711c..a2993ad5d03 100644
--- a/ndb/include/kernel/signaldata/DumpStateOrd.hpp
+++ b/ndb/include/kernel/signaldata/DumpStateOrd.hpp
@@ -64,6 +64,7 @@ public:
// 19 NDBFS Fipple with O_SYNC, O_CREATE etc.
// 20-24 BACKUP
NdbcntrTestStopOnError = 25,
+ NdbcntrStopNodes = 70,
// 100-105 TUP and ACC
// 200-240 UTIL
// 300-305 TRIX
diff --git a/ndb/include/kernel/signaldata/FailRep.hpp b/ndb/include/kernel/signaldata/FailRep.hpp
index 44577f07fdc..f2250f1af73 100644
--- a/ndb/include/kernel/signaldata/FailRep.hpp
+++ b/ndb/include/kernel/signaldata/FailRep.hpp
@@ -18,6 +18,7 @@
#define FAIL_REP_HPP
#include "SignalData.hpp"
+#include <NodeBitmask.hpp>
/**
*
@@ -27,6 +28,7 @@ class FailRep {
* Sender(s) & Reciver(s)
*/
friend class Qmgr;
+ friend class Ndbcntr;
/**
* For printing
@@ -35,7 +37,8 @@ class FailRep {
public:
STATIC_CONST( SignalLength = 2 );
-
+ STATIC_CONST( ExtraLength = 1 + NdbNodeBitmask::Size );
+
enum FailCause {
ZOWN_FAILURE=0,
ZOTHER_NODE_WHEN_WE_START=1,
@@ -43,13 +46,20 @@ public:
ZSTART_IN_REGREQ=3,
ZHEARTBEAT_FAILURE=4,
ZLINK_FAILURE=5,
- ZOTHERNODE_FAILED_DURING_START=6
+ ZOTHERNODE_FAILED_DURING_START=6,
+ ZMULTI_NODE_SHUTDOWN = 7,
+ ZPARTITIONED_CLUSTER = 8
};
-
+
private:
Uint32 failNodeId;
Uint32 failCause;
+ /**
+ * Used when failCause == ZPARTITIONED_CLUSTER
+ */
+ Uint32 president;
+ Uint32 partition[NdbNodeBitmask::Size];
};
diff --git a/ndb/include/kernel/signaldata/StopReq.hpp b/ndb/include/kernel/signaldata/StopReq.hpp
index 8e6a0b90a91..70e195961ce 100644
--- a/ndb/include/kernel/signaldata/StopReq.hpp
+++ b/ndb/include/kernel/signaldata/StopReq.hpp
@@ -32,7 +32,7 @@ class StopReq
friend class MgmtSrvr;
public:
- STATIC_CONST( SignalLength = 9 );
+ STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size);
public:
Uint32 senderRef;
@@ -49,29 +49,34 @@ public:
Int32 readOperationTimeout; // Timeout before read operations are aborted
Int32 operationTimeout; // Timeout before all operations are aborted
+ Uint32 nodes[NdbNodeBitmask::Size];
+
static void setSystemStop(Uint32 & requestInfo, bool value);
static void setPerformRestart(Uint32 & requestInfo, bool value);
static void setNoStart(Uint32 & requestInfo, bool value);
static void setInitialStart(Uint32 & requestInfo, bool value);
- static void setEscalateOnNodeFail(Uint32 & requestInfo, bool value);
/**
* Don't perform "graceful" shutdown/restart...
*/
static void setStopAbort(Uint32 & requestInfo, bool value);
+ static void setStopNodes(Uint32 & requestInfo, bool value);
static bool getSystemStop(const Uint32 & requestInfo);
static bool getPerformRestart(const Uint32 & requestInfo);
static bool getNoStart(const Uint32 & requestInfo);
static bool getInitialStart(const Uint32 & requestInfo);
- static bool getEscalateOnNodeFail(const Uint32 & requestInfo);
static bool getStopAbort(const Uint32 & requestInfo);
+ static bool getStopNodes(const Uint32 & requestInfo);
};
struct StopConf
{
STATIC_CONST( SignalLength = 2 );
Uint32 senderData;
- Uint32 nodeState;
+ union {
+ Uint32 nodeState;
+ Uint32 nodeId;
+ };
};
class StopRef
@@ -87,19 +92,22 @@ class StopRef
friend class Ndbcntr;
public:
- STATIC_CONST( SignalLength = 2 );
+ STATIC_CONST( SignalLength = 3 );
enum ErrorCode {
OK = 0,
NodeShutdownInProgress = 1,
SystemShutdownInProgress = 2,
NodeShutdownWouldCauseSystemCrash = 3,
- TransactionAbortFailed = 4
+ TransactionAbortFailed = 4,
+ UnsupportedNodeShutdown = 5,
+ MultiNodeShutdownNotMaster = 6
};
public:
Uint32 senderData;
Uint32 errorCode;
+ Uint32 masterNodeId;
};
inline
@@ -132,16 +140,16 @@ StopReq::getInitialStart(const Uint32 & requestInfo)
inline
bool
-StopReq::getEscalateOnNodeFail(const Uint32 & requestInfo)
+StopReq::getStopAbort(const Uint32 & requestInfo)
{
- return requestInfo & 16;
+ return requestInfo & 32;
}
inline
bool
-StopReq::getStopAbort(const Uint32 & requestInfo)
+StopReq::getStopNodes(const Uint32 & requestInfo)
{
- return requestInfo & 32;
+ return requestInfo & 64;
}
@@ -187,24 +195,23 @@ StopReq::setInitialStart(Uint32 & requestInfo, bool value)
inline
void
-StopReq::setEscalateOnNodeFail(Uint32 & requestInfo, bool value)
+StopReq::setStopAbort(Uint32 & requestInfo, bool value)
{
if(value)
- requestInfo |= 16;
+ requestInfo |= 32;
else
- requestInfo &= ~16;
+ requestInfo &= ~32;
}
inline
void
-StopReq::setStopAbort(Uint32 & requestInfo, bool value)
+StopReq::setStopNodes(Uint32 & requestInfo, bool value)
{
if(value)
- requestInfo |= 32;
+ requestInfo |= 64;
else
- requestInfo &= ~32;
+ requestInfo &= ~64;
}
-
#endif
diff --git a/ndb/include/kernel/signaldata/WaitGCP.hpp b/ndb/include/kernel/signaldata/WaitGCP.hpp
index ebed28714d2..be2a5b9d5f0 100644
--- a/ndb/include/kernel/signaldata/WaitGCP.hpp
+++ b/ndb/include/kernel/signaldata/WaitGCP.hpp
@@ -46,7 +46,9 @@ public:
Complete = 1, ///< Wait for a GCP to complete
CompleteForceStart = 2, ///< Wait for a GCP to complete start one if needed
CompleteIfRunning = 3, ///< Wait for ongoing GCP
- CurrentGCI = 8 ///< Immediately return current GCI
+ CurrentGCI = 8, ///< Immediately return current GCI
+ BlockStartGcp = 9,
+ UnblockStartGcp = 10
};
Uint32 senderRef;
@@ -70,11 +72,12 @@ class WaitGCPConf {
//friend class Grep::PSCoord;
public:
- STATIC_CONST( SignalLength = 2 );
+ STATIC_CONST( SignalLength = 3 );
public:
Uint32 senderData;
Uint32 gcp;
+ Uint32 blockStatus;
};
class WaitGCPRef {
diff --git a/ndb/include/mgmapi/ndb_logevent.h b/ndb/include/mgmapi/ndb_logevent.h
index 6025ff2725c..d57646c14db 100644
--- a/ndb/include/mgmapi/ndb_logevent.h
+++ b/ndb/include/mgmapi/ndb_logevent.h
@@ -166,10 +166,14 @@ extern "C" {
/** NDB_MGM_EVENT_CATEGORY_BACKUP */
NDB_LE_BackupCompleted = 56,
/** NDB_MGM_EVENT_CATEGORY_BACKUP */
- NDB_LE_BackupAborted = 57
+ NDB_LE_BackupAborted = 57,
/* 58 used in 5.1 */
/* 59 used */
+
+ /** NDB_MGM_EVENT_CATEGORY_STARTUP */
+ NDB_LE_StartReport = 60
+
/* 60 unused */
/* 61 unused */
/* 62 unused */
@@ -625,6 +629,13 @@ extern "C" {
unsigned type;
unsigned node_id;
} SingleUser;
+ /** Log even data @ref NDB_LE_StartReport */
+ struct {
+ unsigned report_type;
+ unsigned remaining_time;
+ unsigned bitmask_size;
+ unsigned bitmask_data[1];
+ } StartReport;
#ifndef DOXYGEN_FIX
};
#else
diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp
index f785cda5215..e1a477b8ea4 100644
--- a/ndb/src/common/debugger/EventLogger.cpp
+++ b/ndb/src/common/debugger/EventLogger.cpp
@@ -707,6 +707,90 @@ void getTextSingleUser(QQQQ) {
}
}
+void getTextStartReport(QQQQ) {
+ Uint32 time = theData[2];
+ Uint32 sz = theData[3];
+ char mask1[100];
+ char mask2[100];
+ char mask3[100];
+ char mask4[100];
+ BitmaskImpl::getText(sz, theData + 4 + (0 * sz), mask1);
+ BitmaskImpl::getText(sz, theData + 4 + (1 * sz), mask2);
+ BitmaskImpl::getText(sz, theData + 4 + (2 * sz), mask3);
+ BitmaskImpl::getText(sz, theData + 4 + (3 * sz), mask4);
+ switch(theData[1]){
+ case 1: // Wait initial
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Initial start, waiting for %s to connect, "
+ " nodes [ all: %s connected: %s no-wait: %s ]",
+ mask4, mask1, mask2, mask3);
+ break;
+ case 2: // Wait partial
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Waiting until nodes: %s connects, "
+ "nodes [ all: %s connected: %s no-wait: %s ]",
+ mask4, mask1, mask2, mask3);
+ break;
+ case 3: // Wait partial timeout
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Waiting %u sec for nodes %s to connect, "
+ "nodes [ all: %s connected: %s no-wait: %s ]",
+
+ time, mask4, mask1, mask2, mask3);
+ break;
+ case 4: // Wait partioned
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Waiting for non partitioned start, "
+ "nodes [ all: %s connected: %s missing: %s no-wait: %s ]",
+
+ mask1, mask2, mask4, mask3);
+ break;
+ case 5:
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Waiting %u sec for non partitioned start, "
+ "nodes [ all: %s connected: %s missing: %s no-wait: %s ]",
+
+ time, mask1, mask2, mask4, mask3);
+ break;
+ case 0x8000: // Do initial
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Initial start with nodes %s [ missing: %s no-wait: %s ]",
+ mask2, mask4, mask3);
+ break;
+ case 0x8001: // Do start
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Start with all nodes %s",
+ mask2);
+ break;
+ case 0x8002: // Do partial
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Start with nodes %s [ missing: %s no-wait: %s ]",
+ mask2, mask4, mask3);
+ break;
+ case 0x8003: // Do partioned
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Start potentially partitioned with nodes %s "
+ " [ missing: %s no-wait: %s ]",
+ mask2, mask4, mask3);
+ break;
+ default:
+ BaseString::snprintf
+ (m_text, m_text_len,
+ "Unknown startreport: 0x%x [ %s %s %s %s ]",
+ theData[1],
+ mask1, mask2, mask3, mask4);
+ }
+}
+
#if 0
BaseString::snprintf(m_text,
m_text_len,
@@ -755,6 +839,7 @@ const EventLoggerBase::EventRepLogLevelMatrix EventLoggerBase::matrix[] = {
ROW(StartREDOLog, LogLevel::llStartUp, 10, Logger::LL_INFO ),
ROW(StartLog, LogLevel::llStartUp, 10, Logger::LL_INFO ),
ROW(UNDORecordsExecuted, LogLevel::llStartUp, 15, Logger::LL_INFO ),
+ ROW(StartReport, LogLevel::llStartUp, 4, Logger::LL_INFO ),
// NODERESTART
ROW(NR_CopyDict, LogLevel::llNodeRestart, 8, Logger::LL_INFO ),
diff --git a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
index a641a85fc91..908e2a81345 100644
--- a/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
+++ b/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
@@ -134,6 +134,9 @@ Cmvmi::~Cmvmi()
{
}
+#ifdef ERROR_INSERT
+NodeBitmask c_error_9000_nodes_mask;
+#endif
void Cmvmi::execNDB_TAMPER(Signal* signal)
{
@@ -419,21 +422,33 @@ void Cmvmi::execOPEN_COMREQ(Signal* signal)
const Uint32 len = signal->getLength();
if(len == 2){
- globalTransporterRegistry.do_connect(tStartingNode);
- globalTransporterRegistry.setIOState(tStartingNode, HaltIO);
- //-----------------------------------------------------
- // Report that the connection to the node is opened
- //-----------------------------------------------------
- signal->theData[0] = NDB_LE_CommunicationOpened;
- signal->theData[1] = tStartingNode;
- sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
- //-----------------------------------------------------
+#ifdef ERROR_INSERT
+ if (! (ERROR_INSERTED(9000) && c_error_9000_nodes_mask.get(tStartingNode)))
+#endif
+ {
+ globalTransporterRegistry.do_connect(tStartingNode);
+ globalTransporterRegistry.setIOState(tStartingNode, HaltIO);
+
+ //-----------------------------------------------------
+ // Report that the connection to the node is opened
+ //-----------------------------------------------------
+ signal->theData[0] = NDB_LE_CommunicationOpened;
+ signal->theData[1] = tStartingNode;
+ sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 2, JBB);
+ //-----------------------------------------------------
+ }
} else {
for(unsigned int i = 1; i < MAX_NODES; i++ ) {
jam();
if (i != getOwnNodeId() && getNodeInfo(i).m_type == tData2){
jam();
+
+#ifdef ERROR_INSERT
+ if (ERROR_INSERTED(9000) && c_error_9000_nodes_mask.get(i))
+ continue;
+#endif
+
globalTransporterRegistry.do_connect(i);
globalTransporterRegistry.setIOState(i, HaltIO);
@@ -1039,7 +1054,8 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal)
}
DumpStateOrd * const & dumpState = (DumpStateOrd *)&signal->theData[0];
- if (dumpState->args[0] == DumpStateOrd::CmvmiDumpConnections){
+ Uint32 arg = dumpState->args[0];
+ if (arg == DumpStateOrd::CmvmiDumpConnections){
for(unsigned int i = 1; i < MAX_NODES; i++ ){
const char* nodeTypeStr = "";
switch(getNodeInfo(i).m_type){
@@ -1072,13 +1088,13 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal)
}
}
- if (dumpState->args[0] == DumpStateOrd::CmvmiDumpLongSignalMemory){
+ if (arg == DumpStateOrd::CmvmiDumpLongSignalMemory){
infoEvent("Cmvmi: g_sectionSegmentPool size: %d free: %d",
g_sectionSegmentPool.getSize(),
g_sectionSegmentPool.getNoOfFree());
}
- if (dumpState->args[0] == DumpStateOrd::CmvmiSetRestartOnErrorInsert)
+ if (arg == DumpStateOrd::CmvmiSetRestartOnErrorInsert)
{
if(signal->getLength() == 1)
{
@@ -1098,7 +1114,7 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal)
}
}
- if (dumpState->args[0] == DumpStateOrd::CmvmiTestLongSigWithDelay) {
+ if (arg == DumpStateOrd::CmvmiTestLongSigWithDelay) {
unsigned i;
Uint32 loopCount = dumpState->args[1];
const unsigned len0 = 11;
@@ -1126,6 +1142,30 @@ Cmvmi::execDUMP_STATE_ORD(Signal* signal)
sendSignal(reference(), GSN_TESTSIG, signal, 8, JBB, ptr, 2);
}
+#ifdef ERROR_INSERT
+ if (arg == 9000)
+ {
+ SET_ERROR_INSERT_VALUE(9000);
+ for (Uint32 i = 1; i<signal->getLength(); i++)
+ c_error_9000_nodes_mask.set(signal->theData[i]);
+ }
+
+ if (arg == 9001)
+ {
+ CLEAR_ERROR_INSERT_VALUE;
+ for (Uint32 i = 0; i<MAX_NODES; i++)
+ {
+ if (c_error_9000_nodes_mask.get(i))
+ {
+ signal->theData[0] = 0;
+ signal->theData[1] = i;
+ EXECUTE_DIRECT(CMVMI, GSN_OPEN_COMREQ, signal, 2);
+ }
+ }
+ c_error_9000_nodes_mask.clear();
+ }
+#endif
+
#ifdef VM_TRACE
#if 0
{
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp
index d6f6b772516..cd987048577 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp
@@ -71,6 +71,7 @@ void Dbdih::initData()
cwaitLcpSr = false;
c_blockCommit = false;
c_blockCommitNo = 1;
+ cntrlblockref = RNIL;
}//Dbdih::initData()
void Dbdih::initRecords()
diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
index c1b5f88c8c2..c8254052a56 100644
--- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
+++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp
@@ -11659,7 +11659,7 @@ void Dbdih::makeNodeGroups(Uint32 nodeArray[])
Uint32 tmngNode;
Uint32 tmngNodeGroup;
Uint32 tmngLimit;
- Uint32 i;
+ Uint32 i, j;
/**-----------------------------------------------------------------------
* ASSIGN ALL ACTIVE NODES INTO NODE GROUPS. HOT SPARE NODES ARE ASSIGNED
@@ -11705,6 +11705,38 @@ void Dbdih::makeNodeGroups(Uint32 nodeArray[])
Sysfile::setNodeGroup(mngNodeptr.i, SYSFILE->nodeGroups, mngNodeptr.p->nodeGroup);
}//if
}//for
+
+ for (i = 0; i<cnoOfNodeGroups; i++)
+ {
+ jam();
+ bool alive = false;
+ NodeGroupRecordPtr NGPtr;
+ NGPtr.i = i;
+ ptrCheckGuard(NGPtr, MAX_NDB_NODES, nodeGroupRecord);
+ for (j = 0; j<NGPtr.p->nodeCount; j++)
+ {
+ jam();
+ mngNodeptr.i = NGPtr.p->nodesInGroup[j];
+ ptrCheckGuard(mngNodeptr, MAX_NDB_NODES, nodeRecord);
+ if (checkNodeAlive(NGPtr.p->nodesInGroup[j]))
+ {
+ alive = true;
+ break;
+ }
+ }
+
+ if (!alive)
+ {
+ char buf[255];
+ BaseString::snprintf
+ (buf, sizeof(buf),
+ "Illegal initial start, no alive node in nodegroup %u", i);
+ progError(__LINE__,
+ NDBD_EXIT_SR_RESTARTCONFLICT,
+ buf);
+
+ }
+ }
}//Dbdih::makeNodeGroups()
/**
@@ -12513,7 +12545,6 @@ void Dbdih::sendStartFragreq(Signal* signal,
void Dbdih::setInitialActiveStatus()
{
NodeRecordPtr siaNodeptr;
- Uint32 tsiaNodeActiveStatus;
Uint32 tsiaNoActiveNodes;
tsiaNoActiveNodes = csystemnodes - cnoHotSpare;
@@ -12521,39 +12552,34 @@ void Dbdih::setInitialActiveStatus()
SYSFILE->nodeStatus[i] = 0;
for (siaNodeptr.i = 1; siaNodeptr.i < MAX_NDB_NODES; siaNodeptr.i++) {
ptrAss(siaNodeptr, nodeRecord);
- if (siaNodeptr.p->nodeStatus == NodeRecord::ALIVE) {
+ switch(siaNodeptr.p->nodeStatus){
+ case NodeRecord::ALIVE:
+ case NodeRecord::DEAD:
if (tsiaNoActiveNodes == 0) {
jam();
siaNodeptr.p->activeStatus = Sysfile::NS_HotSpare;
} else {
jam();
tsiaNoActiveNodes = tsiaNoActiveNodes - 1;
- siaNodeptr.p->activeStatus = Sysfile::NS_Active;
- }//if
- } else {
- jam();
- siaNodeptr.p->activeStatus = Sysfile::NS_NotDefined;
- }//if
- switch (siaNodeptr.p->activeStatus) {
- case Sysfile::NS_Active:
- jam();
- tsiaNodeActiveStatus = Sysfile::NS_Active;
- break;
- case Sysfile::NS_HotSpare:
- jam();
- tsiaNodeActiveStatus = Sysfile::NS_HotSpare;
- break;
- case Sysfile::NS_NotDefined:
- jam();
- tsiaNodeActiveStatus = Sysfile::NS_NotDefined;
+ if (siaNodeptr.p->nodeStatus == NodeRecord::ALIVE)
+ {
+ jam();
+ siaNodeptr.p->activeStatus = Sysfile::NS_Active;
+ }
+ else
+ {
+ siaNodeptr.p->activeStatus = Sysfile::NS_NotActive_NotTakenOver;
+ }
+ }
break;
default:
- ndbrequire(false);
- return;
+ jam();
+ siaNodeptr.p->activeStatus = Sysfile::NS_NotDefined;
break;
- }//switch
- Sysfile::setNodeStatus(siaNodeptr.i, SYSFILE->nodeStatus,
- tsiaNodeActiveStatus);
+ }//if
+ Sysfile::setNodeStatus(siaNodeptr.i,
+ SYSFILE->nodeStatus,
+ siaNodeptr.p->activeStatus);
}//for
}//Dbdih::setInitialActiveStatus()
@@ -14274,11 +14300,36 @@ void Dbdih::execWAIT_GCP_REQ(Signal* signal)
jam();
conf->senderData = senderData;
conf->gcp = cnewgcp;
+ conf->blockStatus = cgcpOrderBlocked;
sendSignal(senderRef, GSN_WAIT_GCP_CONF, signal,
WaitGCPConf::SignalLength, JBB);
return;
}//if
+ if (requestType == WaitGCPReq::BlockStartGcp)
+ {
+ jam();
+ conf->senderData = senderData;
+ conf->gcp = cnewgcp;
+ conf->blockStatus = cgcpOrderBlocked;
+ sendSignal(senderRef, GSN_WAIT_GCP_CONF, signal,
+ WaitGCPConf::SignalLength, JBB);
+ cgcpOrderBlocked = 1;
+ return;
+ }
+
+ if (requestType == WaitGCPReq::UnblockStartGcp)
+ {
+ jam();
+ conf->senderData = senderData;
+ conf->gcp = cnewgcp;
+ conf->blockStatus = cgcpOrderBlocked;
+ sendSignal(senderRef, GSN_WAIT_GCP_CONF, signal,
+ WaitGCPConf::SignalLength, JBB);
+ cgcpOrderBlocked = 0;
+ return;
+ }
+
if(isMaster()) {
/**
* Master
@@ -14290,6 +14341,7 @@ void Dbdih::execWAIT_GCP_REQ(Signal* signal)
jam();
conf->senderData = senderData;
conf->gcp = coldgcp;
+ conf->blockStatus = cgcpOrderBlocked;
sendSignal(senderRef, GSN_WAIT_GCP_CONF, signal,
WaitGCPConf::SignalLength, JBB);
return;
@@ -14376,6 +14428,7 @@ void Dbdih::execWAIT_GCP_CONF(Signal* signal)
conf->senderData = ptr.p->clientData;
conf->gcp = gcp;
+ conf->blockStatus = cgcpOrderBlocked;
sendSignal(ptr.p->clientRef, GSN_WAIT_GCP_CONF, signal,
WaitGCPConf::SignalLength, JBB);
@@ -14443,6 +14496,7 @@ void Dbdih::emptyWaitGCPMasterQueue(Signal* signal)
c_waitGCPMasterList.next(ptr);
conf->senderData = clientData;
+ conf->blockStatus = cgcpOrderBlocked;
sendSignal(clientRef, GSN_WAIT_GCP_CONF, signal,
WaitGCPConf::SignalLength, JBB);
diff --git a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp
index af19d8a83a4..7aa5be7a3cb 100644
--- a/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp
+++ b/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp
@@ -203,6 +203,7 @@ private:
void execWAIT_GCP_CONF(Signal* signal);
void execSTOP_REQ(Signal* signal);
+ void execSTOP_CONF(Signal* signal);
void execRESUME_REQ(Signal* signal);
void execCHANGE_NODE_STATE_CONF(Signal* signal);
@@ -338,6 +339,16 @@ public:
void progError(int line, int cause, const char * extra) {
cntr.progError(line, cause, extra);
}
+
+ enum StopNodesStep {
+ SR_BLOCK_GCP_START_GCP = 0,
+ SR_WAIT_COMPLETE_GCP = 1,
+ SR_UNBLOCK_GCP_START_GCP = 2,
+ SR_QMGR_STOP_REQ = 3,
+ SR_WAIT_NODE_FAILURES = 4,
+ SR_CLUSTER_SHUTDOWN = 12
+ } m_state;
+ SignalCounter m_stop_req_counter;
};
private:
StopRecord c_stopRec;
diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp
index 5a939818d16..564501526a8 100644
--- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp
+++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp
@@ -87,6 +87,7 @@ Ndbcntr::Ndbcntr(const class Configuration & conf):
addRecSignal(GSN_STOP_ME_CONF, &Ndbcntr::execSTOP_ME_CONF);
addRecSignal(GSN_STOP_REQ, &Ndbcntr::execSTOP_REQ);
+ addRecSignal(GSN_STOP_CONF, &Ndbcntr::execSTOP_CONF);
addRecSignal(GSN_RESUME_REQ, &Ndbcntr::execRESUME_REQ);
addRecSignal(GSN_WAIT_GCP_REF, &Ndbcntr::execWAIT_GCP_REF);
diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
index bcf0839adc2..c403aad5516 100644
--- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
+++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp
@@ -42,6 +42,8 @@
#include <signaldata/FsRemoveReq.hpp>
#include <signaldata/ReadConfig.hpp>
+#include <signaldata/FailRep.hpp>
+
#include <AttributeHeader.hpp>
#include <Configuration.hpp>
#include <DebuggerNames.hpp>
@@ -818,17 +820,9 @@ Ndbcntr::trySystemRestart(Signal* signal){
return false;
}
- if(!allNodes && c_start.m_startPartialTimeout > now){
- jam();
- return false;
- }
-
NodeState::StartType srType = NodeState::ST_SYSTEM_RESTART;
- if(c_start.m_waiting.equal(c_start.m_withoutLog)){
- if(!allNodes){
- jam();
- return false;
- }
+ if(c_start.m_waiting.equal(c_start.m_withoutLog))
+ {
jam();
srType = NodeState::ST_INITIAL_START;
c_start.m_starting = c_start.m_withoutLog; // Used for starting...
@@ -858,10 +852,6 @@ Ndbcntr::trySystemRestart(Signal* signal){
ndbrequire(false); // All nodes -> partitioning, which is not allowed
}
- if(c_start.m_startPartitionedTimeout > now){
- jam();
- return false;
- }
break;
}
@@ -1474,13 +1464,74 @@ void Ndbcntr::execNODE_FAILREP(Signal* signal)
sendSignal(SUMA_REF, GSN_NODE_FAILREP, signal,
NodeFailRep::SignalLength, JBB);
+ if (c_stopRec.stopReq.senderRef)
+ {
+ jam();
+ switch(c_stopRec.m_state){
+ case StopRecord::SR_WAIT_NODE_FAILURES:
+ {
+ jam();
+ NdbNodeBitmask tmp;
+ tmp.assign(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+ tmp.bitANDC(allFailed);
+ tmp.copyto(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+
+ if (tmp.isclear())
+ {
+ jam();
+ if (c_stopRec.stopReq.senderRef != RNIL)
+ {
+ jam();
+ StopConf * const stopConf = (StopConf *)&signal->theData[0];
+ stopConf->senderData = c_stopRec.stopReq.senderData;
+ stopConf->nodeState = (Uint32) NodeState::SL_SINGLEUSER;
+ sendSignal(c_stopRec.stopReq.senderRef, GSN_STOP_CONF, signal,
+ StopConf::SignalLength, JBB);
+ }
+
+ c_stopRec.stopReq.senderRef = 0;
+ WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
+ req->senderRef = reference();
+ req->senderData = StopRecord::SR_UNBLOCK_GCP_START_GCP;
+ req->requestType = WaitGCPReq::UnblockStartGcp;
+ sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
+ WaitGCPReq::SignalLength, JBA);
+ }
+ break;
+ }
+ case StopRecord::SR_QMGR_STOP_REQ:
+ {
+ NdbNodeBitmask tmp;
+ tmp.assign(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+ tmp.bitANDC(allFailed);
+
+ if (tmp.isclear())
+ {
+ Uint32 nodeId = allFailed.find(0);
+ tmp.set(nodeId);
+
+ StopConf* conf = (StopConf*)signal->getDataPtrSend();
+ conf->senderData = c_stopRec.stopReq.senderData;
+ conf->nodeId = nodeId;
+ sendSignal(reference(),
+ GSN_STOP_CONF, signal, StopConf::SignalLength, JBB);
+ }
+
+ tmp.copyto(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+
+ break;
+ }
+ }
+ }
+
+ signal->theData[0] = NDB_LE_NODE_FAILREP;
+ signal->theData[2] = 0;
+
Uint32 nodeId = 0;
while(!allFailed.isclear()){
nodeId = allFailed.find(nodeId + 1);
allFailed.clear(nodeId);
- signal->theData[0] = NDB_LE_NODE_FAILREP;
signal->theData[1] = nodeId;
- signal->theData[2] = 0;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
}//for
@@ -1924,13 +1975,15 @@ void
Ndbcntr::execDUMP_STATE_ORD(Signal* signal)
{
DumpStateOrd * const & dumpState = (DumpStateOrd *)&signal->theData[0];
- if(signal->theData[0] == 13){
+ Uint32 arg = dumpState->args[0];
+
+ if(arg == 13){
infoEvent("Cntr: cstartPhase = %d, cinternalStartphase = %d, block = %d",
cstartPhase, cinternalStartphase, cndbBlocksCount);
infoEvent("Cntr: cmasterNodeId = %d", cmasterNodeId);
}
- if (dumpState->args[0] == DumpStateOrd::NdbcntrTestStopOnError){
+ if (arg == DumpStateOrd::NdbcntrTestStopOnError){
if (theConfiguration.stopOnError() == true)
((Configuration&)theConfiguration).stopOnError(false);
@@ -1943,6 +1996,28 @@ Ndbcntr::execDUMP_STATE_ORD(Signal* signal)
SystemError::SignalLength, JBA);
}
+ if (arg == DumpStateOrd::NdbcntrStopNodes)
+ {
+ NdbNodeBitmask mask;
+ for(Uint32 i = 1; i<signal->getLength(); i++)
+ mask.set(signal->theData[i]);
+
+ StopReq* req = (StopReq*)signal->getDataPtrSend();
+ req->senderRef = RNIL;
+ req->senderData = 123;
+ req->requestInfo = 0;
+ req->singleuser = 0;
+ req->singleUserApi = 0;
+ mask.copyto(NdbNodeBitmask::Size, req->nodes);
+ StopReq::setPerformRestart(req->requestInfo, 1);
+ StopReq::setNoStart(req->requestInfo, 1);
+ StopReq::setStopNodes(req->requestInfo, 1);
+ StopReq::setStopAbort(req->requestInfo, 1);
+
+ sendSignal(reference(), GSN_STOP_REQ, signal,
+ StopReq::SignalLength, JBB);
+ return;
+ }
}//Ndbcntr::execDUMP_STATE_ORD()
@@ -2003,9 +2078,12 @@ Ndbcntr::execSTOP_REQ(Signal* signal){
Uint32 senderData = req->senderData;
BlockReference senderRef = req->senderRef;
bool abort = StopReq::getStopAbort(req->requestInfo);
+ bool stopnodes = StopReq::getStopNodes(req->requestInfo);
- if(getNodeState().startLevel < NodeState::SL_STARTED ||
- abort && !singleuser){
+ if(!singleuser &&
+ (getNodeState().startLevel < NodeState::SL_STARTED ||
+ (abort && !stopnodes)))
+ {
/**
* Node is not started yet
*
@@ -2047,21 +2125,74 @@ Ndbcntr::execSTOP_REQ(Signal* signal){
else
ref->errorCode = StopRef::NodeShutdownInProgress;
ref->senderData = senderData;
- sendSignal(senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
+ ref->masterNodeId = cmasterNodeId;
+
+ if (senderRef != RNIL)
+ sendSignal(senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
+ return;
+ }
+
+ if (stopnodes && !abort)
+ {
+ jam();
+ ref->errorCode = StopRef::UnsupportedNodeShutdown;
+ ref->senderData = senderData;
+ ref->masterNodeId = cmasterNodeId;
+ if (senderRef != RNIL)
+ sendSignal(senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
+ return;
+ }
+
+ if (stopnodes && cmasterNodeId != getOwnNodeId())
+ {
+ jam();
+ ref->errorCode = StopRef::MultiNodeShutdownNotMaster;
+ ref->senderData = senderData;
+ ref->masterNodeId = cmasterNodeId;
+ if (senderRef != RNIL)
+ sendSignal(senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
return;
}
c_stopRec.stopReq = * req;
c_stopRec.stopInitiatedTime = NdbTick_CurrentMillisecond();
- if(!singleuser) {
- if(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo)) {
+ if (stopnodes)
+ {
+ jam();
+
+ if(!c_stopRec.checkNodeFail(signal))
+ {
+ jam();
+ return;
+ }
+
+ char buf[100];
+ NdbNodeBitmask mask;
+ mask.assign(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+ infoEvent("Initiating shutdown abort of %s", mask.getText(buf));
+ ndbout_c("Initiating shutdown abort of %s", mask.getText(buf));
+
+ WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
+ req->senderRef = reference();
+ req->senderData = StopRecord::SR_BLOCK_GCP_START_GCP;
+ req->requestType = WaitGCPReq::BlockStartGcp;
+ sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
+ WaitGCPReq::SignalLength, JBB);
+ return;
+ }
+ else if(!singleuser)
+ {
+ if(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo))
+ {
jam();
- if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo)){
+ if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo))
+ {
((Configuration&)theConfiguration).stopOnError(false);
}
}
- if(!c_stopRec.checkNodeFail(signal)){
+ if(!c_stopRec.checkNodeFail(signal))
+ {
jam();
return;
}
@@ -2131,7 +2262,17 @@ Ndbcntr::StopRecord::checkNodeFail(Signal* signal){
*/
NodeBitmask ndbMask;
ndbMask.assign(cntr.c_startedNodes);
- ndbMask.clear(cntr.getOwnNodeId());
+
+ if (StopReq::getStopNodes(stopReq.requestInfo))
+ {
+ NdbNodeBitmask tmp;
+ tmp.assign(NdbNodeBitmask::Size, stopReq.nodes);
+ ndbMask.bitANDC(tmp);
+ }
+ else
+ {
+ ndbMask.clear(cntr.getOwnNodeId());
+ }
CheckNodeGroups* sd = (CheckNodeGroups*)&signal->theData[0];
sd->blockRef = cntr.reference();
@@ -2151,9 +2292,11 @@ Ndbcntr::StopRecord::checkNodeFail(Signal* signal){
ref->senderData = stopReq.senderData;
ref->errorCode = StopRef::NodeShutdownWouldCauseSystemCrash;
+ ref->masterNodeId = cntr.cmasterNodeId;
const BlockReference bref = stopReq.senderRef;
- cntr.sendSignal(bref, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
+ if (bref != RNIL)
+ cntr.sendSignal(bref, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
stopReq.senderRef = 0;
@@ -2203,23 +2346,23 @@ Ndbcntr::StopRecord::checkTcTimeout(Signal* signal){
if(stopReq.getSystemStop(stopReq.requestInfo) || stopReq.singleuser){
jam();
if(stopReq.singleuser)
- {
- jam();
- AbortAllReq * req = (AbortAllReq*)&signal->theData[0];
- req->senderRef = cntr.reference();
- req->senderData = 12;
- cntr.sendSignal(DBTC_REF, GSN_ABORT_ALL_REQ, signal,
- AbortAllReq::SignalLength, JBB);
- }
+ {
+ jam();
+ AbortAllReq * req = (AbortAllReq*)&signal->theData[0];
+ req->senderRef = cntr.reference();
+ req->senderData = 12;
+ cntr.sendSignal(DBTC_REF, GSN_ABORT_ALL_REQ, signal,
+ AbortAllReq::SignalLength, JBB);
+ }
else
- {
- WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
- req->senderRef = cntr.reference();
- req->senderData = 12;
- req->requestType = WaitGCPReq::CompleteForceStart;
- cntr.sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
- WaitGCPReq::SignalLength, JBB);
- }
+ {
+ WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
+ req->senderRef = cntr.reference();
+ req->senderData = StopRecord::SR_CLUSTER_SHUTDOWN;
+ req->requestType = WaitGCPReq::CompleteForceStart;
+ cntr.sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
+ WaitGCPReq::SignalLength, JBB);
+ }
} else {
jam();
StopPermReq * req = (StopPermReq*)&signal->theData[0];
@@ -2298,6 +2441,7 @@ void Ndbcntr::execABORT_ALL_REF(Signal* signal){
StopRef * const stopRef = (StopRef *)&signal->theData[0];
stopRef->senderData = c_stopRec.stopReq.senderData;
stopRef->errorCode = StopRef::TransactionAbortFailed;
+ stopRef->masterNodeId = cmasterNodeId;
sendSignal(c_stopRec.stopReq.senderRef, GSN_STOP_REF, signal, StopRef::SignalLength, JBB);
}
@@ -2381,7 +2525,7 @@ void Ndbcntr::execWAIT_GCP_REF(Signal* signal){
WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
req->senderRef = reference();
- req->senderData = 12;
+ req->senderData = StopRecord::SR_CLUSTER_SHUTDOWN;
req->requestType = WaitGCPReq::CompleteForceStart;
sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
WaitGCPReq::SignalLength, JBB);
@@ -2390,29 +2534,129 @@ void Ndbcntr::execWAIT_GCP_REF(Signal* signal){
void Ndbcntr::execWAIT_GCP_CONF(Signal* signal){
jamEntry();
- ndbrequire(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo));
- NodeState newState(NodeState::SL_STOPPING_3, true);
+ WaitGCPConf* conf = (WaitGCPConf*)signal->getDataPtr();
- /**
- * Inform QMGR so that arbitrator won't kill us
- */
- NodeStateRep * rep = (NodeStateRep *)&signal->theData[0];
- rep->nodeState = newState;
- rep->nodeState.masterNodeId = cmasterNodeId;
- rep->nodeState.setNodeGroup(c_nodeGroup);
- EXECUTE_DIRECT(QMGR, GSN_NODE_STATE_REP, signal, NodeStateRep::SignalLength);
-
- if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo)){
- jam();
- StartOrd * startOrd = (StartOrd *)&signal->theData[0];
- startOrd->restartInfo = c_stopRec.stopReq.requestInfo;
- sendSignalWithDelay(CMVMI_REF, GSN_START_ORD, signal, 500,
- StartOrd::SignalLength);
- } else {
+ switch(conf->senderData){
+ case StopRecord::SR_BLOCK_GCP_START_GCP:
+ {
+ jam();
+ /**
+ *
+ */
+ if(!c_stopRec.checkNodeFail(signal))
+ {
+ jam();
+ goto unblock;
+ }
+
+ WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
+ req->senderRef = reference();
+ req->senderData = StopRecord::SR_WAIT_COMPLETE_GCP;
+ req->requestType = WaitGCPReq::CompleteIfRunning;
+
+ sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
+ WaitGCPReq::SignalLength, JBB);
+ return;
+ }
+ case StopRecord::SR_UNBLOCK_GCP_START_GCP:
+ {
+ jam();
+ return;
+ }
+ case StopRecord::SR_WAIT_COMPLETE_GCP:
+ {
jam();
- sendSignalWithDelay(CMVMI_REF, GSN_STOP_ORD, signal, 500, 1);
+ if(!c_stopRec.checkNodeFail(signal))
+ {
+ jam();
+ goto unblock;
+ }
+
+ NdbNodeBitmask tmp;
+ tmp.assign(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+ c_stopRec.m_stop_req_counter = tmp;
+ NodeReceiverGroup rg(QMGR, tmp);
+ StopReq * stopReq = (StopReq *)&signal->theData[0];
+ * stopReq = c_stopRec.stopReq;
+ stopReq->senderRef = reference();
+ sendSignal(rg, GSN_STOP_REQ, signal, StopReq::SignalLength, JBA);
+ c_stopRec.m_state = StopRecord::SR_QMGR_STOP_REQ;
+ return;
+ }
+ case StopRecord::SR_CLUSTER_SHUTDOWN:
+ {
+ jam();
+ break;
+ }
+ }
+
+ {
+ ndbrequire(StopReq::getSystemStop(c_stopRec.stopReq.requestInfo));
+ NodeState newState(NodeState::SL_STOPPING_3, true);
+
+ /**
+ * Inform QMGR so that arbitrator won't kill us
+ */
+ NodeStateRep * rep = (NodeStateRep *)&signal->theData[0];
+ rep->nodeState = newState;
+ rep->nodeState.masterNodeId = cmasterNodeId;
+ rep->nodeState.setNodeGroup(c_nodeGroup);
+ EXECUTE_DIRECT(QMGR, GSN_NODE_STATE_REP, signal,
+ NodeStateRep::SignalLength);
+
+ if(StopReq::getPerformRestart(c_stopRec.stopReq.requestInfo)){
+ jam();
+ StartOrd * startOrd = (StartOrd *)&signal->theData[0];
+ startOrd->restartInfo = c_stopRec.stopReq.requestInfo;
+ sendSignalWithDelay(CMVMI_REF, GSN_START_ORD, signal, 500,
+ StartOrd::SignalLength);
+ } else {
+ jam();
+ sendSignalWithDelay(CMVMI_REF, GSN_STOP_ORD, signal, 500, 1);
+ }
+ return;
+ }
+
+unblock:
+ WaitGCPReq * req = (WaitGCPReq*)&signal->theData[0];
+ req->senderRef = reference();
+ req->senderData = StopRecord::SR_UNBLOCK_GCP_START_GCP;
+ req->requestType = WaitGCPReq::UnblockStartGcp;
+ sendSignal(DBDIH_REF, GSN_WAIT_GCP_REQ, signal,
+ WaitGCPReq::SignalLength, JBB);
+}
+
+void
+Ndbcntr::execSTOP_CONF(Signal* signal)
+{
+ jamEntry();
+ StopConf *conf = (StopConf*)signal->getDataPtr();
+ ndbrequire(c_stopRec.m_state == StopRecord::SR_QMGR_STOP_REQ);
+ c_stopRec.m_stop_req_counter.clearWaitingFor(conf->nodeId);
+ if (c_stopRec.m_stop_req_counter.done())
+ {
+ char buf[100];
+ NdbNodeBitmask mask;
+ mask.assign(NdbNodeBitmask::Size, c_stopRec.stopReq.nodes);
+ infoEvent("Stopping of %s", mask.getText(buf));
+ ndbout_c("Stopping of %s", mask.getText(buf));
+
+ /**
+ * Kill any node...
+ */
+ FailRep * const failRep = (FailRep *)&signal->theData[0];
+ failRep->failCause = FailRep::ZMULTI_NODE_SHUTDOWN;
+ NodeReceiverGroup rg(QMGR, c_clusterNodes);
+ Uint32 nodeId = 0;
+ while ((nodeId = NdbNodeBitmask::find(c_stopRec.stopReq.nodes, nodeId+1))
+ != NdbNodeBitmask::NotFound)
+ {
+ failRep->failNodeId = nodeId;
+ sendSignal(rg, GSN_FAIL_REP, signal, FailRep::SignalLength, JBA);
+ }
+ c_stopRec.m_state = StopRecord::SR_WAIT_NODE_FAILURES;
+ return;
}
- return;
}
void Ndbcntr::execSTTORRY(Signal* signal){
diff --git a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
index 4a17d56d31e..e728ea81a7d 100644
--- a/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
+++ b/ndb/src/kernel/blocks/qmgr/Qmgr.hpp
@@ -29,6 +29,7 @@
#include <signaldata/CmRegSignalData.hpp>
#include <signaldata/ApiRegSignalData.hpp>
#include <signaldata/FailRep.hpp>
+#include <signaldata/StopReq.hpp>
#include "timer.hpp"
@@ -49,6 +50,7 @@
#define ZAPI_HB_HANDLING 3
#define ZTIMER_HANDLING 4
#define ZARBIT_HANDLING 5
+#define ZSTART_FAILURE_LIMIT 6
/* Error Codes ------------------------------*/
#define ZERRTOOMANY 1101
@@ -100,18 +102,42 @@ public:
};
struct StartRecord {
- void reset(){ m_startKey++; m_startNode = 0;}
+ void reset(){
+ m_startKey++;
+ m_startNode = 0;
+ m_gsn = RNIL;
+ m_nodes.clearWaitingFor();
+ }
Uint32 m_startKey;
Uint32 m_startNode;
Uint64 m_startTimeout;
Uint32 m_gsn;
SignalCounter m_nodes;
- } c_start;
+ Uint32 m_latest_gci;
+ Uint32 m_start_type;
+ NdbNodeBitmask m_skip_nodes;
+ NdbNodeBitmask m_starting_nodes;
+ NdbNodeBitmask m_starting_nodes_w_log;
+
+ Uint16 m_president_candidate;
+ Uint32 m_president_candidate_gci;
+ Uint16 m_regReqReqSent;
+ Uint16 m_regReqReqRecv;
+ } c_start;
+
NdbNodeBitmask c_definedNodes; // DB nodes in config
NdbNodeBitmask c_clusterNodes; // DB nodes in cluster
NodeBitmask c_connectedNodes; // All kinds of connected nodes
+
+ /**
+ * Nodes which we're checking for partitioned cluster
+ *
+ * i.e. nodes that connect to use, when we already have elected president
+ */
+ NdbNodeBitmask c_readnodes_nodes;
+
Uint32 c_maxDynamicId;
// Records
@@ -204,6 +230,7 @@ private:
void execPRES_TOCONF(Signal* signal);
void execDISCONNECT_REP(Signal* signal);
void execSYSTEM_ERROR(Signal* signal);
+ void execSTOP_REQ(Signal* signal);
// Received signals
void execDUMP_STATE_ORD(Signal* signal);
@@ -218,7 +245,12 @@ private:
void execREAD_NODESREQ(Signal* signal);
void execSET_VAR_REQ(Signal* signal);
+ void execREAD_NODESREF(Signal* signal);
+ void execREAD_NODESCONF(Signal* signal);
+ void execDIH_RESTARTREF(Signal* signal);
+ void execDIH_RESTARTCONF(Signal* signal);
+
void execAPI_VERSION_REQ(Signal* signal);
void execAPI_BROADCAST_REP(Signal* signal);
@@ -234,6 +266,9 @@ private:
void execARBIT_STOPREP(Signal* signal);
// Statement blocks
+ void check_readnodes_reply(Signal* signal, Uint32 nodeId, Uint32 gsn);
+ Uint32 check_startup(Signal* signal);
+
void node_failed(Signal* signal, Uint16 aFailedNode);
void checkStartInterface(Signal* signal);
void failReport(Signal* signal,
@@ -251,8 +286,9 @@ private:
// Generated statement blocks
void startphase1(Signal* signal);
- void electionWon();
+ void electionWon(Signal* signal);
void cmInfoconf010Lab(Signal* signal);
+
void apiHbHandlingLab(Signal* signal);
void timerHandlingLab(Signal* signal);
void hbReceivedLab(Signal* signal);
@@ -354,12 +390,12 @@ private:
/* Status flags ----------------------------------*/
Uint32 c_restartPartialTimeout;
+ Uint32 c_restartPartionedTimeout;
+ Uint32 c_restartFailureTimeout;
+ Uint64 c_start_election_time;
Uint16 creadyDistCom;
- Uint16 c_regReqReqSent;
- Uint16 c_regReqReqRecv;
- Uint64 c_stopElectionTime;
- Uint16 cpresidentCandidate;
+
Uint16 cdelayRegreq;
Uint16 cpresidentAlive;
Uint16 cnoFailedNodes;
@@ -387,7 +423,9 @@ private:
Uint16 cfailedNodes[MAX_NDB_NODES];
Uint16 cprepFailedNodes[MAX_NDB_NODES];
Uint16 ccommitFailedNodes[MAX_NDB_NODES];
-
+
+ StopReq c_stopReq;
+ bool check_multi_node_shutdown(Signal* signal);
};
#endif
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
index 751641ae896..f14cbd48695 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp
@@ -35,9 +35,8 @@ void Qmgr::initData()
Uint32 hbDBAPI = 500;
setHbApiDelay(hbDBAPI);
-
- c_connectedNodes.clear();
c_connectedNodes.set(getOwnNodeId());
+ c_stopReq.senderRef = 0;
}//Qmgr::initData()
void Qmgr::initRecords()
@@ -52,6 +51,7 @@ Qmgr::Qmgr(const class Configuration & conf)
// Transit signals
addRecSignal(GSN_DUMP_STATE_ORD, &Qmgr::execDUMP_STATE_ORD);
+ addRecSignal(GSN_STOP_REQ, &Qmgr::execSTOP_REQ);
addRecSignal(GSN_DEBUG_SIG, &Qmgr::execDEBUG_SIG);
addRecSignal(GSN_CONTINUEB, &Qmgr::execCONTINUEB);
addRecSignal(GSN_CM_HEARTBEAT, &Qmgr::execCM_HEARTBEAT);
@@ -96,6 +96,12 @@ Qmgr::Qmgr(const class Configuration & conf)
addRecSignal(GSN_ARBIT_CHOOSEREF, &Qmgr::execARBIT_CHOOSEREF);
addRecSignal(GSN_ARBIT_STOPREP, &Qmgr::execARBIT_STOPREP);
+ addRecSignal(GSN_READ_NODESREF, &Qmgr::execREAD_NODESREF);
+ addRecSignal(GSN_READ_NODESCONF, &Qmgr::execREAD_NODESCONF);
+
+ addRecSignal(GSN_DIH_RESTARTREF, &Qmgr::execDIH_RESTARTREF);
+ addRecSignal(GSN_DIH_RESTARTCONF, &Qmgr::execDIH_RESTARTCONF);
+
initData();
}//Qmgr::Qmgr()
diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index 1cecf69aaad..9a7256b4a55 100644
--- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -56,6 +56,33 @@
#define DEBUG_START3(signal, msg)
#endif
+/**
+ * c_start.m_gsn = GSN_CM_REGREQ
+ * Possible for all nodes
+ * c_start.m_nodes contains all nodes in config
+ *
+ * c_start.m_gsn = GSN_CM_NODEINFOREQ;
+ * Set when receiving CM_REGCONF
+ * State possible for starting node only (not in cluster)
+ *
+ * c_start.m_nodes contains all node in alive cluster that
+ * that has not replied to GSN_CM_NODEINFOREQ
+ * passed by president in GSN_CM_REGCONF
+ *
+ * c_start.m_gsn = GSN_CM_ADD
+ * Possible for president only
+ * Set when receiving and accepting CM_REGREQ (to include node)
+ *
+ * c_start.m_nodes contains all nodes in alive cluster + starting node
+ * that has not replied to GSN_CM_ADD
+ * by sending GSN_CM_ACKADD
+ *
+ * c_start.m_gsn = GSN_CM_NODEINFOCONF
+ * Possible for non presidents only
+ * c_start.m_nodes contains a node that has been accepted by president
+ * but has not connected to us yet
+ */
+
// Signal entries and statement blocks
/* 4 P R O G R A M */
/*******************************/
@@ -119,6 +146,30 @@ void Qmgr::execCONTINUEB(Signal* signal)
runArbitThread(signal);
return;
break;
+ case ZSTART_FAILURE_LIMIT:{
+ if (cpresident != ZNIL)
+ {
+ jam();
+ return;
+ }
+ Uint64 now = NdbTick_CurrentMillisecond();
+ if (now > (c_start_election_time + c_restartFailureTimeout))
+ {
+ jam();
+ BaseString tmp;
+ tmp.append("Shutting down node as total restart time exceeds "
+ " StartFailureTimeout as set in config file ");
+ if(c_restartFailureTimeout == ~0)
+ tmp.append(" 0 (inifinite)");
+ else
+ tmp.appfmt(" %d", c_restartFailureTimeout);
+
+ progError(__LINE__, NDBD_EXIT_SYSTEM_ERROR, tmp.c_str());
+ }
+ signal->theData[0] = ZSTART_FAILURE_LIMIT;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 3000, 1);
+ return;
+ }
default:
jam();
// ZCOULD_NOT_OCCUR_ERROR;
@@ -246,14 +297,28 @@ void Qmgr::startphase1(Signal* signal)
nodePtr.p->phase = ZSTARTING;
nodePtr.p->blockRef = reference();
c_connectedNodes.set(nodePtr.i);
+
+ signal->theData[0] = reference();
+ sendSignal(DBDIH_REF, GSN_DIH_RESTARTREQ, signal, 1, JBB);
+ return;
+}
- signal->theData[0] = 0; // no answer
- signal->theData[1] = 0; // no id
- signal->theData[2] = NodeInfo::DB;
- sendSignal(CMVMI_REF, GSN_OPEN_COMREQ, signal, 3, JBB);
+void
+Qmgr::execDIH_RESTARTREF(Signal*signal)
+{
+ jamEntry();
+ c_start.m_latest_gci = 0;
+ execCM_INFOCONF(signal);
+}
+
+void
+Qmgr::execDIH_RESTARTCONF(Signal*signal)
+{
+ jamEntry();
+
+ c_start.m_latest_gci = signal->theData[1];
execCM_INFOCONF(signal);
- return;
}
void Qmgr::setHbDelay(UintR aHbDelay)
@@ -280,18 +345,24 @@ void Qmgr::execCONNECT_REP(Signal* signal)
{
jamEntry();
const Uint32 nodeId = signal->theData[0];
+
+ if (ERROR_INSERTED(931))
+ {
+ jam();
+ ndbout_c("Discarding CONNECT_REP(%d)", nodeId);
+ infoEvent("Discarding CONNECT_REP(%d)", nodeId);
+ return;
+ }
+
c_connectedNodes.set(nodeId);
NodeRecPtr nodePtr;
nodePtr.i = getOwnNodeId();
ptrCheckGuard(nodePtr, MAX_NODES, nodeRec);
switch(nodePtr.p->phase){
- case ZSTARTING:
case ZRUNNING:
+ ndbrequire(!c_clusterNodes.get(nodeId));
+ case ZSTARTING:
jam();
- if(!c_start.m_nodes.isWaitingFor(nodeId)){
- jam();
- return;
- }
break;
case ZPREPARE_FAIL:
case ZFAIL_CLOSING:
@@ -303,59 +374,126 @@ void Qmgr::execCONNECT_REP(Signal* signal)
case ZAPI_INACTIVE:
return;
}
-
+
+ if (getNodeInfo(nodeId).getType() != NodeInfo::DB)
+ {
+ jam();
+ return;
+ }
+
switch(c_start.m_gsn){
case GSN_CM_REGREQ:
jam();
sendCmRegReq(signal, nodeId);
+
+ /**
+ * We're waiting for CM_REGCONF c_start.m_nodes contains all configured
+ * nodes
+ */
+ ndbrequire(nodePtr.p->phase == ZSTARTING);
+ ndbrequire(c_start.m_nodes.isWaitingFor(nodeId));
return;
case GSN_CM_NODEINFOREQ:
jam();
- sendCmNodeInfoReq(signal, nodeId, nodePtr.p);
+
+ if (c_start.m_nodes.isWaitingFor(nodeId))
+ {
+ jam();
+ ndbrequire(getOwnNodeId() != cpresident);
+ ndbrequire(nodePtr.p->phase == ZSTARTING);
+ sendCmNodeInfoReq(signal, nodeId, nodePtr.p);
+ return;
+ }
return;
- case GSN_CM_ADD:{
+ case GSN_CM_NODEINFOCONF:{
jam();
-
- ndbrequire(getOwnNodeId() != cpresident);
- c_start.m_nodes.clearWaitingFor(nodeId);
- c_start.m_gsn = RNIL;
- NodeRecPtr addNodePtr;
- addNodePtr.i = nodeId;
- ptrCheckGuard(addNodePtr, MAX_NDB_NODES, nodeRec);
- cmAddPrepare(signal, addNodePtr, nodePtr.p);
- return;
+ ndbrequire(getOwnNodeId() != cpresident);
+ ndbrequire(nodePtr.p->phase == ZRUNNING);
+ if (c_start.m_nodes.isWaitingFor(nodeId))
+ {
+ jam();
+ c_start.m_nodes.clearWaitingFor(nodeId);
+ c_start.m_gsn = RNIL;
+
+ NodeRecPtr addNodePtr;
+ addNodePtr.i = nodeId;
+ ptrCheckGuard(addNodePtr, MAX_NDB_NODES, nodeRec);
+ cmAddPrepare(signal, addNodePtr, nodePtr.p);
+ return;
+ }
}
default:
- return;
+ (void)1;
}
+
+ ndbrequire(!c_start.m_nodes.isWaitingFor(nodeId));
+ ndbrequire(!c_readnodes_nodes.get(nodeId));
+ c_readnodes_nodes.set(nodeId);
+ signal->theData[0] = reference();
+ sendSignal(calcQmgrBlockRef(nodeId), GSN_READ_NODESREQ, signal, 1, JBA);
return;
}//Qmgr::execCONNECT_REP()
+void
+Qmgr::execREAD_NODESCONF(Signal* signal)
+{
+ check_readnodes_reply(signal,
+ refToNode(signal->getSendersBlockRef()),
+ GSN_READ_NODESCONF);
+}
+
+void
+Qmgr::execREAD_NODESREF(Signal* signal)
+{
+ check_readnodes_reply(signal,
+ refToNode(signal->getSendersBlockRef()),
+ GSN_READ_NODESREF);
+}
+
/*******************************/
/* CM_INFOCONF */
/*******************************/
void Qmgr::execCM_INFOCONF(Signal* signal)
{
+ /**
+ * Open communcation to all DB nodes
+ */
+ signal->theData[0] = 0; // no answer
+ signal->theData[1] = 0; // no id
+ signal->theData[2] = NodeInfo::DB;
+ sendSignal(CMVMI_REF, GSN_OPEN_COMREQ, signal, 3, JBB);
+
cpresident = ZNIL;
- cpresidentCandidate = getOwnNodeId();
cpresidentAlive = ZFALSE;
- c_stopElectionTime = NdbTick_CurrentMillisecond();
- c_stopElectionTime += c_restartPartialTimeout;
+ c_start_election_time = NdbTick_CurrentMillisecond();
+
+ signal->theData[0] = ZSTART_FAILURE_LIMIT;
+ sendSignalWithDelay(reference(), GSN_CONTINUEB, signal, 3000, 1);
+
cmInfoconf010Lab(signal);
return;
}//Qmgr::execCM_INFOCONF()
+Uint32 g_start_type = 0;
+NdbNodeBitmask g_nowait_nodes; // Set by clo
+
void Qmgr::cmInfoconf010Lab(Signal* signal)
{
c_start.m_startKey = 0;
c_start.m_startNode = getOwnNodeId();
c_start.m_nodes.clearWaitingFor();
c_start.m_gsn = GSN_CM_REGREQ;
+ c_start.m_starting_nodes.clear();
+ c_start.m_starting_nodes_w_log.clear();
+ c_start.m_regReqReqSent = 0;
+ c_start.m_regReqReqRecv = 0;
+ c_start.m_skip_nodes = g_nowait_nodes;
+ c_start.m_skip_nodes.bitAND(c_definedNodes);
+ c_start.m_start_type = g_start_type;
NodeRecPtr nodePtr;
- c_regReqReqSent = c_regReqReqRecv = 0;
cnoOfNodes = 0;
for (nodePtr.i = 1; nodePtr.i < MAX_NDB_NODES; nodePtr.i++) {
jam();
@@ -390,14 +528,18 @@ void Qmgr::cmInfoconf010Lab(Signal* signal)
void
Qmgr::sendCmRegReq(Signal * signal, Uint32 nodeId){
- c_regReqReqSent++;
- CmRegReq * const cmRegReq = (CmRegReq *)&signal->theData[0];
- cmRegReq->blockRef = reference();
- cmRegReq->nodeId = getOwnNodeId();
- cmRegReq->version = NDB_VERSION;
+ CmRegReq * req = (CmRegReq *)&signal->theData[0];
+ req->blockRef = reference();
+ req->nodeId = getOwnNodeId();
+ req->version = NDB_VERSION;
+ req->latest_gci = c_start.m_latest_gci;
+ req->start_type = c_start.m_start_type;
+ c_start.m_skip_nodes.copyto(NdbNodeBitmask::Size, req->skip_nodes);
const Uint32 ref = calcQmgrBlockRef(nodeId);
sendSignal(ref, GSN_CM_REGREQ, signal, CmRegReq::SignalLength, JBB);
DEBUG_START(GSN_CM_REGREQ, nodeId, "");
+
+ c_start.m_regReqReqSent++;
}
/*
@@ -437,6 +579,18 @@ Qmgr::sendCmRegReq(Signal * signal, Uint32 nodeId){
/*******************************/
/* CM_REGREQ */
/*******************************/
+static
+int
+check_start_type(Uint32 starting, Uint32 own)
+{
+ if (starting == (1 << NodeState::ST_INITIAL_START) &&
+ ((own & (1 << NodeState::ST_INITIAL_START)) == 0))
+ {
+ return 1;
+ }
+ return 0;
+}
+
void Qmgr::execCM_REGREQ(Signal* signal)
{
DEBUG_START3(signal, "");
@@ -448,6 +602,17 @@ void Qmgr::execCM_REGREQ(Signal* signal)
const BlockReference Tblockref = cmRegReq->blockRef;
const Uint32 startingVersion = cmRegReq->version;
addNodePtr.i = cmRegReq->nodeId;
+ Uint32 gci = 1;
+ Uint32 start_type = ~0;
+ NdbNodeBitmask skip_nodes;
+
+ if (signal->getLength() == CmRegReq::SignalLength)
+ {
+ jam();
+ gci = cmRegReq->latest_gci;
+ start_type = cmRegReq->start_type;
+ skip_nodes.assign(NdbNodeBitmask::Size, cmRegReq->skip_nodes);
+ }
if (creadyDistCom == ZFALSE) {
jam();
@@ -461,11 +626,19 @@ void Qmgr::execCM_REGREQ(Signal* signal)
return;
}
- ptrCheckGuard(addNodePtr, MAX_NDB_NODES, nodeRec);
-
- if (cpresident != getOwnNodeId()){
+ if (check_start_type(start_type, c_start.m_start_type))
+ {
+ jam();
+ sendCmRegrefLab(signal, Tblockref, CmRegRef::ZINCOMPATIBLE_START_TYPE);
+ return;
+ }
+
+ if (cpresident != getOwnNodeId())
+ {
jam();
- if (cpresident == ZNIL) {
+
+ if (cpresident == ZNIL)
+ {
/***
* We don't know the president.
* If the node to be added has lower node id
@@ -473,13 +646,18 @@ void Qmgr::execCM_REGREQ(Signal* signal)
* candidate
*/
jam();
- if (addNodePtr.i < cpresidentCandidate) {
+ if (gci > c_start.m_president_candidate_gci ||
+ (gci == c_start.m_president_candidate_gci &&
+ addNodePtr.i < c_start.m_president_candidate))
+ {
jam();
- cpresidentCandidate = addNodePtr.i;
- }//if
+ c_start.m_president_candidate = addNodePtr.i;
+ c_start.m_president_candidate_gci = gci;
+ }
sendCmRegrefLab(signal, Tblockref, CmRegRef::ZELECTION);
return;
- }
+ }
+
/**
* We are not the president.
* We know the president.
@@ -489,7 +667,8 @@ void Qmgr::execCM_REGREQ(Signal* signal)
return;
}//if
- if (c_start.m_startNode != 0){
+ if (c_start.m_startNode != 0)
+ {
jam();
/**
* President busy by adding another node
@@ -498,7 +677,8 @@ void Qmgr::execCM_REGREQ(Signal* signal)
return;
}//if
- if (ctoStatus == Q_ACTIVE) {
+ if (ctoStatus == Q_ACTIVE)
+ {
jam();
/**
* Active taking over as president
@@ -507,7 +687,8 @@ void Qmgr::execCM_REGREQ(Signal* signal)
return;
}//if
- if (getNodeInfo(addNodePtr.i).m_type != NodeInfo::DB) {
+ if (getNodeInfo(addNodePtr.i).m_type != NodeInfo::DB)
+ {
jam();
/**
* The new node is not in config file
@@ -516,13 +697,15 @@ void Qmgr::execCM_REGREQ(Signal* signal)
return;
}
+ ptrCheckGuard(addNodePtr, MAX_NDB_NODES, nodeRec);
Phase phase = addNodePtr.p->phase;
- if (phase != ZINIT){
+ if (phase != ZINIT)
+ {
jam();
DEBUG("phase = " << phase);
sendCmRegrefLab(signal, Tblockref, CmRegRef::ZNOT_DEAD);
return;
- }//if
+ }
jam();
/**
@@ -594,7 +777,12 @@ void Qmgr::sendCmRegrefLab(Signal* signal, BlockReference TBRef,
ref->blockRef = reference();
ref->nodeId = getOwnNodeId();
ref->errorCode = Terror;
- ref->presidentCandidate = (cpresident == ZNIL ? cpresidentCandidate : cpresident);
+ ref->presidentCandidate =
+ (cpresident == ZNIL ? c_start.m_president_candidate : cpresident);
+ ref->candidate_latest_gci = c_start.m_president_candidate_gci;
+ ref->latest_gci = c_start.m_latest_gci;
+ ref->start_type = c_start.m_start_type;
+ c_start.m_skip_nodes.copyto(NdbNodeBitmask::Size, ref->skip_nodes);
sendSignal(TBRef, GSN_CM_REGREF, signal,
CmRegRef::SignalLength, JBB);
DEBUG_START(GSN_CM_REGREF, refToNode(TBRef), "");
@@ -622,22 +810,33 @@ void Qmgr::execCM_REGCONF(Signal* signal)
jamEntry();
const CmRegConf * const cmRegConf = (CmRegConf *)&signal->theData[0];
+ Uint32 presidentNodeId = cmRegConf->presidentNodeId;
if (!ndbCompatible_ndb_ndb(NDB_VERSION, cmRegConf->presidentVersion)) {
jam();
char buf[128];
- BaseString::snprintf(buf,sizeof(buf),"incompatible version own=0x%x other=0x%x, shutting down", NDB_VERSION, cmRegConf->presidentVersion);
+ BaseString::snprintf(buf,sizeof(buf),
+ "incompatible version own=0x%x other=0x%x, "
+ " shutting down",
+ NDB_VERSION, cmRegConf->presidentVersion);
systemErrorLab(signal, __LINE__, buf);
return;
}
-
+ myNodePtr.i = getOwnNodeId();
+ ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
+
+ ndbrequire(c_start.m_gsn == GSN_CM_REGREQ);
+ ndbrequire(myNodePtr.p->phase = ZSTARTING);
+
cpdistref = cmRegConf->presidentBlockRef;
cpresident = cmRegConf->presidentNodeId;
UintR TdynamicId = cmRegConf->dynamicId;
c_maxDynamicId = TdynamicId;
c_clusterNodes.assign(NdbNodeBitmask::Size, cmRegConf->allNdbNodes);
+ myNodePtr.p->ndynamicId = TdynamicId;
+
/*--------------------------------------------------------------*/
// Send this as an EVENT REPORT to inform about hearing about
// other NDB node proclaiming to be president.
@@ -648,10 +847,6 @@ void Qmgr::execCM_REGCONF(Signal* signal)
signal->theData[3] = TdynamicId;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB);
- myNodePtr.i = getOwnNodeId();
- ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
- myNodePtr.p->ndynamicId = TdynamicId;
-
for (nodePtr.i = 1; nodePtr.i < MAX_NDB_NODES; nodePtr.i++) {
jam();
if (c_clusterNodes.get(nodePtr.i)){
@@ -675,6 +870,84 @@ void Qmgr::execCM_REGCONF(Signal* signal)
}//Qmgr::execCM_REGCONF()
void
+Qmgr::check_readnodes_reply(Signal* signal, Uint32 nodeId, Uint32 gsn)
+{
+ NodeRecPtr myNodePtr;
+ myNodePtr.i = getOwnNodeId();
+ ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
+
+ NodeRecPtr nodePtr;
+ nodePtr.i = nodeId;
+ ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRec);
+
+ ndbrequire(c_readnodes_nodes.get(nodeId));
+ ReadNodesConf* conf = (ReadNodesConf*)signal->getDataPtr();
+ if (gsn == GSN_READ_NODESREF)
+ {
+ jam();
+retry:
+ signal->theData[0] = reference();
+ sendSignal(calcQmgrBlockRef(nodeId), GSN_READ_NODESREQ, signal, 1, JBA);
+ return;
+ }
+
+ if (conf->masterNodeId == ZNIL)
+ {
+ jam();
+ goto retry;
+ }
+
+ Uint32 president = conf->masterNodeId;
+ if (president == cpresident)
+ {
+ jam();
+ c_readnodes_nodes.clear(nodeId);
+ return;
+ }
+
+ char buf[255];
+ BaseString::snprintf(buf, sizeof(buf),
+ "Partitioned cluster! check StartPartialTimeout, "
+ " node %d thinks %d is president, "
+ " I think president is: %d",
+ nodeId, president, cpresident);
+
+ ndbout_c(buf);
+ CRASH_INSERTION(933);
+
+ if (getNodeState().startLevel == NodeState::SL_STARTED)
+ {
+ jam();
+ NdbNodeBitmask part;
+ part.assign(NdbNodeBitmask::Size, conf->clusterNodes);
+ FailRep* rep = (FailRep*)signal->getDataPtrSend();
+ rep->failCause = FailRep::ZPARTITIONED_CLUSTER;
+ rep->president = cpresident;
+ c_clusterNodes.copyto(NdbNodeBitmask::Size, rep->partition);
+ Uint32 ref = calcQmgrBlockRef(nodeId);
+ Uint32 i = 0;
+ while((i = part.find(i + 1)) != NdbNodeBitmask::NotFound)
+ {
+ if (i == nodeId)
+ continue;
+ rep->failNodeId = i;
+ sendSignal(ref, GSN_FAIL_REP, signal, FailRep::SignalLength, JBA);
+ }
+ rep->failNodeId = nodeId;
+ sendSignal(ref, GSN_FAIL_REP, signal, FailRep::SignalLength, JBB);
+ return;
+ }
+
+ CRASH_INSERTION(932);
+
+ progError(__LINE__,
+ NDBD_EXIT_ARBIT_SHUTDOWN,
+ buf);
+
+ ndbrequire(false);
+}
+
+void
Qmgr::sendCmNodeInfoReq(Signal* signal, Uint32 nodeId, const NodeRec * self){
CmNodeInfoReq * const req = (CmNodeInfoReq*)signal->getDataPtrSend();
req->nodeId = getOwnNodeId();
@@ -703,26 +976,105 @@ Qmgr::sendCmNodeInfoReq(Signal* signal, Uint32 nodeId, const NodeRec * self){
/*******************************/
/* CM_REGREF */
/*******************************/
+static
+const char *
+get_start_type_string(Uint32 st)
+{
+ static char buf[256];
+
+ if (st == 0)
+ {
+ return "<ANY>";
+ }
+ else
+ {
+ buf[0] = 0;
+ for(Uint32 i = 0; i<NodeState::ST_ILLEGAL_TYPE; i++)
+ {
+ if (st & (1 << i))
+ {
+ if (buf[0])
+ strcat(buf, "/");
+ switch(i){
+ case NodeState::ST_INITIAL_START:
+ strcat(buf, "inital start");
+ break;
+ case NodeState::ST_SYSTEM_RESTART:
+ strcat(buf, "system restart");
+ break;
+ case NodeState::ST_NODE_RESTART:
+ strcat(buf, "node restart");
+ break;
+ case NodeState::ST_INITIAL_NODE_RESTART:
+ strcat(buf, "initial node restart");
+ break;
+ }
+ }
+ }
+ return buf;
+ }
+}
+
void Qmgr::execCM_REGREF(Signal* signal)
{
jamEntry();
- c_regReqReqRecv++;
- // Ignore block reference in data[0]
- UintR TaddNodeno = signal->theData[1];
- UintR TrefuseReason = signal->theData[2];
- Uint32 candidate = signal->theData[3];
+ CmRegRef* ref = (CmRegRef*)signal->getDataPtr();
+ UintR TaddNodeno = ref->nodeId;
+ UintR TrefuseReason = ref->errorCode;
+ Uint32 candidate = ref->presidentCandidate;
+ Uint32 node_gci = 1;
+ Uint32 candidate_gci = 1;
+ Uint32 start_type = ~0;
+ NdbNodeBitmask skip_nodes;
DEBUG_START3(signal, TrefuseReason);
-
- if(candidate != cpresidentCandidate){
+
+ if (signal->getLength() == CmRegRef::SignalLength)
+ {
jam();
- c_regReqReqRecv = ~0;
+ node_gci = ref->latest_gci;
+ candidate_gci = ref->candidate_latest_gci;
+ start_type = ref->start_type;
+ skip_nodes.assign(NdbNodeBitmask::Size, ref->skip_nodes);
}
+
+ c_start.m_regReqReqRecv++;
+ // Ignore block reference in data[0]
+
+ if(candidate != c_start.m_president_candidate)
+ {
+ jam();
+ c_start.m_regReqReqRecv = ~0;
+ }
+
+ c_start.m_starting_nodes.set(TaddNodeno);
+ if (node_gci)
+ {
+ jam();
+ c_start.m_starting_nodes_w_log.set(TaddNodeno);
+ }
+
+ skip_nodes.bitAND(c_definedNodes);
+ c_start.m_skip_nodes.bitOR(skip_nodes);
+
+ char buf[100];
switch (TrefuseReason) {
case CmRegRef::ZINCOMPATIBLE_VERSION:
jam();
- systemErrorLab(signal, __LINE__, "incompatible version, connection refused by running ndb node");
+ systemErrorLab(signal, __LINE__,
+ "incompatible version, "
+ "connection refused by running ndb node");
+ case CmRegRef::ZINCOMPATIBLE_START_TYPE:
+ jam();
+ BaseString::snprintf(buf, sizeof(buf),
+ "incompatible start type detected: node %d"
+ " reports %s(%d) my start type: %s(%d)",
+ TaddNodeno,
+ get_start_type_string(start_type), start_type,
+ get_start_type_string(c_start.m_start_type),
+ c_start.m_start_type);
+ progError(__LINE__, NDBD_EXIT_SR_RESTARTCONFLICT, buf);
break;
case CmRegRef::ZBUSY:
case CmRegRef::ZBUSY_TO_PRES:
@@ -741,14 +1093,18 @@ void Qmgr::execCM_REGREF(Signal* signal)
break;
case CmRegRef::ZELECTION:
jam();
- if (cpresidentCandidate > TaddNodeno) {
+ if (candidate_gci > c_start.m_president_candidate_gci ||
+ (candidate_gci == c_start.m_president_candidate_gci &&
+ candidate < c_start.m_president_candidate))
+ {
jam();
//----------------------------------------
/* We may already have a candidate */
/* choose the lowest nodeno */
//----------------------------------------
signal->theData[3] = 2;
- cpresidentCandidate = TaddNodeno;
+ c_start.m_president_candidate = candidate;
+ c_start.m_president_candidate_gci = candidate_gci;
} else {
signal->theData[3] = 4;
}//if
@@ -776,32 +1132,34 @@ void Qmgr::execCM_REGREF(Signal* signal)
//-----------------------------------------
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB);
- if(cpresidentAlive == ZTRUE){
+ if(cpresidentAlive == ZTRUE)
+ {
jam();
- DEBUG("");
+ DEBUG("cpresidentAlive");
return;
}
- if(c_regReqReqSent != c_regReqReqRecv){
+ if(c_start.m_regReqReqSent != c_start.m_regReqReqRecv)
+ {
jam();
- DEBUG( c_regReqReqSent << " != " << c_regReqReqRecv);
+ DEBUG(c_start.m_regReqReqSent << " != " << c_start.m_regReqReqRecv);
return;
}
- if(cpresidentCandidate != getOwnNodeId()){
+ if(c_start.m_president_candidate != getOwnNodeId())
+ {
jam();
- DEBUG("");
+ DEBUG("i'm not the candidate");
return;
}
-
+
/**
- * All configured nodes has agreed
+ * All connected nodes has agreed
*/
- Uint64 now = NdbTick_CurrentMillisecond();
- if((c_regReqReqRecv == cnoOfNodes) || now > c_stopElectionTime){
+ if(check_startup(signal))
+ {
jam();
- electionWon();
- sendSttorryLab(signal);
+ electionWon(signal);
/**
* Start timer handling
@@ -813,8 +1171,193 @@ void Qmgr::execCM_REGREF(Signal* signal)
return;
}//Qmgr::execCM_REGREF()
+Uint32
+Qmgr::check_startup(Signal* signal)
+{
+ Uint64 now = NdbTick_CurrentMillisecond();
+ Uint64 partial_timeout = c_start_election_time + c_restartPartialTimeout;
+ Uint64 partitioned_timeout = partial_timeout + c_restartPartionedTimeout;
+
+ /**
+ * First see if we should wait more...
+ */
+ NdbNodeBitmask tmp;
+ tmp.bitOR(c_start.m_skip_nodes);
+ tmp.bitOR(c_start.m_starting_nodes);
+
+ NdbNodeBitmask wait;
+ wait.assign(c_definedNodes);
+ wait.bitANDC(tmp);
+
+ Uint32 retVal = 0;
+ NdbNodeBitmask report_mask;
+
+ if ((c_start.m_latest_gci == 0) ||
+ (c_start.m_start_type == (1 << NodeState::ST_INITIAL_START)))
+ {
+ if (!tmp.equal(c_definedNodes))
+ {
+ jam();
+ signal->theData[1] = 1;
+ signal->theData[2] = ~0;
+ report_mask.assign(wait);
+ retVal = 0;
+ goto start_report;
+ }
+ else
+ {
+ jam();
+ signal->theData[1] = 0x8000;
+ report_mask.assign(c_definedNodes);
+ report_mask.bitANDC(c_start.m_starting_nodes);
+ retVal = 1;
+ goto start_report;
+ }
+ }
+ {
+ const bool all = c_start.m_starting_nodes.equal(c_definedNodes);
+ CheckNodeGroups* sd = (CheckNodeGroups*)&signal->theData[0];
+
+ {
+ /**
+ * Check for missing node group directly
+ */
+ char buf[100];
+ NdbNodeBitmask check;
+ check.assign(c_definedNodes);
+ check.bitANDC(c_start.m_starting_nodes); // Not connected nodes
+ check.bitOR(c_start.m_starting_nodes_w_log);
+
+ sd->blockRef = reference();
+ sd->requestType = CheckNodeGroups::Direct | CheckNodeGroups::ArbitCheck;
+ sd->mask = check;
+ EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal,
+ CheckNodeGroups::SignalLength);
+
+ if (sd->output == CheckNodeGroups::Lose)
+ {
+ jam();
+ goto missing_nodegroup;
+ }
+ }
+
+ sd->blockRef = reference();
+ sd->requestType = CheckNodeGroups::Direct | CheckNodeGroups::ArbitCheck;
+ sd->mask = c_start.m_starting_nodes;
+ EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal,
+ CheckNodeGroups::SignalLength);
+
+ const Uint32 result = sd->output;
+
+ sd->blockRef = reference();
+ sd->requestType = CheckNodeGroups::Direct | CheckNodeGroups::ArbitCheck;
+ sd->mask = c_start.m_starting_nodes_w_log;
+ EXECUTE_DIRECT(DBDIH, GSN_CHECKNODEGROUPSREQ, signal,
+ CheckNodeGroups::SignalLength);
+
+ const Uint32 result_w_log = sd->output;
+
+ if (tmp.equal(c_definedNodes))
+ {
+ /**
+ * All nodes (wrt no-wait nodes) has connected...
+ * this means that we will now start or die
+ */
+ jam();
+ switch(result_w_log){
+ case CheckNodeGroups::Lose:
+ {
+ jam();
+ goto missing_nodegroup;
+ }
+ case CheckNodeGroups::Win:
+ signal->theData[1] = all ? 0x8001 : 0x8002;
+ report_mask.assign(c_definedNodes);
+ report_mask.bitANDC(c_start.m_starting_nodes);
+ retVal = 1;
+ goto start_report;
+ case CheckNodeGroups::Partitioning:
+ ndbrequire(result != CheckNodeGroups::Lose);
+ signal->theData[1] =
+ all ? 0x8001 : (result == CheckNodeGroups::Win ? 0x8002 : 0x8003);
+ report_mask.assign(c_definedNodes);
+ report_mask.bitANDC(c_start.m_starting_nodes);
+ retVal = 1;
+ goto start_report;
+ }
+ }
+
+ if (now < partial_timeout)
+ {
+ jam();
+ signal->theData[1] = c_restartPartialTimeout == ~0 ? 2 : 3;
+ signal->theData[2] = Uint32((partial_timeout - now + 500) / 1000);
+ report_mask.assign(wait);
+ retVal = 0;
+ goto start_report;
+ }
+
+ /**
+ * Start partial has passed...check for partitioning...
+ */
+ switch(result_w_log){
+ case CheckNodeGroups::Lose:
+ jam();
+ goto missing_nodegroup;
+ case CheckNodeGroups::Partitioning:
+ if (now < partitioned_timeout && result != CheckNodeGroups::Win)
+ {
+ signal->theData[1] = c_restartPartionedTimeout == ~0 ? 4 : 5;
+ signal->theData[2] = Uint32((partitioned_timeout - now + 500) / 1000);
+ report_mask.assign(c_definedNodes);
+ report_mask.bitANDC(c_start.m_starting_nodes);
+ retVal = 0;
+ goto start_report;
+ }
+ // Fall through...
+ case CheckNodeGroups::Win:
+ signal->theData[1] =
+ all ? 0x8001 : (result == CheckNodeGroups::Win ? 0x8002 : 0x8003);
+ report_mask.assign(c_definedNodes);
+ report_mask.bitANDC(c_start.m_starting_nodes);
+ retVal = 1;
+ goto start_report;
+ }
+ }
+ ndbrequire(false);
+
+start_report:
+ jam();
+ {
+ Uint32 sz = NdbNodeBitmask::Size;
+ signal->theData[0] = NDB_LE_StartReport;
+ signal->theData[3] = sz;
+ Uint32* ptr = signal->theData+4;
+ c_definedNodes.copyto(sz, ptr); ptr += sz;
+ c_start.m_starting_nodes.copyto(sz, ptr); ptr += sz;
+ c_start.m_skip_nodes.copyto(sz, ptr); ptr += sz;
+ report_mask.copyto(sz, ptr); ptr+= sz;
+ sendSignal(CMVMI_REF, GSN_EVENT_REP, signal,
+ 4+4*NdbNodeBitmask::Size, JBB);
+ }
+ return retVal;
+
+missing_nodegroup:
+ jam();
+ char buf[100], mask1[100], mask2[100];
+ c_start.m_starting_nodes.getText(mask1);
+ tmp.assign(c_start.m_starting_nodes);
+ tmp.bitANDC(c_start.m_starting_nodes_w_log);
+ tmp.getText(mask2);
+ BaseString::snprintf(buf, sizeof(buf),
+ "Unable to start missing node group! "
+ " starting: %s (missing fs for: %s)",
+ mask1, mask2);
+ progError(__LINE__, NDBD_EXIT_SR_RESTARTCONFLICT, buf);
+}
+
void
-Qmgr::electionWon(){
+Qmgr::electionWon(Signal* signal){
NodeRecPtr myNodePtr;
cpresident = getOwnNodeId(); /* This node becomes president. */
myNodePtr.i = getOwnNodeId();
@@ -831,8 +1374,21 @@ Qmgr::electionWon(){
c_clusterNodes.set(getOwnNodeId());
cpresidentAlive = ZTRUE;
- c_stopElectionTime = ~0;
+ c_start_election_time = ~0;
c_start.reset();
+
+ signal->theData[0] = NDB_LE_CM_REGCONF;
+ signal->theData[1] = getOwnNodeId();
+ signal->theData[2] = cpresident;
+ signal->theData[3] = 1;
+ sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB);
+
+ c_start.m_starting_nodes.clear(getOwnNodeId());
+ if (c_start.m_starting_nodes.isclear())
+ {
+ jam();
+ sendSttorryLab(signal);
+ }
}
/*
@@ -846,7 +1402,14 @@ Qmgr::electionWon(){
/*--------------------------------------------------------------*/
void Qmgr::regreqTimeLimitLab(Signal* signal)
{
- if(cpresident == ZNIL){
+ if(cpresident == ZNIL)
+ {
+ if (c_start.m_president_candidate == ZNIL)
+ {
+ jam();
+ c_start.m_president_candidate = getOwnNodeId();
+ }
+
cmInfoconf010Lab(signal);
}
}//Qmgr::regreqTimelimitLab()
@@ -967,7 +1530,7 @@ Qmgr::cmAddPrepare(Signal* signal, NodeRecPtr nodePtr, const NodeRec * self){
ndbrequire(signal->header.theVerId_signalNumber == GSN_CM_ADD);
c_start.m_nodes.clearWaitingFor();
c_start.m_nodes.setWaitingFor(nodePtr.i);
- c_start.m_gsn = GSN_CM_ADD;
+ c_start.m_gsn = GSN_CM_NODEINFOCONF;
#else
warningEvent("Enabling communication to CM_ADD node %u state=%d",
nodePtr.i,
@@ -1256,6 +1819,17 @@ void Qmgr::execCM_ACKADD(Signal* signal)
*/
handleArbitNdbAdd(signal, addNodePtr.i);
c_start.reset();
+
+ if (c_start.m_starting_nodes.get(addNodePtr.i))
+ {
+ jam();
+ c_start.m_starting_nodes.clear(addNodePtr.i);
+ if (c_start.m_starting_nodes.isclear())
+ {
+ jam();
+ sendSttorryLab(signal);
+ }
+ }
return;
}//switch
ndbrequire(false);
@@ -1409,7 +1983,8 @@ void Qmgr::initData(Signal* signal)
cnoPrepFailedNodes = 0;
creadyDistCom = ZFALSE;
cpresident = ZNIL;
- cpresidentCandidate = ZNIL;
+ c_start.m_president_candidate = ZNIL;
+ c_start.m_president_candidate_gci = 0;
cpdistref = 0;
cneighbourh = ZNIL;
cneighbourl = ZNIL;
@@ -1437,15 +2012,33 @@ void Qmgr::initData(Signal* signal)
Uint32 hbDBAPI = 1500;
Uint32 arbitTimeout = 1000;
c_restartPartialTimeout = 30000;
+ c_restartPartionedTimeout = 60000;
+ c_restartFailureTimeout = ~0;
ndb_mgm_get_int_parameter(p, CFG_DB_HEARTBEAT_INTERVAL, &hbDBDB);
ndb_mgm_get_int_parameter(p, CFG_DB_API_HEARTBEAT_INTERVAL, &hbDBAPI);
ndb_mgm_get_int_parameter(p, CFG_DB_ARBIT_TIMEOUT, &arbitTimeout);
ndb_mgm_get_int_parameter(p, CFG_DB_START_PARTIAL_TIMEOUT,
&c_restartPartialTimeout);
- if(c_restartPartialTimeout == 0){
+ ndb_mgm_get_int_parameter(p, CFG_DB_START_PARTITION_TIMEOUT,
+ &c_restartPartionedTimeout);
+ ndb_mgm_get_int_parameter(p, CFG_DB_START_FAILURE_TIMEOUT,
+ &c_restartFailureTimeout);
+
+ if(c_restartPartialTimeout == 0)
+ {
c_restartPartialTimeout = ~0;
}
+ if (c_restartPartionedTimeout ==0)
+ {
+ c_restartPartionedTimeout = ~0;
+ }
+
+ if (c_restartFailureTimeout == 0)
+ {
+ c_restartFailureTimeout = ~0;
+ }
+
setHbDelay(hbDBDB);
setHbApiDelay(hbDBAPI);
setArbitTimeout(arbitTimeout);
@@ -1872,10 +2465,23 @@ void Qmgr::execDISCONNECT_REP(Signal* signal)
const Uint32 nodeId = rep->nodeId;
const Uint32 err = rep->err;
c_connectedNodes.clear(nodeId);
-
+ c_readnodes_nodes.clear(nodeId);
+
NodeRecPtr nodePtr;
nodePtr.i = getOwnNodeId();
ptrCheckGuard(nodePtr, MAX_NODES, nodeRec);
+
+ char buf[100];
+ if (getNodeInfo(nodeId).getType() == NodeInfo::DB &&
+ getNodeState().startLevel < NodeState::SL_STARTED)
+ {
+ jam();
+ CRASH_INSERTION(932);
+ BaseString::snprintf(buf, 100, "Node %u disconected", nodeId);
+ progError(__LINE__, NDBD_EXIT_SR_OTHERNODEFAILED, buf);
+ ndbrequire(false);
+ }
+
switch(nodePtr.p->phase){
case ZRUNNING:
jam();
@@ -1893,9 +2499,12 @@ void Qmgr::execDISCONNECT_REP(Signal* signal)
case ZAPI_ACTIVE:
ndbrequire(false);
case ZAPI_INACTIVE:
+ {
+ BaseString::snprintf(buf, 100, "Node %u disconected", nodeId);
+ progError(__LINE__, NDBD_EXIT_SR_OTHERNODEFAILED, buf);
ndbrequire(false);
}
-
+ }
node_failed(signal, nodeId);
}//DISCONNECT_REP
@@ -2150,10 +2759,20 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode,
failedNodePtr.i = aFailedNode;
ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec);
+ FailRep* rep = (FailRep*)signal->getDataPtr();
+
+ if (check_multi_node_shutdown(signal))
+ {
+ jam();
+ return;
+ }
+
if (failedNodePtr.i == getOwnNodeId()) {
jam();
+ Uint32 code = 0;
const char * msg = 0;
+ char extra[100];
switch(aFailCause){
case FailRep::ZOWN_FAILURE:
msg = "Own failure";
@@ -2174,17 +2793,51 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode,
case FailRep::ZLINK_FAILURE:
msg = "Connection failure";
break;
+ case FailRep::ZPARTITIONED_CLUSTER:
+ {
+ code = NDBD_EXIT_ARBIT_SHUTDOWN;
+ char buf1[100], buf2[100];
+ c_clusterNodes.getText(buf1);
+ if (signal->getLength()== FailRep::SignalLength + FailRep::ExtraLength &&
+ signal->header.theVerId_signalNumber == GSN_FAIL_REP)
+ {
+ jam();
+ NdbNodeBitmask part;
+ part.assign(NdbNodeBitmask::Size, rep->partition);
+ part.getText(buf2);
+ BaseString::snprintf(extra, sizeof(extra),
+ "Partitioned cluster!"
+ " Our cluster: %s other cluster: %s",
+ buf1, buf2);
+ }
+ else
+ {
+ jam();
+ BaseString::snprintf(extra, sizeof(extra),
+ "Partitioned cluster!"
+ " Our cluster: %s ", buf1);
+ }
+ msg = extra;
+ break;
+ }
+ case FailRep::ZMULTI_NODE_SHUTDOWN:
+ msg = "Multi node shutdown";
+ break;
+ default:
+ msg = "<UNKNOWN>";
}
- char buf[100];
- BaseString::snprintf(buf, 100,
+ CRASH_INSERTION(932);
+
+ char buf[255];
+ BaseString::snprintf(buf, sizeof(buf),
"We(%u) have been declared dead by %u reason: %s(%u)",
getOwnNodeId(),
refToNode(signal->getSendersBlockRef()),
- aFailCause,
- msg ? msg : "<Unknown>");
-
- progError(__LINE__, 0, buf);
+ msg ? msg : "<Unknown>",
+ aFailCause);
+
+ progError(__LINE__, code, buf);
return;
}//if
@@ -2241,7 +2894,13 @@ void Qmgr::execPREP_FAILREQ(Signal* signal)
{
NodeRecPtr myNodePtr;
jamEntry();
-
+
+ if (check_multi_node_shutdown(signal))
+ {
+ jam();
+ return;
+ }
+
PrepFailReqRef * const prepFail = (PrepFailReqRef *)&signal->theData[0];
BlockReference Tblockref = prepFail->xxxBlockRef;
@@ -3893,6 +4552,7 @@ Qmgr::stateArbitCrash(Signal* signal)
if (! (arbitRec.getTimediff() > getArbitTimeout()))
return;
#endif
+ CRASH_INSERTION(932);
progError(__LINE__, NDBD_EXIT_ARBIT_SHUTDOWN,
"Arbitrator decided to shutdown this node");
}
@@ -3956,8 +4616,10 @@ Qmgr::execDUMP_STATE_ORD(Signal* signal)
case 1:
infoEvent("creadyDistCom = %d, cpresident = %d\n",
creadyDistCom, cpresident);
- infoEvent("cpresidentAlive = %d, cpresidentCand = %d\n",
- cpresidentAlive, cpresidentCandidate);
+ infoEvent("cpresidentAlive = %d, cpresidentCand = %d (gci: %d)\n",
+ cpresidentAlive,
+ c_start.m_president_candidate,
+ c_start.m_president_candidate_gci);
infoEvent("ctoStatus = %d\n", ctoStatus);
for(Uint32 i = 1; i<MAX_NDB_NODES; i++){
if(getNodeInfo(i).getType() == NodeInfo::DB){
@@ -4054,3 +4716,42 @@ Qmgr::execAPI_BROADCAST_REP(Signal* signal)
NodeReceiverGroup rg(API_CLUSTERMGR, mask);
sendSignal(rg, api.gsn, signal, len, JBB); // forward sections
}
+
+void
+Qmgr::execSTOP_REQ(Signal* signal)
+{
+ jamEntry();
+ c_stopReq = * (StopReq*)signal->getDataPtr();
+
+ if (c_stopReq.senderRef)
+ {
+ ndbrequire(NdbNodeBitmask::get(c_stopReq.nodes, getOwnNodeId()));
+
+ StopConf *conf = (StopConf*)signal->getDataPtrSend();
+ conf->senderData = c_stopReq.senderData;
+ conf->nodeState = getOwnNodeId();
+ sendSignal(c_stopReq.senderRef,
+ GSN_STOP_CONF, signal, StopConf::SignalLength, JBA);
+ }
+}
+
+bool
+Qmgr::check_multi_node_shutdown(Signal* signal)
+{
+ if (c_stopReq.senderRef &&
+ NdbNodeBitmask::get(c_stopReq.nodes, getOwnNodeId()))
+ {
+ jam();
+ if(StopReq::getPerformRestart(c_stopReq.requestInfo))
+ {
+ jam();
+ StartOrd * startOrd = (StartOrd *)&signal->theData[0];
+ startOrd->restartInfo = c_stopReq.requestInfo;
+ EXECUTE_DIRECT(CMVMI, GSN_START_ORD, signal, 2);
+ } else {
+ EXECUTE_DIRECT(CMVMI, GSN_STOP_ORD, signal, 1);
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp
index 831145a7a41..f8c79a53fb7 100644
--- a/ndb/src/kernel/vm/Configuration.cpp
+++ b/ndb/src/kernel/vm/Configuration.cpp
@@ -55,6 +55,12 @@ enum ndbd_options {
NDB_STD_OPTS_VARS;
// XXX should be my_bool ???
static int _daemon, _no_daemon, _foreground, _initial, _no_start;
+static int _initialstart;
+static const char* _nowait_nodes;
+
+extern Uint32 g_start_type;
+extern NdbNodeBitmask g_nowait_nodes;
+
/**
* Arguments to NDB process
*/
@@ -82,6 +88,14 @@ static struct my_option my_long_options[] =
" (implies --nodaemon)",
(gptr*) &_foreground, (gptr*) &_foreground, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "nowait-nodes", NO_ARG,
+ "Nodes that will not be waited for during start",
+ (gptr*) &_nowait_nodes, (gptr*) &_nowait_nodes, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { "initial-start", NO_ARG,
+ "Perform initial start",
+ (gptr*) &_initialstart, (gptr*) &_initialstart, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
static void short_usage_sub(void)
@@ -150,6 +164,37 @@ Configuration::init(int argc, char** argv)
globalData.ownId= 0;
+ if (_nowait_nodes)
+ {
+ BaseString str(_nowait_nodes);
+ Vector<BaseString> arr;
+ str.split(arr, ",");
+ for (Uint32 i = 0; i<arr.size(); i++)
+ {
+ char *endptr = 0;
+ long val = strtol(arr[i].c_str(), &endptr, 10);
+ if (*endptr)
+ {
+ ndbout_c("Unable to parse nowait-nodes argument: %s : %s",
+ arr[i].c_str(), _nowait_nodes);
+ exit(-1);
+ }
+ if (! (val > 0 && val < MAX_NDB_NODES))
+ {
+ ndbout_c("Invalid nodeid specified in nowait-nodes: %d : %s",
+ val, _nowait_nodes);
+ exit(-1);
+ }
+ g_nowait_nodes.set(val);
+ }
+ }
+
+ if (_initialstart)
+ {
+ _initialStart = true;
+ g_start_type |= (1 << NodeState::ST_INITIAL_START);
+ }
+
return true;
}
diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp
index 74d7f879f9c..39c84fd8055 100644
--- a/ndb/src/mgmclient/CommandInterpreter.cpp
+++ b/ndb/src/mgmclient/CommandInterpreter.cpp
@@ -25,6 +25,7 @@
#endif
#include <mgmapi.h>
+#include <util/BaseString.hpp>
class MgmtSrvr;
@@ -70,6 +71,9 @@ private:
*/
void analyseAfterFirstToken(int processId, char* allAfterFirstTokenCstr);
+ void executeCommand(Vector<BaseString> &command_list,
+ unsigned command_pos,
+ int *node_ids, int no_of_nodes);
/**
* Parse the block specification part of the LOG* commands,
* things after LOG*: [BLOCK = {ALL|<blockName>+}]
@@ -104,10 +108,14 @@ private:
public:
void executeStop(int processId, const char* parameters, bool all);
+ void executeStop(Vector<BaseString> &command_list, unsigned command_pos,
+ int *node_ids, int no_of_nodes);
void executeEnterSingleUser(char* parameters);
void executeExitSingleUser(char* parameters);
void executeStart(int processId, const char* parameters, bool all);
void executeRestart(int processId, const char* parameters, bool all);
+ void executeRestart(Vector<BaseString> &command_list, unsigned command_pos,
+ int *node_ids, int no_of_nodes);
void executeLogLevel(int processId, const char* parameters, bool all);
void executeError(int processId, const char* parameters, bool all);
void executeLog(int processId, const char* parameters, bool all);
@@ -643,9 +651,16 @@ CommandInterpreter::execute_impl(const char *_line)
}
} while (do_continue);
// if there is anything in the line proceed
+ Vector<BaseString> command_list;
+ {
+ BaseString tmp(line);
+ tmp.split(command_list);
+ for (unsigned i= 0; i < command_list.size();)
+ command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
+ }
char* firstToken = strtok(line, " ");
char* allAfterFirstToken = strtok(NULL, "");
-
+
if (strcasecmp(firstToken, "HELP") == 0 ||
strcasecmp(firstToken, "?") == 0) {
executeHelp(allAfterFirstToken);
@@ -723,22 +738,45 @@ CommandInterpreter::execute_impl(const char *_line)
analyseAfterFirstToken(-1, allAfterFirstToken);
} else {
/**
- * First token should be a digit, node ID
+ * First tokens should be digits, node ID's
*/
- int nodeId;
-
- if (! convert(firstToken, nodeId)) {
+ int node_ids[MAX_NODES];
+ unsigned pos;
+ for (pos= 0; pos < command_list.size(); pos++)
+ {
+ int node_id;
+ if (convert(command_list[pos].c_str(), node_id))
+ {
+ if (node_id <= 0) {
+ ndbout << "Invalid node ID: " << command_list[pos].c_str()
+ << "." << endl;
+ DBUG_RETURN(true);
+ }
+ node_ids[pos]= node_id;
+ continue;
+ }
+ break;
+ }
+ int no_of_nodes= pos;
+ if (no_of_nodes == 0)
+ {
+ /* No digit found */
invalid_command(_line);
DBUG_RETURN(true);
}
-
- if (nodeId <= 0) {
- ndbout << "Invalid node ID: " << firstToken << "." << endl;
+ if (pos == command_list.size())
+ {
+ /* No command found */
+ invalid_command(_line);
DBUG_RETURN(true);
}
-
- analyseAfterFirstToken(nodeId, allAfterFirstToken);
-
+ if (no_of_nodes == 1)
+ {
+ analyseAfterFirstToken(node_ids[0], allAfterFirstToken);
+ DBUG_RETURN(true);
+ }
+ executeCommand(command_list, pos, node_ids, no_of_nodes);
+ DBUG_RETURN(true);
}
DBUG_RETURN(true);
}
@@ -808,6 +846,27 @@ CommandInterpreter::analyseAfterFirstToken(int processId,
ndbout << endl;
}
+void
+CommandInterpreter::executeCommand(Vector<BaseString> &command_list,
+ unsigned command_pos,
+ int *node_ids, int no_of_nodes)
+{
+ const char *cmd= command_list[command_pos].c_str();
+ if (strcasecmp("STOP", cmd) == 0)
+ {
+ executeStop(command_list, command_pos+1, node_ids, no_of_nodes);
+ return;
+ }
+ if (strcasecmp("RESTART", cmd) == 0)
+ {
+ executeRestart(command_list, command_pos+1, node_ids, no_of_nodes);
+ return;
+ }
+ ndbout_c("Invalid command: '%s' after multi node id list. "
+ "Expected STOP or RESTART.", cmd);
+ return;
+}
+
/**
* Get next nodeid larger than the give node_id. node_id will be
* set to the next node_id in the list. node_id should be set
@@ -1400,24 +1459,60 @@ CommandInterpreter::executeClusterLog(char* parameters)
//*****************************************************************************
void
-CommandInterpreter::executeStop(int processId, const char *, bool all)
+CommandInterpreter::executeStop(int processId, const char *parameters,
+ bool all)
{
- int result = 0;
- if(all) {
- result = ndb_mgm_stop(m_mgmsrv, 0, 0);
- } else {
- result = ndb_mgm_stop(m_mgmsrv, 1, &processId);
+ Vector<BaseString> command_list;
+ if (parameters)
+ {
+ BaseString tmp(parameters);
+ tmp.split(command_list);
+ for (unsigned i= 0; i < command_list.size();)
+ command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
}
- if (result < 0) {
- ndbout << "Shutdown failed." << endl;
+ if (all)
+ executeStop(command_list, 0, 0, 0);
+ else
+ executeStop(command_list, 0, &processId, 1);
+}
+
+void
+CommandInterpreter::executeStop(Vector<BaseString> &command_list,
+ unsigned command_pos,
+ int *node_ids, int no_of_nodes)
+{
+ int abort= 0;
+ for (; command_pos < command_list.size(); command_pos++)
+ {
+ const char *item= command_list[command_pos].c_str();
+ if (strcasecmp(item, "-A") == 0)
+ {
+ abort= 1;
+ continue;
+ }
+ ndbout_c("Invalid option: %s. Expecting -A after STOP",
+ item);
+ return;
+ }
+
+ int result= ndb_mgm_stop2(m_mgmsrv, no_of_nodes, node_ids, abort);
+ if (result < 0)
+ {
+ ndbout_c("Shutdown failed.");
printError();
- } else
+ }
+ else
+ {
+ if (node_ids == 0)
+ ndbout_c("NDB Cluster has shutdown.");
+ else
{
- if(all)
- ndbout << "NDB Cluster has shutdown." << endl;
- else
- ndbout << "Node " << processId << " has shutdown." << endl;
+ ndbout << "Node";
+ for (int i= 0; i < no_of_nodes; i++)
+ ndbout << " " << node_ids[i];
+ ndbout_c(" has shutdown.");
}
+ }
}
void
@@ -1483,47 +1578,74 @@ CommandInterpreter::executeStart(int processId, const char* parameters,
void
CommandInterpreter::executeRestart(int processId, const char* parameters,
- bool all)
+ bool all)
+{
+ Vector<BaseString> command_list;
+ if (parameters)
+ {
+ BaseString tmp(parameters);
+ tmp.split(command_list);
+ for (unsigned i= 0; i < command_list.size();)
+ command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
+ }
+ if (all)
+ executeRestart(command_list, 0, 0, 0);
+ else
+ executeRestart(command_list, 0, &processId, 1);
+}
+
+void
+CommandInterpreter::executeRestart(Vector<BaseString> &command_list,
+ unsigned command_pos,
+ int *node_ids, int no_of_nodes)
{
int result;
- int nostart = 0;
- int initialstart = 0;
- int abort = 0;
-
- if(parameters != 0 && strlen(parameters) != 0){
- char * tmpString = my_strdup(parameters,MYF(MY_WME));
- My_auto_ptr<char> ap1(tmpString);
- char * tmpPtr = 0;
- char * item = strtok_r(tmpString, " ", &tmpPtr);
- while(item != NULL){
- if(strcasecmp(item, "-N") == 0)
- nostart = 1;
- if(strcasecmp(item, "-I") == 0)
- initialstart = 1;
- if(strcasecmp(item, "-A") == 0)
- abort = 1;
- item = strtok_r(NULL, " ", &tmpPtr);
+ int nostart= 0;
+ int initialstart= 0;
+ int abort= 0;
+
+ for (; command_pos < command_list.size(); command_pos++)
+ {
+ const char *item= command_list[command_pos].c_str();
+ if (strcasecmp(item, "-N") == 0)
+ {
+ nostart= 1;
+ continue;
+ }
+ if (strcasecmp(item, "-I") == 0)
+ {
+ initialstart= 1;
+ continue;
}
+ if (strcasecmp(item, "-A") == 0)
+ {
+ abort= 1;
+ continue;
+ }
+ ndbout_c("Invalid option: %s. Expecting -A,-N or -I after RESTART",
+ item);
+ return;
}
- if(all) {
- result = ndb_mgm_restart2(m_mgmsrv, 0, NULL, initialstart, nostart, abort);
- } else {
- int v[1];
- v[0] = processId;
- result = ndb_mgm_restart2(m_mgmsrv, 1, v, initialstart, nostart, abort);
- }
+ result= ndb_mgm_restart2(m_mgmsrv, no_of_nodes, node_ids,
+ initialstart, nostart, abort);
if (result <= 0) {
- ndbout.println("Restart failed.", result);
+ ndbout_c("Restart failed.");
printError();
- } else
+ }
+ else
+ {
+ if (node_ids == 0)
+ ndbout_c("NDB Cluster is being restarted.");
+ else
{
- if(all)
- ndbout << "NDB Cluster is being restarted." << endl;
- else
- ndbout_c("Node %d is being restarted.", processId);
+ ndbout << "Node";
+ for (int i= 0; i < no_of_nodes; i++)
+ ndbout << " " << node_ids[i];
+ ndbout_c(" is being restarted");
}
+ }
}
void
diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp
index 76a045bc806..9b518ba938b 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.cpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -294,6 +294,8 @@ static ErrorItem errorTable[] =
{MgmtSrvr::SYSTEM_SHUTDOWN_IN_PROGRESS, "System shutdown in progress" },
{MgmtSrvr::NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH,
"Node shutdown would cause system crash" },
+ {MgmtSrvr::UNSUPPORTED_NODE_SHUTDOWN,
+ "Unsupported multi node shutdown. Abort option required." },
{MgmtSrvr::NODE_NOT_API_NODE, "The specified node is not an API node." },
{MgmtSrvr::OPERATION_NOT_ALLOWED_START_STOP,
"Operation not allowed while nodes are starting or stopping."},
@@ -312,6 +314,9 @@ int MgmtSrvr::translateStopRef(Uint32 errCode)
case StopRef::NodeShutdownWouldCauseSystemCrash:
return NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH;
break;
+ case StopRef::UnsupportedNodeShutdown:
+ return UNSUPPORTED_NODE_SHUTDOWN;
+ break;
}
return 4999;
}
@@ -386,8 +391,9 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server,
_ownReference(0),
theSignalIdleList(NULL),
theWaitState(WAIT_SUBSCRIBE_CONF),
+ m_local_mgm_handle(0),
m_event_listner(this),
- m_local_mgm_handle(0)
+ m_master_node(0)
{
DBUG_ENTER("MgmtSrvr::MgmtSrvr");
@@ -677,23 +683,16 @@ MgmtSrvr::~MgmtSrvr()
int MgmtSrvr::okToSendTo(NodeId nodeId, bool unCond)
{
- if(nodeId == 0)
- return 0;
-
- if (getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB)
+ if(nodeId == 0 || getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB)
return WRONG_PROCESS_TYPE;
-
// Check if we have contact with it
if(unCond){
if(theFacade->theClusterMgr->getNodeInfo(nodeId).connected)
return 0;
- return NO_CONTACT_WITH_PROCESS;
}
- if (theFacade->get_node_alive(nodeId) == 0) {
- return NO_CONTACT_WITH_PROCESS;
- } else {
+ else if (theFacade->get_node_alive(nodeId) == true)
return 0;
- }
+ return NO_CONTACT_WITH_PROCESS;
}
void report_unknown_signal(SimpleSignal *signal)
@@ -935,7 +934,7 @@ int MgmtSrvr::sendStopMgmd(NodeId nodeId,
* distributed communication up.
*/
-int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
+int MgmtSrvr::sendSTOP_REQ(const Vector<NodeId> &node_ids,
NodeBitmask &stoppedNodes,
Uint32 singleUserNodeId,
bool abort,
@@ -945,6 +944,12 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
bool initialStart)
{
int error = 0;
+ DBUG_ENTER("MgmtSrvr::sendSTOP_REQ");
+ DBUG_PRINT("enter", ("no of nodes: %d singleUseNodeId: %d "
+ "abort: %d stop: %d restart: %d "
+ "nostart: %d initialStart: %d",
+ node_ids.size(), singleUserNodeId,
+ abort, stop, restart, nostart, initialStart));
stoppedNodes.clear();
@@ -982,36 +987,49 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
// send the signals
NodeBitmask nodes;
- if (nodeId)
+ NodeId nodeId= 0;
+ int use_master_node= 0;
+ int do_send= 0;
+ int do_stop_self= 0;
+ NdbNodeBitmask nodes_to_stop;
{
- if(nodeId==getOwnNodeId())
- {
- if(restart)
- g_RestartServer= true;
- g_StopServer= true;
- return 0;
- }
- if(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB)
+ for (unsigned i= 0; i < node_ids.size(); i++)
{
- int r;
- if((r= okToSendTo(nodeId, true)) != 0)
- return r;
- if (ss.sendSignal(nodeId, &ssig) != SEND_OK)
- return SEND_OR_RECEIVE_FAILED;
+ nodeId= node_ids[i];
+ if (getNodeType(nodeId) != NDB_MGM_NODE_TYPE_MGM)
+ nodes_to_stop.set(nodeId);
+ else if (nodeId != getOwnNodeId())
+ {
+ error= sendStopMgmd(nodeId, abort, stop, restart,
+ nostart, initialStart);
+ if (error == 0)
+ stoppedNodes.set(nodeId);
+ }
+ else
+ do_stop_self= 1;;
}
- else if(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM)
+ }
+ int no_of_nodes_to_stop= nodes_to_stop.count();
+ if (node_ids.size())
+ {
+ if (no_of_nodes_to_stop)
{
- error= sendStopMgmd(nodeId, abort, stop, restart, nostart, initialStart);
- if(error==0)
- stoppedNodes.set(nodeId);
- return error;
+ do_send= 1;
+ if (no_of_nodes_to_stop == 1)
+ {
+ nodeId= nodes_to_stop.find(0);
+ }
+ else // multi node stop, send to master
+ {
+ use_master_node= 1;
+ nodes_to_stop.copyto(NdbNodeBitmask::Size, stopReq->nodes);
+ StopReq::setStopNodes(stopReq->requestInfo, 1);
+ }
}
- else
- return WRONG_PROCESS_TYPE;
- nodes.set(nodeId);
}
else
{
+ nodeId= 0;
while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB))
{
if(okToSendTo(nodeId, true) == 0)
@@ -1032,8 +1050,30 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
}
// now wait for the replies
- while (!nodes.isclear())
+ while (!nodes.isclear() || do_send)
{
+ if (do_send)
+ {
+ int r;
+ assert(nodes.count() == 0);
+ if (use_master_node)
+ nodeId= m_master_node;
+ if ((r= okToSendTo(nodeId, true)) != 0)
+ {
+ bool next;
+ if (!use_master_node)
+ DBUG_RETURN(r);
+ m_master_node= nodeId= 0;
+ while((next= getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ (r= okToSendTo(nodeId, true)) != 0);
+ if (!next)
+ DBUG_RETURN(NO_CONTACT_WITH_DB_NODES);
+ }
+ if (ss.sendSignal(nodeId, &ssig) != SEND_OK)
+ DBUG_RETURN(SEND_OR_RECEIVE_FAILED);
+ nodes.set(nodeId);
+ do_send= 0;
+ }
SimpleSignal *signal = ss.waitFor();
int gsn = signal->readSignalNumber();
switch (gsn) {
@@ -1045,6 +1085,13 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
#endif
assert(nodes.get(nodeId));
nodes.clear(nodeId);
+ if (ref->errorCode == StopRef::MultiNodeShutdownNotMaster)
+ {
+ assert(use_master_node);
+ m_master_node= ref->masterNodeId;
+ do_send= 1;
+ continue;
+ }
error = translateStopRef(ref->errorCode);
break;
}
@@ -1055,9 +1102,16 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
ndbout_c("Node %d single user mode", nodeId);
#endif
assert(nodes.get(nodeId));
- assert(singleUserNodeId != 0);
+ if (singleUserNodeId != 0)
+ {
+ stoppedNodes.set(nodeId);
+ }
+ else
+ {
+ assert(no_of_nodes_to_stop > 1);
+ stoppedNodes.bitOR(nodes_to_stop);
+ }
nodes.clear(nodeId);
- stoppedNodes.set(nodeId);
break;
}
case GSN_NF_COMPLETEREP:{
@@ -1096,17 +1150,24 @@ int MgmtSrvr::sendSTOP_REQ(NodeId nodeId,
#ifdef VM_TRACE
ndbout_c("Unknown signal %d", gsn);
#endif
- return SEND_OR_RECEIVE_FAILED;
+ DBUG_RETURN(SEND_OR_RECEIVE_FAILED);
}
}
- return error;
+ if (!error && do_stop_self)
+ {
+ if (restart)
+ g_RestartServer= true;
+ g_StopServer= true;
+ }
+ DBUG_RETURN(error);
}
/*
- * Stop one node
+ * Stop one nodes
*/
-int MgmtSrvr::stopNode(int nodeId, bool abort)
+int MgmtSrvr::stopNodes(const Vector<NodeId> &node_ids,
+ int *stopCount, bool abort)
{
if (!abort)
{
@@ -1121,14 +1182,17 @@ int MgmtSrvr::stopNode(int nodeId, bool abort)
}
}
NodeBitmask nodes;
- return sendSTOP_REQ(nodeId,
- nodes,
- 0,
- abort,
- false,
- false,
- false,
- false);
+ int ret= sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ false,
+ false,
+ false,
+ false);
+ if (stopCount)
+ *stopCount= nodes.count();
+ return ret;
}
/*
@@ -1138,7 +1202,8 @@ int MgmtSrvr::stopNode(int nodeId, bool abort)
int MgmtSrvr::stop(int * stopCount, bool abort)
{
NodeBitmask nodes;
- int ret = sendSTOP_REQ(0,
+ Vector<NodeId> node_ids;
+ int ret = sendSTOP_REQ(node_ids,
nodes,
0,
abort,
@@ -1169,7 +1234,8 @@ int MgmtSrvr::enterSingleUser(int * stopCount, Uint32 singleUserNodeId)
return OPERATION_NOT_ALLOWED_START_STOP;
}
NodeBitmask nodes;
- int ret = sendSTOP_REQ(0,
+ Vector<NodeId> node_ids;
+ int ret = sendSTOP_REQ(node_ids,
nodes,
singleUserNodeId,
false,
@@ -1186,18 +1252,22 @@ int MgmtSrvr::enterSingleUser(int * stopCount, Uint32 singleUserNodeId)
* Perform node restart
*/
-int MgmtSrvr::restartNode(int nodeId, bool nostart, bool initialStart,
- bool abort)
+int MgmtSrvr::restartNodes(const Vector<NodeId> &node_ids,
+ int * stopCount, bool nostart,
+ bool initialStart, bool abort)
{
NodeBitmask nodes;
- return sendSTOP_REQ(nodeId,
- nodes,
- 0,
- abort,
- false,
- true,
- nostart,
- initialStart);
+ int ret= sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ false,
+ true,
+ nostart,
+ initialStart);
+ if (stopCount)
+ *stopCount = nodes.count();
+ return ret;
}
/*
@@ -1208,7 +1278,8 @@ int MgmtSrvr::restart(bool nostart, bool initialStart,
bool abort, int * stopCount )
{
NodeBitmask nodes;
- int ret = sendSTOP_REQ(0,
+ Vector<NodeId> node_ids;
+ int ret = sendSTOP_REQ(node_ids,
nodes,
0,
abort,
@@ -2135,12 +2206,16 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted)
SignalSender ss(theFacade);
ss.lock(); // lock will be released on exit
- bool next;
- NodeId nodeId = 0;
- while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
- theFacade->get_node_alive(nodeId) == false);
-
- if(!next) return NO_CONTACT_WITH_DB_NODES;
+ NodeId nodeId = m_master_node;
+ if (okToSendTo(nodeId, false) != 0)
+ {
+ bool next;
+ nodeId = m_master_node = 0;
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ okToSendTo(nodeId, false) != 0);
+ if(!next)
+ return NO_CONTACT_WITH_DB_NODES;
+ }
SimpleSignal ssig;
BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend());
@@ -2208,7 +2283,7 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted)
const BackupRef * const ref =
CAST_CONSTPTR(BackupRef, signal->getDataPtr());
if(ref->errorCode == BackupRef::IAmNotMaster){
- nodeId = refToNode(ref->masterRef);
+ m_master_node = nodeId = refToNode(ref->masterRef);
#ifdef VM_TRACE
ndbout_c("I'm not master resending to %d", nodeId);
#endif
diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp
index 46bdb112cb9..fe1603a1953 100644
--- a/ndb/src/mgmsrv/MgmtSrvr.hpp
+++ b/ndb/src/mgmsrv/MgmtSrvr.hpp
@@ -176,6 +176,7 @@ public:
STATIC_CONST( NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH = 5028 );
STATIC_CONST( NO_CONTACT_WITH_DB_NODES = 5030 );
+ STATIC_CONST( UNSUPPORTED_NODE_SHUTDOWN = 5031 );
STATIC_CONST( NODE_NOT_API_NODE = 5062 );
STATIC_CONST( OPERATION_NOT_ALLOWED_START_STOP = 5063 );
@@ -252,7 +253,7 @@ public:
* @param processId: Id of the DB process to stop
* @return 0 if succeeded, otherwise: as stated above, plus:
*/
- int stopNode(int nodeId, bool abort = false);
+ int stopNodes(const Vector<NodeId> &node_ids, int *stopCount, bool abort);
/**
* Stop the system
@@ -286,11 +287,12 @@ public:
int start(int processId);
/**
- * Restart a node
+ * Restart nodes
* @param processId: Id of the DB process to start
*/
- int restartNode(int processId, bool nostart, bool initialStart,
- bool abort = false);
+ int restartNodes(const Vector<NodeId> &node_ids,
+ int *stopCount, bool nostart,
+ bool initialStart, bool abort);
/**
* Restart the system
@@ -494,7 +496,7 @@ private:
bool nostart,
bool initialStart);
- int sendSTOP_REQ(NodeId nodeId,
+ int sendSTOP_REQ(const Vector<NodeId> &node_ids,
NodeBitmask &stoppedNodes,
Uint32 singleUserNodeId,
bool abort,
@@ -653,6 +655,8 @@ private:
friend class Ndb_mgmd_event_service;
Ndb_mgmd_event_service m_event_listner;
+ NodeId m_master_node;
+
/**
* Handles the thread wich upon a 'Node is started' event will
* set the node's previous loglevel settings.
diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp
index 3564c5c40ba..a80827abd8f 100644
--- a/ndb/src/mgmsrv/Services.cpp
+++ b/ndb/src/mgmsrv/Services.cpp
@@ -866,14 +866,11 @@ MgmApiSession::restart(Parser<MgmApiSession>::Context &,
}
int restarted = 0;
- int result = 0;
-
- for(size_t i = 0; i < nodes.size(); i++)
- if((result = m_mgmsrv.restartNode(nodes[i],
- nostart != 0,
- initialstart != 0,
- abort != 0)) == 0)
- restarted++;
+ int result= m_mgmsrv.restartNodes(nodes,
+ &restarted,
+ nostart != 0,
+ initialstart != 0,
+ abort != 0);
m_output->println("restart reply");
if(result != 0){
@@ -998,7 +995,12 @@ MgmApiSession::stop(Parser<MgmApiSession>::Context &,
args.get("node", (const char **)&nodes_str);
if(nodes_str == NULL)
+ {
+ m_output->println("stop reply");
+ m_output->println("result: empty node list");
+ m_output->println("");
return;
+ }
args.get("abort", &abort);
char *p, *last;
@@ -1008,29 +1010,10 @@ MgmApiSession::stop(Parser<MgmApiSession>::Context &,
nodes.push_back(atoi(p));
}
- int stop_self= 0;
- size_t i;
-
- for(i=0; i < nodes.size(); i++) {
- if (nodes[i] == m_mgmsrv.getOwnNodeId()) {
- stop_self= 1;
- if (i != nodes.size()-1) {
- m_output->println("stop reply");
- m_output->println("result: server must be stopped last");
- m_output->println("");
- return;
- }
- }
- }
-
- int stopped = 0, result = 0;
-
- for(i=0; i < nodes.size(); i++)
- if (nodes[i] != m_mgmsrv.getOwnNodeId()) {
- if((result = m_mgmsrv.stopNode(nodes[i], abort != 0)) == 0)
- stopped++;
- } else
- stopped++;
+ int stopped= 0;
+ int result= 0;
+ if (nodes.size())
+ result= m_mgmsrv.stopNodes(nodes, &stopped, abort != 0);
m_output->println("stop reply");
if(result != 0)
@@ -1039,9 +1022,6 @@ MgmApiSession::stop(Parser<MgmApiSession>::Context &,
m_output->println("result: Ok");
m_output->println("stopped: %d", stopped);
m_output->println("");
-
- if (stop_self)
- g_StopServer= true;
}
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index da344dc6164..f7a28eb989c 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -1109,9 +1109,14 @@ NdbDictInterface::getTable(const BaseString& name, bool fullyQualifiedNames)
// Copy name to m_buffer to get a word sized buffer
m_buffer.clear();
- m_buffer.grow(namelen_words*4);
+ m_buffer.grow(namelen_words*4+4);
m_buffer.append(name.c_str(), namelen);
+#ifndef IGNORE_VALGRIND_WARNINGS
+ Uint32 pad = 0;
+ m_buffer.append(&pad, 4);
+#endif
+
LinearSectionPtr ptr[1];
ptr[0].p= (Uint32*)m_buffer.get_data();
ptr[0].sz= namelen_words;
diff --git a/ndb/src/ndbapi/NdbLinHash.hpp b/ndb/src/ndbapi/NdbLinHash.hpp
index 05670534c95..0655e81ce9d 100644
--- a/ndb/src/ndbapi/NdbLinHash.hpp
+++ b/ndb/src/ndbapi/NdbLinHash.hpp
@@ -427,19 +427,26 @@ NdbLinHash<C>::getNext(NdbElement_t<C> * curr){
return curr->next;
int dir = 0, seg = 0;
-
- if(curr != 0){
+ int counts;
+ if(curr != 0)
+ {
getBucket(curr->hash, &dir, &seg);
+ counts = seg + 1;
+ }
+ else
+ {
+ counts = 0;
}
for(int countd = dir; countd < DIRECTORYSIZE;countd++ ){
if (directory[countd] != 0) {
- for(int counts = seg + 1; counts < SEGMENTSIZE; counts++ ){
+ for(; counts < SEGMENTSIZE; counts++ ){
if (directory[countd]->elements[counts] != 0) {
return directory[countd]->elements[counts];
}
}
}
+ counts = 0;
}
return 0;
diff --git a/ndb/test/ndbapi/testNodeRestart.cpp b/ndb/test/ndbapi/testNodeRestart.cpp
index ba195290e9e..aed0b39f196 100644
--- a/ndb/test/ndbapi/testNodeRestart.cpp
+++ b/ndb/test/ndbapi/testNodeRestart.cpp
@@ -22,7 +22,7 @@
#include <NdbRestarts.hpp>
#include <Vector.hpp>
#include <signaldata/DumpStateOrd.hpp>
-
+#include <Bitmask.hpp>
int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
@@ -669,6 +669,206 @@ err:
return NDBT_FAILED;
}
+int
+runBug18612(NDBT_Context* ctx, NDBT_Step* step){
+
+ // Assume two replicas
+ NdbRestarter restarter;
+ if (restarter.getNumDbNodes() < 2)
+ {
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+
+ Uint32 cnt = restarter.getNumDbNodes();
+
+ for(int loop = 0; loop < ctx->getNumLoops(); loop++)
+ {
+ int partition0[256];
+ int partition1[256];
+ bzero(partition0, sizeof(partition0));
+ bzero(partition1, sizeof(partition1));
+ Bitmask<4> nodesmask;
+
+ Uint32 node1 = restarter.getDbNodeId(rand()%cnt);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ {
+ do {
+ int tmp = restarter.getRandomNodeOtherNodeGroup(node1, rand());
+ if (tmp == -1)
+ break;
+ node1 = tmp;
+ } while(nodesmask.get(node1));
+
+ partition0[i] = node1;
+ partition1[i] = restarter.getRandomNodeSameNodeGroup(node1, rand());
+
+ ndbout_c("nodes %d %d", node1, partition1[i]);
+
+ assert(!nodesmask.get(node1));
+ assert(!nodesmask.get(partition1[i]));
+ nodesmask.set(node1);
+ nodesmask.set(partition1[i]);
+ }
+
+ ndbout_c("done");
+
+ int dump[255];
+ dump[0] = DumpStateOrd::NdbcntrStopNodes;
+ memcpy(dump + 1, partition0, sizeof(int)*cnt/2);
+
+ Uint32 master = restarter.getMasterNodeId();
+
+ if (restarter.dumpStateOneNode(master, dump, 1+cnt/2))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(partition0, cnt/2))
+ return NDBT_FAILED;
+
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+
+ if (restarter.dumpStateAllNodes(val2, 2))
+ return NDBT_FAILED;
+
+ if (restarter.insertErrorInAllNodes(932))
+ return NDBT_FAILED;
+
+ dump[0] = 9000;
+ memcpy(dump + 1, partition0, sizeof(int)*cnt/2);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateOneNode(partition1[i], dump, 1+cnt/2))
+ return NDBT_FAILED;
+
+ dump[0] = 9000;
+ memcpy(dump + 1, partition1, sizeof(int)*cnt/2);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateOneNode(partition0[i], dump, 1+cnt/2))
+ return NDBT_FAILED;
+
+ if (restarter.startNodes(partition0, cnt/2))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesStartPhase(partition0, cnt/2, 2))
+ return NDBT_FAILED;
+
+ dump[0] = 9001;
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateAllNodes(dump, 2))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(partition0, cnt/2))
+ return NDBT_FAILED;
+
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.restartOneDbNode(partition0[i], true, true, true))
+ return NDBT_FAILED;
+
+ if (restarter.waitNodesNoStart(partition0, cnt/2))
+ return NDBT_FAILED;
+
+ if (restarter.startAll())
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStarted())
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+int
+runBug18612SR(NDBT_Context* ctx, NDBT_Step* step){
+
+ // Assume two replicas
+ NdbRestarter restarter;
+ if (restarter.getNumDbNodes() < 2)
+ {
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+
+ Uint32 cnt = restarter.getNumDbNodes();
+
+ for(int loop = 0; loop < ctx->getNumLoops(); loop++)
+ {
+ int partition0[256];
+ int partition1[256];
+ bzero(partition0, sizeof(partition0));
+ bzero(partition1, sizeof(partition1));
+ Bitmask<4> nodesmask;
+
+ Uint32 node1 = restarter.getDbNodeId(rand()%cnt);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ {
+ do {
+ int tmp = restarter.getRandomNodeOtherNodeGroup(node1, rand());
+ if (tmp == -1)
+ break;
+ node1 = tmp;
+ } while(nodesmask.get(node1));
+
+ partition0[i] = node1;
+ partition1[i] = restarter.getRandomNodeSameNodeGroup(node1, rand());
+
+ ndbout_c("nodes %d %d", node1, partition1[i]);
+
+ assert(!nodesmask.get(node1));
+ assert(!nodesmask.get(partition1[i]));
+ nodesmask.set(node1);
+ nodesmask.set(partition1[i]);
+ }
+
+ ndbout_c("done");
+
+ if (restarter.restartAll(false, true, false))
+ return NDBT_FAILED;
+
+ int dump[255];
+ dump[0] = 9000;
+ memcpy(dump + 1, partition0, sizeof(int)*cnt/2);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateOneNode(partition1[i], dump, 1+cnt/2))
+ return NDBT_FAILED;
+
+ dump[0] = 9000;
+ memcpy(dump + 1, partition1, sizeof(int)*cnt/2);
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateOneNode(partition0[i], dump, 1+cnt/2))
+ return NDBT_FAILED;
+
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+
+ if (restarter.dumpStateAllNodes(val2, 2))
+ return NDBT_FAILED;
+
+ if (restarter.insertErrorInAllNodes(932))
+ return NDBT_FAILED;
+
+ if (restarter.startAll())
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStartPhase(2))
+ return NDBT_FAILED;
+
+ dump[0] = 9001;
+ for (Uint32 i = 0; i<cnt/2; i++)
+ if (restarter.dumpStateAllNodes(dump, 2))
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterNoStart(30))
+ if (restarter.waitNodesNoStart(partition0, cnt/2, 10))
+ if (restarter.waitNodesNoStart(partition1, cnt/2, 10))
+ return NDBT_FAILED;
+
+ if (restarter.startAll())
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStarted())
+ return NDBT_FAILED;
+ }
+ return NDBT_OK;
+}
+
+
NDBT_TESTSUITE(testNodeRestart);
TESTCASE("NoLoad",
"Test that one node at a time can be stopped and then restarted "\
@@ -963,6 +1163,18 @@ TESTCASE("Bug18414",
STEP(runBug18414);
FINALIZER(runClearTable);
}
+TESTCASE("Bug18612",
+ "Test bug with partitioned clusters"){
+ INITIALIZER(runLoadTable);
+ STEP(runBug18612);
+ FINALIZER(runClearTable);
+}
+TESTCASE("Bug18612SR",
+ "Test bug with partitioned clusters"){
+ INITIALIZER(runLoadTable);
+ STEP(runBug18612SR);
+ FINALIZER(runClearTable);
+}
NDBT_TESTSUITE_END(testNodeRestart);
int main(int argc, const char** argv){
diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt
index 594c3a21b75..e845413c008 100644
--- a/ndb/test/run-test/daily-basic-tests.txt
+++ b/ndb/test/run-test/daily-basic-tests.txt
@@ -433,10 +433,18 @@ args: -n Bug16772 T1
#cmd: testSystemRestart
#args: -n Bug18385 T1
#
-max-time: 500
+max-time: 1000
cmd: testNodeRestart
args: -n Bug18414 T1
+max-time: 1000
+cmd: testNodeRestart
+args: -n Bug18612 T1
+
+max-time: 1000
+cmd: testNodeRestart
+args: -n Bug18612SR T1
+
# OLD FLEX
max-time: 500
cmd: flexBench
diff --git a/ndb/test/src/NdbRestarts.cpp b/ndb/test/src/NdbRestarts.cpp
index eea4af437c4..8465caaab48 100644
--- a/ndb/test/src/NdbRestarts.cpp
+++ b/ndb/test/src/NdbRestarts.cpp
@@ -445,8 +445,7 @@ int twoNodeFailure(NdbRestarter& _restarter,
<< ") secs " << endl;
NdbSleep_SecSleep(seconds);
- randomId = (rand() % _restarter.getNumDbNodes());
- nodeId = _restarter.getDbNodeId(randomId);
+ nodeId = _restarter.getRandomNodeOtherNodeGroup(nodeId, rand());
g_info << _restart->m_name << ": node = "<< nodeId << endl;
CHECK(_restarter.insertErrorInNode(nodeId, 9999) == 0,
diff --git a/sql/field.cc b/sql/field.cc
index 617d34e89a8..bdf84c588e1 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7942,9 +7942,10 @@ Field_bit::Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
- : Field(ptr_arg, len_arg >> 3, null_ptr_arg, null_bit_arg,
+ : Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg),
- bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7)
+ bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
+ bytes_in_rec(len_arg / 8)
{
/*
Ensure that Field::eq() can distinguish between two different bit fields.
@@ -7980,14 +7981,14 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
int delta;
for (; length && !*from; from++, length--); // skip left 0's
- delta= field_length - length;
+ delta= bytes_in_rec - length;
if (delta < -1 ||
(delta == -1 && (uchar) *from > ((1 << bit_len) - 1)) ||
(!bit_len && delta < 0))
{
set_rec_bits(0xff, bit_ptr, bit_ofs, bit_len);
- memset(ptr, 0xff, field_length);
+ memset(ptr, 0xff, bytes_in_rec);
if (table->in_use->really_abort_on_warning())
set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1);
else
@@ -8015,7 +8016,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
set_rec_bits((uchar) *from, bit_ptr, bit_ofs, bit_len);
from++;
}
- memcpy(ptr, from, field_length);
+ memcpy(ptr, from, bytes_in_rec);
}
return 0;
}
@@ -8056,10 +8057,10 @@ longlong Field_bit::val_int(void)
if (bit_len)
{
bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
- bits<<= (field_length * 8);
+ bits<<= (bytes_in_rec * 8);
}
- switch (field_length) {
+ switch (bytes_in_rec) {
case 0: return bits;
case 1: return bits | (ulonglong) (uchar) ptr[0];
case 2: return bits | mi_uint2korr(ptr);
@@ -8068,7 +8069,7 @@ longlong Field_bit::val_int(void)
case 5: return bits | mi_uint5korr(ptr);
case 6: return bits | mi_uint6korr(ptr);
case 7: return bits | mi_uint7korr(ptr);
- default: return mi_uint8korr(ptr + field_length - sizeof(longlong));
+ default: return mi_uint8korr(ptr + bytes_in_rec - sizeof(longlong));
}
}
@@ -8121,7 +8122,7 @@ int Field_bit::cmp_offset(uint row_offset)
if ((flag= (int) (bits_a - bits_b)))
return flag;
}
- return memcmp(ptr, ptr + row_offset, field_length);
+ return memcmp(ptr, ptr + row_offset, bytes_in_rec);
}
@@ -8133,7 +8134,7 @@ void Field_bit::get_key_image(char *buff, uint length, imagetype type)
*buff++= bits;
length--;
}
- memcpy(buff, ptr, min(length, field_length));
+ memcpy(buff, ptr, min(length, bytes_in_rec));
}
@@ -8141,22 +8142,22 @@ void Field_bit::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();
ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "bit(%d)",
- (int) field_length * 8 + bit_len);
+ "bit(%d)", (int) field_length);
res.length((uint) length);
}
char *Field_bit::pack(char *to, const char *from, uint max_length)
{
- uint length= min(field_length + (bit_len > 0), max_length);
+ DBUG_ASSERT(max_length);
+ uint length;
if (bit_len)
{
uchar bits= get_rec_bits(bit_ptr, bit_ofs, bit_len);
*to++= bits;
- length--;
}
- memcpy(to, from, length);
+ length= min(bytes_in_rec, max_length - (bit_len > 0));
+ memcpy(to, from, length);
return to + length;
}
@@ -8168,8 +8169,8 @@ const char *Field_bit::unpack(char *to, const char *from)
set_rec_bits(*from, bit_ptr, bit_ofs, bit_len);
from++;
}
- memcpy(to, from, field_length);
- return from + field_length;
+ memcpy(to, from, bytes_in_rec);
+ return from + bytes_in_rec;
}
@@ -8183,26 +8184,25 @@ Field_bit_as_char::Field_bit_as_char(char *ptr_arg, uint32 len_arg,
const char *field_name_arg,
struct st_table *table_arg)
: Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0,
- 0, unireg_check_arg, field_name_arg, table_arg),
- create_length(len_arg)
+ 0, unireg_check_arg, field_name_arg, table_arg)
{
bit_len= 0;
- field_length= ((len_arg + 7) & ~7) / 8;
+ bytes_in_rec= (len_arg + 7) / 8;
}
int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
{
int delta;
- uchar bits= create_length & 7;
+ uchar bits= field_length & 7;
for (; length && !*from; from++, length--); // skip left 0's
- delta= field_length - length;
+ delta= bytes_in_rec - length;
if (delta < 0 ||
(delta == 0 && bits && (uint) (uchar) *from >= (uint) (1 << bits)))
{
- memset(ptr, 0xff, field_length);
+ memset(ptr, 0xff, bytes_in_rec);
if (bits)
*ptr&= ((1 << bits) - 1); /* set first byte */
if (table->in_use->really_abort_on_warning())
@@ -8221,7 +8221,7 @@ void Field_bit_as_char::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();
ulong length= cs->cset->snprintf(cs, (char*) res.ptr(), res.alloced_length(),
- "bit(%d)", (int) create_length);
+ "bit(%d)", (int) field_length);
res.length((uint) length);
}
@@ -8947,11 +8947,6 @@ create_field::create_field(Field *old_field,Field *orig_field)
geom_type= ((Field_geom*)old_field)->geom_type;
break;
#endif
- case FIELD_TYPE_BIT:
- length= (old_field->key_type() == HA_KEYTYPE_BIT) ?
- ((Field_bit *) old_field)->bit_len + length * 8 :
- ((Field_bit_as_char *) old_field)->create_length;
- break;
default:
break;
}
diff --git a/sql/field.h b/sql/field.h
index a4bdcc4da02..f4d27e46877 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1312,17 +1312,18 @@ public:
uchar *bit_ptr; // position in record where 'uneven' bits store
uchar bit_ofs; // offset to 'uneven' high bits
uint bit_len; // number of 'uneven' high bits
+ uint bytes_in_rec;
Field_bit(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
enum_field_types type() const { return FIELD_TYPE_BIT; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
- uint32 key_length() const { return (uint32) field_length + (bit_len > 0); }
- uint32 max_length() { return (uint32) field_length * 8 + bit_len; }
+ uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
+ uint32 max_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
- void reset(void) { bzero(ptr, field_length); }
+ void reset(void) { bzero(ptr, bytes_in_rec); }
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -1344,9 +1345,8 @@ public:
{ Field_bit::store(buff, length, &my_charset_bin); }
void sort_string(char *buff, uint length)
{ get_key_image(buff, length, itRAW); }
- uint32 pack_length() const
- { return (uint32) field_length + (bit_len > 0); }
- uint32 pack_length_in_rec() const { return field_length; }
+ uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
+ uint32 pack_length_in_rec() const { return bytes_in_rec; }
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
const char *unpack(char* to, const char *from);
@@ -1363,13 +1363,11 @@ public:
class Field_bit_as_char: public Field_bit {
public:
- uchar create_length;
Field_bit_as_char(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
- uint32 max_length() { return (uint32) create_length; }
uint size_of() const { return sizeof(*this); }
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr) { return Field_bit::store(nr); }
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 3dea2d82779..feb54272f4b 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -3959,7 +3959,7 @@ static int create_ndb_column(NDBCOL &col,
break;
case MYSQL_TYPE_BIT:
{
- int no_of_bits= field->field_length*8 + ((Field_bit *) field)->bit_len;
+ int no_of_bits= field->field_length;
col.setType(NDBCOL::Bit);
if (!no_of_bits)
col.setLength(1);
diff --git a/sql/item.cc b/sql/item.cc
index e1bde85e200..e3da950ceef 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3054,6 +3054,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
int found_match_degree= 0;
Item_ident *cur_field;
int cur_match_degree= 0;
+ char name_buff[NAME_LEN+1];
if (find_item->type() == Item::FIELD_ITEM ||
find_item->type() == Item::REF_ITEM)
@@ -3065,6 +3066,14 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
else
return NULL;
+ if (db_name && lower_case_table_names)
+ {
+ /* Convert database to lower case for comparison */
+ strmake(name_buff, db_name, sizeof(name_buff)-1);
+ my_casedn_str(files_charset_info, name_buff);
+ db_name= name_buff;
+ }
+
DBUG_ASSERT(field_name != 0);
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 24075ac838d..6e1afd4ef09 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -55,8 +55,8 @@ static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
bool all_constant= TRUE;
/* If the first argument is a FIELD_ITEM, pull out the field. */
- if (items[0]->type() == Item::FIELD_ITEM)
- field=((Item_field *)items[0])->field;
+ if (items[0]->real_item()->type() == Item::FIELD_ITEM)
+ field=((Item_field *)(items[0]->real_item()))->field;
/* But if it can't be compared as a longlong, we don't really care. */
if (field && !field->can_be_compared_as_longlong())
field= NULL;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 63a7f1f130b..e139eba385e 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2213,7 +2213,7 @@ longlong Item_extract::val_int()
switch (int_type) {
case INTERVAL_YEAR: return ltime.year;
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
- case INTERVAL_QUARTER: return ltime.month/3 + 1;
+ case INTERVAL_QUARTER: return (ltime.month+2)/3;
case INTERVAL_MONTH: return ltime.month;
case INTERVAL_WEEK:
{
diff --git a/sql/key.cc b/sql/key.cc
index 9d86095f33e..75161e4f616 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -192,7 +192,8 @@ void key_restore(byte *to_record, byte *from_key, KEY *key_info,
Field_bit *field= (Field_bit *) (key_part->field);
if (field->bit_len)
{
- uchar bits= *(from_key + key_part->length - field->field_length -1);
+ uchar bits= *(from_key + key_part->length -
+ field->pack_length_in_rec() - 1);
set_rec_bits(bits, to_record + key_part->null_offset +
(key_part->null_bit == 128),
field->bit_ofs, field->bit_len);
diff --git a/sql/log.cc b/sql/log.cc
index 85e8c4dae2f..ba02c9ba082 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1882,7 +1882,11 @@ DBUG_skip_commit:
rotate binlog, if necessary.
*/
if (commit_event->get_type_code() == XID_EVENT)
- thread_safe_increment(prepared_xids, &LOCK_prep_xids);
+ {
+ pthread_mutex_lock(&LOCK_prep_xids);
+ prepared_xids++;
+ pthread_mutex_unlock(&LOCK_prep_xids);
+ }
else
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e9ff220a6a1..9dd37bbebc9 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -5531,7 +5531,7 @@ log and this option does nothing anymore.",
"Sets the maximum number of threads allowed inside InnoDB. Value 0"
" will disable the thread throttling.",
(gptr*) &srv_thread_concurrency, (gptr*) &srv_thread_concurrency,
- 0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0},
+ 0, GET_LONG, REQUIRED_ARG, 8, 0, 1000, 0, 1, 0},
{"innodb_thread_sleep_delay", OPT_INNODB_THREAD_SLEEP_DELAY,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0"
" disable a sleep",
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index cf3ba9c8c40..31201474c05 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -830,6 +830,11 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
flags.sql_mode,
flags.max_sort_length,
flags.group_concat_max_len));
+ /*
+ Make InnoDB to release the adaptive hash index latch before
+ acquiring the query cache mutex.
+ */
+ ha_release_temporary_latches(thd);
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size == 0)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 59391a333c3..5a6bbe01183 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -919,14 +919,12 @@ bool select_send::send_data(List<Item> &items)
return 0;
}
-#ifdef HAVE_INNOBASE_DB
/*
We may be passing the control from mysqld to the client: release the
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd
*/
ha_release_temporary_latches(thd);
-#endif
List_iterator_fast<Item> li(items);
Protocol *protocol= thd->protocol;
@@ -956,12 +954,10 @@ bool select_send::send_data(List<Item> &items)
bool select_send::send_eof()
{
-#ifdef HAVE_INNOBASE_DB
/* We may be passing the control from mysqld to the client: release the
InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
by thd */
ha_release_temporary_latches(thd);
-#endif
/* Unlock tables before sending packet to gain some speed */
if (thd->lock)
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 33ad27b9d14..2784e71ccae 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -445,9 +445,8 @@ Sensitive_cursor::fetch(ulong num_rows)
if (error == NESTED_LOOP_CURSOR_LIMIT)
join->resume_nested_loop= TRUE;
-#ifdef USING_TRANSACTIONS
ha_release_temporary_latches(thd);
-#endif
+
/* Grab free_list here to correctly free it in close */
thd->restore_active_arena(this, &backup_arena);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 07678d97800..85d93767486 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -466,6 +466,12 @@ impossible position";
(rli->group_master_log_pos)
*/
int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0);
+ /*
+ if reconnect master sends FD event with `created' as 0
+ to avoid destroying temp tables.
+ */
+ int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
+ ST_CREATED_OFFSET+1, (ulong) 0);
/* send it */
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{