3538 Ole John Aske 2011-08-17 [merge]
Merge from telco-7.0
removed:
mysql-test/suite/ndb/r/ndb_statistics.result
mysql-test/suite/ndb/t/ndb_statistics.test
added:
mysql-test/suite/ndb/r/ndb_index_stat.result
mysql-test/suite/ndb/r/ndb_statistics0.result
mysql-test/suite/ndb/r/ndb_statistics1.result
mysql-test/suite/ndb/t/ndb_index_stat.test
mysql-test/suite/ndb/t/ndb_index_stat_enable.inc
mysql-test/suite/ndb/t/ndb_statistics.inc
mysql-test/suite/ndb/t/ndb_statistics0.test
mysql-test/suite/ndb/t/ndb_statistics1.test
modified:
mysql-test/suite/ndb/r/ndb_restore_misc.result
mysql-test/suite/ndb/t/ndb_restore_misc.test
sql/ha_ndb_index_stat.cc
sql/ha_ndb_index_stat.h
sql/ha_ndbcluster.cc
sql/ha_ndbcluster.h
storage/ndb/include/ndb_constants.h
storage/ndb/include/ndbapi/NdbIndexStat.hpp
storage/ndb/include/util/NdbPack.hpp
storage/ndb/src/common/util/NdbPack.cpp
storage/ndb/src/ndbapi/NdbIndexStat.cpp
storage/ndb/src/ndbapi/NdbIndexStatImpl.cpp
storage/ndb/src/ndbapi/NdbIndexStatImpl.hpp
storage/ndb/src/ndbapi/NdbQueryOperation.cpp
storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp
storage/ndb/test/ndbapi/testIndexStat.cpp
storage/ndb/tools/ndb_index_stat.cpp
3537 Ole John Aske 2011-08-17 [merge]
Merge
modified:
storage/ndb/src/ndbapi/NdbQueryOperation.cpp
storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp
=== added file 'mysql-test/suite/ndb/r/ndb_index_stat.result'
--- a/mysql-test/suite/ndb/r/ndb_index_stat.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/r/ndb_index_stat.result 2011-08-17 12:51:57 +0000
@@ -0,0 +1,498 @@
+DROP TABLE IF EXISTS t1, t2;
+set @is_enable_default = @@global.ndb_index_stat_enable;
+set @is_enable = 1;
+set @is_enable = NULL;
+# is_enable_on=1 is_enable_off=0
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+set @@global.ndb_index_stat_enable = 1;
+set @@local.ndb_index_stat_enable = 1;
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+show global variables like 'ndb_index_stat_option';
+Variable_name Value
+ndb_index_stat_option loop_checkon=1000ms,loop_idle=1000ms,loop_busy=100ms,update_batch=1,read_batch=4,idle_batch=32,check_batch=32,check_delay=1m,delete_batch=8,clean_delay=0,error_batch=4,error_delay=1m,evict_batch=8,evict_delay=1m,cache_limit=32M,cache_lowpct=90
+set @save_option = @@global.ndb_index_stat_option;
+set @@global.ndb_index_stat_option = 'loop_idle=3333,cache_limit=44M';
+set @@global.ndb_index_stat_option = 'cache_lowpct=85,evict_delay=55';
+set @@global.ndb_index_stat_option = 'check_delay=234s';
+show global variables like 'ndb_index_stat_option';
+Variable_name Value
+ndb_index_stat_option loop_checkon=1000ms,loop_idle=3333ms,loop_busy=100ms,update_batch=1,read_batch=4,idle_batch=32,check_batch=32,check_delay=234s,delete_batch=8,clean_delay=0,error_batch=4,error_delay=1m,evict_batch=8,evict_delay=55s,cache_limit=44M,cache_lowpct=85
+set @@global.ndb_index_stat_option = @save_option;
+show global variables like 'ndb_index_stat_option';
+Variable_name Value
+ndb_index_stat_option loop_checkon=1000ms,loop_idle=1000ms,loop_busy=100ms,update_batch=1,read_batch=4,idle_batch=32,check_batch=32,check_delay=1m,delete_batch=8,clean_delay=0,error_batch=4,error_delay=1m,evict_batch=8,evict_delay=1m,cache_limit=32M,cache_lowpct=90
+create table t1 (
+a1 int unsigned not null,
+b1 int unsigned not null,
+c1 int unsigned not null,
+primary key (a1),
+index b1x (b1),
+index c1x (c1)
+) engine=ndb;
+create table t2 (
+a2 int unsigned not null,
+b2 int unsigned not null,
+c2 int unsigned not null,
+primary key (a2),
+index b2x (b2),
+index c2x (c2)
+) engine=ndb;
+analyze table t1, t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+# must use b1x
+explain select * from t1
+where b1 = 5 and c1 = 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref b1x,c1x b1x 4 const # Using where with pushed condition
+# must use c2x
+explain select * from t2
+where b2 = 5 and c2 = 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref b2x,c2x c2x 4 const # Using where with pushed condition
+# must use b1x, c2x
+explain select * from t1, t2
+where c1 = c2 and b1 = 5 and b2 = 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref b1x,c1x b1x 4 const # Parent of 2 pushed join@1
+1 SIMPLE t2 ref b2x,c2x c2x 4 test.t1.c1 # Child of 't1' in pushed join@1; Using where with pushed condition
+# must use c2x, b1x
+explain select * from t1, t2
+where b1 = b2 and c1 = 5 and c2 = 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref b2x,c2x c2x 4 const # Parent of 2 pushed join@1
+1 SIMPLE t1 ref b1x,c1x b1x 4 test.t2.b2 # Child of 't2' in pushed join@1; Using where with pushed condition
+# must use t1, c2x
+explain select * from t1, t2
+where c1 = c2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL c1x NULL NULL NULL # Parent of 2 pushed join@1
+1 SIMPLE t2 ref c2x c2x 4 test.t1.c1 # Child of 't1' in pushed join@1
+# must use t2, b1x
+explain select * from t1, t2
+where b1 = b2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL b2x NULL NULL NULL # Parent of 2 pushed join@1
+1 SIMPLE t1 ref b1x b1x 4 test.t2.b2 # Child of 't2' in pushed join@1
+# should NOT say: Using index for group-by
+explain select distinct (a1) from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL #
+# must say: Using index for group by
+explain select distinct (b1) from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b1x 4 NULL #
+# must say: Using index for group by
+explain select distinct (c1) from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c1x 4 NULL #
+drop table t1, t2;
+create table t1 (a int, b int, c varchar(10) not null,
+primary key using hash (a), index(b,c)) engine=ndb;
+insert into t1 values
+(1,10,'aaa'),(2,10,'bbb'),(3,10,'ccc'),
+(4,20,'aaa'),(5,20,'bbb'),(6,20,'ccc'),
+(7,30,'aaa'),(8,30,'bbb'),(9,30,'ccc');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+set @@local.ndb_index_stat_enable = 0;
+select count(*) from t1 where b < 10;
+count(*)
+0
+select count(*) from t1 where b >= 10 and c >= 'bbb';
+count(*)
+6
+select count(*) from t1 where b > 10;
+count(*)
+6
+select count(*) from t1 where b <= 20 and c < 'ccc';
+count(*)
+4
+select count(*) from t1 where b = 20 and c = 'ccc';
+count(*)
+1
+select count(*) from t1 where b > 20;
+count(*)
+3
+select count(*) from t1 where b = 30 and c > 'aaa';
+count(*)
+2
+select count(*) from t1 where b <= 20;
+count(*)
+6
+select count(*) from t1 where b >= 20 and c > 'aaa';
+count(*)
+4
+set @@local.ndb_index_stat_enable = 1;
+select count(*) from t1 where b < 10;
+count(*)
+0
+select count(*) from t1 where b >= 10 and c >= 'bbb';
+count(*)
+6
+select count(*) from t1 where b > 10;
+count(*)
+6
+select count(*) from t1 where b <= 20 and c < 'ccc';
+count(*)
+4
+select count(*) from t1 where b = 20 and c = 'ccc';
+count(*)
+1
+select count(*) from t1 where b > 20;
+count(*)
+3
+select count(*) from t1 where b = 30 and c > 'aaa';
+count(*)
+2
+select count(*) from t1 where b <= 20;
+count(*)
+6
+select count(*) from t1 where b >= 20 and c > 'aaa';
+count(*)
+4
+set @@local.ndb_index_stat_enable = 0;
+select count(*) from t1 where b < 10;
+count(*)
+0
+select count(*) from t1 where b >= 10 and c >= 'bbb';
+count(*)
+6
+select count(*) from t1 where b > 10;
+count(*)
+6
+select count(*) from t1 where b <= 20 and c < 'ccc';
+count(*)
+4
+select count(*) from t1 where b = 20 and c = 'ccc';
+count(*)
+1
+select count(*) from t1 where b > 20;
+count(*)
+3
+select count(*) from t1 where b = 30 and c > 'aaa';
+count(*)
+2
+select count(*) from t1 where b <= 20;
+count(*)
+6
+select count(*) from t1 where b >= 20 and c > 'aaa';
+count(*)
+4
+set @@local.ndb_index_stat_enable = 1;
+select count(*) from t1 where b < 10;
+count(*)
+0
+select count(*) from t1 where b >= 10 and c >= 'bbb';
+count(*)
+6
+select count(*) from t1 where b > 10;
+count(*)
+6
+select count(*) from t1 where b <= 20 and c < 'ccc';
+count(*)
+4
+select count(*) from t1 where b = 20 and c = 'ccc';
+count(*)
+1
+select count(*) from t1 where b > 20;
+count(*)
+3
+select count(*) from t1 where b = 30 and c > 'aaa';
+count(*)
+2
+select count(*) from t1 where b <= 20;
+count(*)
+6
+select count(*) from t1 where b >= 20 and c > 'aaa';
+count(*)
+4
+drop table t1;
+create table t1 (a int, b int, primary key using hash (a), index x1 (b))
+engine=ndb;
+insert into t1 values (1,11),(2,22),(3,33);
+select * from t1 order by a;
+a b
+1 11
+2 22
+3 33
+select * from t1 order by a;
+a b
+1 11
+2 22
+3 33
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+drop table t1;
+create table t1 (
+pk int not null,
+a tinyint not null,
+b tinyint unsigned not null,
+c smallint not null,
+d smallint unsigned not null,
+e mediumint not null,
+f mediumint unsigned not null,
+g int not null,
+h int unsigned not null,
+i bigint not null,
+j bigint unsigned not null,
+k float not null,
+l double not null,
+m decimal not null,
+n decimal unsigned not null,
+primary key using hash (pk),
+index (a),
+index (b),
+index (c),
+index (d),
+index (e),
+index (f),
+index (g),
+index (h),
+index (i),
+index (j),
+index (k),
+index (l),
+index (m),
+index (n)
+) engine=ndb;
+insert into t1 values
+(1,11,11,11,11,11,11,11,11,11,11,11,11,11,11),
+(2,22,22,22,22,22,22,22,22,22,22,22,22,22,22),
+(3,33,33,33,33,33,33,33,33,33,33,33,33,33,33);
+select count(*) from t1 where a > 22;
+count(*)
+1
+select count(*) from t1 where b > 22;
+count(*)
+1
+select count(*) from t1 where c > 22;
+count(*)
+1
+select count(*) from t1 where d > 22;
+count(*)
+1
+select count(*) from t1 where e > 22;
+count(*)
+1
+select count(*) from t1 where f > 22;
+count(*)
+1
+select count(*) from t1 where g > 22;
+count(*)
+1
+select count(*) from t1 where h > 22;
+count(*)
+1
+select count(*) from t1 where i > 22;
+count(*)
+1
+select count(*) from t1 where j > 22;
+count(*)
+1
+select count(*) from t1 where k > 22;
+count(*)
+1
+select count(*) from t1 where l > 22;
+count(*)
+1
+select count(*) from t1 where m > 22;
+count(*)
+1
+select count(*) from t1 where n > 22;
+count(*)
+1
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select count(*) from t1 where a > 22;
+count(*)
+1
+select count(*) from t1 where b > 22;
+count(*)
+1
+select count(*) from t1 where c > 22;
+count(*)
+1
+select count(*) from t1 where d > 22;
+count(*)
+1
+select count(*) from t1 where e > 22;
+count(*)
+1
+select count(*) from t1 where f > 22;
+count(*)
+1
+select count(*) from t1 where g > 22;
+count(*)
+1
+select count(*) from t1 where h > 22;
+count(*)
+1
+select count(*) from t1 where i > 22;
+count(*)
+1
+select count(*) from t1 where j > 22;
+count(*)
+1
+select count(*) from t1 where k > 22;
+count(*)
+1
+select count(*) from t1 where l > 22;
+count(*)
+1
+select count(*) from t1 where m > 22;
+count(*)
+1
+select count(*) from t1 where n > 22;
+count(*)
+1
+drop table t1;
+create table t1 (
+pk int not null,
+a datetime not null,
+b date not null,
+c year not null,
+d time not null,
+e timestamp not null,
+primary key using hash (pk),
+index (a),
+index (b),
+index (c),
+index (d),
+index (e)
+) engine=ndb;
+insert into t1 values
+(1,'1971-01-01 01:01:01','1971-01-01','1971','01:01:01','1971-01-01 01:01:01'),
+(2,'1972-02-02 02:02:02','1972-02-02','1972','02:02:02','1972-02-02 02:02:02'),
+(3,'1973-03-03 03:03:03','1973-03-03','1973','03:03:03','1973-03-03 03:03:03');
+select count(*) from t1 where a > '1972-02-02 02:02:02';
+count(*)
+1
+select count(*) from t1 where b > '1972-02-02';
+count(*)
+1
+select count(*) from t1 where c > '1972';
+count(*)
+1
+select count(*) from t1 where d > '02:02:02';
+count(*)
+1
+select count(*) from t1 where e > '1972-02-02 02:02:02';
+count(*)
+1
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select count(*) from t1 where a > '1972-02-02 02:02:02';
+count(*)
+1
+select count(*) from t1 where b > '1972-02-02';
+count(*)
+1
+select count(*) from t1 where c > '1972';
+count(*)
+1
+select count(*) from t1 where d > '02:02:02';
+count(*)
+1
+select count(*) from t1 where e > '1972-02-02 02:02:02';
+count(*)
+1
+drop table t1;
+create table t1 (
+pk int not null,
+a char(10) not null,
+b varchar(10) not null,
+c varchar(1000) not null,
+d binary(10) not null,
+e varbinary(10) not null,
+f varbinary(1000) not null,
+primary key using hash (pk),
+index (a),
+index (b),
+index (c),
+index (d),
+index (e),
+index (f)
+) engine=ndb;
+insert into t1 values
+('1','111','111','111','111','111','111'),
+('2','222','222','222','222','222','222'),
+('3','333','333','333','333','333','333');
+select count(*) from t1 where a > '222';
+count(*)
+1
+select count(*) from t1 where b > '222';
+count(*)
+1
+select count(*) from t1 where c > '222';
+count(*)
+1
+select count(*) from t1 where d > '222';
+count(*)
+2
+select count(*) from t1 where e > '222';
+count(*)
+1
+select count(*) from t1 where f > '222';
+count(*)
+1
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+select count(*) from t1 where a > '222';
+count(*)
+1
+select count(*) from t1 where b > '222';
+count(*)
+1
+select count(*) from t1 where c > '222';
+count(*)
+1
+select count(*) from t1 where d > '222';
+count(*)
+2
+select count(*) from t1 where e > '222';
+count(*)
+1
+select count(*) from t1 where f > '222';
+count(*)
+1
+drop table t1;
+set @is_enable = @is_enable_default;
+set @is_enable = NULL;
+# is_enable_on=0 is_enable_off=1
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+set @@local.ndb_index_stat_enable = 0;
+set @@global.ndb_index_stat_enable = 0;
+drop table mysql.ndb_index_stat_sample;
+drop table mysql.ndb_index_stat_head;
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
=== modified file 'mysql-test/suite/ndb/r/ndb_restore_misc.result'
--- a/mysql-test/suite/ndb/r/ndb_restore_misc.result 2011-05-31 08:28:58 +0000
+++ b/mysql-test/suite/ndb/r/ndb_restore_misc.result 2011-07-19 10:54:29 +0000
@@ -623,8 +623,12 @@ name VARCHAR(255)
ndb_show_tables completed.....
+select id into @tmp1 from ndb_show_tables_results
+where name like '%ndb_index_stat_sample_x1%';
select * from ndb_show_tables_results
where type like '%Index%'
+and name not like '%ndb_index_stat_sample_x1%'
+and name not like concat('%NDB$INDEX_',@tmp1,'_CUSTOM%')
order by 1,2,3,4,5,6,7;
id type state logging _database _schema name
drop table ndb_show_tables_results;
=== removed file 'mysql-test/suite/ndb/r/ndb_statistics.result'
--- a/mysql-test/suite/ndb/r/ndb_statistics.result 2011-03-17 13:54:30 +0000
+++ b/mysql-test/suite/ndb/r/ndb_statistics.result 1970-01-01 00:00:00 +0000
@@ -1,161 +0,0 @@
-drop table if exists t1, t2, t3, t4;
-CREATE TABLE t10(
-K INT NOT NULL AUTO_INCREMENT,
-I INT, J INT,
-PRIMARY KEY(K),
-KEY(I,J),
-UNIQUE KEY(J,K)
-) ENGINE=ndbcluster;
-INSERT INTO t10(I,J) VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
-CREATE TABLE t100 LIKE t10;
-INSERT INTO t100(I,J)
-SELECT X.J, X.J+(10*Y.J) FROM t10 AS X,t10 AS Y;
-CREATE TABLE t10000 LIKE t10;
-INSERT INTO t10000(I,J)
-SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
-WHERE X.J<50;
-INSERT INTO t10000(I,J)
-SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
-WHERE X.J>=50;
-ANALYZE TABLE t10,t100,t10000;
-Table Op Msg_type Msg_text
-test.t10 analyze status OK
-test.t100 analyze status OK
-test.t10000 analyze status OK
-SELECT COUNT(*) FROM t10;
-COUNT(*)
-10
-SELECT COUNT(*) FROM t100;
-COUNT(*)
-100
-SELECT COUNT(*) FROM t10000;
-COUNT(*)
-10000
-EXPLAIN
-SELECT * FROM t10000 WHERE k = 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 const PRIMARY PRIMARY 4 const 1
-EXPLAIN
-SELECT * FROM t10000 WHERE k >= 42 and k < 10000;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k < 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k > 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 AS X JOIN t10000 AS Y
-ON Y.I=X.I AND Y.J = X.I;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE X ALL I NULL NULL NULL 10000 Parent of 2 pushed join@1
-1 SIMPLE Y ref J,I I 10 test.X.I,test.X.I 11 Child of 'X' in pushed join@1; Using where
-EXPLAIN
-SELECT * FROM t100 WHERE k < 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 10 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t100 WHERE k > 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 10 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k < 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k > 42;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t100 WHERE k BETWEEN 42 AND 10000;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 5 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref I I 5 const 200 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J J 5 const 100 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J,I I 10 const,const 4 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref I I 5 const 200 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J > 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I I 10 NULL 100 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J < 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I I 10 NULL 50 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J BETWEEN 1 AND 10;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I I 10 NULL 50 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J = 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J,I I 10 const,const 4 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J J 5 const 100 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K > 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY,J J 9 NULL 50 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K < 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY,J J 9 NULL 50 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K BETWEEN 1 AND 10;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range PRIMARY,J J 9 NULL 25 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K = 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 const PRIMARY,J PRIMARY 4 const 1 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J <> 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I I 10 NULL 150 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I <> 0 AND J = 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J,I J 5 const 100 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE I <> 0 AND J <> 1;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I J 5 NULL 1500 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J <> 1 AND I = 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I I 10 NULL 150 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 1 AND I <> 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 ref J,I J 5 const 100 Using where with pushed condition
-EXPLAIN
-SELECT * FROM t10000 WHERE J <> 1 AND I <> 0;
-id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t10000 range J,I J 5 NULL 1500 Using where with pushed condition
-DROP TABLE t10,t100,t10000;
-End of 5.1 tests
=== added file 'mysql-test/suite/ndb/r/ndb_statistics0.result'
--- a/mysql-test/suite/ndb/r/ndb_statistics0.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/r/ndb_statistics0.result 2011-08-17 12:51:57 +0000
@@ -0,0 +1,197 @@
+set @is_enable_default = @@global.ndb_index_stat_enable;
+set @is_enable = 0;
+set @is_enable = NULL;
+# is_enable_on=0 is_enable_off=0
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+drop table if exists t1, t2, t3, t4;
+CREATE TABLE t10(
+K INT NOT NULL AUTO_INCREMENT,
+I INT, J INT,
+PRIMARY KEY(K),
+KEY(I,J),
+UNIQUE KEY(J,K)
+) ENGINE=ndbcluster
+partition by key (K) partitions 1;
+INSERT INTO t10(I,J) VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+CREATE TABLE t100 LIKE t10;
+INSERT INTO t100(I,J)
+SELECT X.J, X.J+(10*Y.J) FROM t10 AS X,t10 AS Y;
+CREATE TABLE t10000 LIKE t10;
+INSERT INTO t10000(I,J)
+SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+WHERE X.J<50;
+INSERT INTO t10000(I,J)
+SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+WHERE X.J>=50;
+ANALYZE TABLE t10,t100,t10000;
+Table Op Msg_type Msg_text
+test.t10 analyze status OK
+test.t100 analyze status OK
+test.t10000 analyze status OK
+SELECT COUNT(*) FROM t10;
+COUNT(*)
+10
+SELECT COUNT(*) FROM t100;
+COUNT(*)
+100
+SELECT COUNT(*) FROM t10000;
+COUNT(*)
+10000
+EXPLAIN
+SELECT * FROM t10000 WHERE k = 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 const PRIMARY PRIMARY 4 const 1
+EXPLAIN
+SELECT * FROM t10000 WHERE k >= 42 and k < 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 AS X JOIN t10000 AS Y
+ON Y.I=X.I AND Y.J = X.I;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE X ALL I NULL NULL NULL 10000 Parent of 2 pushed join@1
+1 SIMPLE Y ref J,I I 10 test.X.I,test.X.I 11 Child of 'X' in pushed join@1; Using where
+EXPLAIN
+SELECT * FROM t100 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 10 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t100 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 10 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 1000 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t100 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 5 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 500 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref I I 5 const 200 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J J 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I I 10 const,const 4 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref I I 5 const 200 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J > 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J < 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 50 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J BETWEEN 1 AND 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 50 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I I 10 const,const 4 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J J 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K > 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J J 9 NULL 50 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K < 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J J 9 NULL 50 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K BETWEEN 1 AND 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J J 9 NULL 25 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 const PRIMARY,J PRIMARY 4 const 1 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J <> 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 150 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J <> 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I J 5 NULL 1500 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 150 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 1 AND I <> 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I <> 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I J 5 NULL 1500 Using where with pushed condition
+DROP TABLE t10,t100,t10000;
+End of 5.1 tests
+set @is_enable = @is_enable_default;
+set @is_enable = NULL;
+# is_enable_on=0 is_enable_off=0
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
=== added file 'mysql-test/suite/ndb/r/ndb_statistics1.result'
--- a/mysql-test/suite/ndb/r/ndb_statistics1.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/r/ndb_statistics1.result 2011-08-17 12:51:57 +0000
@@ -0,0 +1,203 @@
+set @is_enable_default = @@global.ndb_index_stat_enable;
+set @is_enable = 1;
+set @is_enable = NULL;
+# is_enable_on=1 is_enable_off=0
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+set @@global.ndb_index_stat_enable = 1;
+set @@local.ndb_index_stat_enable = 1;
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+drop table if exists t1, t2, t3, t4;
+CREATE TABLE t10(
+K INT NOT NULL AUTO_INCREMENT,
+I INT, J INT,
+PRIMARY KEY(K),
+KEY(I,J),
+UNIQUE KEY(J,K)
+) ENGINE=ndbcluster
+partition by key (K) partitions 1;
+INSERT INTO t10(I,J) VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+CREATE TABLE t100 LIKE t10;
+INSERT INTO t100(I,J)
+SELECT X.J, X.J+(10*Y.J) FROM t10 AS X,t10 AS Y;
+CREATE TABLE t10000 LIKE t10;
+INSERT INTO t10000(I,J)
+SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+WHERE X.J<50;
+INSERT INTO t10000(I,J)
+SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+WHERE X.J>=50;
+ANALYZE TABLE t10,t100,t10000;
+Table Op Msg_type Msg_text
+test.t10 analyze status OK
+test.t100 analyze status OK
+test.t10000 analyze status OK
+SELECT COUNT(*) FROM t10;
+COUNT(*)
+10
+SELECT COUNT(*) FROM t100;
+COUNT(*)
+100
+SELECT COUNT(*) FROM t10000;
+COUNT(*)
+10000
+EXPLAIN
+SELECT * FROM t10000 WHERE k = 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 const PRIMARY PRIMARY 4 const 1
+EXPLAIN
+SELECT * FROM t10000 WHERE k >= 42 and k < 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 42 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 9958 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 AS X JOIN t10000 AS Y
+ON Y.I=X.I AND Y.J = X.I;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE X ALL I NULL NULL NULL 10000 Parent of 2 pushed join@1
+1 SIMPLE Y ref J,I I 10 test.X.I,test.X.I 1 Child of 'X' in pushed join@1; Using where
+EXPLAIN
+SELECT * FROM t100 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 42 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t100 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 58 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 42 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 9958 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t100 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t100 range PRIMARY PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref I I 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref I I 5 const 100 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J > 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 99 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J < 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I J 5 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J BETWEEN 1 AND 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I J 5 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K > 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J J 9 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K < 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K BETWEEN 1 AND 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range PRIMARY,J PRIMARY 4 NULL 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 const PRIMARY,J PRIMARY 4 const 1 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J <> 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 101 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J = 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J <> 1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 5 NULL 9902 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I = 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 10 NULL 101 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 1 AND I <> 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 ref J,I J 5 const 2 Using where with pushed condition
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I <> 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t10000 range J,I I 5 NULL 9902 Using where with pushed condition
+DROP TABLE t10,t100,t10000;
+End of 5.1 tests
+set @is_enable = @is_enable_default;
+set @is_enable = NULL;
+# is_enable_on=0 is_enable_off=1
+# ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable ON
+set @@local.ndb_index_stat_enable = 0;
+set @@global.ndb_index_stat_enable = 0;
+drop table mysql.ndb_index_stat_sample;
+drop table mysql.ndb_index_stat_head;
+# ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
+show local variables like 'ndb_index_stat_enable';
+Variable_name Value
+ndb_index_stat_enable OFF
=== added file 'mysql-test/suite/ndb/t/ndb_index_stat.test'
--- a/mysql-test/suite/ndb/t/ndb_index_stat.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_index_stat.test 2011-07-23 14:35:37 +0000
@@ -0,0 +1,313 @@
+-- source include/have_ndb.inc
+
+# Notes on index stats in *.test.
+#
+# Most tables here have few table rows. Index stats are not very
+# useful in such cases but the optimizer seems to use them anyway.
+# One reason may be that nested joins is only join method.
+#
+# In real production index stats are computed daily or weekly.
+# But tests here must compute them at once if "explain" is used.
+# Thus: insert (or other dml) - analyze table - explain.
+#
+# Index stats are approximate since only one replica was scanned
+# and values are interpolated from samples. MTR however should be
+# deterministic. If not use --replace column 9 # (rows).
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+set @is_enable_default = @@global.ndb_index_stat_enable;
+
+set @is_enable = 1;
+source ndb_index_stat_enable.inc;
+
+# test changing suboptions
+show global variables like 'ndb_index_stat_option';
+set @save_option = @@global.ndb_index_stat_option;
+# some options
+set @@global.ndb_index_stat_option = 'loop_idle=3333,cache_limit=44M';
+set @@global.ndb_index_stat_option = 'cache_lowpct=85,evict_delay=55';
+set @@global.ndb_index_stat_option = 'check_delay=234s';
+show global variables like 'ndb_index_stat_option';
+set @@global.ndb_index_stat_option = @save_option;
+show global variables like 'ndb_index_stat_option';
+
+# TEST: main
+create table t1 (
+ a1 int unsigned not null,
+ b1 int unsigned not null,
+ c1 int unsigned not null,
+ primary key (a1),
+ index b1x (b1),
+ index c1x (c1)
+) engine=ndb;
+
+create table t2 (
+ a2 int unsigned not null,
+ b2 int unsigned not null,
+ c2 int unsigned not null,
+ primary key (a2),
+ index b2x (b2),
+ index c2x (c2)
+) engine=ndb;
+
+# enough rows to make index stats more approximate
+
+--disable_query_log
+let $i = 1000;
+while ($i)
+{
+ dec $i;
+ eval insert into t1 values ($i, $i % 100, $i % 10);
+}
+let $i = 1000;
+while ($i)
+{
+ dec $i;
+ eval insert into t2 values ($i, $i % 10, $i % 100);
+}
+--enable_query_log
+analyze table t1, t2;
+
+# TEST: key equal constant
+
+--echo # must use b1x
+--replace_column 9 #
+explain select * from t1
+ where b1 = 5 and c1 = 5;
+
+--echo # must use c2x
+--replace_column 9 #
+explain select * from t2
+ where b2 = 5 and c2 = 5;
+
+# TEST: keys equal constant in join
+
+--echo # must use b1x, c2x
+--replace_column 9 #
+explain select * from t1, t2
+ where c1 = c2 and b1 = 5 and b2 = 5;
+
+--echo # must use c2x, b1x
+--replace_column 9 #
+explain select * from t1, t2
+ where b1 = b2 and c1 = 5 and c2 = 5;
+
+# TEST: join via keys of different selectivity
+
+--echo # must use t1, c2x
+--replace_column 9 #
+explain select * from t1, t2
+ where c1 = c2;
+--echo # must use t2, b1x
+--replace_column 9 #
+explain select * from t1, t2
+ where b1 = b2;
+
+# TEST: bug#44760 quick distinct
+# QUICK_GROUP_MIN_MAX_SELECT says "Using index for group-by".
+# Should happen only for low cardinality index.
+# wl4124_todo: result is wrong until HA_KEYREAD_ONLY is set
+
+--echo # should NOT say: Using index for group-by
+--replace_column 9 #
+explain select distinct (a1) from t1;
+
+--echo # must say: Using index for group by
+--replace_column 9 #
+explain select distinct (b1) from t1;
+
+--echo # must say: Using index for group by
+--replace_column 9 #
+explain select distinct (c1) from t1;
+
+# TEST: end
+drop table t1, t2;
+
+# turn index stats OFF in client (falls back on other methods)
+# code snippet moved from ndb_index_ordered.test
+
+create table t1 (a int, b int, c varchar(10) not null,
+ primary key using hash (a), index(b,c)) engine=ndb;
+insert into t1 values
+ (1,10,'aaa'),(2,10,'bbb'),(3,10,'ccc'),
+ (4,20,'aaa'),(5,20,'bbb'),(6,20,'ccc'),
+ (7,30,'aaa'),(8,30,'bbb'),(9,30,'ccc');
+analyze table t1;
+let $is_loop = 4;
+while ($is_loop)
+{
+ # 4-OFF 3-ON 2-OFF 1-ON
+ let $is_enable = `select ($is_loop=3 or $is_loop=1)`;
+ dec $is_loop;
+ eval set @@local.ndb_index_stat_enable = $is_enable;
+
+select count(*) from t1 where b < 10;
+select count(*) from t1 where b >= 10 and c >= 'bbb';
+select count(*) from t1 where b > 10;
+select count(*) from t1 where b <= 20 and c < 'ccc';
+select count(*) from t1 where b = 20 and c = 'ccc';
+select count(*) from t1 where b > 20;
+select count(*) from t1 where b = 30 and c > 'aaa';
+select count(*) from t1 where b <= 20;
+select count(*) from t1 where b >= 20 and c > 'aaa';
+}
+drop table t1;
+
+# bug#XXXXX
+# autocreate=false,enable=1 is now acceptable
+# following gives warning while "no stats" is counted as error
+create table t1 (a int, b int, primary key using hash (a), index x1 (b))
+engine=ndb;
+insert into t1 values (1,11),(2,22),(3,33);
+# make_join_statistics() -> info() -> ndb_index_stat_set_rpk()
+# error 4715 - no stats
+select * from t1 order by a;
+# error 9003 suppressed - previous recent error
+select * from t1 order by a;
+# analyze clears previous error at once
+analyze table t1;
+drop table t1;
+
+# bug#XXXXX
+# wrong byte size from some types to NdbPack
+# before error fixes causes stats to be ignored silently (error 4716)
+# best seen with debug and export NDB_PACK_ABORT_ON_ERROR=1
+# affected types: mediumint datetime date time timestamp
+
+create table t1 (
+ pk int not null,
+ a tinyint not null,
+ b tinyint unsigned not null,
+ c smallint not null,
+ d smallint unsigned not null,
+ e mediumint not null,
+ f mediumint unsigned not null,
+ g int not null,
+ h int unsigned not null,
+ i bigint not null,
+ j bigint unsigned not null,
+ k float not null,
+ l double not null,
+ m decimal not null,
+ n decimal unsigned not null,
+ primary key using hash (pk),
+ index (a),
+ index (b),
+ index (c),
+ index (d),
+ index (e),
+ index (f),
+ index (g),
+ index (h),
+ index (i),
+ index (j),
+ index (k),
+ index (l),
+ index (m),
+ index (n)
+) engine=ndb;
+insert into t1 values
+(1,11,11,11,11,11,11,11,11,11,11,11,11,11,11),
+(2,22,22,22,22,22,22,22,22,22,22,22,22,22,22),
+(3,33,33,33,33,33,33,33,33,33,33,33,33,33,33);
+let $i = 2;
+while ($i)
+{
+ dec $i;
+ if (!$i)
+ {
+ eval analyze table t1;
+ }
+ eval select count(*) from t1 where a > 22;
+ eval select count(*) from t1 where b > 22;
+ eval select count(*) from t1 where c > 22;
+ eval select count(*) from t1 where d > 22;
+ eval select count(*) from t1 where e > 22;
+ eval select count(*) from t1 where f > 22;
+ eval select count(*) from t1 where g > 22;
+ eval select count(*) from t1 where h > 22;
+ eval select count(*) from t1 where i > 22;
+ eval select count(*) from t1 where j > 22;
+ eval select count(*) from t1 where k > 22;
+ eval select count(*) from t1 where l > 22;
+ eval select count(*) from t1 where m > 22;
+ eval select count(*) from t1 where n > 22;
+}
+drop table t1;
+
+create table t1 (
+ pk int not null,
+ a datetime not null,
+ b date not null,
+ c year not null,
+ d time not null,
+ e timestamp not null,
+ primary key using hash (pk),
+ index (a),
+ index (b),
+ index (c),
+ index (d),
+ index (e)
+) engine=ndb;
+insert into t1 values
+(1,'1971-01-01 01:01:01','1971-01-01','1971','01:01:01','1971-01-01 01:01:01'),
+(2,'1972-02-02 02:02:02','1972-02-02','1972','02:02:02','1972-02-02 02:02:02'),
+(3,'1973-03-03 03:03:03','1973-03-03','1973','03:03:03','1973-03-03 03:03:03');
+let $i = 2;
+while ($i)
+{
+ dec $i;
+ if (!$i)
+ {
+ eval analyze table t1;
+ }
+ eval select count(*) from t1 where a > '1972-02-02 02:02:02';
+ eval select count(*) from t1 where b > '1972-02-02';
+ eval select count(*) from t1 where c > '1972';
+ eval select count(*) from t1 where d > '02:02:02';
+ eval select count(*) from t1 where e > '1972-02-02 02:02:02';
+}
+drop table t1;
+
+create table t1 (
+ pk int not null,
+ a char(10) not null,
+ b varchar(10) not null,
+ c varchar(1000) not null,
+ d binary(10) not null,
+ e varbinary(10) not null,
+ f varbinary(1000) not null,
+ primary key using hash (pk),
+ index (a),
+ index (b),
+ index (c),
+ index (d),
+ index (e),
+ index (f)
+) engine=ndb;
+insert into t1 values
+('1','111','111','111','111','111','111'),
+('2','222','222','222','222','222','222'),
+('3','333','333','333','333','333','333');
+let $i = 2;
+while ($i)
+{
+ dec $i;
+ if (!$i)
+ {
+ eval analyze table t1;
+ }
+ eval select count(*) from t1 where a > '222';
+ eval select count(*) from t1 where b > '222';
+ eval select count(*) from t1 where c > '222';
+ eval select count(*) from t1 where d > '222';
+ eval select count(*) from t1 where e > '222';
+ eval select count(*) from t1 where f > '222';
+}
+drop table t1;
+
+set @is_enable = @is_enable_default;
+source ndb_index_stat_enable.inc;
=== added file 'mysql-test/suite/ndb/t/ndb_index_stat_enable.inc'
--- a/mysql-test/suite/ndb/t/ndb_index_stat_enable.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_index_stat_enable.inc 2011-07-02 07:05:32 +0000
@@ -0,0 +1,39 @@
+# turn ndb_index_stat_enable ON or OFF
+# caller sets @is_enable 0/1
+# based on global variable, local follows global
+# do nothing if value is already correct
+# setting OFF drops stats tables to avoid MTR diff
+
+let is_enable_on = `select @is_enable and not @@global.ndb_index_stat_enable`;
+let is_enable_off = `select not @is_enable and @@global.ndb_index_stat_enable`;
+set @is_enable = NULL;
+
+--echo # is_enable_on=$is_enable_on is_enable_off=$is_enable_off
+
+--echo # ndb_index_stat_enable - before
+show global variables like 'ndb_index_stat_enable';
+show local variables like 'ndb_index_stat_enable';
+
+if ($is_enable_on)
+{
+ # first global
+ eval set @@global.ndb_index_stat_enable = 1;
+ eval set @@local.ndb_index_stat_enable = 1;
+
+ # stats thread creates stats tables
+}
+
+if ($is_enable_off)
+{
+ # first local
+ eval set @@local.ndb_index_stat_enable = 0;
+ eval set @@global.ndb_index_stat_enable = 0;
+
+ # stats thread does not (and must not) drop stats tables
+ eval drop table mysql.ndb_index_stat_sample;
+ eval drop table mysql.ndb_index_stat_head;
+}
+
+--echo # ndb_index_stat_enable - after
+show global variables like 'ndb_index_stat_enable';
+show local variables like 'ndb_index_stat_enable';
=== modified file 'mysql-test/suite/ndb/t/ndb_restore_misc.test'
--- a/mysql-test/suite/ndb/t/ndb_restore_misc.test 2011-05-31 08:28:58 +0000
+++ b/mysql-test/suite/ndb/t/ndb_restore_misc.test 2011-07-19 10:54:29 +0000
@@ -546,8 +546,15 @@ CREATE TEMPORARY TABLE IF NOT EXISTS ndb
name VARCHAR(255)
);
--source ndb_show_tables_result.inc
+# the db fields include single quotes...
+--disable_warnings
+select id into @tmp1 from ndb_show_tables_results
+where name like '%ndb_index_stat_sample_x1%';
+--enable_warnings
select * from ndb_show_tables_results
where type like '%Index%'
+and name not like '%ndb_index_stat_sample_x1%'
+and name not like concat('%NDB$INDEX_',@tmp1,'_CUSTOM%')
order by 1,2,3,4,5,6,7;
drop table ndb_show_tables_results;
=== added file 'mysql-test/suite/ndb/t/ndb_statistics.inc'
--- a/mysql-test/suite/ndb/t/ndb_statistics.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_statistics.inc 2011-07-02 07:05:32 +0000
@@ -0,0 +1,145 @@
+-- source include/have_ndb.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3, t4;
+--enable_warnings
+
+CREATE TABLE t10(
+ K INT NOT NULL AUTO_INCREMENT,
+ I INT, J INT,
+ PRIMARY KEY(K),
+ KEY(I,J),
+ UNIQUE KEY(J,K)
+) ENGINE=ndbcluster
+ partition by key (K) partitions 1;
+
+INSERT INTO t10(I,J) VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+
+CREATE TABLE t100 LIKE t10;
+INSERT INTO t100(I,J)
+ SELECT X.J, X.J+(10*Y.J) FROM t10 AS X,t10 AS Y;
+
+CREATE TABLE t10000 LIKE t10;
+
+# Insert into t10000 in two chunks to not
+# exhaust MaxNoOfConcurrentOperations
+INSERT INTO t10000(I,J)
+ SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+ WHERE X.J<50;
+INSERT INTO t10000(I,J)
+ SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
+ WHERE X.J>=50;
+
+ANALYZE TABLE t10,t100,t10000;
+
+SELECT COUNT(*) FROM t10;
+SELECT COUNT(*) FROM t100;
+SELECT COUNT(*) FROM t10000;
+
+#
+# Bug #59517: Incorrect detection of single row access in
+# ha_ndbcluster::records_in_range()
+
+# Expect a single row (or const) when PK is excact specified
+EXPLAIN
+SELECT * FROM t10000 WHERE k = 42;
+
+# All queries below should *not* return a single row
+EXPLAIN
+SELECT * FROM t10000 WHERE k >= 42 and k < 10000;
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+
+#
+# Bug #59519 ::set_rec_per_key() assumes ORDER_INDEX to be unique
+#
+
+# 'REF' join of 'Y' should match >1 rows
+EXPLAIN
+SELECT * FROM t10000 AS X JOIN t10000 AS Y
+ ON Y.I=X.I AND Y.J = X.I;
+
+#
+# Bug #11804277: INCORRECT INDEX MAY BE SELECTED DUE TO INSUFFICIENT
+# STATISTICS FROM CLUSTER
+#
+
+# Open bounded range should return 10% of #rows in table
+EXPLAIN
+SELECT * FROM t100 WHERE k < 42;
+EXPLAIN
+SELECT * FROM t100 WHERE k > 42;
+EXPLAIN
+SELECT * FROM t10000 WHERE k < 42;
+EXPLAIN
+SELECT * FROM t10000 WHERE k > 42;
+
+#Closed bounded range should return 5% of #rows in table
+EXPLAIN
+SELECT * FROM t100 WHERE k BETWEEN 42 AND 10000;
+EXPLAIN
+SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
+
+#EQ-range selectivity depends on
+# - key length specified
+# - #rows in table.
+# - unique/non-unique index
+# - min 2% selectivity
+#
+# Possibly combined with open/closed ranges as
+# above which further improves selectivity
+#
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 0;
+
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0;
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J > 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J < 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J BETWEEN 1 AND 10;
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J = 1;
+
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K > 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K < 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K BETWEEN 1 AND 10;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 0 AND K = 1;
+
+## Verify selection of 'best' index
+## (The one of index I/J being EQ)
+EXPLAIN
+SELECT * FROM t10000 WHERE I = 0 AND J <> 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J = 1;
+EXPLAIN
+SELECT * FROM t10000 WHERE I <> 0 AND J <> 1;
+
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I = 0;
+EXPLAIN
+SELECT * FROM t10000 WHERE J = 1 AND I <> 0;
+EXPLAIN
+SELECT * FROM t10000 WHERE J <> 1 AND I <> 0;
+
+
+DROP TABLE t10,t100,t10000;
+
+--echo End of 5.1 tests
=== removed file 'mysql-test/suite/ndb/t/ndb_statistics.test'
--- a/mysql-test/suite/ndb/t/ndb_statistics.test 2011-02-28 10:42:04 +0000
+++ b/mysql-test/suite/ndb/t/ndb_statistics.test 1970-01-01 00:00:00 +0000
@@ -1,144 +0,0 @@
--- source include/have_ndb.inc
-
---disable_warnings
-drop table if exists t1, t2, t3, t4;
---enable_warnings
-
-CREATE TABLE t10(
- K INT NOT NULL AUTO_INCREMENT,
- I INT, J INT,
- PRIMARY KEY(K),
- KEY(I,J),
- UNIQUE KEY(J,K)
-) ENGINE=ndbcluster;
-
-INSERT INTO t10(I,J) VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
-
-CREATE TABLE t100 LIKE t10;
-INSERT INTO t100(I,J)
- SELECT X.J, X.J+(10*Y.J) FROM t10 AS X,t10 AS Y;
-
-CREATE TABLE t10000 LIKE t10;
-
-# Insert into t10000 in two chunks to not
-# exhaust MaxNoOfConcurrentOperations
-INSERT INTO t10000(I,J)
- SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
- WHERE X.J<50;
-INSERT INTO t10000(I,J)
- SELECT X.J, X.J+(100*Y.J) FROM t100 AS X,t100 AS Y
- WHERE X.J>=50;
-
-ANALYZE TABLE t10,t100,t10000;
-
-SELECT COUNT(*) FROM t10;
-SELECT COUNT(*) FROM t100;
-SELECT COUNT(*) FROM t10000;
-
-#
-# Bug #59517: Incorrect detection of single row access in
-# ha_ndbcluster::records_in_range()
-
-# Expect a single row (or const) when PK is excact specified
-EXPLAIN
-SELECT * FROM t10000 WHERE k = 42;
-
-# All queries below should *not* return a single row
-EXPLAIN
-SELECT * FROM t10000 WHERE k >= 42 and k < 10000;
-EXPLAIN
-SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
-EXPLAIN
-SELECT * FROM t10000 WHERE k < 42;
-EXPLAIN
-SELECT * FROM t10000 WHERE k > 42;
-
-#
-# Bug #59519 ::set_rec_per_key() assumes ORDER_INDEX to be unique
-#
-
-# 'REF' join of 'Y' should match >1 rows
-EXPLAIN
-SELECT * FROM t10000 AS X JOIN t10000 AS Y
- ON Y.I=X.I AND Y.J = X.I;
-
-#
-# Bug #11804277: INCORRECT INDEX MAY BE SELECTED DUE TO INSUFFICIENT
-# STATISTICS FROM CLUSTER
-#
-
-# Open bounded range should return 10% of #rows in table
-EXPLAIN
-SELECT * FROM t100 WHERE k < 42;
-EXPLAIN
-SELECT * FROM t100 WHERE k > 42;
-EXPLAIN
-SELECT * FROM t10000 WHERE k < 42;
-EXPLAIN
-SELECT * FROM t10000 WHERE k > 42;
-
-#Closed bounded range should return 5% of #rows in table
-EXPLAIN
-SELECT * FROM t100 WHERE k BETWEEN 42 AND 10000;
-EXPLAIN
-SELECT * FROM t10000 WHERE k BETWEEN 42 AND 10000;
-
-#EQ-range selectivity depends on
-# - key length specified
-# - #rows in table.
-# - unique/non-unique index
-# - min 2% selectivity
-#
-# Possibly combined with open/closed ranges as
-# above which further improves selectivity
-#
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0;
-
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J = 0;
-
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0;
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J > 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J < 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J BETWEEN 1 AND 10;
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J = 1;
-
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K > 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K < 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K BETWEEN 1 AND 10;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 0 AND K = 1;
-
-## Verify selection of 'best' index
-## (The one of index I/J being EQ)
-EXPLAIN
-SELECT * FROM t10000 WHERE I = 0 AND J <> 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE I <> 0 AND J = 1;
-EXPLAIN
-SELECT * FROM t10000 WHERE I <> 0 AND J <> 1;
-
-EXPLAIN
-SELECT * FROM t10000 WHERE J <> 1 AND I = 0;
-EXPLAIN
-SELECT * FROM t10000 WHERE J = 1 AND I <> 0;
-EXPLAIN
-SELECT * FROM t10000 WHERE J <> 1 AND I <> 0;
-
-
-DROP TABLE t10,t100,t10000;
-
---echo End of 5.1 tests
=== added file 'mysql-test/suite/ndb/t/ndb_statistics0.test'
--- a/mysql-test/suite/ndb/t/ndb_statistics0.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_statistics0.test 2011-07-02 07:05:32 +0000
@@ -0,0 +1,11 @@
+# index stats OFF
+
+set @is_enable_default = @@global.ndb_index_stat_enable;
+
+set @is_enable = 0;
+source ndb_index_stat_enable.inc;
+
+--source ndb_statistics.inc
+
+set @is_enable = @is_enable_default;
+source ndb_index_stat_enable.inc;
=== added file 'mysql-test/suite/ndb/t/ndb_statistics1.test'
--- a/mysql-test/suite/ndb/t/ndb_statistics1.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb/t/ndb_statistics1.test 2011-07-02 07:05:32 +0000
@@ -0,0 +1,11 @@
+# index stats ON
+
+set @is_enable_default = @@global.ndb_index_stat_enable;
+
+set @is_enable = 1;
+source ndb_index_stat_enable.inc;
+
+--source ndb_statistics.inc
+
+set @is_enable = @is_enable_default;
+source ndb_index_stat_enable.inc;
=== modified file 'sql/ha_ndb_index_stat.cc'
--- a/sql/ha_ndb_index_stat.cc 2011-07-01 09:00:54 +0000
+++ b/sql/ha_ndb_index_stat.cc 2011-08-16 11:53:13 +0000
@@ -62,6 +62,7 @@ struct Ndb_index_stat {
time_t check_time; /* when checked for updated stats (>= read_time) */
bool cache_clean; /* old caches have been deleted */
uint force_update; /* one-time force update from analyze table */
+ bool no_stats; /* have detected that no stats exist */
NdbIndexStat::Error error;
time_t error_time;
int error_count;
@@ -498,40 +499,33 @@ struct Ndb_index_stat_glob {
uint total_count;
uint force_update;
uint wait_update;
+ uint no_stats;
uint cache_query_bytes; /* In use */
uint cache_clean_bytes; /* Obsolete versions not yet removed */
- bool is_locked;
Ndb_index_stat_glob() :
total_count(0),
force_update(0),
wait_update(0),
+ no_stats(0),
cache_query_bytes(0),
- cache_clean_bytes(0),
- is_locked(false)
+ cache_clean_bytes(0)
{
}
void set_list_count()
{
+ total_count= 0;
int lt;
for (lt= 0; lt < Ndb_index_stat::LT_Count; lt++)
{
const Ndb_index_stat_list &list= ndb_index_stat_list[lt];
list_count[lt]= list.count;
+ total_count++;
}
}
- void lock()
+ void set_status_variables()
{
- pthread_mutex_lock(&ndb_index_stat_glob_mutex);
- assert(!is_locked);
- is_locked= true;
- }
- void unlock()
- {
- assert(is_locked);
g_ndb_status_index_stat_cache_query= cache_query_bytes;
g_ndb_status_index_stat_cache_clean= cache_clean_bytes;
- is_locked= false;
- pthread_mutex_unlock(&ndb_index_stat_glob_mutex);
}
};
@@ -554,6 +548,7 @@ Ndb_index_stat::Ndb_index_stat()
check_time= 0;
cache_clean= false;
force_update= 0;
+ no_stats= false;
error_time= 0;
error_count= 0;
share_next= 0;
@@ -567,7 +562,6 @@ Ndb_index_stat::Ndb_index_stat()
void
ndb_index_stat_error(Ndb_index_stat *st, const char* place, int line)
{
- pthread_mutex_lock(&ndb_index_stat_stat_mutex);
time_t now= ndb_index_stat_time();
NdbIndexStat::Error error= st->is->getNdbError();
if (error.code == 0)
@@ -581,13 +575,18 @@ ndb_index_stat_error(Ndb_index_stat *st,
st->error= error;
st->error_time= now;
st->error_count++;
- pthread_cond_broadcast(&ndb_index_stat_stat_cond);
- pthread_mutex_unlock(&ndb_index_stat_stat_mutex);
DBUG_PRINT("index_stat", ("%s line %d: error %d line %d extra %d",
place, line, error.code, error.line, error.extra));
}
+void
+ndb_index_stat_clear_error(Ndb_index_stat *st)
+{
+ st->error.code= 0;
+ st->error.status= NdbError::Success;
+}
+
/* Lists across shares */
Ndb_index_stat_list::Ndb_index_stat_list(int the_lt, const char* the_name)
@@ -611,9 +610,8 @@ Ndb_index_stat_list ndb_index_stat_list[
};
void
-ndb_index_stat_list_add(Ndb_index_stat* st, int lt, int place= +1)
+ndb_index_stat_list_add(Ndb_index_stat* st, int lt)
{
- Ndb_index_stat_glob &glob= ndb_index_stat_glob;
assert(st != 0 && st->lt == 0);
assert(st->list_next == 0 && st->list_prev == 0);
assert(1 <= lt && lt < Ndb_index_stat::LT_Count);
@@ -627,13 +625,6 @@ ndb_index_stat_list_add(Ndb_index_stat*
list.head= st;
list.tail= st;
}
- else if (place < 0)
- {
- assert(list.head != 0 && list.head->list_prev == 0);
- st->list_next= list.head;
- list.head->list_prev= st;
- list.head= st;
- }
else
{
assert(list.tail != 0 && list.tail->list_next == 0);
@@ -642,9 +633,6 @@ ndb_index_stat_list_add(Ndb_index_stat*
list.tail= st;
}
list.count++;
- glob.lock();
- glob.total_count++;
- glob.unlock();
st->lt= lt;
}
@@ -652,7 +640,6 @@ ndb_index_stat_list_add(Ndb_index_stat*
void
ndb_index_stat_list_remove(Ndb_index_stat* st)
{
- Ndb_index_stat_glob &glob= ndb_index_stat_glob;
assert(st != 0);
int lt= st->lt;
assert(1 <= lt && lt < Ndb_index_stat::LT_Count);
@@ -669,10 +656,6 @@ ndb_index_stat_list_remove(Ndb_index_sta
list.tail= prev;
assert(list.count != 0);
list.count--;
- glob.lock();
- assert(glob.total_count != 0);
- glob.total_count--;
- glob.unlock();
if (next != 0)
next->list_prev= prev;
@@ -686,66 +669,85 @@ ndb_index_stat_list_remove(Ndb_index_sta
}
void
-ndb_index_stat_list_move(Ndb_index_stat *st, int lt, int place= +1)
+ndb_index_stat_list_move(Ndb_index_stat *st, int lt)
{
assert(st != 0);
ndb_index_stat_list_remove(st);
- ndb_index_stat_list_add(st, lt, place);
+ ndb_index_stat_list_add(st, lt);
}
-/* Move entry in / out error list */
+/* Stats entry changes (must hold stat_mutex) */
void
-ndb_index_stat_list_to_error(Ndb_index_stat *st)
+ndb_index_stat_force_update(Ndb_index_stat *st, bool onoff)
{
Ndb_index_stat_glob &glob= ndb_index_stat_glob;
-
- assert(st != 0);
- const int lt= st->lt; NDB_IGNORE_VALUE(lt);
- assert(1 <= lt && lt < Ndb_index_stat::LT_Count);
- assert(lt != Ndb_index_stat::LT_Error);
-
- if (st->force_update != 0)
+ if (onoff)
{
- glob.lock();
+ /* One more request */
+ glob.force_update++;
+ st->force_update++;
+ }
+ else
+ {
+ /* All done */
assert(glob.force_update >= st->force_update);
glob.force_update-= st->force_update;
- glob.unlock();
st->force_update= 0;
}
-
- time_t now= ndb_index_stat_time();
- st->error_time= now;
- ndb_index_stat_list_move(st, Ndb_index_stat::LT_Error);
}
void
-ndb_index_stat_list_from_error(Ndb_index_stat *st)
+ndb_index_stat_no_stats(Ndb_index_stat *st, bool flag)
{
- assert(st != 0);
- assert(st->lt == Ndb_index_stat::LT_Error);
- if (st->force_update)
- ndb_index_stat_list_move(st, Ndb_index_stat::LT_Update);
- else
- ndb_index_stat_list_move(st, Ndb_index_stat::LT_Read);
- st->error.code= 0;
- st->error.status= NdbError::Success;
+ Ndb_index_stat_glob &glob= ndb_index_stat_glob;
+ if (st->no_stats != flag)
+ {
+ if (flag)
+ {
+ glob.no_stats++;
+ st->no_stats= true;
+ }
+ else
+ {
+ assert(glob.no_stats >= 1);
+ glob.no_stats-= 1;
+ st->no_stats= false;
+ }
+ }
}
/* Find or add entry under the share */
Ndb_index_stat*
-ndb_index_stat_alloc()
+ndb_index_stat_alloc(const NDBINDEX *index,
+ const NDBTAB *table,
+ int &err_out)
{
+ err_out= 0;
Ndb_index_stat *st= new Ndb_index_stat;
NdbIndexStat *is= new NdbIndexStat;
if (st != 0 && is != 0)
{
st->is= is;
- return st;
+ st->index_id= index->getObjectId();
+ st->index_version= index->getObjectVersion();
+#ifndef DBUG_OFF
+ my_snprintf(st->id, sizeof(st->id), "%d.%d", st->index_id, st->index_version);
+#endif
+ if (is->set_index(*index, *table) == 0)
+ return st;
+ ndb_index_stat_error(st, "set_index", __LINE__);
+ err_out= st->error.code;
+ }
+ else
+ {
+ err_out= NdbIndexStat::NoMemError;
}
- delete is;
- delete st;
+ if (is != 0)
+ delete is;
+ if (st != 0)
+ delete st;
return 0;
}
@@ -773,70 +775,65 @@ ndb_index_stat_find_share(NDB_SHARE *sha
}
/* Subroutine, have lock */
-Ndb_index_stat*
+void
ndb_index_stat_add_share(NDB_SHARE *share,
- const NDBINDEX *index,
- const NDBTAB *table,
+ Ndb_index_stat *st,
Ndb_index_stat *st_last)
{
- struct Ndb_index_stat *st= ndb_index_stat_alloc();
- if (st != 0)
- {
- st->share= share;
- if (st_last == 0)
- share->index_stat_list= st;
- else
- st_last->share_next= st;
- st->index_id= index->getObjectId();
- st->index_version= index->getObjectVersion();
-#ifndef DBUG_OFF
- my_snprintf(st->id, sizeof(st->id), "%d.%d", st->index_id, st->index_version);
-#endif
- if (st->is->set_index(*index, *table) == -1)
- {
- ndb_index_stat_error(st, "set_index", __LINE__);
- /* Caller assigns list */
- }
- }
- return st;
+ st->share= share;
+ if (st_last == 0)
+ share->index_stat_list= st;
+ else
+ st_last->share_next= st;
}
Ndb_index_stat*
ndb_index_stat_get_share(NDB_SHARE *share,
const NDBINDEX *index,
const NDBTAB *table,
+ int &err_out,
bool allow_add,
bool force_update)
{
pthread_mutex_lock(&share->mutex);
pthread_mutex_lock(&ndb_index_stat_list_mutex);
+ pthread_mutex_lock(&ndb_index_stat_stat_mutex);
time_t now= ndb_index_stat_time();
+ err_out= 0;
struct Ndb_index_stat *st= 0;
struct Ndb_index_stat *st_last= 0;
- if (ndb_index_stat_allow())
+ do
{
- st= ndb_index_stat_find_share(share, index, st_last);
- if (st == 0 && allow_add)
+ if (unlikely(!ndb_index_stat_allow()))
{
- st= ndb_index_stat_add_share(share, index, table, st_last);
- if (st != 0)
- ndb_index_stat_list_add(st, Ndb_index_stat::LT_New);
+ err_out= Ndb_index_stat_error_NOT_ALLOW;
+ break;
}
- if (st != 0)
+ st= ndb_index_stat_find_share(share, index, st_last);
+ if (st == 0)
{
- if (force_update != 0)
+ if (!allow_add)
+ {
+ err_out= Ndb_index_stat_error_NOT_FOUND;
+ break;
+ }
+ st= ndb_index_stat_alloc(index, table, err_out);
+ if (st == 0)
{
- st->force_update++;
- Ndb_index_stat_glob &glob= ndb_index_stat_glob;
- glob.lock();
- glob.force_update++;
- glob.unlock();
+ assert(err_out != 0);
+ break;
}
- st->access_time= now;
+ ndb_index_stat_add_share(share, st, st_last);
+ ndb_index_stat_list_add(st, Ndb_index_stat::LT_New);
}
+ if (force_update)
+ ndb_index_stat_force_update(st, true);
+ st->access_time= now;
}
+ while (0);
+ pthread_mutex_unlock(&ndb_index_stat_stat_mutex);
pthread_mutex_unlock(&ndb_index_stat_list_mutex);
pthread_mutex_unlock(&share->mutex);
return st;
@@ -893,6 +890,39 @@ ndb_index_stat_free(NDB_SHARE *share)
pthread_mutex_unlock(&ndb_index_stat_list_mutex);
}
+/* Find entry across shares */
+/* wl4124_todo mutex overkill, hash table, can we find table share */
+Ndb_index_stat*
+ndb_index_stat_find_entry(int index_id, int index_version, int table_id)
+{
+ DBUG_ENTER("ndb_index_stat_find_entry");
+ pthread_mutex_lock(&ndbcluster_mutex);
+ pthread_mutex_lock(&ndb_index_stat_list_mutex);
+ DBUG_PRINT("index_stat", ("find index:%d version:%d table:%d",
+ index_id, index_version, table_id));
+
+ int lt;
+ for (lt=1; lt < Ndb_index_stat::LT_Count; lt++)
+ {
+ Ndb_index_stat *st=ndb_index_stat_list[lt].head;
+ while (st != 0)
+ {
+ if (st->index_id == index_id &&
+ st->index_version == index_version)
+ {
+ pthread_mutex_unlock(&ndb_index_stat_list_mutex);
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ DBUG_RETURN(st);
+ }
+ st= st->list_next;
+ }
+ }
+
+ pthread_mutex_unlock(&ndb_index_stat_list_mutex);
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ DBUG_RETURN(0);
+}
+
/* Statistics thread sub-routines */
void
@@ -909,12 +939,11 @@ ndb_index_stat_cache_move(Ndb_index_stat
DBUG_PRINT("index_stat", ("st %s cache move: query:%u clean:%u",
st->id, new_query_bytes, old_query_bytes));
st->is->move_cache();
- glob.lock();
assert(glob.cache_query_bytes >= old_query_bytes);
glob.cache_query_bytes-= old_query_bytes;
glob.cache_query_bytes+= new_query_bytes;
glob.cache_clean_bytes+= old_query_bytes;
- glob.unlock();
+ glob.set_status_variables();
}
void
@@ -928,20 +957,21 @@ ndb_index_stat_cache_clean(Ndb_index_sta
DBUG_PRINT("index_stat", ("st %s cache clean: clean:%u",
st->id, old_clean_bytes));
st->is->clean_cache();
- glob.lock();
assert(glob.cache_clean_bytes >= old_clean_bytes);
glob.cache_clean_bytes-= old_clean_bytes;
- glob.unlock();
+ glob.set_status_variables();
}
/* Misc in/out parameters for process steps */
struct Ndb_index_stat_proc {
+ NdbIndexStat* is_util; // For metadata and polling
Ndb *ndb;
time_t now;
int lt;
bool busy;
bool end;
Ndb_index_stat_proc() :
+ is_util(0),
ndb(0),
now(0),
lt(0),
@@ -1021,8 +1051,25 @@ ndb_index_stat_proc_read(Ndb_index_stat_
NdbIndexStat::Head head;
if (st->is->read_stat(pr.ndb) == -1)
{
+ pthread_mutex_lock(&ndb_index_stat_stat_mutex);
ndb_index_stat_error(st, "read_stat", __LINE__);
- pr.lt= Ndb_index_stat::LT_Error;
+ const uint force_update= st->force_update;
+ ndb_index_stat_force_update(st, false);
+
+ /* no stats is not unexpected error, unless analyze was done */
+ if (st->is->getNdbError().code == NdbIndexStat::NoIndexStats &&
+ force_update == 0)
+ {
+ ndb_index_stat_no_stats(st, true);
+ pr.lt= Ndb_index_stat::LT_Idle;
+ }
+ else
+ {
+ pr.lt= Ndb_index_stat::LT_Error;
+ }
+
+ pthread_cond_broadcast(&ndb_index_stat_stat_cond);
+ pthread_mutex_unlock(&ndb_index_stat_stat_mutex);
return;
}
@@ -1033,15 +1080,8 @@ ndb_index_stat_proc_read(Ndb_index_stat_
st->read_time= pr.now;
st->sample_version= head.m_sampleVersion;
- if (st->force_update != 0)
- {
- Ndb_index_stat_glob &glob= ndb_index_stat_glob;
- glob.lock();
- assert(glob.force_update >= st->force_update);
- glob.force_update-= st->force_update;
- glob.unlock();
- st->force_update= 0;
- }
+ ndb_index_stat_force_update(st, false);
+ ndb_index_stat_no_stats(st, false);
ndb_index_stat_cache_move(st);
st->cache_clean= false;
@@ -1073,6 +1113,7 @@ ndb_index_stat_proc_read(Ndb_index_stat_
pr.busy= true;
}
+// wl4124_todo detect force_update faster
void
ndb_index_stat_proc_idle(Ndb_index_stat_proc &pr, Ndb_index_stat *st)
{
@@ -1124,11 +1165,9 @@ ndb_index_stat_proc_idle(Ndb_index_stat_
st_loop= st_loop->list_next;
DBUG_PRINT("index_stat", ("st %s proc %s", st->id, list.name));
ndb_index_stat_proc_idle(pr, st);
- if (pr.lt != lt)
- {
- ndb_index_stat_list_move(st, pr.lt);
- cnt++;
- }
+ // rotates list if entry remains LT_Idle
+ ndb_index_stat_list_move(st, pr.lt);
+ cnt++;
}
if (cnt == batch)
pr.busy= true;
@@ -1143,7 +1182,16 @@ ndb_index_stat_proc_check(Ndb_index_stat
if (st->is->read_head(pr.ndb) == -1)
{
ndb_index_stat_error(st, "read_head", __LINE__);
- pr.lt= Ndb_index_stat::LT_Error;
+ /* no stats is not unexpected error */
+ if (st->is->getNdbError().code == NdbIndexStat::NoIndexStats)
+ {
+ ndb_index_stat_no_stats(st, true);
+ pr.lt= Ndb_index_stat::LT_Idle;
+ }
+ else
+ {
+ pr.lt= Ndb_index_stat::LT_Error;
+ }
return;
}
st->is->get_head(head);
@@ -1213,9 +1261,7 @@ ndb_index_stat_proc_evict()
{
const Ndb_index_stat_opt &opt= ndb_index_stat_opt;
Ndb_index_stat_glob &glob= ndb_index_stat_glob;
- glob.lock();
uint curr_size= glob.cache_query_bytes + glob.cache_clean_bytes;
- glob.unlock();
const uint cache_lowpct= opt.get(Ndb_index_stat_opt::Icache_lowpct);
const uint cache_limit= opt.get(Ndb_index_stat_opt::Icache_limit);
if (100 * curr_size <= cache_lowpct * cache_limit)
@@ -1330,11 +1376,15 @@ ndb_index_stat_proc_error(Ndb_index_stat
const int error_delay= opt.get(Ndb_index_stat_opt::Ierror_delay);
const time_t error_wait= st->error_time + error_delay - pr.now;
- if (error_wait <= 0)
- {
- ndb_index_stat_list_from_error(st);
- DBUG_PRINT("index_stat", ("st %s error wait:%ds error count:%u",
- st->id, (int)error_wait, st->error_count));
+ if (error_wait <= 0 ||
+ /* Analyze issued after previous error */
+ st->force_update)
+ {
+ DBUG_PRINT("index_stat", ("st %s error wait:%ds error count:%u"
+ " force update:%u",
+ st->id, (int)error_wait, st->error_count,
+ st->force_update));
+ ndb_index_stat_clear_error(st);
if (st->force_update)
pr.lt= Ndb_index_stat::LT_Update;
else
@@ -1361,16 +1411,82 @@ ndb_index_stat_proc_error(Ndb_index_stat
st_loop= st_loop->list_next;
DBUG_PRINT("index_stat", ("st %s proc %s", st->id, list.name));
ndb_index_stat_proc_error(pr, st);
- if (pr.lt != lt)
- {
- ndb_index_stat_list_move(st, pr.lt);
- cnt++;
- }
+ ndb_index_stat_list_move(st, pr.lt);
+ cnt++;
}
if (cnt == batch)
pr.busy= true;
}
+void
+ndb_index_stat_proc_event(Ndb_index_stat_proc &pr, Ndb_index_stat *st)
+{
+ /*
+ Put on Check list if idle.
+ We get event also for our own analyze but this should not matter.
+ */
+ pr.lt= st->lt;
+ if (st->lt == Ndb_index_stat::LT_Idle ||
+ st->lt == Ndb_index_stat::LT_Error)
+ pr.lt= Ndb_index_stat::LT_Check;
+}
+
+void
+ndb_index_stat_proc_event(Ndb_index_stat_proc &pr)
+{
+ NdbIndexStat *is= pr.is_util;
+ Ndb *ndb= pr.ndb;
+ int ret;
+ ret= is->poll_listener(ndb, 0);
+ DBUG_PRINT("index_stat", ("poll_listener ret: %d", ret));
+ if (ret == -1)
+ {
+ // wl4124_todo report error
+ DBUG_ASSERT(false);
+ return;
+ }
+ if (ret == 0)
+ return;
+
+ while (1)
+ {
+ ret= is->next_listener(ndb);
+ DBUG_PRINT("index_stat", ("next_listener ret: %d", ret));
+ if (ret == -1)
+ {
+ // wl4124_todo report error
+ DBUG_ASSERT(false);
+ return;
+ }
+ if (ret == 0)
+ break;
+
+ NdbIndexStat::Head head;
+ is->get_head(head);
+ DBUG_PRINT("index_stat", ("next_listener eventType: %d indexId: %u",
+ head.m_eventType, head.m_indexId));
+
+ Ndb_index_stat *st= ndb_index_stat_find_entry(head.m_indexId,
+ head.m_indexVersion,
+ head.m_tableId);
+ /*
+ Another process can update stats for an index which is not found
+ in this mysqld. Ignore it.
+ */
+ if (st != 0)
+ {
+ DBUG_PRINT("index_stat", ("st %s proc %s", st->id, "Event"));
+ ndb_index_stat_proc_event(pr, st);
+ if (pr.lt != st->lt)
+ ndb_index_stat_list_move(st, pr.lt);
+ }
+ else
+ {
+ DBUG_PRINT("index_stat", ("entry not found in this mysqld"));
+ }
+ }
+}
+
#ifndef DBUG_OFF
void
ndb_index_stat_report(const Ndb_index_stat_glob& old_glob)
@@ -1427,15 +1543,11 @@ ndb_index_stat_report(const Ndb_index_st
/* Updates waited for and forced updates */
{
- pthread_mutex_lock(&ndb_index_stat_list_mutex);
uint wait_update= new_glob.wait_update;
uint force_update= new_glob.force_update;
- pthread_mutex_unlock(&ndb_index_stat_list_mutex);
- if (wait_update != 0 || force_update != 0)
- {
- DBUG_PRINT("index_stat", ("wait update:%u force update:%u",
- wait_update, force_update));
- }
+ uint no_stats= new_glob.no_stats;
+ DBUG_PRINT("index_stat", ("wait update:%u force update:%u no stats:%u",
+ wait_update, force_update, no_stats));
}
}
#endif
@@ -1458,6 +1570,7 @@ ndb_index_stat_proc(Ndb_index_stat_proc
ndb_index_stat_proc_evict(pr);
ndb_index_stat_proc_delete(pr);
ndb_index_stat_proc_error(pr);
+ ndb_index_stat_proc_event(pr);
#ifndef DBUG_OFF
ndb_index_stat_report(old_glob);
@@ -1503,11 +1616,14 @@ ndb_index_stat_end()
/* Index stats thread */
-static int
-ndb_index_stat_check_or_create_systables(NdbIndexStat* is, Ndb* ndb)
+int
+ndb_index_stat_check_or_create_systables(Ndb_index_stat_proc &pr)
{
DBUG_ENTER("ndb_index_stat_check_or_create_systables");
+ NdbIndexStat *is= pr.is_util;
+ Ndb *ndb= pr.ndb;
+
if (is->check_systables(ndb) == 0)
{
DBUG_PRINT("index_stat", ("using existing index stats tables"));
@@ -1520,7 +1636,8 @@ ndb_index_stat_check_or_create_systables
DBUG_RETURN(0);
}
- if (is->getNdbError().code == 721)
+ if (is->getNdbError().code == 721 ||
+ is->getNdbError().code == 4244)
{
// race between mysqlds, maybe
DBUG_PRINT("index_stat", ("create index stats tables failed: error %d line %d",
@@ -1533,6 +1650,82 @@ ndb_index_stat_check_or_create_systables
DBUG_RETURN(-1);
}
+int
+ndb_index_stat_check_or_create_sysevents(Ndb_index_stat_proc &pr)
+{
+ DBUG_ENTER("ndb_index_stat_check_or_create_sysevents");
+
+ NdbIndexStat *is= pr.is_util;
+ Ndb *ndb= pr.ndb;
+
+ if (is->check_sysevents(ndb) == 0)
+ {
+ DBUG_PRINT("index_stat", ("using existing index stats events"));
+ DBUG_RETURN(0);
+ }
+
+ if (is->create_sysevents(ndb) == 0)
+ {
+ DBUG_PRINT("index_stat", ("created index stats events"));
+ DBUG_RETURN(0);
+ }
+
+ if (is->getNdbError().code == 746)
+ {
+ // race between mysqlds, maybe
+ DBUG_PRINT("index_stat", ("create index stats events failed: error %d line %d",
+ is->getNdbError().code, is->getNdbError().line));
+ DBUG_RETURN(-1);
+ }
+
+ sql_print_warning("create index stats events failed: error %d line %d",
+ is->getNdbError().code, is->getNdbError().line);
+ DBUG_RETURN(-1);
+}
+
+int
+ndb_index_stat_start_listener(Ndb_index_stat_proc &pr)
+{
+ DBUG_ENTER("ndb_index_stat_start_listener");
+
+ NdbIndexStat *is= pr.is_util;
+ Ndb *ndb= pr.ndb;
+
+ if (is->create_listener(ndb) == -1)
+ {
+ sql_print_warning("create index stats listener failed: error %d line %d",
+ is->getNdbError().code, is->getNdbError().line);
+ DBUG_RETURN(-1);
+ }
+
+ if (is->execute_listener(ndb) == -1)
+ {
+ sql_print_warning("execute index stats listener failed: error %d line %d",
+ is->getNdbError().code, is->getNdbError().line);
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+int
+ndb_index_stat_stop_listener(Ndb_index_stat_proc &pr)
+{
+ DBUG_ENTER("ndb_index_stat_stop_listener");
+
+ NdbIndexStat *is= pr.is_util;
+ Ndb *ndb= pr.ndb;
+
+ if (is->drop_listener(ndb) == -1)
+ {
+ sql_print_warning("drop index stats listener failed: error %d line %d",
+ is->getNdbError().code, is->getNdbError().line);
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
pthread_handler_t
ndb_index_stat_thread_func(void *arg __attribute__((unused)))
{
@@ -1543,6 +1736,11 @@ ndb_index_stat_thread_func(void *arg __a
my_thread_init();
DBUG_ENTER("ndb_index_stat_thread_func");
+ Ndb_index_stat_proc pr;
+
+ bool have_listener;
+ have_listener= false;
+
// wl4124_todo remove useless stuff copied from utility thread
pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
@@ -1613,6 +1811,14 @@ ndb_index_stat_thread_func(void *arg __a
}
pthread_mutex_unlock(&LOCK_ndb_index_stat_thread);
+ /* Get instance used for sys objects check and create */
+ if (!(pr.is_util= new NdbIndexStat))
+ {
+ sql_print_error("Could not allocate NdbIndexStat is_util object");
+ pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
+ goto ndb_index_stat_thread_end;
+ }
+
/* Get thd_ndb for this thread */
if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
{
@@ -1629,6 +1835,7 @@ ndb_index_stat_thread_func(void *arg __a
pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
goto ndb_index_stat_thread_end;
}
+ pr.ndb= thd_ndb->ndb;
ndb_index_stat_allow(1);
bool enable_ok;
@@ -1653,9 +1860,6 @@ ndb_index_stat_thread_func(void *arg __a
/* const bool enable_ok_new= THDVAR(NULL, index_stat_enable); */
const bool enable_ok_new= ndb_index_stat_get_enable(NULL);
- Ndb_index_stat_proc pr;
- pr.ndb= thd_ndb->ndb;
-
do
{
if (enable_ok != enable_ok_new)
@@ -1665,13 +1869,24 @@ ndb_index_stat_thread_func(void *arg __a
if (enable_ok_new)
{
- // at enable check or create stats tables
- NdbIndexStat is;
- if (ndb_index_stat_check_or_create_systables(&is, thd_ndb->ndb) == -1)
+ // at enable check or create stats tables and events
+ if (ndb_index_stat_check_or_create_systables(pr) == -1 ||
+ ndb_index_stat_check_or_create_sysevents(pr) == -1 ||
+ ndb_index_stat_start_listener(pr) == -1)
{
// try again in next loop
break;
}
+ have_listener= true;
+ }
+ else
+ {
+ // not a normal use-case
+ if (have_listener)
+ {
+ if (ndb_index_stat_stop_listener(pr) == 0)
+ have_listener= false;
+ }
}
enable_ok= enable_ok_new;
}
@@ -1702,6 +1917,16 @@ ndb_index_stat_thread_end:
net_end(&thd->net);
ndb_index_stat_thread_fail:
+ if (have_listener)
+ {
+ if (ndb_index_stat_stop_listener(pr) == 0)
+ have_listener= false;
+ }
+ if (pr.is_util)
+ {
+ delete pr.is_util;
+ pr.is_util= 0;
+ }
if (thd_ndb)
{
ha_ndbcluster::release_thd_ndb(thd_ndb);
@@ -1738,22 +1963,37 @@ ndb_index_stat_round(double x)
}
int
-ha_ndbcluster::ndb_index_stat_wait(Ndb_index_stat *st,
- uint sample_version)
+ndb_index_stat_wait(Ndb_index_stat *st,
+ uint sample_version,
+ bool from_analyze)
{
- DBUG_ENTER("ha_ndbcluster::ndb_index_stat_wait");
+ DBUG_ENTER("ndb_index_stat_wait");
pthread_mutex_lock(&ndb_index_stat_stat_mutex);
int err= 0;
uint count= 0;
- (void)count; // USED
struct timespec abstime;
- while (true) {
+ while (true)
+ {
int ret= 0;
- if (st->error.code != 0 &&
- (st->error.code != NdbIndexStat::NoIndexStats ||
- st->force_update == 0))
+ if (count == 0)
+ {
+ if (st->lt == Ndb_index_stat::LT_Error && !from_analyze)
+ {
+ err= Ndb_index_stat_error_HAS_ERROR;
+ break;
+ }
+ ndb_index_stat_clear_error(st);
+ }
+ if (st->no_stats && !from_analyze)
{
+ /* Have detected no stats now or before */
+ err= NdbIndexStat::NoIndexStats;
+ break;
+ }
+ if (st->error.code != 0)
+ {
+ /* A new error has occured */
err= st->error.code;
break;
}
@@ -1775,7 +2015,8 @@ ha_ndbcluster::ndb_index_stat_wait(Ndb_i
}
}
pthread_mutex_unlock(&ndb_index_stat_stat_mutex);
- if (err != 0) {
+ if (err != 0)
+ {
DBUG_PRINT("index_stat", ("st %s wait error: %d",
st->id, err));
DBUG_RETURN(err);
@@ -1806,14 +2047,12 @@ ha_ndbcluster::ndb_index_stat_query(uint
ib.range_no= 0;
Ndb_index_stat *st=
- ndb_index_stat_get_share(m_share, index, m_table, true, false);
+ ndb_index_stat_get_share(m_share, index, m_table, err, true, false);
if (st == 0)
- {
- DBUG_PRINT("index_stat", ("failed to add index stat share"));
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- }
+ DBUG_RETURN(err);
- err= ndb_index_stat_wait(st, 0);
+ /* Pass old version 0 so existing stats terminates wait at once */
+ err= ndb_index_stat_wait(st, 0, false);
if (err != 0)
DBUG_RETURN(err);
@@ -1927,10 +2166,9 @@ ha_ndbcluster::ndb_index_stat_analyze(Nd
DBUG_PRINT("index_stat", ("force update: %s", index->getName()));
Ndb_index_stat *st=
- ndb_index_stat_get_share(m_share, index, m_table, true, true);
-
+ ndb_index_stat_get_share(m_share, index, m_table, err, true, true);
if (st == 0)
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ DBUG_RETURN(err);
old[i].sample_version= st->sample_version;
old[i].error_count= st->error_count;
@@ -1945,11 +2183,11 @@ ha_ndbcluster::ndb_index_stat_analyze(Nd
DBUG_PRINT("index_stat", ("wait for update: %s", index->getName()));
Ndb_index_stat *st=
- ndb_index_stat_get_share(m_share, index, m_table, false, false);
+ ndb_index_stat_get_share(m_share, index, m_table, err, false, false);
if (st == 0)
- DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+ DBUG_RETURN(err);
- err= ndb_index_stat_wait(st, old[i].sample_version);
+ err= ndb_index_stat_wait(st, old[i].sample_version, true);
if (err != 0)
DBUG_RETURN(err);
}
=== modified file 'sql/ha_ndb_index_stat.h'
--- a/sql/ha_ndb_index_stat.h 2011-06-15 10:37:56 +0000
+++ b/sql/ha_ndb_index_stat.h 2011-08-11 17:11:30 +0000
@@ -19,16 +19,21 @@
extern struct st_ndb_status g_ndb_status;
+extern pthread_mutex_t ndbcluster_mutex;
+
extern pthread_t ndb_index_stat_thread;
extern pthread_cond_t COND_ndb_index_stat_thread;
extern pthread_mutex_t LOCK_ndb_index_stat_thread;
-extern pthread_mutex_t ndb_index_stat_glob_mutex;
+
+/* protect entry lists where needed */
extern pthread_mutex_t ndb_index_stat_list_mutex;
+
+/* protect and signal changes in stats entries */
extern pthread_mutex_t ndb_index_stat_stat_mutex;
extern pthread_cond_t ndb_index_stat_stat_cond;
+/* these have to live in ha_ndbcluster.cc */
extern bool ndb_index_stat_get_enable(THD *thd);
-
extern long g_ndb_status_index_stat_cache_query;
extern long g_ndb_status_index_stat_cache_clean;
@@ -36,3 +41,14 @@ void
compute_index_bounds(NdbIndexScanOperation::IndexBound & bound,
const KEY *key_info,
const key_range *start_key, const key_range *end_key);
+
+/* error codes local to ha_ndb */
+
+/* stats thread is not open for requests (should not happen) */
+#define Ndb_index_stat_error_NOT_ALLOW 9001
+
+/* stats entry for existing index not found (should not happen) */
+#define Ndb_index_stat_error_NOT_FOUND 9002
+
+/* request on stats entry with recent error was ignored */
+#define Ndb_index_stat_error_HAS_ERROR 9003
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2011-07-09 11:16:31 +0000
+++ b/sql/ha_ndbcluster.cc 2011-08-17 12:51:57 +0000
@@ -43,6 +43,7 @@
#include "ha_ndbcluster_cond.h"
#include "ha_ndbcluster_tables.h"
#include "ha_ndbcluster_connection.h"
+#include "ha_ndb_index_stat.h"
#include "abstract_query_plan.h"
#include <mysql/plugin.h>
@@ -447,7 +448,6 @@ int ndb_index_stat_thread_running= 0;
pthread_mutex_t LOCK_ndb_index_stat_thread;
pthread_cond_t COND_ndb_index_stat_thread;
pthread_cond_t COND_ndb_index_stat_ready;
-pthread_mutex_t ndb_index_stat_glob_mutex;
pthread_mutex_t ndb_index_stat_list_mutex;
pthread_mutex_t ndb_index_stat_stat_mutex;
pthread_cond_t ndb_index_stat_stat_cond;
@@ -1396,6 +1396,7 @@ void ha_ndbcluster::set_rec_per_key()
*/
for (uint i=0 ; i < table_share->keys ; i++)
{
+ KEY* key_info= table->key_info + i;
switch (get_index_type(i))
{
case UNIQUE_ORDERED_INDEX:
@@ -1405,7 +1406,6 @@ void ha_ndbcluster::set_rec_per_key()
{
// Index is unique when all 'key_parts' are specified,
// else distribution is unknown and not specified here.
- KEY* key_info= table->key_info + i;
key_info->rec_per_key[key_info->key_parts-1]= 1;
break;
}
@@ -1419,8 +1419,18 @@ void ha_ndbcluster::set_rec_per_key()
if (index_stat_enable)
{
int err= ndb_index_stat_set_rpk(i);
- if (err == 0)
- break;
+ if (err != 0 &&
+ /* no stats is not unexpected error */
+ err != NdbIndexStat::NoIndexStats &&
+ /* warning was printed at first error */
+ err != Ndb_index_stat_error_HAS_ERROR)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_GET_STAT, /* pun? */
+ "index stats (RPK) for key %s:"
+ " unexpected error %d",
+ key_info->name, err);
+ }
}
// no fallback method...
break;
@@ -11943,7 +11953,6 @@ static int ndbcluster_init(void *p)
pthread_mutex_init(&LOCK_ndb_index_stat_thread, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_ndb_index_stat_thread, NULL);
pthread_cond_init(&COND_ndb_index_stat_ready, NULL);
- pthread_mutex_init(&ndb_index_stat_glob_mutex, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&ndb_index_stat_list_mutex, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&ndb_index_stat_stat_mutex, MY_MUTEX_INIT_FAST);
pthread_cond_init(&ndb_index_stat_stat_cond, NULL);
@@ -12055,7 +12064,6 @@ static int ndbcluster_init(void *p)
pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_ready);
- pthread_mutex_destroy(&ndb_index_stat_glob_mutex);
pthread_mutex_destroy(&ndb_index_stat_list_mutex);
pthread_mutex_destroy(&ndb_index_stat_stat_mutex);
pthread_cond_destroy(&ndb_index_stat_stat_cond);
@@ -12076,7 +12084,6 @@ static int ndbcluster_init(void *p)
pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_ready);
- pthread_mutex_destroy(&ndb_index_stat_glob_mutex);
pthread_mutex_destroy(&ndb_index_stat_list_mutex);
pthread_mutex_destroy(&ndb_index_stat_stat_mutex);
pthread_cond_destroy(&ndb_index_stat_stat_cond);
@@ -12338,6 +12345,18 @@ ha_ndbcluster::records_in_range(uint inx
rows = 2;
DBUG_RETURN(rows);
}
+ if (err != 0 &&
+ /* no stats is not unexpected error */
+ err != NdbIndexStat::NoIndexStats &&
+ /* warning was printed at first error */
+ err != Ndb_index_stat_error_HAS_ERROR)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_CANT_GET_STAT, /* pun? */
+ "index stats (RIR) for key %s:"
+ " unexpected error %d",
+ key_info->name, err);
+ }
/*fall through*/
}
=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h 2011-07-09 11:16:31 +0000
+++ b/sql/ha_ndbcluster.h 2011-08-17 12:51:57 +0000
@@ -930,17 +930,15 @@ private:
void no_uncommitted_rows_reset(THD *);
/* Ordered index statistics v4 */
+ int ndb_index_stat_query(uint inx,
+ const key_range *min_key,
+ const key_range *max_key,
+ NdbIndexStat::Stat& stat);
int ndb_index_stat_get_rir(uint inx,
key_range *min_key,
key_range *max_key,
ha_rows *rows_out);
int ndb_index_stat_set_rpk(uint inx);
- int ndb_index_stat_wait(struct Ndb_index_stat *st,
- uint sample_version);
- int ndb_index_stat_query(uint inx,
- const key_range *min_key,
- const key_range *max_key,
- NdbIndexStat::Stat& stat);
int ndb_index_stat_analyze(Ndb *ndb,
uint *inx_list,
uint inx_count);
=== modified file 'storage/ndb/include/ndb_constants.h'
--- a/storage/ndb/include/ndb_constants.h 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/include/ndb_constants.h 2011-08-11 17:11:30 +0000
@@ -120,6 +120,7 @@
#define NDB_INDEX_STAT_HEAD_TABLE "ndb_index_stat_head"
#define NDB_INDEX_STAT_SAMPLE_TABLE "ndb_index_stat_sample"
#define NDB_INDEX_STAT_SAMPLE_INDEX1 "ndb_index_stat_sample_x1"
+#define NDB_INDEX_STAT_HEAD_EVENT "ndb_index_stat_head_event"
#define NDB_INDEX_STAT_PREFIX "ndb_index_stat"
=== modified file 'storage/ndb/include/ndbapi/NdbIndexStat.hpp'
--- a/storage/ndb/include/ndbapi/NdbIndexStat.hpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/include/ndbapi/NdbIndexStat.hpp 2011-08-11 17:11:30 +0000
@@ -100,7 +100,10 @@ public:
InvalidCache = 4718,
InternalError = 4719,
BadSysTables = 4720, // sys tables partly missing or invalid
- HaveSysTables = 4244 // create error if all sys tables exist
+ HaveSysTables = 4244, // create error if all sys tables exist
+ NoSysEvents = 4710,
+ BadSysEvents = BadSysTables,
+ HaveSysEvents = 746
};
/*
@@ -191,6 +194,7 @@ public:
*/
struct Head {
Int32 m_found; // -1 no read done, 0 = no record, 1 = exists
+ Int32 m_eventType; // if polling, NdbDictionary::Event::TE_INSERT etc
Uint32 m_indexId;
Uint32 m_indexVersion;
Uint32 m_tableId;
@@ -327,15 +331,51 @@ public:
static void get_rule(const Stat& stat, char* buffer);
/*
- * Memory allocator for the stats caches. By default each instance
- * uses its own malloc-based implementation.
+ * Events (there is 1) for polling. These are dictionary objects.
+ * Correct sys tables must exist. Drop ignores non-existing events.
+ */
+ int create_sysevents(Ndb* ndb);
+ int drop_sysevents(Ndb* ndb);
+ int check_sysevents(Ndb* ndb);
+
+ /*
+ * Create listener for stats updates. Only 1 is allowed.
+ */
+ int create_listener(Ndb* ndb);
+
+ /*
+ * Start listening for events (call NdbEventOperation::execute).
+ */
+ int execute_listener(Ndb* ndb);
+
+ /*
+ * Poll the listener (call Ndb::pollEvents). Returns 1 if there are
+ * events available and 0 otherwise, or -1 on failure as usual.
+ */
+ int poll_listener(Ndb* ndb, int max_wait_ms);
+
+ /*
+ * Get next available event. Returns 1 if a new event was returned
+ * and 0 otherwise, or -1 on failure as usual. Use get_heed() to
+ * retrieve event type and data.
+ */
+ int next_listener(Ndb* ndb);
+
+ /*
+ * Drop the listener.
+ */
+ int drop_listener(Ndb* ndb);
+
+ /*
+ * Memory allocator for stats cache data (key and value byte arrays).
+ * Implementation default uses malloc/free. The memory in use is the
+ * sum of CacheInfo::m_totalBytes from all cache types.
*/
struct Mem {
Mem();
virtual ~Mem();
virtual void* mem_alloc(UintPtr size) = 0;
virtual void mem_free(void* ptr) = 0;
- virtual UintPtr mem_used() const = 0;
};
/*
=== modified file 'storage/ndb/include/util/NdbPack.hpp'
--- a/storage/ndb/include/util/NdbPack.hpp 2011-05-04 09:44:18 +0000
+++ b/storage/ndb/include/util/NdbPack.hpp 2011-08-09 15:37:45 +0000
@@ -117,7 +117,7 @@ public:
class Endian {
public:
enum Value {
- Native = 0,
+ Native = 0, // replaced by actual value
Little = 1,
Big = 2
};
@@ -300,6 +300,10 @@ public:
* Instance of an array of data values. The values are packed into
* a byte buffer. The buffer is also maintained as a single varbinary
* value if non-zero var bytes (length bytes) is specified.
+ *
+ * Data instances can be received from another source (such as table
+ * in database) and may not be native-endian. Such instances must
+ * first be completed with desc_all() and convert().
*/
class Data : public DataC {
public:
@@ -324,7 +328,7 @@ public:
// convert endian
int convert(Endian::Value to_endian);
// create complete instance from buffer contents
- int desc_all(Uint32 cnt);
+ int desc_all(Uint32 cnt, Endian::Value from_endian);
// getters
Uint32 get_max_len() const;
Uint32 get_max_len4() const;
@@ -351,7 +355,7 @@ public:
const Uint32 m_varBytes;
Uint8* m_buf;
Uint32 m_bufMaxLen;
- Endian::Value m_endian; // Native until finalize()
+ Endian::Value m_endian;
// iterator on items added
Iter m_iter;
};
@@ -685,7 +689,7 @@ NdbPack::Data::Data(const Spec& spec, bo
{
m_buf = 0;
m_bufMaxLen = 0;
- m_endian = Endian::Native;
+ m_endian = Endian::get_endian();
}
inline void
@@ -704,7 +708,7 @@ NdbPack::Data::reset()
m_cnt = 0; // in DataC
const Uint32 bytes = m_varBytes + m_spec.get_nullmask_len(m_allNullable);
memset(m_buf, 0, bytes);
- m_endian = Endian::Native;
+ m_endian = Endian::get_endian();
m_iter.reset();
}
@@ -713,17 +717,14 @@ NdbPack::Data::finalize()
{
if (m_varBytes == 0 ||
finalize_impl() == 0)
- {
- m_endian = Endian::get_endian();
return 0;
- }
return -1;
}
inline int
NdbPack::Data::convert(Endian::Value to_endian)
{
- if (unlikely(to_endian == Endian::Native))
+ if (to_endian == Endian::Native)
to_endian = Endian::get_endian();
if (m_endian == to_endian)
return 0;
=== modified file 'storage/ndb/src/common/util/NdbPack.cpp'
--- a/storage/ndb/src/common/util/NdbPack.cpp 2011-05-09 15:35:25 +0000
+++ b/storage/ndb/src/common/util/NdbPack.cpp 2011-08-09 15:37:45 +0000
@@ -560,8 +560,11 @@ NdbPack::Data::finalize_impl()
}
int
-NdbPack::Data::desc_all(Uint32 cnt)
+NdbPack::Data::desc_all(Uint32 cnt, Endian::Value from_endian)
{
+ if (from_endian == NdbPack::Endian::Native)
+ from_endian = NdbPack::Endian::get_endian();
+ m_endian = from_endian;
assert(m_cnt == 0); // reset() would destroy nullmask
for (Uint32 i = 0; i < cnt; i++)
{
@@ -757,7 +760,7 @@ NdbPack::Spec::print(char* buf, Uint32 b
// print DataC
-bool g_ndb_pack_print_hex_always = false;
+bool g_ndb_pack_print_hex_always = true;
NdbOut&
operator<<(NdbOut& out, const NdbPack::DataC& a)
@@ -1836,7 +1839,7 @@ testdesc(const Tdata& tdata)
Uint8 buf_new[Tspec::MaxBuf];
data_new.set_buf(buf_new, sizeof(buf_new));
memcpy(buf_new, buf_old, fullLen);
- chk2(data_new.desc_all(cnt) == 0, data_new);
+ chk2(data_new.desc_all(cnt, NdbPack::Endian::Native) == 0, data_new);
chk1(memcmp(buf_new, data.get_full_buf(), data.get_full_len()) == 0);
chk1(data_new.get_data_len() == data.get_data_len());
chk1(data_new.get_cnt() == data.get_cnt());
@@ -1903,28 +1906,17 @@ testconvert(const Tdata& tdata)
require(data.get_cnt() == data_new.get_cnt());
const Uint32 cnt = tdata.m_cnt;
Uint32 num_eq;
- switch (NdbPack::Endian::get_endian()) {
- case NdbPack::Endian::Little:
- chk2(data_new.convert(NdbPack::Endian::Little) == 0, data_new);
- num_eq = ~(Uint32)0;
- chk1(data.cmp(data_new, cnt, num_eq) == 0);
- chk2(data_new.convert(NdbPack::Endian::Big) == 0, data_new);
- chk2(data_new.convert(NdbPack::Endian::Little) == 0, data_new);
- num_eq = ~(Uint32)0;
- chk1(data.cmp(data_new, cnt, num_eq) == 0);
- break;
- case NdbPack::Endian::Big:
- chk2(data_new.convert(NdbPack::Endian::Big) == 0, data_new);
- num_eq = ~(Uint32)0;
- chk1(data.cmp(data_new, cnt, num_eq) == 0);
- chk2(data_new.convert(NdbPack::Endian::Little) == 0, data_new);
- chk2(data_new.convert(NdbPack::Endian::Big) == 0, data_new);
- num_eq = ~(Uint32)0;
- chk1(data.cmp(data_new, cnt, num_eq) == 0);
- break;
- default:
- require(false);
- break;
+ int i;
+ for (i = 0; i < 10; i++) {
+ int k = getrandom(3); // assumes Endian::Value 0,1,2
+ NdbPack::Endian::Value v = (NdbPack::Endian::Value)k;
+ chk2(data_new.convert(v) == 0, data_new);
+ if (v == NdbPack::Endian::Native ||
+ v == NdbPack::Endian::get_endian()) {
+ num_eq = ~(Uint32)0;
+ chk1(data.cmp(data_new, cnt, num_eq) == 0);
+ require(num_eq == cnt);
+ }
}
}
=== modified file 'storage/ndb/src/ndbapi/NdbIndexStat.cpp'
--- a/storage/ndb/src/ndbapi/NdbIndexStat.cpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/src/ndbapi/NdbIndexStat.cpp 2011-08-11 17:11:30 +0000
@@ -656,6 +656,82 @@ NdbIndexStat::get_rule(const Stat& stat_
DBUG_VOID_RETURN;
}
+// events and polling
+
+int
+NdbIndexStat::create_sysevents(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::create_sysevents");
+ if (m_impl.create_sysevents(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+int
+NdbIndexStat::drop_sysevents(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::drop_sysevents");
+ if (m_impl.drop_sysevents(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+int
+NdbIndexStat::check_sysevents(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::check_sysevents");
+ if (m_impl.check_sysevents(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+int
+NdbIndexStat::create_listener(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::create_listener");
+ if (m_impl.create_listener(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+int
+NdbIndexStat::execute_listener(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::execute_listener");
+ if (m_impl.execute_listener(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+int
+NdbIndexStat::poll_listener(Ndb* ndb, int max_wait_ms)
+{
+ DBUG_ENTER("NdbIndexStat::poll_listener");
+ int ret = m_impl.poll_listener(ndb, max_wait_ms);
+ if (ret == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(ret);
+}
+
+int
+NdbIndexStat::next_listener(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::next_listener");
+ int ret = m_impl.next_listener(ndb);
+ if (ret == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(ret);
+}
+
+int
+NdbIndexStat::drop_listener(Ndb* ndb)
+{
+ DBUG_ENTER("NdbIndexStat::drop_listener");
+ if (m_impl.drop_listener(ndb) == -1)
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
// mem
NdbIndexStat::Mem::Mem()
=== modified file 'storage/ndb/src/ndbapi/NdbIndexStatImpl.cpp'
--- a/storage/ndb/src/ndbapi/NdbIndexStatImpl.cpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/src/ndbapi/NdbIndexStatImpl.cpp 2011-08-12 05:16:41 +0000
@@ -22,6 +22,7 @@
#include <Bitmask.hpp>
#include <NdbSqlUtil.hpp>
#include <NdbRecord.hpp>
+#include <NdbEventOperation.hpp>
#include "NdbIndexStatImpl.hpp"
#undef min
@@ -33,8 +34,8 @@ static const char* const g_headtable_nam
static const char* const g_sampletable_name = NDB_INDEX_STAT_SAMPLE_TABLE;
static const char* const g_sampleindex1_name = NDB_INDEX_STAT_SAMPLE_INDEX1;
-const int ERR_NoSuchObject[] = { 709, 723, 4243, 0 };
-const int ERR_TupleNotFound[] = { 626, 0 };
+static const int ERR_NoSuchObject[] = { 709, 723, 4243, 0 };
+static const int ERR_TupleNotFound[] = { 626, 0 };
NdbIndexStatImpl::NdbIndexStatImpl(NdbIndexStat& facade) :
NdbIndexStat(*this),
@@ -45,7 +46,8 @@ NdbIndexStatImpl::NdbIndexStatImpl(NdbIn
init();
m_query_mutex = NdbMutex_Create();
assert(m_query_mutex != 0);
- m_mem_handler = &g_mem_default_handler;
+ m_eventOp = 0;
+ m_mem_handler = &c_mem_default_handler;
}
void
@@ -544,10 +546,8 @@ NdbIndexStatImpl::drop_systables(Ndb* nd
}
int
-NdbIndexStatImpl::check_systables(Ndb* ndb)
+NdbIndexStatImpl::check_systables(Sys& sys)
{
- Sys sys(this, ndb);
-
if (get_systables(sys) == -1)
return -1;
@@ -566,6 +566,17 @@ NdbIndexStatImpl::check_systables(Ndb* n
return 0;
}
+int
+NdbIndexStatImpl::check_systables(Ndb* ndb)
+{
+ Sys sys(this, ndb);
+
+ if (check_systables(sys) == -1)
+ return -1;
+
+ return 0;
+}
+
// operation context
NdbIndexStatImpl::Con::Con(NdbIndexStatImpl* impl, Head& head, Ndb* ndb) :
@@ -725,7 +736,7 @@ NdbIndexStatImpl::set_index(const NdbDic
}
NdbPack::Type type (
icol->getType(),
- icol->getArrayType() + icol->getSize() * icol->getLength(),
+ icol->getSizeInBytes(),
icol->getNullable(),
icol->getCharset() != 0 ? icol->getCharset()->number : 0
);
@@ -742,7 +753,7 @@ NdbIndexStatImpl::set_index(const NdbDic
// rir + rpk
if (m_valueSpec.add(type, m_valueAttrs) == -1)
{
- setError(InternalError, __LINE__);
+ setError(InternalError, __LINE__, m_valueSpec.get_error_code());
return -1;
}
}
@@ -781,6 +792,7 @@ void
NdbIndexStatImpl::init_head(Head& head)
{
head.m_found = -1;
+ head.m_eventType = -1;
head.m_indexId = 0;
head.m_indexVersion = 0;
head.m_tableId = 0;
@@ -1153,15 +1165,32 @@ NdbIndexStatImpl::read_next(Con& con)
setError(con, __LINE__);
return ret;
}
- // create consistent NdbPack::Data instances
- if (m_keyData.desc_all(m_keyAttrs) == -1)
+
+ /*
+ * Key and value are raw data and little-endian. Create the complete
+ * NdbPack::Data instance and convert it to native-endian.
+ */
+ const NdbPack::Endian::Value from_endian = NdbPack::Endian::Little;
+ const NdbPack::Endian::Value to_endian = NdbPack::Endian::Native;
+
+ if (m_keyData.desc_all(m_keyAttrs, from_endian) == -1)
{
- setError(InternalError, __LINE__);
+ setError(InternalError, __LINE__, m_keyData.get_error_code());
return -1;
}
- if (m_valueData.desc_all(m_valueAttrs) == -1)
+ if (m_keyData.convert(to_endian) == -1)
{
- setError(InternalError, __LINE__);
+ setError(InternalError, __LINE__, m_keyData.get_error_code());
+ return -1;
+ }
+ if (m_valueData.desc_all(m_valueAttrs, from_endian) == -1)
+ {
+ setError(InternalError, __LINE__, m_valueData.get_error_code());
+ return -1;
+ }
+ if (m_valueData.convert(to_endian) == -1)
+ {
+ setError(InternalError, __LINE__, m_valueData.get_error_code());
return -1;
}
return 0;
@@ -1183,13 +1212,12 @@ NdbIndexStatImpl::read_commit(Con& con)
int
NdbIndexStatImpl::save_start(Con& con)
{
- Mem* mem = m_mem_handler;
if (m_cacheBuild != 0)
{
free_cache(m_cacheBuild);
m_cacheBuild = 0;
}
- con.m_cacheBuild = (Cache*)mem->mem_alloc(sizeof(Cache));
+ con.m_cacheBuild = new Cache;
if (con.m_cacheBuild == 0)
{
setError(NoMemError, __LINE__);
@@ -1725,7 +1753,7 @@ NdbIndexStatImpl::free_cache(Cache* c)
mem->mem_free(c->m_addrArray);
mem->mem_free(c->m_keyArray);
mem->mem_free(c->m_valueArray);
- mem->mem_free(c);
+ delete c;
}
void
@@ -1838,7 +1866,9 @@ NdbIndexStatImpl::convert_range(Range& r
Uint32 len_out;
for (uint i = 0; i < key_count; i++)
{
- const NdbRecord::Attr& attr = key_record->columns[i];
+ const uint i2 = key_record->key_indexes[i];
+ require(i2 < key_record->noOfColumns);
+ const NdbRecord::Attr& attr = key_record->columns[i2];
if (!attr.is_null(key))
{
const char* data = key + attr.offset;
@@ -1855,7 +1885,7 @@ NdbIndexStatImpl::convert_range(Range& r
}
if (bound.m_data.add(data, &len_out) == -1)
{
- setError(InternalError, __LINE__);
+ setError(InternalError, __LINE__, bound.m_data.get_error_code());
return -1;
}
}
@@ -1863,7 +1893,7 @@ NdbIndexStatImpl::convert_range(Range& r
{
if (bound.m_data.add_null(&len_out) == -1)
{
- setError(InternalError, __LINE__);
+ setError(InternalError, __LINE__, bound.m_data.get_error_code());
return -1;
}
}
@@ -2241,59 +2271,206 @@ NdbIndexStatImpl::query_keycmp(const Cac
return res;
}
-// mem alloc - default impl
+// events and polling
-NdbIndexStatImpl::MemDefault
-NdbIndexStatImpl::g_mem_default_handler;
+int
+NdbIndexStatImpl::create_sysevents(Ndb* ndb)
+{
+ Sys sys(this, ndb);
+ NdbDictionary::Dictionary* const dic = ndb->getDictionary();
-NdbIndexStatImpl::MemDefault::MemDefault()
+ if (check_systables(sys) == -1)
+ return -1;
+ const NdbDictionary::Table* tab = sys.m_headtable;
+ require(tab != 0);
+
+ const char* const evname = NDB_INDEX_STAT_HEAD_EVENT;
+ NdbDictionary::Event ev(evname, *tab);
+ ev.addTableEvent(NdbDictionary::Event::TE_INSERT);
+ ev.addTableEvent(NdbDictionary::Event::TE_DELETE);
+ ev.addTableEvent(NdbDictionary::Event::TE_UPDATE);
+ for (int i = 0; i < tab->getNoOfColumns(); i++)
+ ev.addEventColumn(i);
+ ev.setReport(NdbDictionary::Event::ER_UPDATED);
+
+ if (dic->createEvent(ev) == -1)
+ {
+ setError(dic->getNdbError().code, __LINE__);
+ return -1;
+ }
+ return 0;
+}
+
+int
+NdbIndexStatImpl::drop_sysevents(Ndb* ndb)
{
- m_used = 0;
+ Sys sys(this, ndb);
+ NdbDictionary::Dictionary* const dic = ndb->getDictionary();
+
+ if (check_systables(sys) == -1)
+ return -1;
+
+ const char* const evname = NDB_INDEX_STAT_HEAD_EVENT;
+ if (dic->dropEvent(evname) == -1)
+ {
+ int code = dic->getNdbError().code;
+ if (code != 4710)
+ {
+ setError(dic->getNdbError().code, __LINE__);
+ return -1;
+ }
+ }
+ return 0;
}
-NdbIndexStatImpl::MemDefault::~MemDefault()
+int
+NdbIndexStatImpl::check_sysevents(Ndb* ndb)
{
- assert(m_used == 0);
+ Sys sys(this, ndb);
+ NdbDictionary::Dictionary* const dic = ndb->getDictionary();
+
+ if (check_systables(sys) == -1)
+ return -1;
+
+ const char* const evname = NDB_INDEX_STAT_HEAD_EVENT;
+ const NdbDictionary::Event* ev = dic->getEvent(evname);
+ if (ev == 0)
+ {
+ setError(dic->getNdbError().code, __LINE__);
+ return -1;
+ }
+ delete ev; // getEvent() creates new instance
+ return 0;
}
-void*
-NdbIndexStatImpl::MemDefault::mem_alloc(UintPtr size)
+int
+NdbIndexStatImpl::create_listener(Ndb* ndb)
{
- if (size == 0 || size % 4 != 0)
+ if (m_eventOp != 0)
{
- size += 4 - size % 4;
+ setError(UsageError, __LINE__);
+ return -1;
}
- Item* item = (Item*)malloc(sizeof(Item) + size);
- if (item != 0)
+ const char* const evname = NDB_INDEX_STAT_HEAD_EVENT;
+ m_eventOp = ndb->createEventOperation(evname);
+ if (m_eventOp == 0)
{
- item->m_magic = MemMagic;
- item->m_size = size;
- void* ptr = &item[1];
- m_used += size;
- return ptr;
+ setError(ndb->getNdbError().code, __LINE__);
+ return -1;
+ }
+
+ // all columns are non-nullable
+ Head& head = m_facadeHead;
+ if (m_eventOp->getValue("index_id", (char*)&head.m_indexId) == 0 ||
+ m_eventOp->getValue("index_version", (char*)&head.m_indexVersion) == 0 ||
+ m_eventOp->getValue("table_id", (char*)&head.m_tableId) == 0 ||
+ m_eventOp->getValue("frag_count", (char*)&head.m_fragCount) == 0 ||
+ m_eventOp->getValue("value_format", (char*)&head.m_valueFormat) == 0 ||
+ m_eventOp->getValue("sample_version", (char*)&head.m_sampleVersion) == 0 ||
+ m_eventOp->getValue("load_time", (char*)&head.m_loadTime) == 0 ||
+ m_eventOp->getValue("sample_count", (char*)&head.m_sampleCount) == 0 ||
+ m_eventOp->getValue("key_bytes", (char*)&head.m_keyBytes) == 0)
+ {
+ setError(m_eventOp->getNdbError().code, __LINE__);
+ return -1;
+ }
+ // wl4124_todo why this
+ static Head xxx;
+ if (m_eventOp->getPreValue("index_id", (char*)&xxx.m_indexId) == 0 ||
+ m_eventOp->getPreValue("index_version", (char*)&xxx.m_indexVersion) == 0 ||
+ m_eventOp->getPreValue("table_id", (char*)&xxx.m_tableId) == 0 ||
+ m_eventOp->getPreValue("frag_count", (char*)&xxx.m_fragCount) == 0 ||
+ m_eventOp->getPreValue("value_format", (char*)&xxx.m_valueFormat) == 0 ||
+ m_eventOp->getPreValue("sample_version", (char*)&xxx.m_sampleVersion) == 0 ||
+ m_eventOp->getPreValue("load_time", (char*)&xxx.m_loadTime) == 0 ||
+ m_eventOp->getPreValue("sample_count", (char*)&xxx.m_sampleCount) == 0 ||
+ m_eventOp->getPreValue("key_bytes", (char*)&xxx.m_keyBytes) == 0)
+ {
+ setError(m_eventOp->getNdbError().code, __LINE__);
+ return -1;
}
return 0;
}
-void
-NdbIndexStatImpl::MemDefault::mem_free(void* ptr)
+int
+NdbIndexStatImpl::execute_listener(Ndb* ndb)
{
- if (ptr != 0)
+ if (m_eventOp == 0)
+ {
+ setError(UsageError, __LINE__);
+ return -1;
+ }
+ if (m_eventOp->execute() == -1)
+ {
+ setError(m_eventOp->getNdbError().code, __LINE__);
+ return -1;
+ }
+ return 0;
+}
+
+int
+NdbIndexStatImpl::poll_listener(Ndb* ndb, int max_wait_ms)
+{
+ int ret;
+ if ((ret = ndb->pollEvents(max_wait_ms)) < 0)
+ {
+ setError(ndb->getNdbError().code, __LINE__);
+ return -1;
+ }
+ return (ret == 0 ? 0 : 1);
+}
+
+int
+NdbIndexStatImpl::next_listener(Ndb* ndb)
+{
+ NdbEventOperation* op = ndb->nextEvent();
+ if (op == 0)
+ return 0;
+
+ Head& head = m_facadeHead;
+ head.m_eventType = (int)op->getEventType();
+ return 1;
+}
+
+int
+NdbIndexStatImpl::drop_listener(Ndb* ndb)
+{
+ if (m_eventOp == 0)
{
- Item* item = (Item*)ptr - 1;
- assert(item->m_magic == MemMagic);
- size_t size = item->m_size;
- item->m_magic = 0;
- free(item);
- assert(m_used >= size);
- m_used -= size;
+ setError(UsageError, __LINE__);
+ return -1;
+ }
+ if (ndb->dropEventOperation(m_eventOp) != 0)
+ {
+ setError(ndb->getNdbError().code, __LINE__);
+ return -1;
}
+ m_eventOp = 0;
+ return 0;
}
-UintPtr
-NdbIndexStatImpl::MemDefault::mem_used() const
+// mem alloc - default impl
+
+NdbIndexStatImpl::MemDefault::MemDefault()
+{
+}
+
+NdbIndexStatImpl::MemDefault::~MemDefault()
+{
+}
+
+void*
+NdbIndexStatImpl::MemDefault::mem_alloc(UintPtr size)
+{
+ void* ptr = malloc(size);
+ return ptr;
+}
+
+void
+NdbIndexStatImpl::MemDefault::mem_free(void* ptr)
{
- return m_used;
+ if (ptr != 0)
+ free(ptr);
}
// error
=== modified file 'storage/ndb/src/ndbapi/NdbIndexStatImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbIndexStatImpl.hpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/src/ndbapi/NdbIndexStatImpl.hpp 2011-08-11 17:11:30 +0000
@@ -29,6 +29,7 @@ class NdbTransaction;
class NdbIndexScanOperation;
class NdbRecAttr;
class NdbOperation;
+class NdbEventOperation;
extern const uint g_ndb_index_stat_head_frm_len;
extern const uint8 g_ndb_index_stat_head_frm_data[];
@@ -71,6 +72,7 @@ public:
Cache* m_cacheClean;
// mutex for query cache switch, memory barrier would do
NdbMutex* m_query_mutex;
+ NdbEventOperation* m_eventOp;
Mem* m_mem_handler;
NdbIndexStat::Error m_error;
@@ -98,6 +100,7 @@ public:
int get_systables(Sys& sys);
int create_systables(Ndb* ndb);
int drop_systables(Ndb* ndb);
+ int check_systables(Sys& sys);
int check_systables(Ndb* ndb);
// operation context
@@ -279,22 +282,25 @@ public:
void query_search(const Cache&, const Bound&, StatBound&);
int query_keycmp(const Cache&, const Bound&, uint pos, Uint32& numEq);
+ // events and polling
+ int create_sysevents(Ndb* ndb);
+ int drop_sysevents(Ndb* ndb);
+ int check_sysevents(Ndb* ndb);
+ //
+ int create_listener(Ndb* ndb);
+ int execute_listener(Ndb* ndb);
+ int poll_listener(Ndb* ndb, int max_wait_ms);
+ int next_listener(Ndb* ndb);
+ int drop_listener(Ndb* ndb);
+
// default memory allocator
struct MemDefault : public Mem {
virtual void* mem_alloc(UintPtr bytes);
- virtual void mem_free(void* p);
- virtual UintPtr mem_used() const;
+ virtual void mem_free(void* ptr);
MemDefault();
virtual ~MemDefault();
- private:
- enum { MemMagic = 0xf1f2f3f4 };
- struct Item {
- Uint32 m_magic;
- size_t m_size;
- };
- size_t m_used;
};
- static MemDefault g_mem_default_handler;
+ MemDefault c_mem_default_handler;
// error
const NdbIndexStat::Error& getNdbError() const;
=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2011-08-17 08:12:33 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2011-08-17 12:51:57 +0000
@@ -181,6 +181,8 @@ public:
*/
void init(NdbQueryImpl& query, Uint32 fragNo);
+ static void clear(NdbRootFragment* frags, Uint32 noOfFrags);
+
Uint32 getFragNo() const
{ return m_fragNo; }
@@ -192,7 +194,11 @@ public:
/**
* Prepare for reading another batch of results.
*/
- void prepareResultSet();
+ void grabNextResultSet(); // Need mutex lock
+
+ bool hasReceivedMore() const; // Need mutex lock
+
+ void setReceivedMore(); // Need mutex lock
void incrOutstandingResults(Int32 delta)
{
@@ -273,12 +279,19 @@ private:
NdbResultStream* m_resultStreams;
/**
- * The number of outstanding TCKEYREF or TRANSID_AI
- * messages for the fragment. This includes both messages related to the
+ * Number of available prefetched ResultSets which are completely
+ * received. Will be made available for reading by calling
+ * ::grabNextResultSet()
+ */
+ Uint32 m_availResultSets; // Need mutex
+
+ /**
+ * The number of outstanding TCKEYREF or TRANSID_AI messages to receive
+ * for the fragment. This includes both messages related to the
* root operation and any descendant operation that was instantiated as
* a consequence of tuples found by the root operation.
- * This number may temporarily be negative if e.g. TRANSID_AI arrives before
- * SCAN_TABCONF.
+ * This number may temporarily be negative if e.g. TRANSID_AI arrives
+ * before SCAN_TABCONF.
*/
Int32 m_outstandingResults;
@@ -287,7 +300,8 @@ private:
* operation accesses (i.e. one for a lookup, all for a table scan).
*
* Each element is true iff a SCAN_TABCONF (for that fragment) or
- * TCKEYCONF message has been received */
+ * TCKEYCONF message has been received
+ */
bool m_confReceived;
/**
@@ -1034,6 +1048,7 @@ NdbRootFragment::NdbRootFragment():
m_query(NULL),
m_fragNo(voidFragNo),
m_resultStreams(NULL),
+ m_availResultSets(0),
m_outstandingResults(0),
m_confReceived(false),
m_remainingScans(0),
@@ -1094,6 +1109,45 @@ NdbRootFragment::getResultStream(Uint32
return m_resultStreams[operationNo];
}
+/**
+ * Throw any pending ResultSets from specified rootFrags[]
+ */
+//static
+void NdbRootFragment::clear(NdbRootFragment* rootFrags, Uint32 noOfFrags)
+{
+ if (rootFrags != NULL)
+ {
+ for (Uint32 fragNo = 0; fragNo < noOfFrags; fragNo++)
+ {
+ rootFrags[fragNo].m_availResultSets = 0;
+ }
+ }
+}
+
+/**
+ * Signal that another complete ResultSet is available for
+ * this NdbRootFragment.
+ * Need mutex lock as 'm_availResultSets' is accesed both from
+ * receiver and application thread.
+ */
+void NdbRootFragment::setReceivedMore()
+{
+ assert(m_availResultSets==0);
+ m_availResultSets++;
+}
+
+/**
+ * Check if another ResultSets has been received and is available
+ * for reading. It will be given to the application thread when it
+ * call ::grabNextResultSet().
+ * Need mutex lock as 'm_availResultSets' is accesed both from
+ * receiver and application thread.
+ */
+bool NdbRootFragment::hasReceivedMore() const
+{
+ return (m_availResultSets > 0);
+}
+
void NdbRootFragment::reset()
{
assert(m_fragNo!=voidFragNo);
@@ -1114,8 +1168,17 @@ void NdbRootFragment::reset()
m_confReceived = false;
}
-void NdbRootFragment::prepareResultSet()
+/**
+ * Let the application thread takes ownership of an available
+ * ResultSet, prepare it for reading first row.
+ * Need mutex lock as 'm_availResultSets' is accesed both from
+ * receiver and application thread.
+ */
+void NdbRootFragment::grabNextResultSet()
{
+ assert(m_availResultSets>0);
+ m_availResultSets--;
+
NdbResultStream& rootStream = getResultStream(0);
rootStream.prepareResultSet(m_remainingScans);
@@ -1137,7 +1200,7 @@ void NdbRootFragment::setConfReceived(Ui
bool NdbRootFragment::finalBatchReceived() const
{
- return getReceiverTcPtrI()==RNIL;
+ return m_confReceived && getReceiverTcPtrI()==RNIL;
}
bool NdbRootFragment::isEmpty() const
@@ -1587,6 +1650,7 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio
m_next(NULL),
m_queryDef(&queryDef),
m_error(),
+ m_errorReceived(0),
m_transaction(trans),
m_scanTransaction(NULL),
m_operations(0),
@@ -1596,7 +1660,6 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio
m_rootFragCount(0),
m_rootFrags(NULL),
m_applFrags(),
- m_fullFrags(),
m_finalBatchFrags(0),
m_num_bounds(0),
m_shortestBound(0xffffffff),
@@ -2060,10 +2123,9 @@ NdbQueryImpl::nextResult(bool fetchAllow
NdbQuery::NextResultOutcome
NdbQueryImpl::nextRootResult(bool fetchAllowed, bool forceSend)
{
- /* To minimize lock contention, each query has two separate root fragment
- * conatiners (m_fullFrags and m_applFrags). m_applFrags is only
- * accessed by the application thread, so it is safe to use it without
- * locks.
+ /* To minimize lock contention, each query has the separate root fragment
+ * conatiner 'm_applFrags'. m_applFrags is only accessed by the application
+ * thread, so it is safe to use it without locks.
*/
while (m_state != EndOfData) // Or likely: return when 'gotRow' or error
{
@@ -2179,23 +2241,17 @@ NdbQueryImpl::awaitMoreResults(bool forc
*/
while (likely(!hasReceivedError()))
{
- /* m_fullFrags contains any fragments that are complete (for this batch)
- * but have not yet been moved (under mutex protection) to
- * m_applFrags.
+ /* Scan m_rootFrags (under mutex protection) for fragments
+ * which has received a complete batch. Add these to m_applFrags.
*/
- NdbRootFragment* frag;
- while ((frag=m_fullFrags.pop()) != NULL)
- {
- frag->prepareResultSet();
- m_applFrags.add(*frag);
- }
+ m_applFrags.prepareMoreResults(m_rootFrags,m_rootFragCount);
if (m_applFrags.getCurrent() != NULL)
{
return FetchResult_ok;
}
- /* There are noe more available frament results available without
- * first waiting for more to be received from datanodes
+ /* There are no more available fragment results available without
+ * first waiting for more to be received from the datanodes
*/
if (m_pendingFrags == 0)
{
@@ -2236,16 +2292,9 @@ NdbQueryImpl::awaitMoreResults(bool forc
/* The root operation is a lookup. Lookups are guaranteed to be complete
* before NdbTransaction::execute() returns. Therefore we do not set
* the lock, because we know that the signal receiver thread will not
- * be accessing m_fullFrags at this time.
+ * be accessing m_rootFrags at this time.
*/
- NdbRootFragment* frag;
- if ((frag=m_fullFrags.pop()) != NULL)
- {
- frag->prepareResultSet();
- m_applFrags.add(*frag);
- }
- assert(m_fullFrags.pop()==NULL); // Only one stream for lookups.
-
+ m_applFrags.prepareMoreResults(m_rootFrags,m_rootFragCount);
if (m_applFrags.getCurrent() != NULL)
{
return FetchResult_ok;
@@ -2266,8 +2315,8 @@ NdbQueryImpl::awaitMoreResults(bool forc
/*
::handleBatchComplete() is intended to be called when receiving signals only.
- The PollGuard mutex is then set and the shared 'm_pendingFrags',
- 'm_finalBatchFrags' and 'm_fullFrags' can safely be updated.
+ The PollGuard mutex is then set and the shared 'm_pendingFrags' and
+ 'm_finalBatchFrags' can safely be updated and ::setReceivedMore() signaled.
returns: 'true' when application thread should be resumed.
*/
@@ -2286,7 +2335,7 @@ NdbQueryImpl::handleBatchComplete(NdbRoo
* terminated the scan. We are about to close this query,
* and didn't expect any more data - ignore it!
*/
- if (likely(m_fullFrags.m_errorCode == 0))
+ if (likely(m_errorReceived == 0))
{
assert(rootFrag.isFragBatchComplete());
@@ -2300,10 +2349,10 @@ NdbQueryImpl::handleBatchComplete(NdbRoo
assert(m_finalBatchFrags <= m_rootFragCount);
}
- /* When application thread ::awaitMoreResults() it will later be moved
- * from m_fullFrags to m_applFrags under mutex protection.
+ /* When application thread ::awaitMoreResults() it will later be
+ * added to m_applFrags under mutex protection.
*/
- m_fullFrags.push(rootFrag);
+ rootFrag.setReceivedMore();
return true;
}
@@ -2327,7 +2376,7 @@ NdbQueryImpl::close(bool forceSend)
}
// Throw any pending results
- m_fullFrags.clear();
+ NdbRootFragment::clear(m_rootFrags,m_rootFragCount);
m_applFrags.clear();
Ndb* const ndb = m_transaction.getNdb();
@@ -2423,7 +2472,7 @@ NdbQueryImpl::setFetchTerminated(int err
}
if (errorCode!=0)
{
- m_fullFrags.m_errorCode = errorCode;
+ m_errorReceived = errorCode;
}
m_pendingFrags = 0;
} // NdbQueryImpl::setFetchTerminated()
@@ -2436,9 +2485,9 @@ NdbQueryImpl::setFetchTerminated(int err
bool
NdbQueryImpl::hasReceivedError()
{
- if (unlikely(m_fullFrags.m_errorCode))
+ if (unlikely(m_errorReceived))
{
- setErrorCode(m_fullFrags.m_errorCode);
+ setErrorCode(m_errorReceived);
return true;
}
return false;
@@ -2543,8 +2592,7 @@ NdbQueryImpl::prepareSend()
}
// Allocate space for ptrs to NdbResultStream and NdbRootFragment objects.
error = m_pointerAlloc.init(m_rootFragCount *
- (SharedFragStack::pointersPerFragment +
- OrderedFragSet::pointersPerFragment));
+ (OrderedFragSet::pointersPerFragment));
if (error != 0)
{
setErrorCode(error);
@@ -2631,21 +2679,17 @@ NdbQueryImpl::prepareSend()
keyRec = getRoot().getQueryOperationDef().getIndex()->getDefaultRecord();
assert(keyRec!=NULL);
}
- if (unlikely((error = m_applFrags.prepare(m_pointerAlloc,
- getRoot().getOrdering(),
- m_rootFragCount,
- keyRec,
- getRoot().m_ndbRecord)) != 0)
- || (error = m_fullFrags.prepare(m_pointerAlloc,
- m_rootFragCount)) != 0) {
- setErrorCode(error);
- return -1;
- }
+ m_applFrags.prepare(m_pointerAlloc,
+ getRoot().getOrdering(),
+ m_rootFragCount,
+ keyRec,
+ getRoot().m_ndbRecord);
if (getQueryDef().isScanQuery())
{
NdbRootFragment::buildReciverIdMap(m_rootFrags, m_rootFragCount);
}
+
#ifdef TRACE_SERIALIZATION
ndbout << "Serialized ATTRINFO : ";
for(Uint32 i = 0; i < m_attrInfo.getSize(); i++){
@@ -3183,8 +3227,8 @@ NdbQueryImpl::closeTcCursor(bool forceSe
} // while
assert(m_pendingFrags==0);
- m_fullFrags.clear(); // Throw any unhandled results
- m_fullFrags.m_errorCode = 0; // Clear errors caused by previous fetching
+ NdbRootFragment::clear(m_rootFrags,m_rootFragCount);
+ m_errorReceived = 0; // Clear errors caused by previous fetching
m_error.code = 0;
if (m_finalBatchFrags < getRootFragCount()) // TC has an open scan cursor.
@@ -3271,39 +3315,6 @@ int NdbQueryImpl::isPrunable(bool& pruna
/****************
- * NdbQueryImpl::SharedFragStack methods.
- ***************/
-
-NdbQueryImpl::SharedFragStack::SharedFragStack():
- m_errorCode(0),
- m_capacity(0),
- m_current(-1),
- m_array(NULL)
-{}
-
-int
-NdbQueryImpl::SharedFragStack::prepare(NdbBulkAllocator& allocator,
- int capacity)
-{
- assert(m_array==NULL);
- assert(m_capacity==0);
- if (capacity > 0)
- { m_capacity = capacity;
- m_array =
- reinterpret_cast<NdbRootFragment**>(allocator.allocObjMem(capacity));
- }
- return 0;
-}
-
-void
-NdbQueryImpl::SharedFragStack::push(NdbRootFragment& frag)
-{
- m_current++;
- assert(m_current<m_capacity);
- m_array[m_current] = &frag;
-}
-
-/****************
* NdbQueryImpl::OrderedFragSet methods.
***************/
@@ -3327,7 +3338,7 @@ NdbQueryImpl::OrderedFragSet::~OrderedFr
}
-int
+void
NdbQueryImpl::OrderedFragSet::prepare(NdbBulkAllocator& allocator,
NdbQueryOptions::ScanOrdering ordering,
int capacity,
@@ -3345,6 +3356,7 @@ NdbQueryImpl::OrderedFragSet::prepare(Nd
m_activeFrags =
reinterpret_cast<NdbRootFragment**>(allocator.allocObjMem(capacity));
bzero(m_activeFrags, capacity * sizeof(NdbRootFragment*));
+
m_emptiedFrags =
reinterpret_cast<NdbRootFragment**>(allocator.allocObjMem(capacity));
bzero(m_emptiedFrags, capacity * sizeof(NdbRootFragment*));
@@ -3352,7 +3364,6 @@ NdbQueryImpl::OrderedFragSet::prepare(Nd
m_ordering = ordering;
m_keyRecord = keyRecord;
m_resultRecord = resultRecord;
- return 0;
} // OrderedFragSet::prepare()
@@ -3479,6 +3490,23 @@ NdbQueryImpl::OrderedFragSet::add(NdbRoo
reorganize(); // Move into position
} // OrderedFragSet::add()
+void
+NdbQueryImpl::OrderedFragSet::prepareMoreResults(NdbRootFragment rootFrags[], Uint32 cnt)
+{
+ for (Uint32 fragNo = 0; fragNo < cnt; fragNo++)
+ {
+ NdbRootFragment& rootFrag = rootFrags[fragNo];
+ if (rootFrag.hasReceivedMore()) // Another ResultSet is available
+ {
+ rootFrag.grabNextResultSet(); // Get new ResultSet.
+ add(rootFrag); // Make avail. to appl. thread
+ }
+ } // for all 'rootFrags[]'
+
+ assert(m_activeFragCount + m_emptiedFragCount + m_finalFragCount
+ <= m_capacity);
+} // OrderedFragSet::prepareMoreResults()
+
void NdbQueryImpl::OrderedFragSet::clear()
{
m_activeFragCount = 0;
=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2011-08-17 08:10:27 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2011-08-17 12:06:04 +0000
@@ -271,58 +271,13 @@ private:
FetchResult_noMoreCache = 2
};
- /** A stack of NdbRootFragment pointers.
- * NdbRootFragments which are 'BatchComplete' are pushed on this stack by
- * the receiver thread, and later pop'ed into the application thread when
- * it need more results to process.
- * Due to this shared usage, the PollGuard mutex must be set before
- * accessing SharedFragStack.
+ /**
+ * Container of root fragments that the application is currently
+ * iterating over. 'Owned' by application thread and can be accesed
+ * without requiring a mutex lock.
+ * RootFragments are appended to a OrderedFragSet by ::prepareMoreResults()
+ *
*/
- class SharedFragStack{
- public:
- // For calculating need for dynamically allocated memory.
- static const Uint32 pointersPerFragment = 1;
-
- explicit SharedFragStack();
-
- /**
- * Prepare internal datastructures.
- * param[in] allocator For allocating arrays of pointers.
- * param[in] capacity Max no of root fragments.
- * @return 0 if ok, else errorcode
- */
- int prepare(NdbBulkAllocator& allocator, int capacity);
-
- NdbRootFragment* pop() {
- return m_current>=0 ? m_array[m_current--] : NULL;
- }
-
- void push(NdbRootFragment& frag);
-
- int size() const {
- return (m_current+1);
- }
-
- void clear() {
- m_current = -1;
- }
-
- /** Possible error received from TC / datanodes. */
- int m_errorCode;
-
- private:
- /** Capacity of stack.*/
- int m_capacity;
-
- /** Index of current top of stack.*/
- int m_current;
- NdbRootFragment** m_array;
-
- // No copying.
- SharedFragStack(const SharedFragStack&);
- SharedFragStack& operator=(const SharedFragStack&);
- }; // class SharedFragStack
-
class OrderedFragSet{
public:
// For calculating need for dynamically allocated memory.
@@ -339,11 +294,20 @@ private:
* param[in] capacity Max no of root fragments.
* @return 0 if ok, else errorcode
*/
- int prepare(NdbBulkAllocator& allocator,
- NdbQueryOptions::ScanOrdering ordering,
- int capacity,
- const NdbRecord* keyRecord,
- const NdbRecord* resultRecord);
+ void prepare(NdbBulkAllocator& allocator,
+ NdbQueryOptions::ScanOrdering ordering,
+ int capacity,
+ const NdbRecord* keyRecord,
+ const NdbRecord* resultRecord);
+
+ /**
+ * Add root fragments with completed ResultSets to this OrderedFragSet.
+ * The PollGuard mutex must locked, and under its protection
+ * completed root fragments are 'consumed' from rootFrags[] and
+ * added to OrderedFragSet where it become available for the
+ * application thread.
+ */
+ void prepareMoreResults(NdbRootFragment rootFrags[], Uint32 cnt); // Need mutex lock
/** Get the root fragment from which to read the next row.*/
NdbRootFragment* getCurrent() const;
@@ -355,9 +319,6 @@ private:
*/
void reorganize();
- /** Add a complete fragment that has been received.*/
- void add(NdbRootFragment& frag);
-
/** Reset object to an empty state.*/
void clear();
@@ -397,6 +358,9 @@ private:
OrderedFragSet(const OrderedFragSet&);
OrderedFragSet& operator=(const OrderedFragSet&);
+ /** Add a complete fragment that has been received.*/
+ void add(NdbRootFragment& frag);
+
/** For sorting fragment reads according to index value of first record.
* Also f1<f2 if f2 has reached end of data and f1 has not.
* @return 1 if f1>f2, 0 if f1==f2, -1 if f1<f2.*/
@@ -433,6 +397,14 @@ private:
/** Possible error status of this query.*/
NdbError m_error;
+
+ /**
+ * Possible error received from TC / datanodes.
+ * Only access w/ PollGuard mutex as it is set by receiver thread.
+ * Checked and moved into 'm_error' with ::hasReceivedError().
+ */
+ int m_errorReceived; // BEWARE: protect with PollGuard mutex
+
/** Transaction in which this query instance executes.*/
NdbTransaction& m_transaction;
@@ -452,7 +424,7 @@ private:
Uint32 m_globalCursor;
/** Number of root fragments not yet completed within the current batch.
- * Only access w/ PollGuard mutex as it is also updated by receiver threa
+ * Only access w/ PollGuard mutex as it is also updated by receiver thread
*/
Uint32 m_pendingFrags; // BEWARE: protect with PollGuard mutex
@@ -473,11 +445,6 @@ private:
*/
OrderedFragSet m_applFrags;
- /** Root frgaments that have received a complete batch. Shared between
- * application thread and receiving thread. Access should be mutex protected.
- */
- SharedFragStack m_fullFrags; // BEWARE: protect with PollGuard mutex
-
/** Number of root fragments for which confirmation for the final batch
* (with tcPtrI=RNIL) has been received. Observe that even if
* m_finalBatchFrags==m_rootFragCount, all tuples for the final batches may
@@ -557,7 +524,8 @@ private:
bool forceSend);
/** Wait for more scan results which already has been REQuested to arrive.
- * @return 0 if some rows did arrive, a negative value if there are errors (in m_error.code),
+ * @return 0 if some rows did arrive, a negative value if there are errors
+ * (in m_error.code),
* and 1 of there are no more rows to receive.
*/
FetchResult awaitMoreResults(bool forceSend);
=== modified file 'storage/ndb/test/ndbapi/testIndexStat.cpp'
--- a/storage/ndb/test/ndbapi/testIndexStat.cpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/test/ndbapi/testIndexStat.cpp 2011-08-11 17:11:30 +0000
@@ -110,7 +110,8 @@ static const NdbRecord* g_ind_rec = 0;
struct my_record
{
- Uint32 m_null_bm;
+ Uint8 m_null_bm;
+ Uint8 fill[3];
Uint32 m_a;
Uint32 m_b;
char m_c[1+g_charlen];
@@ -133,6 +134,7 @@ static NdbIndexScanOperation* g_rangesca
static NdbIndexStat* g_is = 0;
static bool g_has_created_stat_tables = false;
+static bool g_has_created_stat_events = false;
static uint
urandom()
@@ -212,7 +214,7 @@ errdb()
ll0(++any << " rangescan_op: error " << e);
}
if (g_is != 0) {
- const NdbError& e = g_is->getNdbError();
+ const NdbIndexStat::Error& e = g_is->getNdbError();
if (e.code != 0)
ll0(++any << " stat: error " << e);
}
@@ -376,6 +378,7 @@ struct Val {
void copy(const Val& val2);
void make(uint numattrs, const Lim& lim);
int cmp(const Val& val2, uint numattrs = g_numattrs, uint* num_eq = 0) const;
+ void fromib(const NdbIndexScanOperation::IndexBound& ib, uint j);
private:
Val& operator=(const Val&);
@@ -556,6 +559,40 @@ Val::cmp(const Val& val2, uint numattrs,
return k;
}
+void
+Val::fromib(const NdbIndexScanOperation::IndexBound& ib, uint j)
+{
+ const char* key = (j == 0 ? ib.low_key : ib.high_key);
+ const uint numattrs = (j == 0 ? ib.low_key_count : ib.high_key_count);
+ const Uint8 nullbits = *(const Uint8*)key;
+ require(numattrs <= g_numattrs);
+ if (numattrs >= 1) {
+ if (nullbits & (1 << g_ndbrec_b_nb_offset))
+ b_null = 1;
+ else {
+ memcpy(&b, &key[g_ndbrec_b_offset], sizeof(b));
+ b_null = 0;
+ }
+ }
+ if (numattrs >= 2) {
+ if (nullbits & (1 << g_ndbrec_c_nb_offset))
+ c_null = 1;
+ else {
+ memcpy(c, &key[g_ndbrec_c_offset], sizeof(c));
+ c_null = 0;
+ }
+ }
+ if (numattrs >= 3) {
+ if (nullbits & (1 << g_ndbrec_d_nb_offset))
+ d_null = 1;
+ else {
+ memcpy(&d, &key[g_ndbrec_d_offset], sizeof(d));
+ d_null = 0;
+ }
+ }
+ m_numattrs = numattrs;
+}
+
// index keys
struct Key {
@@ -844,7 +881,9 @@ struct Bnd {
Bnd& make(uint minattrs);
Bnd& make(uint minattrs, const Val& theval);
int cmp(const Key& key) const;
+ int cmp(const Bnd& bnd2);
int type(uint colno) const; // for setBound
+ void fromib(const NdbIndexScanOperation::IndexBound& ib, uint j);
private:
Bnd& operator=(const Bnd&);
@@ -937,6 +976,52 @@ Bnd::cmp(const Key& key) const
}
int
+Bnd::cmp(const Bnd& bnd2)
+{
+ int place; // debug
+ int ret;
+ const Bnd& bnd1 = *this;
+ const Val& val1 = bnd1.m_val;
+ const Val& val2 = bnd2.m_val;
+ const uint numattrs1 = val1.m_numattrs;
+ const uint numattrs2 = val2.m_numattrs;
+ const uint n = (numattrs1 < numattrs2 ? numattrs1 : numattrs2);
+ do {
+ int k = val1.cmp(val2, n);
+ if (k != 0) {
+ place = 1;
+ ret = k;
+ break;
+ }
+ if (numattrs1 < numattrs2) {
+ place = 2;
+ ret = (+1) * bnd1.m_side;
+ break;
+ }
+ if (numattrs1 > numattrs2) {
+ place = 3;
+ ret = (-1) * bnd1.m_side;
+ break;
+ }
+ if (bnd1.m_side < bnd2.m_side) {
+ place = 4;
+ ret = -1;
+ break;
+ }
+ if (bnd1.m_side > bnd2.m_side) {
+ place = 5;
+ ret = +1;
+ break;
+ }
+ place = 6;
+ ret = 0;
+ } while (0);
+ ll3("bnd: " << *this << " cmp bnd: " << bnd2
+ << " ret: " << ret << " place: " << place);
+ return ret;
+}
+
+int
Bnd::type(uint colno) const
{
int t;
@@ -960,6 +1045,21 @@ Bnd::type(uint colno) const
return t;
}
+void
+Bnd::fromib(const NdbIndexScanOperation::IndexBound& ib, uint j)
+{
+ Val& val = m_val;
+ val.fromib(ib, j);
+ const uint numattrs = (j == 0 ? ib.low_key_count : ib.high_key_count);
+ const bool inclusive = (j == 0 ? ib.low_inclusive : ib.high_inclusive);
+ if (numattrs == 0) {
+ m_side = 0;
+ } else {
+ m_side = (j == 0 ? (inclusive ? -1 : +1) : (inclusive ? +1 : -1));
+ }
+ m_lohi = j;
+}
+
// stats values
struct Stval {
@@ -1016,6 +1116,7 @@ struct Rng {
void copy(const Rng& rng2);
int cmp(const Key& key) const; // -1,0,+1 = key is before,in,after range
uint rowcount() const;
+ void fromib(const NdbIndexScanOperation::IndexBound& ib);
private:
Rng& operator=(const Rng&);
@@ -1164,6 +1265,15 @@ Rng::rowcount() const
return count;
}
+void
+Rng::fromib(const NdbIndexScanOperation::IndexBound& ib)
+{
+ for (uint j = 0; j <= 1; j++) {
+ Bnd& bnd = m_bnd[j];
+ bnd.fromib(ib, j);
+ }
+}
+
static Rng* g_rnglist = 0;
static void
@@ -1409,6 +1519,40 @@ readstat()
return 0;
}
+// test polling after updatestat
+
+static int
+startlistener()
+{
+ ll1("startlistener");
+ chkdb(g_is->create_listener(g_ndb_sys) == 0);
+ chkdb(g_is->execute_listener(g_ndb_sys) == 0);
+ return 0;
+}
+
+static int
+runlistener()
+{
+ ll1("runlistener");
+ int ret;
+ chkdb((ret = g_is->poll_listener(g_ndb_sys, 10000)) != -1);
+ chkrc(ret == 1);
+ // one event is expected
+ chkdb((ret = g_is->next_listener(g_ndb_sys)) != -1);
+ chkrc(ret == 1);
+ chkdb((ret = g_is->next_listener(g_ndb_sys)) != -1);
+ chkrc(ret == 0);
+ return 0;
+}
+
+static int
+stoplistener()
+{
+ ll1("stoplistener");
+ chkdb(g_is->drop_listener(g_ndb_sys) != -1);
+ return 0;
+}
+
// stats queries
// exact stats from scan results
@@ -1475,7 +1619,8 @@ queryscan(Rng& rng)
*/
static int
initialiseIndexBound(const Rng& rng,
- NdbIndexScanOperation::IndexBound& ib)
+ NdbIndexScanOperation::IndexBound& ib,
+ my_record* low_key, my_record* high_key)
{
ll3("initialiseIndexBound: " << rng);
uint i;
@@ -1483,9 +1628,13 @@ initialiseIndexBound(const Rng& rng,
Uint32 colsInBound[2]= {0, 0};
bool boundInclusive[2]= {false, false};
+ memset(&ib, 0xf1, sizeof(ib));
+ memset(low_key, 0xf2, sizeof(*low_key));
+ memset(high_key, 0xf3, sizeof(*high_key));
+
// Clear nullbit storage
- *((char *)ib.low_key) =
- *((char *)ib.high_key) = 0;
+ low_key->m_null_bm = 0;
+ high_key->m_null_bm = 0;
for (i = 0; i < g_numattrs; i++) {
const Uint32 no = i; // index attribute number
@@ -1499,7 +1648,7 @@ initialiseIndexBound(const Rng& rng,
}
for (j = 0; j <= 1; j++) {
/* Get ptr to key storage space for this bound */
- my_record* keyBuf= (my_record *)( (j==0) ? ib.low_key : ib.high_key);
+ my_record* keyBuf= (j==0) ? low_key : high_key;
int t = type[j];
if (t == -1)
continue;
@@ -1542,8 +1691,10 @@ initialiseIndexBound(const Rng& rng,
}
/* Now have everything we need to initialise the IndexBound */
+ ib.low_key = (char*)low_key;
ib.low_key_count= colsInBound[0];
ib.low_inclusive= boundInclusive[0];
+ ib.high_key = (char*)high_key;
ib.high_key_count= colsInBound[1];
ib.high_inclusive= boundInclusive[1];
ib.range_no= 0;
@@ -1554,11 +1705,18 @@ initialiseIndexBound(const Rng& rng,
" high_inc=" << ib.high_inclusive);
ll3(" low bound b=" << *((Uint32*) &ib.low_key[g_ndbrec_b_offset]) <<
" d=" << *((Uint16*) &ib.low_key[g_ndbrec_d_offset]) <<
- " first byte=%xu" << ib.low_key[0]);
+ " first byte=" << ib.low_key[0]);
ll3(" high bound b=" << *((Uint32*) &ib.high_key[g_ndbrec_b_offset]) <<
" d=" << *((Uint16*) &ib.high_key[g_ndbrec_d_offset]) <<
- " first byte=%xu" << ib.high_key[0]);
+ " first byte=" << ib.high_key[0]);
+ // verify by reverse
+ {
+ Rng rng;
+ rng.fromib(ib);
+ require(rng.m_bnd[0].cmp(bnd[0]) == 0);
+ require(rng.m_bnd[1].cmp(bnd[1]) == 0);
+ }
return 0;
}
@@ -1568,13 +1726,12 @@ querystat_v2(Rng& rng)
ll3("querystat_v2");
/* Create IndexBound and key storage space */
- char keySpace[2][g_ndbrecord_bytes];
NdbIndexScanOperation::IndexBound ib;
- ib.low_key= keySpace[0];
- ib.high_key= keySpace[1];
+ my_record low_key;
+ my_record high_key;
chkdb((g_con = g_ndb->startTransaction()) != 0);
- chkrc(initialiseIndexBound(rng, ib) == 0);
+ chkrc(initialiseIndexBound(rng, ib, &low_key, &high_key) == 0);
Uint64 count = ~(Uint64)0;
chkdb(g_is->records_in_range(g_ind,
@@ -1610,10 +1767,9 @@ querystat(Rng& rng)
// convert to IndexBound (like in mysqld)
NdbIndexScanOperation::IndexBound ib;
- char keySpace[2][g_ndbrecord_bytes];
- ib.low_key = keySpace[0];
- ib.high_key = keySpace[1];
- chkrc(initialiseIndexBound(rng, ib) == 0);
+ my_record low_key;
+ my_record high_key;
+ chkrc(initialiseIndexBound(rng, ib, &low_key, &high_key) == 0);
chkrc(g_is->convert_range(range, g_ind_rec, &ib) == 0);
// index stat query
@@ -1960,6 +2116,7 @@ runtest()
chkrc(createindex() == 0);
chkrc(createNdbRecords() == 0);
chkrc(definestat() == 0);
+ chkrc(startlistener() == 0);
for (g_loop = 0; g_opts.loops == 0 || g_loop < g_opts.loops; g_loop++) {
ll0("=== loop " << g_loop << " ===");
@@ -1973,6 +2130,7 @@ runtest()
makeranges();
chkrc(scanranges() == 0);
chkrc(updatestat() == 0);
+ chkrc(runlistener() == 0);
chkrc(readstat() == 0);
chkrc(queryranges() == 0);
loopstats();
@@ -1980,6 +2138,7 @@ runtest()
}
finalstats();
+ chkrc(stoplistener() == 0);
if (!g_opts.keeptable)
chkrc(droptable() == 0);
freeranges();
@@ -2113,22 +2272,66 @@ docreate_stat_tables()
{
if (g_is->check_systables(g_ndb_sys) == 0)
return 0;
+ ll1("check_systables: " << g_is->getNdbError());
- if (g_is->create_systables(g_ndb_sys) == 0)
- {
- g_has_created_stat_tables = true;
- return 0;
- }
- return -1;
+ ll0("create stat tables");
+ chkdb(g_is->create_systables(g_ndb_sys) == 0);
+ g_has_created_stat_tables = true;
+ return 0;
}
static
-void
+int
dodrop_stat_tables()
{
if (g_has_created_stat_tables == false)
- return;
- g_is->drop_systables(g_ndb_sys);
+ return 0;
+
+ ll0("drop stat tables");
+ chkdb(g_is->drop_systables(g_ndb_sys) == 0);
+ return 0;
+}
+
+static int
+docreate_stat_events()
+{
+ if (g_is->check_sysevents(g_ndb_sys) == 0)
+ return 0;
+ ll1("check_sysevents: " << g_is->getNdbError());
+
+ ll0("create stat events");
+ chkdb(g_is->create_sysevents(g_ndb_sys) == 0);
+ g_has_created_stat_events = true;
+ return 0;
+}
+
+static int
+dodrop_stat_events()
+{
+ if (g_has_created_stat_events == false)
+ return 0;
+
+ ll0("drop stat events");
+ chkdb(g_is->drop_sysevents(g_ndb_sys) == 0);
+ return 0;
+}
+
+static int
+docreate_sys_objects()
+{
+ require(g_is != 0 && g_ndb_sys != 0);
+ chkrc(docreate_stat_tables() == 0);
+ chkrc(docreate_stat_events() == 0);
+ return 0;
+}
+
+static int
+dodrop_sys_objects()
+{
+ require(g_is != 0 && g_ndb_sys != 0);
+ chkrc(dodrop_stat_events() == 0);
+ chkrc(dodrop_stat_tables() == 0);
+ return 0;
}
int
@@ -2156,17 +2359,22 @@ main(int argc, char** argv)
ll0("connect failed");
return NDBT_ProgramExit(NDBT_FAILED);
}
- if (docreate_stat_tables() == -1){
- ll0("failed to create stat tables");
- return NDBT_ProgramExit(NDBT_FAILED);
+ if (docreate_sys_objects() == -1) {
+ ll0("failed to check or create stat tables and events");
+ goto failed;
}
if (runtest() == -1) {
ll0("test failed");
- dodrop_stat_tables();
- dodisconnect();
- return NDBT_ProgramExit(NDBT_FAILED);
+ goto failed;
+ }
+ if (dodrop_sys_objects() == -1) {
+ ll0("failed to drop created stat tables or events");
+ goto failed;
}
- dodrop_stat_tables();
dodisconnect();
return NDBT_ProgramExit(NDBT_OK);
+failed:
+ (void)dodrop_sys_objects();
+ dodisconnect();
+ return NDBT_ProgramExit(NDBT_FAILED);
}
=== modified file 'storage/ndb/tools/ndb_index_stat.cpp'
--- a/storage/ndb/tools/ndb_index_stat.cpp 2011-07-04 13:37:56 +0000
+++ b/storage/ndb/tools/ndb_index_stat.cpp 2011-08-11 17:11:30 +0000
@@ -35,6 +35,8 @@ static my_bool _sys_create = false;
static my_bool _sys_create_if_not_exist = false;
static my_bool _sys_create_if_not_valid = false;
static my_bool _sys_check = false;
+static my_bool _sys_skip_tables = false;
+static my_bool _sys_skip_events = false;
static int _sys_any = 0;
// other
static my_bool _verbose = false;
@@ -88,11 +90,13 @@ doconnect()
CHK2(g_ncc->connect(6, 5) == 0, getNdbError(g_ncc));
CHK2(g_ncc->wait_until_ready(30, 10) == 0, getNdbError(g_ncc));
- g_ndb = new Ndb(g_ncc, _dbname);
- CHK2(g_ndb->init() == 0, g_ndb->getNdbError());
- CHK2(g_ndb->waitUntilReady(30) == 0, g_ndb->getNdbError());
-
- g_dic = g_ndb->getDictionary();
+ if (!_sys_any)
+ {
+ g_ndb = new Ndb(g_ncc, _dbname);
+ CHK2(g_ndb->init() == 0, g_ndb->getNdbError());
+ CHK2(g_ndb->waitUntilReady(30) == 0, g_ndb->getNdbError());
+ g_dic = g_ndb->getDictionary();
+ }
g_ndb_sys = new Ndb(g_ncc, NDB_INDEX_STAT_DB);
CHK2(g_ndb_sys->init() == 0, g_ndb_sys->getNdbError());
@@ -112,7 +116,7 @@ dodisconnect()
delete g_ndb_sys;
delete g_ndb;
delete g_ncc;
- g_info << "disconnected" << endl;
+ g_info << "disconnected" << endl;
}
static const char*
@@ -380,69 +384,146 @@ dosys()
{
if (_sys_drop)
{
- g_info << "dropping any sys tables" << endl;
- CHK2(g_is->drop_systables(g_ndb_sys) == 0, g_is->getNdbError());
- CHK2(g_is->check_systables(g_ndb_sys) == -1, "unexpected success");
- CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
- "unexpected error: " << g_is->getNdbError());
+ if (!_sys_skip_events)
+ {
+ g_info << "dropping sys events" << endl;
+ CHK2(g_is->drop_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_sysevents(g_ndb_sys) == -1, "unexpected success");
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysEvents,
+ "unexpected error: " << g_is->getNdbError());
+ }
+
+ if (!_sys_skip_tables)
+ {
+ g_info << "dropping all sys tables" << endl;
+ CHK2(g_is->drop_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_systables(g_ndb_sys) == -1, "unexpected success");
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
+ "unexpected error: " << g_is->getNdbError());
+ }
g_info << "drop done" << endl;
}
if (_sys_create)
{
- g_info << "creating all sys tables" << endl;
- CHK2(g_is->create_systables(g_ndb_sys) == 0, g_is->getNdbError());
- CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
- g_info << "create done" << endl;
- }
-
- if (_sys_create_if_not_exist)
- {
- if (g_is->check_systables(g_ndb_sys) == -1)
+ if (!_sys_skip_tables)
{
- CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
- g_is->getNdbError());
g_info << "creating all sys tables" << endl;
CHK2(g_is->create_systables(g_ndb_sys) == 0, g_is->getNdbError());
CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ }
+
+ if (!_sys_skip_events)
+ {
+ g_info << "creating sys events" << endl;
+ CHK2(g_is->create_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
g_info << "create done" << endl;
}
- else
+ }
+
+ if (_sys_create_if_not_exist)
+ {
+ if (!_sys_skip_tables)
{
- g_info << "using existing sys tables" << endl;
+ if (g_is->check_systables(g_ndb_sys) == -1)
+ {
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
+ g_is->getNdbError());
+ g_info << "creating all sys tables" << endl;
+ CHK2(g_is->create_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "create done" << endl;
+ }
+ else
+ {
+ g_info << "using existing sys tables" << endl;
+ }
+ }
+
+ if (!_sys_skip_events)
+ {
+ if (g_is->check_sysevents(g_ndb_sys) == -1)
+ {
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysEvents,
+ g_is->getNdbError());
+ g_info << "creating sys events" << endl;
+ CHK2(g_is->create_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "create done" << endl;
+ }
+ else
+ {
+ g_info << "using existing sys events" << endl;
+ }
}
}
if (_sys_create_if_not_valid)
{
- if (g_is->check_systables(g_ndb_sys) == -1)
+ if (!_sys_skip_tables)
{
- if (g_is->getNdbError().code != NdbIndexStat::NoSysTables)
+ if (g_is->check_systables(g_ndb_sys) == -1)
{
- CHK2(g_is->getNdbError().code == NdbIndexStat::BadSysTables,
- g_is->getNdbError());
- g_info << "dropping invalid sys tables" << endl;
- CHK2(g_is->drop_systables(g_ndb_sys) == 0, g_is->getNdbError());
- CHK2(g_is->check_systables(g_ndb_sys) == -1, "unexpected success");
- CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
- "unexpected error: " << g_is->getNdbError());
- g_info << "drop done" << endl;
+ if (g_is->getNdbError().code != NdbIndexStat::NoSysTables)
+ {
+ CHK2(g_is->getNdbError().code == NdbIndexStat::BadSysTables,
+ g_is->getNdbError());
+ g_info << "dropping invalid sys tables" << endl;
+ CHK2(g_is->drop_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_systables(g_ndb_sys) == -1, "unexpected success");
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysTables,
+ "unexpected error: " << g_is->getNdbError());
+ g_info << "drop done" << endl;
+ }
+ g_info << "creating all sys tables" << endl;
+ CHK2(g_is->create_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "create done" << endl;
+ }
+ else
+ {
+ g_info << "using existing sys tables" << endl;
}
- g_info << "creating all sys tables" << endl;
- CHK2(g_is->create_systables(g_ndb_sys) == 0, g_is->getNdbError());
- CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
- g_info << "create done" << endl;
}
- else
+ if (!_sys_skip_events)
{
- g_info << "using existing sys tables" << endl;
+ if (g_is->check_sysevents(g_ndb_sys) == -1)
+ {
+ if (g_is->getNdbError().code != NdbIndexStat::NoSysEvents)
+ {
+ CHK2(g_is->getNdbError().code == NdbIndexStat::BadSysEvents,
+ g_is->getNdbError());
+ g_info << "dropping invalid sys events" << endl;
+ CHK2(g_is->drop_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_sysevents(g_ndb_sys) == -1, "unexpected success");
+ CHK2(g_is->getNdbError().code == NdbIndexStat::NoSysEvents,
+ "unexpected error: " << g_is->getNdbError());
+ g_info << "drop done" << endl;
+ }
+ g_info << "creating sys events" << endl;
+ CHK2(g_is->create_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ CHK2(g_is->check_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "create done" << endl;
+ }
+ else
+ {
+ g_info << "using existing sys events" << endl;
+ }
}
}
if (_sys_check)
{
- CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
- g_info << "sys tables ok" << endl;
+ if (!_sys_skip_tables)
+ {
+ CHK2(g_is->check_systables(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "sys tables ok" << endl;
+ }
+ if (!_sys_skip_events)
+ {
+ CHK2(g_is->check_sysevents(g_ndb_sys) == 0, g_is->getNdbError());
+ g_info << "sys events ok" << endl;
+ }
}
}
while (0);
@@ -512,25 +593,33 @@ my_long_options[] =
GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
// sys options
{ "sys-drop", ++oi,
- "Drop any stats tables in NDB kernel (all stats is lost)",
+ "Drop any stats tables and events in NDB kernel (all stats is lost)",
(uchar **)&_sys_drop, (uchar **)&_sys_drop, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "sys-create", ++oi,
- "Create stats tables in NDB kernel (must not exist)",
+ "Create stats tables and events in NDB kernel (must not exist)",
(uchar **)&_sys_create, (uchar **)&_sys_create, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "sys-create-if-not-exist", ++oi,
- "Like --sys-create but do nothing if correct stats tables exist",
+ "Like --sys-create but do nothing if correct objects exist",
(uchar **)&_sys_create_if_not_exist, (uchar **)&_sys_create_if_not_exist, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "sys-create-if-not-valid", ++oi,
- "Like --sys-create-if-not-exist but first drop any invalid tables",
+ "Like --sys-create-if-not-exist but first drop any invalid objects",
(uchar **)&_sys_create_if_not_valid, (uchar **)&_sys_create_if_not_valid, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "sys-check", ++oi,
- "Check that correct stats tables exist in NDB kernel",
+ "Check that correct stats tables and events exist in NDB kernel",
(uchar **)&_sys_check, (uchar **)&_sys_check, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "sys-skip-tables", ++oi,
+ "Do not apply sys options to tables",
+ (uchar **)&_sys_skip_tables, (uchar **)&_sys_skip_tables, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "sys-skip-events", ++oi,
+ "Do not apply sys options to events",
+ (uchar **)&_sys_skip_events, (uchar **)&_sys_skip_events, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
// other
{ "verbose", 'v',
"Verbose messages",
@@ -579,7 +668,9 @@ checkopts(int argc, char** argv)
(_sys_create_if_not_exist != 0) +
(_sys_create_if_not_valid != 0) +
(_sys_drop != 0) +
- ( _sys_check != 0);
+ ( _sys_check != 0) +
+ (_sys_skip_tables != 0) +
+ (_sys_skip_events != 0);
if (!_sys_any)
{
if (_dbname == 0)
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch(ole.john.aske:3537 to 3538) | Ole John Aske | 22 Aug |