diff options
63 files changed, 1812 insertions, 1136 deletions
@@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=21 +MYSQL_VERSION_PATCH=20 MYSQL_VERSION_EXTRA= diff --git a/mysql-test/suite/percona/percona_flush_contiguous_neighbors-master.opt b/mysql-test/suite/percona/percona_flush_contiguous_neighbors-master.opt new file mode 100644 index 00000000000..075af88054f --- /dev/null +++ b/mysql-test/suite/percona/percona_flush_contiguous_neighbors-master.opt @@ -0,0 +1 @@ +--innodb_flush_neighbor_pages=cont diff --git a/mysql-test/suite/percona/percona_flush_contiguous_neighbors.result b/mysql-test/suite/percona/percona_flush_contiguous_neighbors.result new file mode 100644 index 00000000000..8c6b81f0848 --- /dev/null +++ b/mysql-test/suite/percona/percona_flush_contiguous_neighbors.result @@ -0,0 +1,21 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +DROP TABLE t1; diff --git a/mysql-test/suite/percona/percona_flush_contiguous_neighbors.test b/mysql-test/suite/percona/percona_flush_contiguous_neighbors.test new file mode 100644 index 00000000000..4eb967fcd16 --- /dev/null +++ b/mysql-test/suite/percona/percona_flush_contiguous_neighbors.test @@ -0,0 +1,37 @@ +# Test for innodb_flush_neighbor_pages=contiguous. +# The test is very crude: we simply overflow the buffer pool with such a number of +# new/modified pages that some flushing is bound to happen. + +--source include/have_innodb.inc +--source include/big_test.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; + +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; +INSERT INTO t1(foo) SELECT foo FROM t1; + +# TODO: cannot record a stable value here. A check of > 0 should be enough, +# but the variable is not accessible through INFORMATION_SCHEMA currently. +# SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_flushed'; + +DROP TABLE t1; diff --git a/mysql-test/suite/percona/percona_query_response_time-replication.result b/mysql-test/suite/percona/percona_query_response_time-replication.result index c00520110c2..a6e88be6103 100644 --- a/mysql-test/suite/percona/percona_query_response_time-replication.result +++ b/mysql-test/suite/percona/percona_query_response_time-replication.result @@ -100,10 +100,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -146,10 +146,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -251,10 +251,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -297,10 +297,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -375,7 +375,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -391,7 +391,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -469,7 +469,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -488,7 +488,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -556,7 +556,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 34 12.250000 156.000000 33 77.099997 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -565,7 +565,7 @@ time count total 1.000000 34 12.250000 156.000000 33 77.099997 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -632,7 +632,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -640,7 +640,7 @@ time count total 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; @@ -709,7 +709,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -717,7 +717,7 @@ time count total 0.001000 0 0.000000 1.000000 34 12.250000 1000.000000 33 77.099997 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; SET GLOBAL QUERY_RESPONSE_TIME_STATS=default; diff --git a/mysql-test/suite/percona/percona_query_response_time-stored.result b/mysql-test/suite/percona/percona_query_response_time-stored.result index 7385231241e..fb458d6e7ab 100644 --- a/mysql-test/suite/percona/percona_query_response_time-stored.result +++ b/mysql-test/suite/percona/percona_query_response_time-stored.result @@ -80,10 +80,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -126,10 +126,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -204,10 +204,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -250,10 +250,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -301,7 +301,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -317,7 +317,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -368,7 +368,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -387,7 +387,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -428,7 +428,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 55 8.450000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -437,7 +437,7 @@ time count total 1.000000 55 8.450000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -477,7 +477,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -485,7 +485,7 @@ time count total 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -527,7 +527,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -535,7 +535,7 @@ time count total 0.001000 0 0.000000 1.000000 55 8.450000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; diff --git a/mysql-test/suite/percona/percona_query_response_time.result b/mysql-test/suite/percona/percona_query_response_time.result index 4c4d50319c0..1eb90d3cdd4 100644 --- a/mysql-test/suite/percona/percona_query_response_time.result +++ b/mysql-test/suite/percona/percona_query_response_time.result @@ -45,10 +45,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -91,10 +91,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -231,10 +231,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -277,10 +277,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -328,10 +328,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -374,10 +374,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -514,10 +514,10 @@ SHOW QUERY_RESPONSE_TIME; 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -560,10 +560,10 @@ time count total 131072.000000 0 0.000000 262144.000000 0 0.000000 524288.000000 0 0.000000 - 1048576.00000 0 0.000000 - 2097152.00000 0 0.000000 - 4194304.00000 0 0.000000 - 8388608.00000 0 0.000000 +1048576.000000 0 0.000000 +2097152.000000 0 0.000000 +4194304.000000 0 0.000000 +8388608.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -584,7 +584,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -600,7 +600,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -710,7 +710,7 @@ SHOW QUERY_RESPONSE_TIME; 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -726,7 +726,7 @@ time count total 1000.000000 0 0.000000 10000.000000 0 0.000000 100000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -750,7 +750,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -769,7 +769,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -882,7 +882,7 @@ SHOW QUERY_RESPONSE_TIME; 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -901,7 +901,7 @@ time count total 16807.000000 0 0.000000 117649.000000 0 0.000000 823543.000000 0 0.000000 - 5764801.00000 0 0.000000 +5764801.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -915,7 +915,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 0 0.000000 156.000000 0 0.000000 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -924,7 +924,7 @@ time count total 1.000000 0 0.000000 156.000000 0 0.000000 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1027,7 +1027,7 @@ SHOW QUERY_RESPONSE_TIME; 1.000000 11 4.050000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1036,7 +1036,7 @@ time count total 1.000000 11 4.050000 156.000000 11 25.699999 24336.000000 0 0.000000 - 3796416.00000 0 0.000000 +3796416.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -1049,7 +1049,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1057,7 +1057,7 @@ time count total 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1159,7 +1159,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1167,7 +1167,7 @@ time count total 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET SESSION query_exec_time=0.1; @@ -1182,7 +1182,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1190,7 +1190,7 @@ time count total 0.001000 0 0.000000 1.000000 0 0.000000 1000.000000 0 0.000000 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET GLOBAL QUERY_RESPONSE_TIME_STATS=1; SET SESSION query_exec_time=0.31; @@ -1292,7 +1292,7 @@ SHOW QUERY_RESPONSE_TIME; 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME; time count total @@ -1300,7 +1300,7 @@ time count total 0.001000 0 0.000000 1.000000 11 4.050000 1000.000000 11 25.699999 - 1000000.00000 0 0.000000 +1000000.000000 0 0.000000 TOO LONG 0 TOO LONG SET SESSION query_exec_time=default; SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default; diff --git a/mysql-test/suite/percona/percona_server_variables_debug.result b/mysql-test/suite/percona/percona_server_variables_debug.result index ea1c02e7716..ae02a48c8fa 100644 --- a/mysql-test/suite/percona/percona_server_variables_debug.result +++ b/mysql-test/suite/percona/percona_server_variables_debug.result @@ -109,6 +109,7 @@ INNODB_FILE_FORMAT INNODB_FILE_FORMAT_CHECK INNODB_FILE_FORMAT_MAX INNODB_FILE_PER_TABLE +INNODB_FLUSH_CHECKPOINT_DEBUG INNODB_FLUSH_LOG_AT_TRX_COMMIT INNODB_FLUSH_METHOD INNODB_FLUSH_NEIGHBOR_PAGES @@ -228,6 +229,7 @@ MAX_SP_RECURSION_DEPTH MAX_TMP_TABLES MAX_USER_CONNECTIONS MAX_WRITE_LOCK_COUNT +METADATA_LOCKS_CACHE_SIZE MIN_EXAMINED_ROW_LIMIT MULTI_RANGE_COUNT MYISAM_DATA_POINTER_SIZE diff --git a/mysql-test/suite/percona/percona_server_variables_release.result b/mysql-test/suite/percona/percona_server_variables_release.result index e5965cf7e5e..29ac402c144 100644 --- a/mysql-test/suite/percona/percona_server_variables_release.result +++ b/mysql-test/suite/percona/percona_server_variables_release.result @@ -225,6 +225,7 @@ MAX_SP_RECURSION_DEPTH MAX_TMP_TABLES MAX_USER_CONNECTIONS MAX_WRITE_LOCK_COUNT +METADATA_LOCKS_CACHE_SIZE MIN_EXAMINED_ROW_LIMIT MULTI_RANGE_COUNT MYISAM_DATA_POINTER_SIZE diff --git a/mysql-test/suite/percona/percona_sync_flush.result b/mysql-test/suite/percona/percona_sync_flush.result new file mode 100644 index 00000000000..12335257b32 --- /dev/null +++ b/mysql-test/suite/percona/percona_sync_flush.result @@ -0,0 +1,35 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; +SET @@global.innodb_flush_checkpoint_debug=1; +INSERT INTO t1(foo) VALUES ('a'), ('b'); +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +INSERT INTO t1(foo) SELECT foo FROM t1; +UPDATE t1 SET foo='c'; +SET @@global.innodb_flush_checkpoint_debug=0; +UPDATE t1 SET foo='d' WHERE foo='c'; +DROP TABLE t1; diff --git a/mysql-test/suite/percona/percona_sync_flush.test b/mysql-test/suite/percona/percona_sync_flush.test new file mode 100644 index 00000000000..35e8d8f92d2 --- /dev/null +++ b/mysql-test/suite/percona/percona_sync_flush.test @@ -0,0 +1,33 @@ +# Test for InnoDB sync state flushing. + +--source include/have_innodb.inc +--source include/have_debug.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (id INT AUTO_INCREMENT, foo CHAR(255), PRIMARY KEY (id)) ENGINE=InnoDB; + +# It is hard to get to InnoDB sync state flushing in MTR with regular workload. Perhaps +# it is possible with many parallel connections, but that would be brittle anyway. +# So, just disable preflushing and checkpointing and issue simple workload. +SET @@global.innodb_flush_checkpoint_debug=1; + +INSERT INTO t1(foo) VALUES ('a'), ('b'); + +let $rep=0; +while ($rep < 14) +{ + INSERT INTO t1(foo) SELECT foo FROM t1; + UPDATE t1 SET foo='c'; + inc $rep; +} + +# By now checkpoint age should be well past sync flush point. Allow +# preflushing/checkpointing again and do some work in order to do the sync flush. +SET @@global.innodb_flush_checkpoint_debug=0; + +UPDATE t1 SET foo='d' WHERE foo='c'; + +DROP TABLE t1; diff --git a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.inc b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.inc index d55e52d5b64..d9804722147 100644 --- a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.inc +++ b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.inc @@ -91,5 +91,27 @@ let $query=select * from t1 -- comment in the end ; --source percona_query_cache_with_comments_eval.inc +let $query=select */* a comment \*/from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select *# a comment \\ +from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select *-- a comment \\ +from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select "\\\\"" /* not a comment */" from t1; +--source include/percona_query_cache_with_comments_eval.inc + +let $query=select "\\\\"" /*! not a comment */" from t1; +--source include/percona_query_cache_with_comments_eval.inc + +# following two queries related to bug #856404. +# There are different queries, but opt_query_cache_strip_comments thinks that they are equal. let $query=select ' \' ' from t1; --source percona_query_cache_with_comments_eval.inc + +let $query=select ' \' /* comment inside quotes with internal backslash quote */' from t1; +--source percona_query_cache_with_comments_eval.inc diff --git a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.result b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.result index 169fdf80fef..d1a6ded08d7 100644 --- a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.result +++ b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments.result @@ -831,7 +831,7 @@ show status like "Qcache_hits"; Variable_name Value Qcache_hits 50 ----------------------------------------------------- -select ' \' ' from t1 +select */* a comment \*/from t1 ----------------------------------------------------- show status like "Qcache_queries_in_cache"; Variable_name Value @@ -842,6 +842,167 @@ Qcache_inserts 1 show status like "Qcache_hits"; Variable_name Value Qcache_hits 50 +select */* a comment \*/from t1; +a +1 +2 +3 +select */* a comment \*/from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 52 +----------------------------------------------------- +select *# a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 52 +select *# a comment \ +from t1; +a +1 +2 +3 +select *# a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 54 +----------------------------------------------------- +select *-- a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 54 +select *-- a comment \ +from t1; +a +1 +2 +3 +select *-- a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 56 +----------------------------------------------------- +select "\\"" /* not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 56 +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 57 +----------------------------------------------------- +select "\\"" /*! not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 57 +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 58 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 3 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 58 select ' \' ' from t1; ' ' @@ -854,13 +1015,44 @@ select ' \' ' from t1; ' show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 4 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 2 +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 59 +----------------------------------------------------- +select ' \' /* comment inside quotes with internal backslash quote */' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 4 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 4 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 59 +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 5 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 5 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 51 +Qcache_hits 60 DROP TABLE t1; SET GLOBAL query_cache_size=default; set global query_cache_strip_comments=OFF; diff --git a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result index a13a44d9a1c..7e793a942c5 100644 --- a/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result +++ b/mysql-test/suite/percona/query_cache_enhance.patch/percona_query_cache_with_comments_disable.result @@ -830,7 +830,7 @@ show status like "Qcache_hits"; Variable_name Value Qcache_hits 25 ----------------------------------------------------- -select ' \' ' from t1 +select */* a comment \*/from t1 ----------------------------------------------------- show status like "Qcache_queries_in_cache"; Variable_name Value @@ -841,6 +841,167 @@ Qcache_inserts 20 show status like "Qcache_hits"; Variable_name Value Qcache_hits 25 +select */* a comment \*/from t1; +a +1 +2 +3 +select */* a comment \*/from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 21 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 21 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +----------------------------------------------------- +select *# a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 21 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 21 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 26 +select *# a comment \ +from t1; +a +1 +2 +3 +select *# a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 22 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 22 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 27 +----------------------------------------------------- +select *-- a comment \ +from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 22 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 22 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 27 +select *-- a comment \ +from t1; +a +1 +2 +3 +select *-- a comment \ +from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 23 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 23 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +----------------------------------------------------- +select "\\"" /* not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 23 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 23 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 28 +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +select "\\"" /* not a comment */" from t1; +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +\" /* not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 24 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 24 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 29 +----------------------------------------------------- +select "\\"" /*! not a comment */" from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 24 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 24 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 29 +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +select "\\"" /*! not a comment */" from t1; +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +\" /*! not a comment */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 25 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 25 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 +----------------------------------------------------- +select ' \' ' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 25 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 25 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 30 select ' \' ' from t1; ' ' @@ -853,13 +1014,44 @@ select ' \' ' from t1; ' show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 21 +Qcache_queries_in_cache 26 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 21 +Qcache_inserts 26 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 26 +Qcache_hits 31 +----------------------------------------------------- +select ' \' /* comment inside quotes with internal backslash quote */' from t1 +----------------------------------------------------- +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 26 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 26 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 31 +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +select ' \' /* comment inside quotes with internal backslash quote */' from t1; +' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ + ' /* comment inside quotes with internal backslash quote */ +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 27 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 27 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 32 DROP TABLE t1; SET GLOBAL query_cache_size=default; set global query_cache_strip_comments=OFF; diff --git a/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result b/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result index 678ed685a5b..c243b8ad02f 100644 --- a/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result +++ b/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.result @@ -3,21 +3,18 @@ flush query cache; flush query cache; reset query cache; flush status; -DROP TABLE IF EXISTS t; -CREATE TABLE t(id INT, number INT); -INSERT INTO t VALUES (0,1); -INSERT INTO t VALUES (1,2); -INSERT INTO t VALUES (2,3); -SET SESSION debug="+d,status_waiting_on_query_cache_mutex_sleep"; -SET DEBUG_SYNC='status_waiting_on_query_cache_mutex SIGNAL thread_ready'; -SELECT number from t where id > 0; -SHOW PROCESSLIST; -Id User Host db Command Time State Info Rows_sent Rows_examined Rows_read -### root ### test Query ### NULL SHOW PROCESSLIST ### ### ### -### root ### test Query ### Waiting on query cache mutex SELECT number from t where id > 0 ### ### ### -SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; -id info state -### SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id executing -### SELECT number from t where id > 0 Waiting on query cache mutex -DROP TABLE t; +SET DEBUG_SYNC='after_query_cache_mutex SIGNAL mutex_locked WAIT_FOR unlock_mutex'; +SELECT "mutex_locked_query" as action; +SET DEBUG_SYNC='now WAIT_FOR mutex_locked'; +SET DEBUG_SYNC='before_query_cache_mutex SIGNAL try_lock_mutex'; +SELECT "try_lock_mutex_query" as action; +SET DEBUG_SYNC='now WAIT_FOR try_lock_mutex'; +SELECT SQL_NO_CACHE state FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info='SELECT "try_lock_mutex_query" as action'; +state +Waiting on query cache mutex +SET DEBUG_SYNC='now SIGNAL unlock_mutex'; +action +mutex_locked_query +action +try_lock_mutex_query SET GLOBAL query_cache_size=0; diff --git a/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test b/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test index 1e586ca4e7a..b20f088d6ae 100644 --- a/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test +++ b/mysql-test/suite/percona/query_cache_enhance.patch/percona_status_wait_query_cache_mutex.test @@ -3,29 +3,33 @@ --source include/have_debug_sync.inc SET GLOBAL query_cache_size=1355776; --source include/percona_query_cache_with_comments_clear.inc +--let try_lock_mutex_query=SELECT "try_lock_mutex_query" as action --- disable_warnings -DROP TABLE IF EXISTS t; --- enable_warnings -CREATE TABLE t(id INT, number INT); -INSERT INTO t VALUES (0,1); -INSERT INTO t VALUES (1,2); -INSERT INTO t VALUES (2,3); +--connect (mutex_locked_conn, localhost, root,,) +--connect (try_mutex_lock_conn, localhost, root,,) ---connect (conn,localhost,root,,) +--connection mutex_locked_conn +SET DEBUG_SYNC='after_query_cache_mutex SIGNAL mutex_locked WAIT_FOR unlock_mutex'; +send SELECT "mutex_locked_query" as action; ---connection conn -SET SESSION debug="+d,status_waiting_on_query_cache_mutex_sleep"; -SET DEBUG_SYNC='status_waiting_on_query_cache_mutex SIGNAL thread_ready'; -SEND SELECT number from t where id > 0; +--connection default +SET DEBUG_SYNC='now WAIT_FOR mutex_locked'; + +--connection try_mutex_lock_conn +SET DEBUG_SYNC='before_query_cache_mutex SIGNAL try_lock_mutex'; +send_eval $try_lock_mutex_query; --connection default ---replace_column 1 ### 3 ### 6 ### 9 ### 10 ### 11 ### -SHOW PROCESSLIST; +SET DEBUG_SYNC='now WAIT_FOR try_lock_mutex'; +eval SELECT SQL_NO_CACHE state FROM INFORMATION_SCHEMA.PROCESSLIST WHERE info='$try_lock_mutex_query'; +SET DEBUG_SYNC='now SIGNAL unlock_mutex'; ---replace_column 1 ### -SELECT id, info, state FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY id; +--connection mutex_locked_conn +reap; +--connection try_mutex_lock_conn +reap; ---disconnect conn -DROP TABLE t; +--connection default +--disconnect mutex_locked_conn +--disconnect try_mutex_lock_conn SET GLOBAL query_cache_size=0; diff --git a/mysql-test/suite/sys_vars/r/innodb_flush_checkpoint_debug_basic.result b/mysql-test/suite/sys_vars/r/innodb_flush_checkpoint_debug_basic.result new file mode 100644 index 00000000000..e543cc30975 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_flush_checkpoint_debug_basic.result @@ -0,0 +1,15 @@ +SELECT @@global.innodb_flush_checkpoint_debug; +@@global.innodb_flush_checkpoint_debug +0 +SET @@global.innodb_flush_checkpoint_debug=1; +SELECT @@global.innodb_flush_checkpoint_debug; +@@global.innodb_flush_checkpoint_debug +1 +SET @@global.innodb_flush_checkpoint_debug=0; +SELECT @@global.innodb_flush_checkpoint_debug; +@@global.innodb_flush_checkpoint_debug +0 +SET @@session.innodb_flush_checkpoint_debug=1; +ERROR HY000: Variable 'innodb_flush_checkpoint_debug' is a GLOBAL variable and should be set with SET GLOBAL +SELECT @@session.innodb_flush_checkpoint_debug; +ERROR HY000: Variable 'innodb_flush_checkpoint_debug' is a GLOBAL variable diff --git a/mysql-test/suite/sys_vars/t/innodb_flush_checkpoint_debug_basic.test b/mysql-test/suite/sys_vars/t/innodb_flush_checkpoint_debug_basic.test new file mode 100644 index 00000000000..093a765e0e5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_flush_checkpoint_debug_basic.test @@ -0,0 +1,12 @@ +--source include/have_debug.inc +--source include/have_xtradb.inc + +SELECT @@global.innodb_flush_checkpoint_debug; +SET @@global.innodb_flush_checkpoint_debug=1; +SELECT @@global.innodb_flush_checkpoint_debug; +SET @@global.innodb_flush_checkpoint_debug=0; +SELECT @@global.innodb_flush_checkpoint_debug; +--error ER_GLOBAL_VARIABLE +SET @@session.innodb_flush_checkpoint_debug=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT @@session.innodb_flush_checkpoint_debug; diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c index ca98afc04ad..433b062bcec 100644 --- a/storage/xtradb/btr/btr0btr.c +++ b/storage/xtradb/btr/btr0btr.c @@ -1523,7 +1523,7 @@ btr_free_root( } ut_a(block); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP; #ifdef UNIV_BTR_DEBUG @@ -1592,7 +1592,7 @@ btr_page_reorganize_low( #ifndef UNIV_HOTBACKUP if (UNIV_LIKELY(!recovery)) { - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); } block->check_index_page_at_flush = TRUE; @@ -1760,7 +1760,7 @@ btr_page_empty( ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); btr_blob_dbg_remove(page, index, "btr_page_empty"); /* Recreate the page: note that global data on page (possible @@ -3093,7 +3093,7 @@ btr_lift_page_up( mem_heap_free(heap); } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); /* Make the father empty */ btr_page_empty(father_block, father_page_zip, index, page_level, mtr); @@ -3317,7 +3317,7 @@ err_exit: goto err_exit; } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ btr_level_list_remove(space, zip_size, page, index, mtr); @@ -3358,7 +3358,7 @@ err_exit: goto err_exit; } - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); #ifdef UNIV_BTR_DEBUG if (UNIV_LIKELY_NULL(merge_page_zip)) { @@ -3473,7 +3473,7 @@ btr_discard_only_page_on_level( ut_a(btr_page_get_next(page, mtr) == FIL_NULL); ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); btr_page_get_father(index, block, mtr, &cursor); father = btr_cur_get_block(&cursor); @@ -3578,7 +3578,7 @@ btr_discard_page( page = buf_block_get_frame(block); ut_a(page_is_comp(merge_page) == page_is_comp(page)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); if (left_page_no == FIL_NULL && !page_is_leaf(page)) { diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c index 717663a123a..43313474071 100644 --- a/storage/xtradb/btr/btr0cur.c +++ b/storage/xtradb/btr/btr0cur.c @@ -488,8 +488,6 @@ btr_cur_search_to_nth_level( cursor->flag = BTR_CUR_BINARY; cursor->index = index; - cursor->ibuf_cnt = ULINT_UNDEFINED; - #ifndef BTR_CUR_ADAPT guess = NULL; #else @@ -800,21 +798,8 @@ retry_page_get: /* We're doing a search on an ibuf tree and we're one level above the leaf page. */ - ulint is_min_rec; - ut_ad(level == 0); - is_min_rec = rec_get_info_bits(node_ptr, 0) - & REC_INFO_MIN_REC_FLAG; - - if (!is_min_rec) { - cursor->ibuf_cnt - = ibuf_rec_get_counter(node_ptr); - - ut_a(cursor->ibuf_cnt <= 0xFFFF - || cursor->ibuf_cnt == ULINT_UNDEFINED); - } - buf_mode = BUF_GET; rw_latch = RW_NO_LATCH; goto retry_page_get; @@ -2007,7 +1992,7 @@ btr_cur_update_in_place( was_delete_marked = rec_get_deleted_flag( rec, page_is_comp(buf_block_get_frame(block))); - is_hashed = block->is_hashed; + is_hashed = (block->index != NULL); if (is_hashed) { /* TO DO: Can we skip this if none of the fields @@ -3683,16 +3668,11 @@ btr_record_not_null_field_in_rec( } for (i = 0; i < n_unique; i++) { - ulint rec_len; - - rec_get_nth_field_offs(offsets, i, &rec_len); - - if (rec_len != UNIV_SQL_NULL) { - n_not_null[i]++; - } else { - /* Break if we hit the first NULL value */ + if (rec_offs_nth_sql_null(offsets, i)) { break; } + + n_not_null[i]++; } } @@ -3840,8 +3820,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - n_cols, offsets_next_rec, - n_not_null); + n_cols, offsets_next_rec, n_not_null); } total_external_size diff --git a/storage/xtradb/btr/btr0pcur.c b/storage/xtradb/btr/btr0pcur.c index 081ef9c9457..e6a9ddcf43e 100644 --- a/storage/xtradb/btr/btr0pcur.c +++ b/storage/xtradb/btr/btr0pcur.c @@ -253,6 +253,8 @@ btr_pcur_restore_position_func( cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE, index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr); + cursor->latch_mode = latch_mode; + cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->block_when_stored = btr_pcur_get_block(cursor); return(FALSE); diff --git a/storage/xtradb/btr/btr0sea.c b/storage/xtradb/btr/btr0sea.c index f27afe216ec..bddbcc79dd6 100644 --- a/storage/xtradb/btr/btr0sea.c +++ b/storage/xtradb/btr/btr0sea.c @@ -44,15 +44,11 @@ Created 2/17/1996 Heikki Tuuri #include "ha0ha.h" #include "srv0srv.h" /** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ +Protected by btr_search_latch. */ UNIV_INTERN char btr_search_enabled = TRUE; -UNIV_INTERN ibool btr_search_fully_disabled = FALSE; UNIV_INTERN ulint btr_search_index_num = 1; -/** Mutex protecting btr_search_enabled */ -static mutex_t btr_search_enabled_mutex; - #ifdef UNIV_PFS_MUTEX /* Key to register btr_search_enabled_mutex with performance schema */ UNIV_INTERN mysql_pfs_key_t btr_search_enabled_mutex_key; @@ -186,8 +182,6 @@ btr_search_sys_create( //rw_lock_create(btr_search_latch_key, &btr_search_latch, // SYNC_SEARCH_SYS); - mutex_create(btr_search_enabled_mutex_key, - &btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); @@ -238,27 +232,40 @@ void btr_search_disable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); + dict_table_t* table; + ulint i; + + mutex_enter(&dict_sys->mutex); btr_search_x_lock_all(); - /* Disable access to hash index, also tell ha_insert_for_fold() - stop adding new nodes to hash index, but still allow updating - existing nodes */ btr_search_enabled = FALSE; - /* Clear all block->is_hashed flags and remove all entries - from btr_search_sys->hash_index. */ - buf_pool_drop_hash_index(); + /* Clear the index->search_info->ref_count of every index in + the data dictionary cache. */ + for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table; + table = UT_LIST_GET_NEXT(table_LRU, table)) { + + dict_index_t* index; + + for (index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { - /* hash index has been cleaned up, disallow any operation to - the hash index */ - btr_search_fully_disabled = TRUE; + index->search_info->ref_count = 0; + } + } + + mutex_exit(&dict_sys->mutex); - /* btr_search_enabled_mutex should guarantee this. */ - ut_ad(!btr_search_enabled); + /* Set all block->index = NULL. */ + buf_pool_clear_hash_index(); + + /* Clear the adaptive hash index. */ + for (i = 0; i < btr_search_index_num; i++) { + hash_table_clear(btr_search_sys->hash_index[i]); + mem_heap_empty(btr_search_sys->hash_index[i]->heap); + } btr_search_x_unlock_all(); - mutex_exit(&btr_search_enabled_mutex); } /********************************************************************//** @@ -268,14 +275,11 @@ void btr_search_enable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); btr_search_x_lock_all(); btr_search_enabled = TRUE; - btr_search_fully_disabled = FALSE; btr_search_x_unlock_all(); - mutex_exit(&btr_search_enabled_mutex); } /*****************************************************************//** @@ -499,7 +503,7 @@ btr_search_update_block_hash_info( && (block->n_bytes == info->n_bytes) && (block->left_side == info->left_side)) { - if ((block->is_hashed) + if ((block->index) && (block->curr_n_fields == info->n_fields) && (block->curr_n_bytes == info->n_bytes) && (block->curr_left_side == info->left_side)) { @@ -528,7 +532,7 @@ btr_search_update_block_hash_info( / BTR_SEARCH_PAGE_BUILD_LIMIT) && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) { - if ((!block->is_hashed) + if ((!block->index) || (block->n_hash_helps > 2 * page_get_n_recs(block->frame)) || (block->n_fields != block->curr_n_fields) @@ -560,9 +564,9 @@ btr_search_update_hash_ref( buf_block_t* block, /*!< in: buffer block where cursor positioned */ btr_cur_t* cursor) /*!< in: cursor */ { + dict_index_t* index; ulint fold; - rec_t* rec; - index_id_t index_id; + const rec_t* rec; ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); #ifdef UNIV_SYNC_DEBUG @@ -573,13 +577,15 @@ btr_search_update_hash_ref( ut_ad(page_align(btr_cur_get_rec(cursor)) == buf_block_get_frame(block)); - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); if ((info->n_hash_potential > 0) && (block->curr_n_fields == info->n_fields) @@ -596,12 +602,11 @@ btr_search_update_hash_ref( return; } - index_id = cursor->index->id; fold = rec_fold(rec, - rec_get_offsets(rec, cursor->index, offsets_, + rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), block->curr_n_fields, - block->curr_n_bytes, index_id); + block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -870,7 +875,7 @@ btr_search_guess_on_hash( { buf_pool_t* buf_pool; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; index_id_t index_id; #ifdef notdefined @@ -956,7 +961,7 @@ btr_search_guess_on_hash( ut_ad(page_rec_is_user_rec(rec)); - btr_cur_position(index, rec, block, cursor); + btr_cur_position(index, (rec_t*) rec, block, cursor); /* Check the validity of the guess within the page */ @@ -1058,11 +1063,10 @@ UNIV_INTERN void btr_search_drop_page_hash_index( /*============================*/ - buf_block_t* block, /*!< in: block containing index page, + buf_block_t* block) /*!< in: block containing index page, s- or x-latched, or an index page for which we know that block->buf_fix_count == 0 */ - dict_index_t* index_in) { hash_table_t* table; ulint n_fields; @@ -1080,24 +1084,14 @@ btr_search_drop_page_hash_index( const dict_index_t* index; ulint* offsets; -#ifdef UNIV_SYNC_DEBUG - if (index_in) { - ut_ad(!rw_lock_own(btr_search_get_latch(index_in->id), RW_LOCK_SHARED)); - ut_ad(!rw_lock_own(btr_search_get_latch(index_in->id), RW_LOCK_EX)); - } -#endif /* UNIV_SYNC_DEBUG */ - retry: - if (index_in) { - index = index_in; - rw_lock_s_lock(btr_search_get_latch(index->id)); - } else if (btr_search_index_num > 1) { + if (btr_search_index_num > 1) { rw_lock_t* btr_search_latch; /* FIXME: This may be optimistic implementation still. */ btr_search_latch = (rw_lock_t*)(block->btr_search_latch); if (UNIV_LIKELY(!btr_search_latch)) { - if (block->is_hashed) { + if (block->index) { goto retry; } return; @@ -1107,7 +1101,7 @@ retry: rw_lock_s_unlock(btr_search_latch); goto retry; } - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!block->index)) { rw_lock_s_unlock(btr_search_latch); goto retry; } @@ -1116,18 +1110,16 @@ retry: } else { /* btr_search_index_num == 1 */ /* btr_search_latch is only one and able to obtain - before evaluating block->is_hashed. */ + before evaluating block->index. */ rw_lock_s_lock(btr_search_latch_part[0]); - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!block->index)) { rw_lock_s_unlock(btr_search_latch_part[0]); return; } index = block->index; } - page = block->frame; - - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!index)) { rw_lock_s_unlock(btr_search_get_latch(index->id)); @@ -1155,6 +1147,7 @@ retry: ut_a(n_fields + n_bytes > 0); + page = block->frame; n_recs = page_get_n_recs(page); /* Calculate and cache fold values into an array for fast deletion @@ -1203,7 +1196,7 @@ next_rec: rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { /* Someone else has meanwhile dropped the hash index */ goto cleanup; @@ -1231,10 +1224,9 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; block->btr_search_latch = NULL; - + cleanup: #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG if (UNIV_UNLIKELY(block->n_pointers)) { @@ -1309,7 +1301,7 @@ retry: if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE || block->index != index - || !block->is_hashed) { + || !block->index) { continue; } @@ -1375,7 +1367,7 @@ next_rec: rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { goto cleanup; } @@ -1400,7 +1392,6 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; block->btr_search_latch = NULL; @@ -1434,8 +1425,8 @@ cleanup: } /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -1448,32 +1439,23 @@ btr_search_drop_page_hash_when_freed( buf_block_t* block; mtr_t mtr; - if (!buf_page_peek_if_search_hashed(space, page_no)) { - - return; - } - mtr_start(&mtr); - /* We assume that if the caller has a latch on the page, then the - caller has already dropped the hash index for the page, and we never - get here. Therefore we can acquire the s-latch to the page without - having to fear a deadlock. */ + /* If the caller has a latch on the page, then the caller must + have a x-latch on the page and it must have already dropped + the hash index for the page. Because of the x-latch that we + are possibly holding, we cannot s-latch the page, but must + (recursively) x-latch it, even though we are only reading. */ - block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL, + block = buf_page_get_gen(space, zip_size, page_no, RW_X_LATCH, NULL, BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__, &mtr); - /* Because the buffer pool mutex was released by - buf_page_peek_if_search_hashed(), it is possible that the - block was removed from the buffer pool by another thread - before buf_page_get_gen() got a chance to acquire the buffer - pool mutex again. Thus, we must check for a NULL return. */ - if (UNIV_LIKELY(block != NULL)) { + if (block && block->index) { buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); } mtr_commit(&mtr); @@ -1501,7 +1483,6 @@ btr_search_build_page_hash_index( rec_t* next_rec; ulint fold; ulint next_fold; - index_id_t index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1526,13 +1507,13 @@ btr_search_build_page_hash_index( rw_lock_s_lock(btr_search_get_latch(index->id)); - if (block->is_hashed && ((block->curr_n_fields != n_fields) + if (block->index && ((block->curr_n_fields != n_fields) || (block->curr_n_bytes != n_bytes) || (block->curr_left_side != left_side))) { rw_lock_s_unlock(btr_search_get_latch(index->id)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); } else { rw_lock_s_unlock(btr_search_get_latch(index->id)); } @@ -1565,7 +1546,7 @@ btr_search_build_page_hash_index( n_cached = 0; - index_id = btr_page_get_index_id(page); + ut_a(index->id == btr_page_get_index_id(page)); rec = page_rec_get_next(page_get_infimum_rec(page)); @@ -1580,7 +1561,7 @@ btr_search_build_page_hash_index( } } - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); if (left_side) { @@ -1607,7 +1588,7 @@ btr_search_build_page_hash_index( offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); if (fold != next_fold) { /* Insert an entry into the hash index */ @@ -1632,13 +1613,13 @@ btr_search_build_page_hash_index( rw_lock_x_lock(btr_search_get_latch(index->id)); - if (UNIV_UNLIKELY(btr_search_fully_disabled)) { + if (UNIV_UNLIKELY(!btr_search_enabled)) { goto exit_func; } - if (block->is_hashed && ((block->curr_n_fields != n_fields) - || (block->curr_n_bytes != n_bytes) - || (block->curr_left_side != left_side))) { + if (block->index && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_left_side != left_side))) { goto exit_func; } @@ -1647,11 +1628,10 @@ btr_search_build_page_hash_index( rebuild hash index for a page that is already hashed, we have to take care not to increment the counter in that case. */ - if (!block->is_hashed) { + if (!block->index) { index->search_info->ref_count++; } - block->is_hashed = TRUE; block->n_hash_helps = 0; block->curr_n_fields = n_fields; @@ -1700,23 +1680,24 @@ btr_search_move_or_delete_hash_entries( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - ut_a(!new_block->is_hashed || new_block->index == index); - ut_a(!block->is_hashed || block->index == index); - ut_a(!(new_block->is_hashed || block->is_hashed) - || !dict_index_is_ibuf(index)); rw_lock_s_lock(btr_search_get_latch(index->id)); - if (new_block->is_hashed) { + ut_a(!new_block->index || new_block->index == index); + ut_a(!block->index || block->index == index); + ut_a(!(new_block->index || block->index) + || !dict_index_is_ibuf(index)); + + if (new_block->index) { rw_lock_s_unlock(btr_search_get_latch(index->id)); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); return; } - if (block->is_hashed) { + if (block->index) { n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1753,42 +1734,48 @@ btr_search_update_hash_on_delete( { hash_table_t* table; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; - index_id_t index_id; + dict_index_t* index; ulint offsets_[REC_OFFS_NORMAL_SIZE]; mem_heap_t* heap = NULL; rec_offs_init(offsets_); - rec = btr_cur_get_rec(cursor); - block = btr_cur_get_block(cursor); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); + ut_a(index == cursor->index); ut_a(block->curr_n_fields + block->curr_n_bytes > 0); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(!dict_index_is_ibuf(index)); table = btr_search_get_hash_index(cursor->index->id); - index_id = cursor->index->id; - fold = rec_fold(rec, rec_get_offsets(rec, cursor->index, offsets_, + rec = btr_cur_get_rec(cursor); + + fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - block->curr_n_fields, block->curr_n_bytes, index_id); + block->curr_n_fields, block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + rw_lock_x_lock(btr_search_get_latch(cursor->index->id)); - ha_search_and_delete_if_found(table, fold, rec); + if (block->index) { + ut_a(block->index == index); + + ha_search_and_delete_if_found(table, fold, rec); + } rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); } @@ -1806,6 +1793,7 @@ btr_search_update_hash_node_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec = btr_cur_get_rec(cursor); @@ -1816,16 +1804,25 @@ btr_search_update_hash_node_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(cursor->index == index); + ut_a(!dict_index_is_ibuf(index)); rw_lock_x_lock(btr_search_get_latch(cursor->index->id)); + if (!block->index) { + + goto func_exit; + } + + ut_a(block->index == index); + if ((cursor->flag == BTR_CUR_HASH) && (cursor->n_fields == block->curr_n_fields) && (cursor->n_bytes == block->curr_n_bytes) @@ -1836,6 +1833,7 @@ btr_search_update_hash_node_on_insert( ha_search_and_update_if_found(table, cursor->fold, rec, block, page_rec_get_next(rec)); +func_exit: rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); } else { rw_lock_x_unlock(btr_search_get_latch(cursor->index->id)); @@ -1857,10 +1855,10 @@ btr_search_update_hash_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec_t* ins_rec; rec_t* next_rec; - index_id_t index_id; ulint fold; ulint ins_fold; ulint next_fold = 0; /* remove warning (??? bug ???) */ @@ -1885,15 +1883,15 @@ btr_search_update_hash_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); - - index_id = cursor->index->id; + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1902,28 +1900,32 @@ btr_search_update_hash_on_insert( ins_rec = page_rec_get_next(rec); next_rec = page_rec_get_next(ins_rec); - offsets = rec_get_offsets(ins_rec, cursor->index, offsets, + offsets = rec_get_offsets(ins_rec, index, offsets, ULINT_UNDEFINED, &heap); - ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index_id); + ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id); if (!page_rec_is_supremum(next_rec)) { - offsets = rec_get_offsets(next_rec, cursor->index, offsets, + offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); } if (!page_rec_is_infimum(rec)) { - offsets = rec_get_offsets(rec, cursor->index, offsets, + offsets = rec_get_offsets(rec, index, offsets, n_fields + (n_bytes > 0), &heap); - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); } else { if (left_side) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + if (!btr_search_enabled) { + goto function_exit; + } + ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1934,9 +1936,13 @@ btr_search_update_hash_on_insert( if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1952,9 +1958,13 @@ check_next_rec: if (!left_side) { if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1967,9 +1977,13 @@ check_next_rec: if (!locked) { - rw_lock_x_lock(btr_search_get_latch(index_id)); + rw_lock_x_lock(btr_search_get_latch(index->id)); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1977,7 +1991,7 @@ check_next_rec: ha_insert_for_fold(table, ins_fold, block, ins_rec); /* fputs("Hash insert for ", stderr); - dict_index_name_print(stderr, cursor->index); + dict_index_name_print(stderr, index); fprintf(stderr, " fold %lu\n", ins_fold); */ } else { @@ -1990,7 +2004,7 @@ function_exit: mem_heap_free(heap); } if (locked) { - rw_lock_x_unlock(btr_search_get_latch(index_id)); + rw_lock_x_unlock(btr_search_get_latch(index->id)); } } @@ -2082,21 +2096,20 @@ btr_search_validate(void) ut_a(!dict_index_is_ibuf(block->index)); - offsets = rec_get_offsets((const rec_t*) node->data, + page_index_id = btr_page_get_index_id(block->frame); + + offsets = rec_get_offsets(node->data, block->index, offsets, block->curr_n_fields + (block->curr_n_bytes > 0), &heap); - page_index_id = btr_page_get_index_id(block->frame); - - if (UNIV_UNLIKELY - (!block->is_hashed || node->fold - != rec_fold((rec_t*)(node->data), - offsets, - block->curr_n_fields, - block->curr_n_bytes, - page_index_id))) { + if (!block->index || node->fold + != rec_fold(node->data, + offsets, + block->curr_n_fields, + block->curr_n_bytes, + page_index_id)) { const page_t* page = block->frame; ok = FALSE; @@ -2112,20 +2125,19 @@ btr_search_validate(void) node->data, (ullint) page_index_id, (ulong) node->fold, - (ulong) rec_fold((rec_t*)(node->data), + (ulong) rec_fold(node->data, offsets, block->curr_n_fields, block->curr_n_bytes, page_index_id)); fputs("InnoDB: Record ", stderr); - rec_print_new(stderr, (rec_t*)node->data, - offsets); + rec_print_new(stderr, node->data, offsets); fprintf(stderr, "\nInnoDB: on that page." - " Page mem address %p, is hashed %lu," + " Page mem address %p, is hashed %p," " n fields %lu, n bytes %lu\n" "InnoDB: side %lu\n", - (void*) page, (ulong) block->is_hashed, + (void*) page, (void*) block->index, (ulong) block->curr_n_fields, (ulong) block->curr_n_bytes, (ulong) block->curr_left_side); diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c index 4bc2c26cde2..11b079dd0ef 100644 --- a/storage/xtradb/buf/buf0buf.c +++ b/storage/xtradb/buf/buf0buf.c @@ -917,6 +917,16 @@ pfs_register_buffer_block( rwlock->pfs_psi = (PSI_server) ? PSI_server->init_rwlock(buf_block_lock_key, rwlock) : NULL; + +# ifdef UNIV_SYNC_DEBUG + rwlock = &block->debug_latch; + ut_a(!rwlock->pfs_psi); + rwlock->pfs_psi = (PSI_server) + ? PSI_server->init_rwlock(buf_block_debug_latch_key, + rwlock) + : NULL; +# endif /* UNIV_SYNC_DEBUG */ + # endif /* UNIV_PFS_RWLOCK */ block++; } @@ -952,8 +962,6 @@ buf_block_init( block->index = NULL; block->btr_search_latch = NULL; - block->is_hashed = FALSE; - #ifdef UNIV_DEBUG block->page.in_page_hash = FALSE; block->page.in_zip_hash = FALSE; @@ -980,17 +988,24 @@ buf_block_init( mutex_create(PFS_NOT_INSTRUMENTED, &block->mutex, SYNC_BUF_BLOCK); rw_lock_create(PFS_NOT_INSTRUMENTED, &block->lock, SYNC_LEVEL_VARYING); + +# ifdef UNIV_SYNC_DEBUG + rw_lock_create(PFS_NOT_INSTRUMENTED, + &block->debug_latch, SYNC_NO_ORDER_CHECK); +# endif /* UNIV_SYNC_DEBUG */ + #else /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ mutex_create(buffer_block_mutex_key, &block->mutex, SYNC_BUF_BLOCK); rw_lock_create(buf_block_lock_key, &block->lock, SYNC_LEVEL_VARYING); + +# ifdef UNIV_SYNC_DEBUG + rw_lock_create(buf_block_debug_latch_key, + &block->debug_latch, SYNC_NO_ORDER_CHECK); +# endif /* UNIV_SYNC_DEBUG */ #endif /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ ut_ad(rw_lock_validate(&(block->lock))); -#ifdef UNIV_SYNC_DEBUG - rw_lock_create(buf_block_debug_latch_key, - &block->debug_latch, SYNC_NO_ORDER_CHECK); -#endif /* UNIV_SYNC_DEBUG */ } /********************************************************************//** @@ -1317,6 +1332,26 @@ buf_pool_free_instance( { buf_chunk_t* chunk; buf_chunk_t* chunks; + buf_page_t* bpage; + + bpage = UT_LIST_GET_LAST(buf_pool->LRU); + while (bpage != NULL) { + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + enum buf_page_state state = buf_page_get_state(bpage); + + ut_ad(buf_page_in_file(bpage)); + ut_ad(bpage->in_LRU_list); + + if (state != BUF_BLOCK_FILE_PAGE) { + /* We must not have any dirty block except + when doing a fast shutdown. */ + ut_ad(state == BUF_BLOCK_ZIP_PAGE + || srv_fast_shutdown == 2); + buf_page_free_descriptor(bpage); + } + + bpage = prev_bpage; + } chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; @@ -1392,87 +1427,13 @@ buf_pool_free( } /********************************************************************//** -Drops adaptive hash index for a buffer pool instance. */ -static -void -buf_pool_drop_hash_index_instance( -/*==============================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - ibool* released_search_latch) /*!< out: flag for signalling - whether the search latch was - released */ -{ - buf_chunk_t* chunks = buf_pool->chunks; - buf_chunk_t* chunk = chunks + buf_pool->n_chunks; - - while (--chunk >= chunks) { - ulint i; - buf_block_t* block = chunk->blocks; - - for (i = chunk->size; i--; block++) { - /* block->is_hashed cannot be modified - when we have an x-latch on btr_search_latch; - see the comment in buf0buf.h */ - - if (!block->is_hashed) { - continue; - } - - /* To follow the latching order, we - have to release btr_search_latch - before acquiring block->latch. */ - btr_search_x_unlock_all(); - /* When we release the search latch, - we must rescan all blocks, because - some may become hashed again. */ - *released_search_latch = TRUE; - - rw_lock_x_lock(&block->lock); - - /* This should be guaranteed by the - callers, which will be holding - btr_search_enabled_mutex. */ - ut_ad(!btr_search_enabled); - - /* Because we did not buffer-fix the - block by calling buf_block_get_gen(), - it is possible that the block has been - allocated for some other use after - btr_search_latch was released above. - We do not care which file page the - block is mapped to. All we want to do - is to drop any hash entries referring - to the page. */ - - /* It is possible that - block->page.state != BUF_FILE_PAGE. - Even that does not matter, because - btr_search_drop_page_hash_index() will - check block->is_hashed before doing - anything. block->is_hashed can only - be set on uncompressed file pages. */ - - btr_search_drop_page_hash_index(block, NULL); - - rw_lock_x_unlock(&block->lock); - - btr_search_x_lock_all(); - - ut_ad(!btr_search_enabled); - } - } -} - -/********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void) -/*==========================*/ +buf_pool_clear_hash_index(void) +/*===========================*/ { - ibool released_search_latch; + ulint p; #ifdef UNIV_SYNC_DEBUG ulint j; @@ -1483,21 +1444,34 @@ buf_pool_drop_hash_index(void) #endif /* UNIV_SYNC_DEBUG */ ut_ad(!btr_search_enabled); - do { - ulint i; + for (p = 0; p < srv_buf_pool_instances; p++) { + buf_pool_t* buf_pool = buf_pool_from_array(p); + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; - released_search_latch = FALSE; + while (--chunk >= chunks) { + buf_block_t* block = chunk->blocks; + ulint i = chunk->size; - for (i = 0; i < srv_buf_pool_instances; i++) { - buf_pool_t* buf_pool; + for (; i--; block++) { + dict_index_t* index = block->index; - buf_pool = buf_pool_from_array(i); + /* We can set block->index = NULL + when we have an x-latch on btr_search_latch; + see the comment in buf0buf.h */ - buf_pool_drop_hash_index_instance( - buf_pool, &released_search_latch); - } + if (!index) { + /* Not hashed */ + continue; + } - } while (released_search_latch); + block->index = NULL; +# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG + block->n_pointers = 0; +# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ + } + } + } } /********************************************************************//** @@ -1638,12 +1612,12 @@ buf_pool_watch_set( rw_lock_x_lock(&buf_pool->page_hash_latch); bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (bpage) { + + if (UNIV_LIKELY_NULL(bpage)) { + block_mutex = buf_page_get_mutex_enter(bpage); ut_a(block_mutex); - } - if (UNIV_LIKELY_NULL(bpage)) { if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { /* The page was loaded meanwhile. */ rw_lock_x_unlock(&buf_pool->page_hash_latch); @@ -1895,40 +1869,6 @@ buf_reset_check_index_page_at_flush( rw_lock_s_unlock(&buf_pool->page_hash_latch); } -/********************************************************************//** -Returns the current state of is_hashed of a page. FALSE if the page is -not in the pool. NOTE that this operation does not fix the page in the -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: page number */ -{ - buf_block_t* block; - ibool is_hashed; - buf_pool_t* buf_pool = buf_pool_get(space, offset); - - //buf_pool_mutex_enter(buf_pool); - rw_lock_s_lock(&buf_pool->page_hash_latch); - - block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); - - if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - is_hashed = FALSE; - } else { - ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); - is_hashed = block->is_hashed; - } - - //buf_pool_mutex_exit(buf_pool); - rw_lock_s_unlock(&buf_pool->page_hash_latch); - - return(is_hashed); -} - #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. @@ -2218,7 +2158,6 @@ buf_block_init_low( block->btr_search_latch = NULL; block->n_hash_helps = 0; - block->is_hashed = FALSE; block->n_fields = 1; block->n_bytes = 0; block->left_side = TRUE; @@ -4473,6 +4412,9 @@ buf_pool_validate_instance( ut_a(rw_lock_is_locked(&block->lock, RW_LOCK_EX)); break; + + case BUF_IO_PIN: + break; } n_lru++; @@ -4502,6 +4444,7 @@ buf_pool_validate_instance( ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE); switch (buf_page_get_io_fix(b)) { case BUF_IO_NONE: + case BUF_IO_PIN: /* All clean blocks should be I/O-unfixed. */ break; case BUF_IO_READ: @@ -4541,6 +4484,7 @@ buf_pool_validate_instance( switch (buf_page_get_io_fix(b)) { case BUF_IO_NONE: case BUF_IO_READ: + case BUF_IO_PIN: break; case BUF_IO_WRITE: switch (buf_page_get_flush_type(b)) { diff --git a/storage/xtradb/buf/buf0flu.c b/storage/xtradb/buf/buf0flu.c index 73a9ff96289..d776a274d14 100644 --- a/storage/xtradb/buf/buf0flu.c +++ b/storage/xtradb/buf/buf0flu.c @@ -1399,6 +1399,7 @@ buf_flush_try_neighbors( ulint high; ulint count = 0; buf_pool_t* buf_pool = buf_pool_get(space, offset); + ibool is_forward_scan; ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); @@ -1429,7 +1430,32 @@ buf_flush_try_neighbors( high = fil_space_get_size(space); } - for (i = low; i < high; i++) { + if (srv_flush_neighbor_pages == 2) { + + /* In the case of contiguous flush where the requested page + does not fall at the start of flush area, first scan backward + from the page and later forward from it. */ + is_forward_scan = (offset == low); + } + else { + is_forward_scan = TRUE; + } + +scan: + if (srv_flush_neighbor_pages == 2) { + if (is_forward_scan) { + i = offset; + } + else { + i = offset - 1; + } + } + else { + i = low; + } + + for (; is_forward_scan ? (i < high) : (i >= low); + is_forward_scan ? i++ : i--) { buf_page_t* bpage; @@ -1460,6 +1486,12 @@ buf_flush_try_neighbors( //buf_pool_mutex_exit(buf_pool); rw_lock_s_unlock(&buf_pool->page_hash_latch); + if (srv_flush_neighbor_pages == 2) { + + /* This is contiguous neighbor page flush and + the pages here are not contiguous. */ + break; + } continue; } @@ -1495,6 +1527,22 @@ buf_flush_try_neighbors( } //buf_pool_mutex_exit(buf_pool); rw_lock_s_unlock(&buf_pool->page_hash_latch); + + if (srv_flush_neighbor_pages == 2) { + + /* We are trying to do the contiguous neighbor page + flush, but the last page we checked was unflushable, + making a "hole" in the flush, so stop this attempt. */ + break; + } + } + + if (!is_forward_scan) { + + /* Backward scan done, now do the forward scan */ + ut_a (srv_flush_neighbor_pages == 2); + is_forward_scan = TRUE; + goto scan; } return(count); @@ -1988,6 +2036,22 @@ buf_flush_list( buf_pool = buf_pool_from_array(i); + if (lsn_limit != IB_ULONGLONG_MAX) { + buf_page_t* bpage; + + buf_flush_list_mutex_enter(buf_pool); + bpage = UT_LIST_GET_LAST(buf_pool->flush_list); + if (!bpage + || bpage->oldest_modification >= lsn_limit) { + + buf_flush_list_mutex_exit(buf_pool); + continue; + } else { + + buf_flush_list_mutex_exit(buf_pool); + } + } + if (!buf_flush_start(buf_pool, BUF_FLUSH_LIST)) { /* We have two choices here. If lsn_limit was specified then skipping an instance of buffer diff --git a/storage/xtradb/buf/buf0lru.c b/storage/xtradb/buf/buf0lru.c index a5a811f7afe..ecad1cf1e64 100644 --- a/storage/xtradb/buf/buf0lru.c +++ b/storage/xtradb/buf/buf0lru.c @@ -68,8 +68,12 @@ allowed to point to either end of the LRU list. */ /** When dropping the search hash index entries before deleting an ibd file, we build a local array of pages belonging to that tablespace -in the buffer pool. Following is the size of that array. */ -#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024 +in the buffer pool. Following is the size of that array. +We also release buf_pool->mutex after scanning this many pages of the +flush_list when dropping a table. This is to ensure that other threads +are not blocked for extended period of time when using very large +buffer pools. */ +#define BUF_LRU_DROP_SEARCH_SIZE 1024 /** If we switch on the InnoDB monitor because there are too few available frames in the buffer pool, we set this to TRUE */ @@ -222,7 +226,7 @@ buf_LRU_drop_page_hash_batch( ulint i; ut_ad(arr != NULL); - ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE); + ut_ad(count <= BUF_LRU_DROP_SEARCH_SIZE); for (i = 0; i < count; ++i) { btr_search_drop_page_hash_when_freed(space_id, zip_size, @@ -256,7 +260,7 @@ buf_LRU_drop_page_hash_for_tablespace( } page_arr = ut_malloc( - sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE); + sizeof(ulint) * BUF_LRU_DROP_SEARCH_SIZE); //buf_pool_mutex_enter(buf_pool); mutex_enter(&buf_pool->LRU_list_mutex); @@ -293,7 +297,7 @@ next_page: //mutex_enter(&((buf_block_t*) bpage)->mutex); is_fixed = bpage->buf_fix_count > 0 - || !((buf_block_t*) bpage)->is_hashed; + || !((buf_block_t*) bpage)->index; //mutex_exit(&((buf_block_t*) bpage)->mutex); if (is_fixed) { @@ -304,12 +308,14 @@ next_page: /* Store the page number so that we can drop the hash index in a batch later. */ page_arr[num_entries] = bpage->offset; + mutex_exit(block_mutex); - ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE); + ut_a(num_entries < BUF_LRU_DROP_SEARCH_SIZE); + ++num_entries; - if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { + if (num_entries < BUF_LRU_DROP_SEARCH_SIZE) { goto next_page; } @@ -366,39 +372,42 @@ next_page: } /******************************************************************//** -Invalidates all pages belonging to a given tablespace inside a specific +Remove all dirty pages belonging to a given tablespace inside a specific buffer pool instance when we are deleting the data file(s) of that -tablespace. */ +tablespace. The pages still remain a part of LRU and are evicted from +the list as they age towards the tail of the LRU. */ static void -buf_LRU_invalidate_tablespace_buf_pool_instance( -/*============================================*/ +buf_LRU_remove_dirty_pages_for_tablespace( +/*======================================*/ buf_pool_t* buf_pool, /*!< buffer pool instance */ ulint id) /*!< in: space id */ { buf_page_t* bpage; ibool all_freed; + ulint i; scan_again: //buf_pool_mutex_enter(buf_pool); mutex_enter(&buf_pool->LRU_list_mutex); rw_lock_x_lock(&buf_pool->page_hash_latch); + buf_flush_list_mutex_enter(buf_pool); all_freed = TRUE; - bpage = UT_LIST_GET_LAST(buf_pool->LRU); + for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0; + bpage != NULL; ++i) { - while (bpage != NULL) { buf_page_t* prev_bpage; mutex_t* block_mutex = NULL; ut_a(buf_page_in_file(bpage)); - prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + prev_bpage = UT_LIST_GET_PREV(flush_list, bpage); /* bpage->space and bpage->io_fix are protected by - buf_pool_mutex and block_mutex. It is safe to check - them while holding buf_pool_mutex only. */ + buf_pool->mutex and block_mutex. It is safe to check + them while holding buf_pool->mutex only. */ if (buf_page_get_space(bpage) != id) { /* Skip this block, as it does not belong to @@ -411,90 +420,97 @@ scan_again: all_freed = FALSE; goto next_page; - } else { - block_mutex = buf_page_get_mutex_enter(bpage); - - if (!block_mutex) { - /* It may be impossible case... - Something wrong, so will be scan_again */ + } - all_freed = FALSE; - goto next_page; - } + /* We have to release the flush_list_mutex to obey the + latching order. We are however guaranteed that the page + will stay in the flush_list because buf_flush_remove() + needs buf_pool->mutex as well. */ + buf_flush_list_mutex_exit(buf_pool); + block_mutex = buf_page_get_mutex_enter(bpage); - if (bpage->buf_fix_count > 0) { + if (!block_mutex) { + /* It may be impossible case... + Something wrong, so will be scan_again */ + all_freed = FALSE; + goto next_page; + } - mutex_exit(block_mutex); - /* We cannot remove this page during - this scan yet; maybe the system is - currently reading it in, or flushing - the modifications to the file */ + if (bpage->buf_fix_count > 0) { + mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); - all_freed = FALSE; + /* We cannot remove this page during + this scan yet; maybe the system is + currently reading it in, or flushing + the modifications to the file */ - goto next_page; - } + all_freed = FALSE; + goto next_page; } - ut_ad(mutex_own(block_mutex)); + ut_ad(bpage->oldest_modification != 0); -#ifdef UNIV_DEBUG - if (buf_debug_prints) { - fprintf(stderr, - "Dropping space %lu page %lu\n", - (ulong) buf_page_get_space(bpage), - (ulong) buf_page_get_page_no(bpage)); + buf_flush_remove(bpage); + + mutex_exit(block_mutex); + buf_flush_list_mutex_enter(buf_pool); +next_page: + bpage = prev_bpage; + + if (!bpage) { + break; } -#endif - if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { - /* This is a compressed-only block - descriptor. Do nothing. */ - } else if (((buf_block_t*) bpage)->is_hashed) { - ulint page_no; - ulint zip_size; - //buf_pool_mutex_exit(buf_pool); - mutex_exit(&buf_pool->LRU_list_mutex); - rw_lock_x_unlock(&buf_pool->page_hash_latch); + /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the + loop we release buf_pool->mutex to let other threads + do their job. */ + if (i < BUF_LRU_DROP_SEARCH_SIZE) { + continue; + } - zip_size = buf_page_get_zip_size(bpage); - page_no = buf_page_get_page_no(bpage); + /* We IO-fix the block to make sure that the block + stays in its position in the flush_list. */ + if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) { + /* Block is already IO-fixed. We don't + want to change the value. Lets leave + this block alone. */ + continue; + } - mutex_exit(block_mutex); + buf_flush_list_mutex_exit(buf_pool); + block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); + buf_page_set_sticky(bpage); + mutex_exit(block_mutex); - /* Note that the following call will acquire - an S-latch on the page */ + /* Now it is safe to release the buf_pool->mutex. */ + //buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->LRU_list_mutex); + rw_lock_x_unlock(&buf_pool->page_hash_latch); - btr_search_drop_page_hash_when_freed( - id, zip_size, page_no); - goto scan_again; - } + os_thread_yield(); + //buf_pool_mutex_enter(buf_pool); + mutex_enter(&buf_pool->LRU_list_mutex); + rw_lock_x_lock(&buf_pool->page_hash_latch); - if (bpage->oldest_modification != 0) { - buf_flush_remove(bpage); - } + mutex_enter(block_mutex); + buf_page_unset_sticky(bpage); + mutex_exit(block_mutex); - /* Remove from the LRU list. */ + buf_flush_list_mutex_enter(buf_pool); + ut_ad(bpage->in_flush_list); - if (buf_LRU_block_remove_hashed_page(bpage, TRUE) - != BUF_BLOCK_ZIP_FREE) { - buf_LRU_block_free_hashed_page((buf_block_t*) bpage, TRUE); - mutex_exit(block_mutex); - } else { - /* The block_mutex should have been released - by buf_LRU_block_remove_hashed_page() when it - returns BUF_BLOCK_ZIP_FREE. */ - ut_ad(block_mutex == &buf_pool->zip_mutex); - ut_ad(!mutex_own(block_mutex)); - } -next_page: - bpage = prev_bpage; + i = 0; } - //buf_pool_mutex_exit(buf_pool); +// buf_pool_mutex_exit(buf_pool); mutex_exit(&buf_pool->LRU_list_mutex); rw_lock_x_unlock(&buf_pool->page_hash_latch); + buf_flush_list_mutex_exit(buf_pool); + + ut_ad(buf_flush_validate(buf_pool)); if (!all_freed) { os_thread_sleep(20000); @@ -525,7 +541,7 @@ buf_LRU_invalidate_tablespace( buf_pool = buf_pool_from_array(i); buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); - buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id); + buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id); } } @@ -567,7 +583,7 @@ buf_LRU_mark_space_was_deleted( for (k = chunk->size; k--; block++) { if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE - || !block->is_hashed + || !block->index || buf_page_get_space(&block->page) != id) { continue; } @@ -575,7 +591,7 @@ buf_LRU_mark_space_was_deleted( btr_search_s_unlock_all(); rw_lock_x_lock(&block->lock); - btr_search_drop_page_hash_index(block, NULL); + btr_search_drop_page_hash_index(block); rw_lock_x_unlock(&block->lock); btr_search_s_lock_all(); @@ -1726,8 +1742,7 @@ not_freed: /* Prevent buf_page_get_gen() from decompressing the block while we release buf_pool->mutex and block_mutex. */ - b->buf_fix_count++; - b->io_fix = BUF_IO_READ; + buf_page_set_sticky(b); mutex_exit(&buf_pool->zip_mutex); } @@ -1744,7 +1759,7 @@ not_freed: UNIV_MEM_VALID(((buf_block_t*) bpage)->frame, UNIV_PAGE_SIZE); - btr_search_drop_page_hash_index((buf_block_t*) bpage, NULL); + btr_search_drop_page_hash_index((buf_block_t*) bpage); UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame, UNIV_PAGE_SIZE); @@ -1772,8 +1787,7 @@ not_freed: if (b) { mutex_enter(&buf_pool->zip_mutex); - b->buf_fix_count--; - buf_page_set_io_fix(b, BUF_IO_NONE); + buf_page_unset_sticky(b); mutex_exit(&buf_pool->zip_mutex); } diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index 07f22e4d1d6..98cf88455bd 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -919,6 +919,11 @@ dict_index_find_on_id_low( dict_table_t* table; dict_index_t* index; + /* This can happen if the system tablespace is the wrong page size */ + if (dict_sys == NULL) { + return(NULL); + } + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); while (table) { diff --git a/storage/xtradb/dict/dict0load.c b/storage/xtradb/dict/dict0load.c index 47f969727fb..5303557548b 100644 --- a/storage/xtradb/dict/dict0load.c +++ b/storage/xtradb/dict/dict0load.c @@ -849,7 +849,7 @@ loop: object and check that the .ibd file exists. */ fil_open_single_table_tablespace(FALSE, space_id, - flags, name); + flags, name, NULL); } mem_free(name); @@ -1904,7 +1904,7 @@ err_exit: if (!fil_open_single_table_tablespace( TRUE, table->space, table->flags == DICT_TF_COMPACT ? 0 : - table->flags & ~(~0 << DICT_TF_BITS), name)) { + table->flags & ~(~0 << DICT_TF_BITS), name, NULL)) { /* We failed to find a sensible tablespace file */ diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c index 41b61be0b5b..8cabf13e2c4 100644 --- a/storage/xtradb/fil/fil0fil.c +++ b/storage/xtradb/fil/fil0fil.c @@ -1827,36 +1827,44 @@ fil_write_flushed_lsn_to_data_files( } /*******************************************************************//** -Reads the flushed lsn and arch no fields from a data file at database -startup. */ +Reads the flushed lsn, arch no, and tablespace flag fields from a data +file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn) /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn) /*!< out: max of flushed + lsn values in data files */ { byte* buf; - byte* buf2; + page_t* page; ib_uint64_t flushed_lsn; - buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); + buf = ut_malloc(2 * UNIV_PAGE_SIZE); /* Align the memory for a possible read from a raw device */ - buf = ut_align(buf2, UNIV_PAGE_SIZE); + page = ut_align(buf, UNIV_PAGE_SIZE); - os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); + os_file_read(data_file, page, 0, 0, UNIV_PAGE_SIZE); - flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN); + *flags = mach_read_from_4(page + + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS); - ut_free(buf2); + flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); + + ut_free(buf); if (!one_read_already) { *min_flushed_lsn = flushed_lsn; @@ -3174,8 +3182,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name) /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx) /*!< in: transaction. This is only used + for IMPORT TABLESPACE, must be NULL + otherwise */ { os_file_t file; char* filepath; @@ -3393,6 +3404,11 @@ skip_info: /* over write space id of all pages */ rec_offs_init(offsets_); + /* Unlock the data dictionary to not block queries + accessing other tables */ + ut_a(trx); + row_mysql_unlock_data_dictionary(trx); + fprintf(stderr, "InnoDB: Progress in %%:"); for (offset = 0; offset < free_limit_bytes; @@ -3594,6 +3610,9 @@ skip_write: fprintf(stderr, " done.\n"); + /* Reacquire the data dictionary lock */ + row_mysql_lock_data_dictionary(trx); + /* update SYS_INDEXES set root page */ index = dict_table_get_first_index(table); while (index) { diff --git a/storage/xtradb/fsp/fsp0fsp.c b/storage/xtradb/fsp/fsp0fsp.c index 5e3959a3c7f..6102c5decd8 100644 --- a/storage/xtradb/fsp/fsp0fsp.c +++ b/storage/xtradb/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -50,67 +50,6 @@ Created 11/29/1995 Heikki Tuuri #include "dict0mem.h" #include "trx0sys.h" -#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header - within a file page */ - -/* The data structures in files are defined just as byte strings in C */ -typedef byte fsp_header_t; -typedef byte xdes_t; - -/* SPACE HEADER - ============ - -File space header data structure: this data structure is contained in the -first page of a space. The space for this header is reserved in every extent -descriptor page, but used only in the first. */ - -/*-------------------------------------*/ -#define FSP_SPACE_ID 0 /* space id */ -#define FSP_NOT_USED 4 /* this field contained a value up to - which we know that the modifications - in the database have been flushed to - the file space; not used now */ -#define FSP_SIZE 8 /* Current size of the space in - pages */ -#define FSP_FREE_LIMIT 12 /* Minimum page number for which the - free list has not been initialized: - the pages >= this limit are, by - definition, free; note that in a - single-table tablespace where size - < 64 pages, this number is 64, i.e., - we have initialized the space - about the first extent, but have not - physically allocted those pages to the - file */ -#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */ -#define FSP_FRAG_N_USED 20 /* number of used pages in the - FSP_FREE_FRAG list */ -#define FSP_FREE 24 /* list of free extents */ -#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) - /* list of partially free extents not - belonging to any segment */ -#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) - /* list of full extents not belonging - to any segment */ -#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) - /* 8 bytes which give the first unused - segment id */ -#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where all the segment inode - slots are reserved */ -#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) - /* list of pages containing segment - headers, where not all the segment - header slots are reserved */ -/*-------------------------------------*/ -/* File space header size */ -#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) - -#define FSP_FREE_ADD 4 /* this many free extents are added - to the free list from above - FSP_FREE_LIMIT at a time */ - /* FILE SEGMENT INODE ================== diff --git a/storage/xtradb/ha/ha0ha.c b/storage/xtradb/ha/ha0ha.c index b28995553e0..2f5051e541f 100644 --- a/storage/xtradb/ha/ha0ha.c +++ b/storage/xtradb/ha/ha0ha.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -89,41 +89,6 @@ ha_create_func( } /*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ulint i; - ulint n; - - ut_ad(table); - ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); -#ifdef UNIV_SYNC_DEBUG - /* cannot identificate which btr_search_latch[i] for now */ - //ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE)); -#endif /* UNIV_SYNC_DEBUG */ - -#ifndef UNIV_HOTBACKUP - /* Free the memory heaps. */ - n = table->n_mutexes; - - for (i = 0; i < n; i++) { - mem_heap_free(table->heaps[i]); - } -#endif /* !UNIV_HOTBACKUP */ - - /* Clear the hash table. */ - n = hash_get_n_cells(table); - - for (i = 0; i < n; i++) { - hash_get_nth_cell(table, i)->node = NULL; - } -} - -/*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node is inserted. If btr_search_enabled is set to FALSE, we will only allow @@ -141,7 +106,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: data, must not be NULL */ + const rec_t* data) /*!< in: data, must not be NULL */ { hash_cell_t* cell; ha_node_t* node; @@ -154,7 +119,11 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->frame == page_align(data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(block->btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); hash = hash_calc_hash(fold, table); @@ -174,7 +143,6 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } - ut_ad(!btr_search_fully_disabled); # endif /* !UNIV_HOTBACKUP */ prev_node->block = block; @@ -187,13 +155,6 @@ ha_insert_for_fold_func( prev_node = prev_node->next; } - /* We are in the process of disabling hash index, do not add - new chain node */ - if (!btr_search_enabled) { - ut_ad(!btr_search_fully_disabled); - return(TRUE); - } - /* We have to allocate a new chain node */ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)); @@ -251,6 +212,10 @@ ha_delete_hash_node( { ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { @@ -273,11 +238,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data)/*!< in: new pointer to the data */ + const rec_t* new_data)/*!< in: new pointer to the data */ { ha_node_t* node; @@ -287,6 +252,13 @@ ha_search_and_update_if_found_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(new_block->frame == page_align(new_data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + + if (!btr_search_enabled) { + return; + } node = ha_search_with_data(table, fold, data); @@ -323,6 +295,10 @@ ha_remove_all_nodes_to_page( ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG + // ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 3aa5ff1622d..504595b1448 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -3035,7 +3035,6 @@ skip_overwrite: /* Get the current high water mark format. */ innobase_file_format_max = (char*) trx_sys_file_format_max_get(); - btr_search_fully_disabled = (!btr_search_enabled); DBUG_RETURN(FALSE); error: DBUG_RETURN(TRUE); @@ -5839,8 +5838,7 @@ no_commit: switch (sql_command) { case SQLCOM_LOAD: - if ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { + if (trx->duplicates) { goto set_max_autoinc; } @@ -6128,8 +6126,7 @@ ha_innobase::update_row( && table->next_number_field && new_row == table->record[0] && thd_sql_command(user_thd) == SQLCOM_INSERT - && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE) { + && trx->duplicates) { ulonglong auto_inc; ulonglong col_max_value; @@ -6515,6 +6512,7 @@ ha_innobase::index_read( (byte*) key_ptr, (ulint) key_len, prebuilt->trx); + DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0); } else { /* We position the cursor to the last or the first entry in the index */ @@ -6616,7 +6614,6 @@ ha_innobase::innobase_get_index( dict_index_t* index = 0; DBUG_ENTER("innobase_get_index"); - ha_statistic_increment(&SSV::ha_read_key_count); if (keynr != MAX_KEY && table->s->keys > 0) { key = table->key_info + keynr; @@ -6630,13 +6627,13 @@ ha_innobase::innobase_get_index( table. Only print message if the index translation table exists */ if (share->idx_trans_tbl.index_mapping) { - sql_print_error("InnoDB could not find " - "index %s key no %u for " - "table %s through its " - "index translation table", - key ? key->name : "NULL", - keynr, - prebuilt->table->name); + sql_print_warning("InnoDB could not find " + "index %s key no %u for " + "table %s through its " + "index translation table", + key ? key->name : "NULL", + keynr, + prebuilt->table->name); } index = dict_table_get_index_on_name(prebuilt->table, @@ -8465,6 +8462,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (min_key ? min_key->length : 0), prebuilt->trx); + DBUG_ASSERT(min_key + ? range_start->n_fields > 0 + : range_start->n_fields == 0); row_sel_convert_mysql_key_to_innobase( range_end, (byte*) key_val_buff2, @@ -8473,6 +8473,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (max_key ? max_key->length : 0), prebuilt->trx); + DBUG_ASSERT(max_key + ? range_end->n_fields > 0 + : range_end->n_fields == 0); mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag : HA_READ_KEY_EXACT); @@ -9217,7 +9220,10 @@ ha_innobase::check( putc('\n', stderr); #endif - if (!btr_validate_index(index, prebuilt->trx)) { + /* If this is an index being created, break */ + if (*index->name == TEMP_INDEX_PREFIX) { + break; + } else if (!btr_validate_index(index, prebuilt->trx)) { is_ok = FALSE; innobase_format_name( @@ -9770,6 +9776,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: reset_template(); + thd_to_trx(ha_thd())->duplicates = 0; break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; @@ -9787,19 +9794,18 @@ ha_innobase::extra( parameters below. We must not invoke update_thd() either, because the calling threads may change. CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */ - case HA_EXTRA_IGNORE_DUP_KEY: + case HA_EXTRA_INSERT_WITH_UPDATE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE; break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE; + break; case HA_EXTRA_WRITE_CAN_REPLACE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE; break; case HA_EXTRA_WRITE_CANNOT_REPLACE: thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE; break; - case HA_EXTRA_NO_IGNORE_DUP_KEY: - thd_to_trx(ha_thd())->duplicates &= - ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE); - break; default:/* Do nothing */ ; } @@ -12549,10 +12555,42 @@ static MYSQL_SYSVAR_ULINT(checkpoint_age_target, srv_checkpoint_age_target, "Control soft limit of checkpoint age. (0 : not control)", NULL, NULL, 0, 0, ~0UL, 0); -static MYSQL_SYSVAR_ULINT(flush_neighbor_pages, srv_flush_neighbor_pages, - PLUGIN_VAR_RQCMDARG, - "Enable/Disable flushing also neighbor pages. 0:disable 1:enable", - NULL, NULL, 1, 0, 1, 0); +static +void +innodb_flush_neighbor_pages_update( + THD* thd, + struct st_mysql_sys_var* var, + void* var_ptr, + const void* save) +{ + *(long *)var_ptr = (*(long *)save) % 3; +} + +const char *flush_neighbor_pages_names[]= +{ + "none", /* 0 */ + "area", + "cont", /* 2 */ + /* For compatibility with the older patch */ + "0", /* "none" + 3 */ + "1", /* "area" + 3 */ + "2", /* "cont" + 3 */ + NullS +}; + +TYPELIB flush_neighbor_pages_typelib= +{ + array_elements(flush_neighbor_pages_names) - 1, + "flush_neighbor_pages_typelib", + flush_neighbor_pages_names, + NULL +}; + +static MYSQL_SYSVAR_ENUM(flush_neighbor_pages, srv_flush_neighbor_pages, + PLUGIN_VAR_RQCMDARG, "Neighbor page flushing behaviour: none: do not flush, " + "[area]: flush selected pages one-by-one, " + "cont: flush a contiguous block of pages", NULL, + innodb_flush_neighbor_pages_update, 1, &flush_neighbor_pages_typelib); static void @@ -12618,6 +12656,14 @@ static MYSQL_SYSVAR_ENUM(adaptive_flushing_method, srv_adaptive_flushing_method, "Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)", NULL, innodb_adaptive_flushing_method_update, 1, &adaptive_flushing_method_typelib); +#ifdef UNIV_DEBUG +static MYSQL_SYSVAR_ULONG(flush_checkpoint_debug, srv_flush_checkpoint_debug, + PLUGIN_VAR_RQCMDARG, + "Debug flags for InnoDB flushing and checkpointing (0=none," + "1=stop preflush and checkpointing)", + NULL, NULL, 0, 0, 1, 0); +#endif + static MYSQL_SYSVAR_ULONG(import_table_from_xtrabackup, srv_expand_import, PLUGIN_VAR_RQCMDARG, "Enable/Disable converting automatically *.ibd files when import tablespace.", @@ -12764,6 +12810,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(purge_threads), MYSQL_SYSVAR(purge_batch_size), MYSQL_SYSVAR(rollback_segments), +#ifdef UNIV_DEBUG + MYSQL_SYSVAR(flush_checkpoint_debug), +#endif MYSQL_SYSVAR(corrupt_table_action), MYSQL_SYSVAR(lazy_drop_table), MYSQL_SYSVAR(fake_changes), diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index 72ff5f7198b..3b87b860a4a 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -3916,7 +3916,7 @@ i_s_innodb_buffer_pool_pages_index_fill( table->field[2]->store(block->page.offset, TRUE); table->field[3]->store(page_get_n_recs(frame), TRUE); table->field[4]->store(page_get_data_size(frame), TRUE); - table->field[5]->store(block->is_hashed, TRUE); + table->field[5]->store(block->index != NULL, TRUE); table->field[6]->store(block->page.access_time, TRUE); table->field[7]->store(block->page.newest_modification != 0, TRUE); table->field[8]->store(block->page.oldest_modification != 0, TRUE); diff --git a/storage/xtradb/ibuf/ibuf0ibuf.c b/storage/xtradb/ibuf/ibuf0ibuf.c index 7def360867d..00b7ea7347d 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.c +++ b/storage/xtradb/ibuf/ibuf0ibuf.c @@ -254,11 +254,20 @@ ibuf_count_check( list of the ibuf */ /* @} */ +#define IBUF_REC_FIELD_SPACE 0 /*!< in the pre-4.1 format, + the page number. later, the space_id */ +#define IBUF_REC_FIELD_MARKER 1 /*!< starting with 4.1, a marker + consisting of 1 byte that is 0 */ +#define IBUF_REC_FIELD_PAGE 2 /*!< starting with 4.1, the + page number */ +#define IBUF_REC_FIELD_METADATA 3 /* the metadata field */ +#define IBUF_REC_FIELD_USER 4 /* first user field */ + /* Various constants for checking the type of an ibuf record and extracting data from it. For details, see the description of the record format at the top of this file. */ -/** @name Format of the fourth column of an insert buffer record +/** @name Format of the IBUF_REC_FIELD_METADATA of an insert buffer record The fourth column in the MySQL 5.5 format contains an operation type, counter, and some flags. */ /* @{ */ @@ -1275,13 +1284,13 @@ ibuf_rec_get_page_no_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len == 1) { /* This is of the >= 4.1.x record format */ ut_a(trx_sys_multiple_tablespace_format); - field = rec_get_nth_field_old(rec, 2, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_PAGE, &len); } else { ut_a(trx_doublewrite_must_reset_space_ids); ut_a(!trx_sys_multiple_tablespace_format); @@ -1321,13 +1330,13 @@ ibuf_rec_get_space_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len == 1) { /* This is of the >= 4.1.x record format */ ut_a(trx_sys_multiple_tablespace_format); - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); return(mach_read_from_4(field)); @@ -1377,9 +1386,9 @@ ibuf_rec_get_info_func( || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(ibuf_inside(mtr)); fields = rec_get_n_fields_old(rec); - ut_a(fields > 4); + ut_a(fields > IBUF_REC_FIELD_USER); - types = rec_get_nth_field_old(rec, 3, &len); + types = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; @@ -1405,7 +1414,8 @@ ibuf_rec_get_info_func( ut_a(op_local < IBUF_OP_COUNT); ut_a((len - info_len_local) == - (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); + (fields - IBUF_REC_FIELD_USER) + * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); if (op) { *op = op_local; @@ -1449,7 +1459,7 @@ ibuf_rec_get_op_type_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); - (void) rec_get_nth_field_old(rec, 1, &len); + (void) rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (len > 1) { /* This is a < 4.1.x format record */ @@ -1478,12 +1488,12 @@ ibuf_rec_get_counter( const byte* ptr; ulint len; - if (rec_get_n_fields_old(rec) < 4) { + if (rec_get_n_fields_old(rec) <= IBUF_REC_FIELD_METADATA) { return(ULINT_UNDEFINED); } - ptr = rec_get_nth_field_old(rec, 3, &len); + ptr = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); if (len >= 2) { @@ -1708,7 +1718,7 @@ ibuf_build_entry_from_ibuf_rec_func( || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(ibuf_inside(mtr)); - data = rec_get_nth_field_old(ibuf_rec, 1, &len); + data = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_MARKER, &len); if (len > 1) { /* This a < 4.1.x format record */ @@ -1720,13 +1730,13 @@ ibuf_build_entry_from_ibuf_rec_func( ut_a(trx_sys_multiple_tablespace_format); ut_a(*data == 0); - ut_a(rec_get_n_fields_old(ibuf_rec) > 4); + ut_a(rec_get_n_fields_old(ibuf_rec) > IBUF_REC_FIELD_USER); - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; + n_fields = rec_get_n_fields_old(ibuf_rec) - IBUF_REC_FIELD_USER; tuple = dtuple_create(heap, n_fields); - types = rec_get_nth_field_old(ibuf_rec, 3, &len); + types = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_METADATA, &len); ibuf_rec_get_info(mtr, ibuf_rec, NULL, &comp, &info_len, NULL); @@ -1740,7 +1750,8 @@ ibuf_build_entry_from_ibuf_rec_func( for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(tuple, i); - data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); + data = rec_get_nth_field_old( + ibuf_rec, i + IBUF_REC_FIELD_USER, &len); dfield_set_data(field, data, len); @@ -1787,7 +1798,7 @@ ibuf_rec_get_size( field_offset = 2; types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE; } else { - field_offset = 4; + field_offset = IBUF_REC_FIELD_USER; types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; } @@ -1848,7 +1859,7 @@ ibuf_rec_get_volume_func( ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); - data = rec_get_nth_field_old(ibuf_rec, 1, &len); + data = rec_get_nth_field_old(ibuf_rec, IBUF_REC_FIELD_MARKER, &len); pre_4_1 = (len > 1); if (pre_4_1) { @@ -1871,7 +1882,8 @@ ibuf_rec_get_volume_func( ut_a(trx_sys_multiple_tablespace_format); ut_a(*data == 0); - types = rec_get_nth_field_old(ibuf_rec, 3, &len); + types = rec_get_nth_field_old( + ibuf_rec, IBUF_REC_FIELD_METADATA, &len); ibuf_rec_get_info(mtr, ibuf_rec, &op, &comp, &info_len, NULL); @@ -1901,7 +1913,8 @@ ibuf_rec_get_volume_func( } types += info_len; - n_fields = rec_get_n_fields_old(ibuf_rec) - 4; + n_fields = rec_get_n_fields_old(ibuf_rec) + - IBUF_REC_FIELD_USER; } data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp); @@ -1956,11 +1969,11 @@ ibuf_entry_build( n_fields = dtuple_get_n_fields(entry); - tuple = dtuple_create(heap, n_fields + 4); + tuple = dtuple_create(heap, n_fields + IBUF_REC_FIELD_USER); /* 1) Space Id */ - field = dtuple_get_nth_field(tuple, 0); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_SPACE); buf = mem_heap_alloc(heap, 4); @@ -1970,7 +1983,7 @@ ibuf_entry_build( /* 2) Marker byte */ - field = dtuple_get_nth_field(tuple, 1); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_MARKER); buf = mem_heap_alloc(heap, 1); @@ -1982,7 +1995,7 @@ ibuf_entry_build( /* 3) Page number */ - field = dtuple_get_nth_field(tuple, 2); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_PAGE); buf = mem_heap_alloc(heap, 4); @@ -2030,10 +2043,7 @@ ibuf_entry_build( ulint fixed_len; const dict_field_t* ifield; - /* We add 4 below because we have the 4 extra fields at the - start of an ibuf record */ - - field = dtuple_get_nth_field(tuple, i + 4); + field = dtuple_get_nth_field(tuple, i + IBUF_REC_FIELD_USER); entry_field = dtuple_get_nth_field(entry, i); dfield_copy(field, entry_field); @@ -2066,13 +2076,13 @@ ibuf_entry_build( /* 4) Type info, part #2 */ - field = dtuple_get_nth_field(tuple, 3); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_METADATA); dfield_set_data(field, type_info, ti - type_info); /* Set all the types in the new tuple binary */ - dtuple_set_types_binary(tuple, n_fields + 4); + dtuple_set_types_binary(tuple, n_fields + IBUF_REC_FIELD_USER); return(tuple); } @@ -2132,11 +2142,11 @@ ibuf_new_search_tuple_build( ut_a(trx_sys_multiple_tablespace_format); - tuple = dtuple_create(heap, 3); + tuple = dtuple_create(heap, IBUF_REC_FIELD_METADATA); /* Store the space id in tuple */ - field = dtuple_get_nth_field(tuple, 0); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_SPACE); buf = mem_heap_alloc(heap, 4); @@ -2146,7 +2156,7 @@ ibuf_new_search_tuple_build( /* Store the new format record marker byte */ - field = dtuple_get_nth_field(tuple, 1); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_MARKER); buf = mem_heap_alloc(heap, 1); @@ -2156,7 +2166,7 @@ ibuf_new_search_tuple_build( /* Store the page number in tuple */ - field = dtuple_get_nth_field(tuple, 2); + field = dtuple_get_nth_field(tuple, IBUF_REC_FIELD_PAGE); buf = mem_heap_alloc(heap, 4); @@ -2164,7 +2174,7 @@ ibuf_new_search_tuple_build( dfield_set_data(field, buf, 4); - dtuple_set_types_binary(tuple, 3); + dtuple_set_types_binary(tuple, IBUF_REC_FIELD_METADATA); return(tuple); } @@ -2833,8 +2843,10 @@ ibuf_get_volume_buffered_hash( ulint fold; ulint bitmask; - len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4, - FALSE, comp); + len = ibuf_rec_get_size( + rec, types, + rec_get_n_fields_old(rec) - IBUF_REC_FIELD_USER, + FALSE, comp); fold = ut_fold_binary(data, len); hash += (fold / (CHAR_BIT * sizeof *hash)) % size; @@ -2886,8 +2898,8 @@ ibuf_get_volume_buffered_count_func( ut_ad(ibuf_inside(mtr)); n_fields = rec_get_n_fields_old(rec); - ut_ad(n_fields > 4); - n_fields -= 4; + ut_ad(n_fields > IBUF_REC_FIELD_USER); + n_fields -= IBUF_REC_FIELD_USER; rec_get_nth_field_offs_old(rec, 1, &len); /* This function is only invoked when buffering new @@ -2896,7 +2908,7 @@ ibuf_get_volume_buffered_count_func( ut_a(len == 1); ut_ad(trx_sys_multiple_tablespace_format); - types = rec_get_nth_field_old(rec, 3, &len); + types = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, IBUF_REC_INFO_SIZE)) { @@ -3208,7 +3220,7 @@ ibuf_update_max_tablespace_id(void) } else { rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); @@ -3230,10 +3242,12 @@ ibuf_update_max_tablespace_id(void) ibuf_get_entry_counter_low_func(rec,space,page_no) #endif /****************************************************************//** -Helper function for ibuf_set_entry_counter. Checks if rec is for (space, -page_no), and if so, reads counter value from it and returns that + 1. -Otherwise, returns 0. -@return new counter value, or 0 */ +Helper function for ibuf_get_entry_counter_func. Checks if rec is for +(space, page_no), and if so, reads counter value from it and returns +that + 1. +@retval ULINT_UNDEFINED if the record does not contain any counter +@retval 0 if the record is not for (space, page_no) +@retval 1 + previous counter value, otherwise */ static ulint ibuf_get_entry_counter_low_func( @@ -3254,7 +3268,7 @@ ibuf_get_entry_counter_low_func( || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(rec_get_n_fields_old(rec) > 2); - field = rec_get_nth_field_old(rec, 1, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_MARKER, &len); if (UNIV_UNLIKELY(len != 1)) { /* pre-4.1 format */ @@ -3267,7 +3281,7 @@ ibuf_get_entry_counter_low_func( ut_a(trx_sys_multiple_tablespace_format); /* Check the tablespace identifier. */ - field = rec_get_nth_field_old(rec, 0, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_SPACE, &len); ut_a(len == 4); if (mach_read_from_4(field) != space) { @@ -3276,7 +3290,7 @@ ibuf_get_entry_counter_low_func( } /* Check the page offset. */ - field = rec_get_nth_field_old(rec, 2, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_PAGE, &len); ut_a(len == 4); if (mach_read_from_4(field) != page_no) { @@ -3285,7 +3299,7 @@ ibuf_get_entry_counter_low_func( } /* Check if the record contains a counter field. */ - field = rec_get_nth_field_old(rec, 3, &len); + field = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len); switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { default: @@ -3301,147 +3315,61 @@ ibuf_get_entry_counter_low_func( } } +#ifdef UNIV_DEBUG +# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ + ibuf_get_entry_counter_func(space,page_no,rec,mtr,exact_leaf) +#else /* UNIV_DEBUG */ +# define ibuf_get_entry_counter(space,page_no,rec,mtr,exact_leaf) \ + ibuf_get_entry_counter_func(space,page_no,rec,exact_leaf) +#endif + /****************************************************************//** -Set the counter field in entry to the correct value based on the current +Calculate the counter field for an entry based on the current last record in ibuf for (space, page_no). -@return FALSE if we should abort this insertion to ibuf */ +@return the counter field, or ULINT_UNDEFINED +if we should abort this insertion to ibuf */ static -ibool -ibuf_set_entry_counter( -/*===================*/ - dtuple_t* entry, /*!< in/out: entry to patch */ +ulint +ibuf_get_entry_counter_func( +/*========================*/ ulint space, /*!< in: space id of entry */ ulint page_no, /*!< in: page number of entry */ - btr_pcur_t* pcur, /*!< in: pcur positioned on the record - found by btr_pcur_open(.., entry, - PAGE_CUR_LE, ..., pcur, ...) */ - ibool is_optimistic, /*!< in: is this an optimistic insert */ - mtr_t* mtr) /*!< in: mtr */ + const rec_t* rec, /*!< in: the record preceding the + insertion point */ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction */ +#endif /* UNIV_DEBUG */ + ibool only_leaf) /*!< in: TRUE if this is the only + leaf page that can contain entries + for (space,page_no), that is, there + was no exact match for (space,page_no) + in the node pointer */ { - dfield_t* field; - byte* data; - ulint counter = 0; - - /* pcur points to either a user rec or to a page's infimum record. */ ut_ad(ibuf_inside(mtr)); - ut_ad(mtr_memo_contains(mtr, btr_pcur_get_block(pcur), - MTR_MEMO_PAGE_X_FIX)); - ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index)); - - if (btr_pcur_is_on_user_rec(pcur)) { - - counter = ibuf_get_entry_counter_low( - mtr, btr_pcur_get_rec(pcur), space, page_no); - - if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { - /* The record lacks a counter field. - Such old records must be merged before - new records can be buffered. */ - - return(FALSE); - } - } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) { - /* Ibuf tree is either completely empty, or the insert - position is at the very first record of a non-empty tree. In - either case we have no previous records for (space, - page_no). */ - - counter = 0; - } else if (btr_pcur_is_before_first_on_page(pcur)) { - btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur); - - if (cursor->low_match < 3) { - /* If low_match < 3, we know that the father node - pointer did not contain the searched for (space, - page_no), which means that the search ended on the - right page regardless of the counter value, and - since we're at the infimum record, there are no - existing records. */ - - counter = 0; - } else { - rec_t* rec; - const page_t* page; - buf_block_t* block; - page_t* prev_page; - ulint prev_page_no; - - ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED); - - page = btr_pcur_get_page(pcur); - prev_page_no = btr_page_get_prev(page, mtr); - - ut_a(prev_page_no != FIL_NULL); - - block = buf_page_get( - IBUF_SPACE_ID, 0, prev_page_no, - RW_X_LATCH, mtr); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)); + ut_ad(page_validate(page_align(rec), ibuf->index)); - buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); - - prev_page = buf_block_get_frame(block); - - rec = page_rec_get_prev( - page_get_supremum_rec(prev_page)); - - ut_ad(page_rec_is_user_rec(rec)); - - counter = ibuf_get_entry_counter_low( - mtr, rec, space, page_no); - - if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { - /* The record lacks a counter field. - Such old records must be merged before - new records can be buffered. */ - - return(FALSE); - } - - if (counter < cursor->ibuf_cnt) { - /* Search ended on the wrong page. */ - - if (is_optimistic) { - /* In an optimistic insert, we can - shift the insert position to the left - page, since it only needs an X-latch - on the page itself, which the - original search acquired for us. */ - - btr_cur_position( - ibuf->index, rec, block, - btr_pcur_get_btr_cur(pcur)); - } else { - /* We can't shift the insert - position to the left page in a - pessimistic insert since it would - require an X-latch on the left - page's left page, so we have to - abort. */ - - return(FALSE); - } - } else { - /* The counter field in the father node is - the same as we would insert; we don't know - whether the insert should go to this page or - the left page (the later fields can differ), - so refuse the insert. */ - - return(FALSE); - } - } + if (page_rec_is_supremum(rec)) { + /* This is just for safety. The record should be a + page infimum or a user record. */ + ut_ad(0); + return(ULINT_UNDEFINED); + } else if (!page_rec_is_infimum(rec)) { + return(ibuf_get_entry_counter_low(mtr, rec, space, page_no)); + } else if (only_leaf + || fil_page_get_prev(page_align(rec)) == FIL_NULL) { + /* The parent node pointer did not contain the + searched for (space, page_no), which means that the + search ended on the correct page regardless of the + counter value, and since we're at the infimum record, + there are no existing records. */ + return(0); } else { - /* The cursor is not positioned at or before a user record. */ - return(FALSE); + /* We used to read the previous page here. It would + break the latching order, because the caller has + buffer-fixed an insert buffer bitmap page. */ + return(ULINT_UNDEFINED); } - - /* Patch counter value in already built entry. */ - field = dtuple_get_nth_field(entry, 3); - data = dfield_get_data(field); - - mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter); - - return(TRUE); } /*********************************************************************//** @@ -3650,16 +3578,27 @@ fail_exit: } } - /* Patch correct counter value to the entry to insert. This can - change the insert position, which can result in the need to abort in - some cases. */ - if (!no_counter - && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur, - mode == BTR_MODIFY_PREV, &mtr)) { + if (!no_counter) { + /* Patch correct counter value to the entry to + insert. This can change the insert position, which can + result in the need to abort in some cases. */ + ulint counter = ibuf_get_entry_counter( + space, page_no, btr_pcur_get_rec(&pcur), &mtr, + btr_pcur_get_btr_cur(&pcur)->low_match + < IBUF_REC_FIELD_METADATA); + dfield_t* field; + + if (counter == ULINT_UNDEFINED) { bitmap_fail: - ibuf_mtr_commit(&bitmap_mtr); + ibuf_mtr_commit(&bitmap_mtr); + goto fail_exit; + } - goto fail_exit; + field = dtuple_get_nth_field( + ibuf_entry, IBUF_REC_FIELD_METADATA); + mach_write_to_2( + (byte*) dfield_get_data(field) + + IBUF_REC_OFFSET_COUNTER, counter); } /* Set the bitmap bit denoting that the insert buffer contains @@ -4003,7 +3942,7 @@ ibuf_insert_to_index_page( ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); - ut_ad(!buf_block_align(page)->is_hashed); + ut_ad(!buf_block_align(page)->index); if (UNIV_UNLIKELY(dict_table_is_comp(index->table) != (ibool)!!page_is_comp(page))) { diff --git a/storage/xtradb/include/btr0cur.h b/storage/xtradb/include/btr0cur.h index be918439f59..4f33aacc48e 100644 --- a/storage/xtradb/include/btr0cur.h +++ b/storage/xtradb/include/btr0cur.h @@ -743,24 +743,6 @@ struct btr_cur_struct { NULL */ ulint fold; /*!< fold value used in the search if flag is BTR_CUR_HASH */ - /*----- Delete buffering -------*/ - ulint ibuf_cnt; /* in searches done on insert buffer - trees, this contains the "counter" - value (the first two bytes of the - fourth field) extracted from the - page above the leaf page, from the - father node pointer that pointed to - the leaf page. in other words, it - contains the minimum counter value - for records to be inserted on the - chosen leaf page. If for some reason - this can't be read, or if the search - ended on the leftmost leaf page in - the tree (in which case the father - node pointer had the 'minimum - record' flag set), this is - ULINT_UNDEFINED. */ - /*------------------------------*/ /* @} */ btr_path_t* path_arr; /*!< in estimating the number of rows in range, we store in this array diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h index f605c476844..140f94466db 100644 --- a/storage/xtradb/include/btr0pcur.h +++ b/storage/xtradb/include/btr0pcur.h @@ -263,14 +263,6 @@ btr_pcur_commit_specify_mtr( /*========================*/ btr_pcur_t* pcur, /*!< in: persistent cursor */ mtr_t* mtr); /*!< in: mtr to commit */ -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur); /*!< in: persistent cursor */ /*********************************************************//** Moves the persistent cursor to the next record in the tree. If no records are left, the cursor stays 'after last in tree'. diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic index d86601e5a32..054ce753c7d 100644 --- a/storage/xtradb/include/btr0pcur.ic +++ b/storage/xtradb/include/btr0pcur.ic @@ -389,38 +389,6 @@ btr_pcur_commit_specify_mtr( } /**************************************************************//** -Sets the pcur latch mode to BTR_NO_LATCHES. */ -UNIV_INLINE -void -btr_pcur_detach( -/*============*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED); - - pcur->latch_mode = BTR_NO_LATCHES; - - pcur->pos_state = BTR_PCUR_WAS_POSITIONED; -} - -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - if (pcur->latch_mode == BTR_NO_LATCHES) { - - return(TRUE); - } - - return(FALSE); -} - -/**************************************************************//** Sets the old_rec_buf field to NULL. */ UNIV_INLINE void diff --git a/storage/xtradb/include/btr0sea.h b/storage/xtradb/include/btr0sea.h index 9e82602934e..d9f2cf9c81b 100644 --- a/storage/xtradb/include/btr0sea.h +++ b/storage/xtradb/include/btr0sea.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -137,11 +137,10 @@ UNIV_INTERN void btr_search_drop_page_hash_index( /*============================*/ - buf_block_t* block, /*!< in: block containing index page, + buf_block_t* block); /*!< in: block containing index page, s- or x-latched, or an index page for which we know that block->buf_fix_count == 0 */ - dict_index_t* index_in); /************************************************************************ Drops a page hash index based on index */ UNIV_INTERN @@ -150,8 +149,8 @@ btr_search_drop_page_hash_index_on_index( /*=====================================*/ dict_index_t* index); /* in: record descriptor */ /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -235,19 +234,6 @@ void btr_search_s_unlock_all(void); /*==========================*/ - -/** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern char btr_search_enabled; - -extern ulint btr_search_index_num; - -/** Flag: whether the search system has completed its disabling process, -It is set to TRUE right after buf_pool_drop_hash_index() in -btr_search_disable(), indicating hash index entries are cleaned up. -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern ibool btr_search_fully_disabled; - /** The search info struct in an index */ struct btr_search_struct{ ulint ref_count; /*!< Number of blocks in this index tree @@ -316,26 +302,6 @@ struct btr_search_sys_struct{ /** The adaptive hash index */ extern btr_search_sys_t* btr_search_sys; -/** @brief The latch protecting the adaptive search system - -This latch protects the -(1) hash index; -(2) columns of a record to which we have a pointer in the hash index; - -but does NOT protect: - -(3) next record offset field in a record; -(4) next or previous records on the same page. - -Bear in mind (3) and (4) when using the hash index. -*/ -//extern rw_lock_t* btr_search_latch_temp; - -extern rw_lock_t** btr_search_latch_part; - -/** The latch protecting the adaptive search system */ -//#define btr_search_latch (*btr_search_latch_temp) - #ifdef UNIV_SEARCH_PERF_STAT /** Number of successful adaptive hash index lookups */ extern ulint btr_search_n_succ; diff --git a/storage/xtradb/include/btr0types.h b/storage/xtradb/include/btr0types.h index 07c06fb18d7..6f515c3f58c 100644 --- a/storage/xtradb/include/btr0types.h +++ b/storage/xtradb/include/btr0types.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -30,6 +30,7 @@ Created 2/17/1996 Heikki Tuuri #include "rem0types.h" #include "page0types.h" +#include "sync0rw.h" /** Persistent cursor */ typedef struct btr_pcur_struct btr_pcur_t; @@ -38,6 +39,32 @@ typedef struct btr_cur_struct btr_cur_t; /** B-tree search information for the adaptive hash index */ typedef struct btr_search_struct btr_search_t; +/** @brief The latch protecting the adaptive search system + +This latch protects the +(1) hash index; +(2) columns of a record to which we have a pointer in the hash index; + +but does NOT protect: + +(3) next record offset field in a record; +(4) next or previous records on the same page. + +Bear in mind (3) and (4) when using the hash index. +*/ +//extern rw_lock_t* btr_search_latch_temp; + +extern rw_lock_t** btr_search_latch_part; + +/** The latch protecting the adaptive search system */ +//#define btr_search_latch (*btr_search_latch_temp) + +/** Flag: has the search system been enabled? +Protected by btr_search_latch. */ +extern char btr_search_enabled; + +extern ulint btr_search_index_num; + #ifdef UNIV_BLOB_DEBUG # include "buf0types.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index d85dac5cc91..0ea74fb9eb2 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -244,13 +244,11 @@ buf_pool_free( ulint n_instances); /*!< in: numbere of instances to free */ /********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void); -/*==========================*/ +buf_pool_clear_hash_index(void); +/*===========================*/ /********************************************************************//** Relocate a buffer control block. Relocates the block on the LRU list @@ -583,17 +581,6 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage); /*!< in: block to make younger */ /********************************************************************//** -Returns the current state of is_hashed of a page. FALSE if the page is -not in the pool. NOTE that this operation does not fix the page in the -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: page number */ -/********************************************************************//** Gets the youngest modification log sequence number for a frame. Returns zero if not file page or no modification occurred yet. @return newest modification to page */ @@ -952,7 +939,27 @@ buf_block_set_io_fix( /*=================*/ buf_block_t* block, /*!< in/out: control block */ enum buf_io_fix io_fix);/*!< in: io_fix state */ - +/*********************************************************************//** +Makes a block sticky. A sticky block implies that even after we release +the buf_pool->mutex and the block->mutex: +* it cannot be removed from the flush_list +* the block descriptor cannot be relocated +* it cannot be removed from the LRU list +Note that: +* the block can still change its position in the LRU list +* the next and previous pointers can change. */ +UNIV_INLINE +void +buf_page_set_sticky( +/*================*/ + buf_page_t* bpage); /*!< in/out: control block */ +/*********************************************************************//** +Removes stickiness of a block. */ +UNIV_INLINE +void +buf_page_unset_sticky( +/*==================*/ + buf_page_t* bpage); /*!< in/out: control block */ /********************************************************************//** Determine if a buffer block can be relocated in memory. The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ @@ -1569,13 +1576,16 @@ struct buf_block_struct{ /* @} */ /** @name Hash search fields - These 6 fields may only be modified when we have + These 5 fields may only be modified when we have an x-latch on btr_search_latch AND - we are holding an s-latch or x-latch on buf_block_struct::lock or - we know that buf_block_struct::buf_fix_count == 0. An exception to this is when we init or create a page - in the buffer pool in buf0buf.c. */ + in the buffer pool in buf0buf.c. + + Another exception is that assigning block->index = NULL + is allowed whenever holding an x-latch on btr_search_latch. */ /* @{ */ @@ -1584,21 +1594,21 @@ struct buf_block_struct{ pointers in the adaptive hash index pointing to this frame */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - volatile unsigned is_hashed:1; /*!< TRUE if hash index has - already been built on this - page; note that it does not - guarantee that the index is - complete, though: there may - have been hash collisions, - record deletions, etc. */ unsigned curr_n_fields:10;/*!< prefix length for hash indexing: number of full fields */ unsigned curr_n_bytes:15;/*!< number of bytes in hash indexing */ unsigned curr_left_side:1;/*!< TRUE or FALSE in hash indexing */ - dict_index_t* index; /*!< Index for which the adaptive - hash index has been created. */ - volatile rw_lock_t* btr_search_latch; + dict_index_t* index; /*!< Index for which the + adaptive hash index has been + created, or NULL if the page + does not exist in the + index. Note that it does not + guarantee that the index is + complete, though: there may + have been hash collisions, + record deletions, etc. */ + volatile rw_lock_t* btr_search_latch; /* @} */ # ifdef UNIV_SYNC_DEBUG /** @name Debug fields */ diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic index 98d575075ba..55d89b66375 100644 --- a/storage/xtradb/include/buf0buf.ic +++ b/storage/xtradb/include/buf0buf.ic @@ -444,6 +444,7 @@ buf_page_get_io_fix( case BUF_IO_NONE: case BUF_IO_READ: case BUF_IO_WRITE: + case BUF_IO_PIN: return(io_fix); } ut_error; @@ -494,6 +495,49 @@ buf_block_set_io_fix( buf_page_set_io_fix(&block->page, io_fix); } +/*********************************************************************//** +Makes a block sticky. A sticky block implies that even after we release +the buf_pool->mutex and the block->mutex: +* it cannot be removed from the flush_list +* the block descriptor cannot be relocated +* it cannot be removed from the LRU list +Note that: +* the block can still change its position in the LRU list +* the next and previous pointers can change. */ +UNIV_INLINE +void +buf_page_set_sticky( +/*================*/ + buf_page_t* bpage) /*!< in/out: control block */ +{ +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); +#endif + ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_NONE); + + bpage->io_fix = BUF_IO_PIN; +} + +/*********************************************************************//** +Removes stickiness of a block. */ +UNIV_INLINE +void +buf_page_unset_sticky( +/*==================*/ + buf_page_t* bpage) /*!< in/out: control block */ +{ +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(mutex_own(&buf_pool->LRU_list_mutex)); +#endif + ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_PIN); + + bpage->io_fix = BUF_IO_NONE; +} + /********************************************************************//** Determine if a buffer block can be relocated in memory. The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ diff --git a/storage/xtradb/include/buf0types.h b/storage/xtradb/include/buf0types.h index 156093aad01..d140936a886 100644 --- a/storage/xtradb/include/buf0types.h +++ b/storage/xtradb/include/buf0types.h @@ -57,7 +57,10 @@ enum buf_flush { enum buf_io_fix { BUF_IO_NONE = 0, /**< no pending I/O */ BUF_IO_READ, /**< read pending */ - BUF_IO_WRITE /**< write pending */ + BUF_IO_WRITE, /**< write pending */ + BUF_IO_PIN /**< disallow relocation of + block and its removal of from + the flush_list */ }; /** Parameters of binary buddy system for compressed pages (buf0buddy.h) */ diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 840a9fbb13a..92fdca0db1b 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -34,6 +34,7 @@ Created 10/25/1995 Heikki Tuuri #include "sync0rw.h" #include "ibuf0types.h" #endif /* !UNIV_HOTBACKUP */ +#include "trx0types.h" /** When mysqld is run, the default directory "." is the mysqld datadir, but in the MySQL Embedded Server Library and ibbackup it is not the default @@ -329,18 +330,23 @@ Reads the flushed lsn and arch no fields from a data file at database startup. */ UNIV_INTERN void -fil_read_flushed_lsn_and_arch_log_no( -/*=================================*/ +fil_read_first_page( +/*================*/ os_file_t data_file, /*!< in: open data file */ ibool one_read_already, /*!< in: TRUE if min and max parameters below already contain sensible data */ + ulint* flags, /*!< out: tablespace flags */ #ifdef UNIV_LOG_ARCHIVE - ulint* min_arch_log_no, /*!< in/out: */ - ulint* max_arch_log_no, /*!< in/out: */ + ulint* min_arch_log_no, /*!< out: min of archived + log numbers in data files */ + ulint* max_arch_log_no, /*!< out: max of archived + log numbers in data files */ #endif /* UNIV_LOG_ARCHIVE */ - ib_uint64_t* min_flushed_lsn, /*!< in/out: */ - ib_uint64_t* max_flushed_lsn); /*!< in/out: */ + ib_uint64_t* min_flushed_lsn, /*!< out: min of flushed + lsn values in data files */ + ib_uint64_t* max_flushed_lsn); /*!< out: max of flushed + lsn values in data files */ /*******************************************************************//** Increments the count of pending insert buffer page merges, if space is not being deleted. @@ -474,8 +480,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name); /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx); /*!< in: transaction. This is only used + for IMPORT TABLESPACE, must be NULL + otherwise */ /********************************************************************//** It is possible, though very improbable, that the lsn's in the tablespace to be imported have risen above the current system lsn, if a lengthy purge, ibuf diff --git a/storage/xtradb/include/fsp0fsp.h b/storage/xtradb/include/fsp0fsp.h index 7abd3914eda..d5e235aa870 100644 --- a/storage/xtradb/include/fsp0fsp.h +++ b/storage/xtradb/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -34,6 +34,90 @@ Created 12/18/1995 Heikki Tuuri #include "page0types.h" #include "fsp0types.h" +/* @defgroup fsp_flags InnoDB Tablespace Flag Constants @{ */ + +/** Number of flag bits used to indicate the tablespace page size */ +#define FSP_FLAGS_WIDTH_PAGE_SSIZE 4 +/** Zero relative shift position of the PAGE_SSIZE field */ +#define FSP_FLAGS_POS_PAGE_SSIZE 6 +/** Bit mask of the PAGE_SSIZE field */ +#define FSP_FLAGS_MASK_PAGE_SSIZE \ + ((~(~0 << FSP_FLAGS_WIDTH_PAGE_SSIZE)) \ + << FSP_FLAGS_POS_PAGE_SSIZE) +/** Return the value of the PAGE_SSIZE field */ +#define FSP_FLAGS_GET_PAGE_SSIZE(flags) \ + ((flags & FSP_FLAGS_MASK_PAGE_SSIZE) \ + >> FSP_FLAGS_POS_PAGE_SSIZE) + +/* @} */ + +/* @defgroup Tablespace Header Constants (moved from fsp0fsp.c) @{ */ + +/** Offset of the space header within a file page */ +#define FSP_HEADER_OFFSET FIL_PAGE_DATA + +/* The data structures in files are defined just as byte strings in C */ +typedef byte fsp_header_t; +typedef byte xdes_t; + +/* SPACE HEADER + ============ + +File space header data structure: this data structure is contained in the +first page of a space. The space for this header is reserved in every extent +descriptor page, but used only in the first. */ + +/*-------------------------------------*/ +#define FSP_SPACE_ID 0 /* space id */ +#define FSP_NOT_USED 4 /* this field contained a value up to + which we know that the modifications + in the database have been flushed to + the file space; not used now */ +#define FSP_SIZE 8 /* Current size of the space in + pages */ +#define FSP_FREE_LIMIT 12 /* Minimum page number for which the + free list has not been initialized: + the pages >= this limit are, by + definition, free; note that in a + single-table tablespace where size + < 64 pages, this number is 64, i.e., + we have initialized the space + about the first extent, but have not + physically allocted those pages to the + file */ +#define FSP_SPACE_FLAGS 16 /* fsp_space_t.flags, similar to + dict_table_t::flags */ +#define FSP_FRAG_N_USED 20 /* number of used pages in the + FSP_FREE_FRAG list */ +#define FSP_FREE 24 /* list of free extents */ +#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE) + /* list of partially free extents not + belonging to any segment */ +#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE) + /* list of full extents not belonging + to any segment */ +#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE) + /* 8 bytes which give the first unused + segment id */ +#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where all the segment inode + slots are reserved */ +#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE) + /* list of pages containing segment + headers, where not all the segment + header slots are reserved */ +/*-------------------------------------*/ +/* File space header size */ +#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE) + +#define FSP_FREE_ADD 4 /* this many free extents are added + to the free list from above + FSP_FREE_LIMIT at a time */ +/* @} */ + +/* @} */ + /**********************************************************************//** Initializes the file space system. */ UNIV_INTERN @@ -352,6 +436,18 @@ fseg_print( mtr_t* mtr); /*!< in: mtr */ #endif /* UNIV_BTR_PRINT */ +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags); /*!< in: tablespace flags */ + #ifndef UNIV_NONINL #include "fsp0fsp.ic" #endif diff --git a/storage/xtradb/include/fsp0fsp.ic b/storage/xtradb/include/fsp0fsp.ic index 434c370b527..c92111a9d89 100644 --- a/storage/xtradb/include/fsp0fsp.ic +++ b/storage/xtradb/include/fsp0fsp.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -43,3 +43,31 @@ fsp_descr_page( return(UNIV_UNLIKELY((page_no & (zip_size - 1)) == FSP_XDES_OFFSET)); } +/********************************************************************//** +Extract the page size from tablespace flags. +This feature, storing the page_ssize into the tablespace flags, is added +to InnoDB 5.6.4. This is here only to protect against a crash if a newer +database is opened with this code branch. +@return page size of the tablespace in bytes */ +UNIV_INLINE +ulint +fsp_flags_get_page_size( +/*====================*/ + ulint flags) /*!< in: tablespace flags */ +{ + ulint page_size = 0; + ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); + + /* Convert from a 'log2 minus 9' to a page size in bytes. */ + if (UNIV_UNLIKELY(ssize)) { + page_size = (512 << ssize); + + ut_ad(page_size <= UNIV_PAGE_SIZE); + } else { + /* If the page size was not stored, then it is the + original 16k. */ + page_size = UNIV_PAGE_SIZE; + } + + return(page_size); +} diff --git a/storage/xtradb/include/ha0ha.h b/storage/xtradb/include/ha0ha.h index 3299000bf3c..8bba564d153 100644 --- a/storage/xtradb/include/ha0ha.h +++ b/storage/xtradb/include/ha0ha.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -31,13 +31,14 @@ Created 8/18/1994 Heikki Tuuri #include "hash0hash.h" #include "page0types.h" #include "buf0types.h" +#include "rem0types.h" /*************************************************************//** Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -51,11 +52,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data);/*!< in: new pointer to the data */ + const rec_t* new_data);/*!< in: new pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** Looks for an element when we know the pointer to the data and @@ -114,14 +115,6 @@ chosen to be a slightly bigger prime number. #endif /* UNIV_SYNC_DEBUG */ /*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table); /*!< in, own: hash table */ - -/*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node is inserted. @@ -138,7 +131,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data); /*!< in: data, must not be NULL */ + const rec_t* data); /*!< in: data, must not be NULL */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** @@ -174,7 +167,7 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data); /*!< in: pointer to the data */ + const rec_t* data); /*!< in: pointer to the data */ #ifndef UNIV_HOTBACKUP /*****************************************************************//** Removes from the chain determined by fold all nodes whose data pointer @@ -217,7 +210,7 @@ struct ha_node_struct { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block; /*!< buffer block containing the data, or NULL */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data; /*!< pointer to the data */ + const rec_t* data; /*!< pointer to the data */ ulint fold; /*!< fold value for the data */ }; diff --git a/storage/xtradb/include/ha0ha.ic b/storage/xtradb/include/ha0ha.ic index 734403c4cd9..f224776c134 100644 --- a/storage/xtradb/include/ha0ha.ic +++ b/storage/xtradb/include/ha0ha.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -25,6 +25,7 @@ Created 8/18/1994 Heikki Tuuri #include "ut0rnd.h" #include "mem0mem.h" +#include "btr0types.h" /***********************************************************//** Deletes a hash node. */ @@ -39,10 +40,10 @@ ha_delete_hash_node( Gets a hash node data. @return pointer to the data */ UNIV_INLINE -void* +const rec_t* ha_node_get_data( /*=============*/ - ha_node_t* node) /*!< in: hash chain node */ + const ha_node_t* node) /*!< in: hash chain node */ { return(node->data); } @@ -57,7 +58,7 @@ ha_node_set_data_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG node->block = block; @@ -107,39 +108,10 @@ ha_chain_get_first( /*************************************************************//** Looks for an element in a hash table. -@return pointer to the first hash table node in chain having the fold -number, NULL if not found */ -UNIV_INLINE -ha_node_t* -ha_search( -/*======*/ - hash_table_t* table, /*!< in: hash table */ - ulint fold) /*!< in: folded value of the searched data */ -{ - ha_node_t* node; - - ASSERT_HASH_MUTEX_OWN(table, fold); - - node = ha_chain_get_first(table, fold); - - while (node) { - if (node->fold == fold) { - - return(node); - } - - node = ha_chain_get_next(node); - } - - return(NULL); -} - -/*************************************************************//** -Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -148,6 +120,10 @@ ha_search_and_get_data( ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG +// ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); @@ -172,12 +148,14 @@ ha_search_with_data( /*================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); + node = ha_chain_get_first(table, fold); while (node) { @@ -202,11 +180,15 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG +// ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_search_with_data(table, fold, data); diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h index c1c659e2b70..1b9f9c84225 100644 --- a/storage/xtradb/include/page0page.h +++ b/storage/xtradb/include/page0page.h @@ -893,6 +893,7 @@ page_parse_create( ulint comp, /*!< in: nonzero=compact page format */ buf_block_t* block, /*!< in: block or NULL */ mtr_t* mtr); /*!< in: mtr or NULL */ +#ifndef UNIV_HOTBACKUP /************************************************************//** Prints record contents including the data relevant only in the index page context. */ @@ -902,6 +903,7 @@ page_rec_print( /*===========*/ const rec_t* rec, /*!< in: physical record */ const ulint* offsets);/*!< in: record descriptor */ +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -941,6 +943,8 @@ page_print( in directory */ ulint rn); /*!< in: print rn first and last records in directory */ +# endif /* UNIV_BTR_PRINT */ +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** The following is used to validate a record on a page. This function differs from rec_validate as it can also check the n_owned field and diff --git a/storage/xtradb/include/row0upd.ic b/storage/xtradb/include/row0upd.ic index 11db82f64da..10646241125 100644 --- a/storage/xtradb/include/row0upd.ic +++ b/storage/xtradb/include/row0upd.ic @@ -28,7 +28,6 @@ Created 12/27/1996 Heikki Tuuri # include "trx0trx.h" # include "trx0undo.h" # include "row0row.h" -# include "btr0sea.h" #endif /* !UNIV_HOTBACKUP */ #include "page0zip.h" diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 6f985eacdf3..65b341c0f13 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -288,6 +288,9 @@ extern ibool srv_print_lock_waits; extern ibool srv_print_buf_io; extern ibool srv_print_log_io; extern ibool srv_print_latch_waits; + +extern ulint srv_flush_checkpoint_debug; + #else /* UNIV_DEBUG */ # define srv_print_thread_releases FALSE # define srv_print_lock_waits FALSE diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h index 6420bc5d3bf..971099c91f5 100644 --- a/storage/xtradb/include/sync0rw.h +++ b/storage/xtradb/include/sync0rw.h @@ -543,7 +543,7 @@ mutex. */ UNIV_INTERN void rw_lock_debug_mutex_enter(void); -/*==========================*/ +/*===========================*/ /******************************************************************//** Releases the debug mutex. */ UNIV_INTERN @@ -634,7 +634,8 @@ struct rw_lock_struct { }; #ifdef UNIV_SYNC_DEBUG -/** The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /*!< The thread id of the thread which diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic index a6dfa603c59..3eaa6172631 100644 --- a/storage/xtradb/include/sync0rw.ic +++ b/storage/xtradb/include/sync0rw.ic @@ -406,6 +406,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h index 6440a670f14..f9434ed54be 100644 --- a/storage/xtradb/include/sync0sync.h +++ b/storage/xtradb/include/sync0sync.h @@ -674,7 +674,6 @@ or row lock! */ #define SYNC_LOG_FLUSH_ORDER 156 #define SYNC_RECV 168 #define SYNC_WORK_QUEUE 162 -#define SYNC_SEARCH_SYS_CONF 161 /* for assigning btr_search_enabled */ #define SYNC_SEARCH_SYS 160 /* NOTE that if we have a memory heap that can be extended to the buffer pool, its logical level is diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index a03f7aceafa..eded5c303fa 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -494,6 +494,7 @@ struct trx_struct{ this is set to 1 then registered should also be set to 1. This is used in the XA code */ + unsigned called_commit_ordered:1;/* 1 if innobase_commit_ordered has run. */ /*------------------------------*/ ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */ ulint check_foreigns; /* normally TRUE, but if the user diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 0287ea40509..1a48d68d0d7 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -54,7 +54,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_BUGFIX 8 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 20.1 +#define PERCONA_INNODB_VERSION 24.1 #endif /* The following is the InnoDB version as shown in diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c index d9676707cfd..af0c801a4ec 100644 --- a/storage/xtradb/log/log0log.c +++ b/storage/xtradb/log/log0log.c @@ -1693,10 +1693,13 @@ log_preflush_pool_modified_pages( recv_apply_hashed_log_recs(TRUE); } + retry: n_pages = buf_flush_list(ULINT_MAX, new_oldest); - if (sync) { - buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + if (sync && n_pages != 0) { + //buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + os_thread_sleep(100000); + goto retry; } if (n_pages == ULINT_UNDEFINED) { @@ -2020,6 +2023,13 @@ log_checkpoint( { ib_uint64_t oldest_lsn; +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) { + + return TRUE; + } +#endif + if (recv_recovery_is_on()) { recv_apply_hashed_log_recs(TRUE); } @@ -2124,7 +2134,11 @@ log_make_checkpoint_at( physical write will always be made to log files */ { - /* Preflush pages synchronously */ +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif +/* Preflush pages synchronously */ while (!log_preflush_pool_modified_pages(lsn, TRUE)); @@ -2216,7 +2230,13 @@ log_checkpoint_margin(void) ibool checkpoint_sync; ibool do_checkpoint; ibool success; -loop: + +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif + + loop: sync = FALSE; checkpoint_sync = FALSE; do_checkpoint = FALSE; @@ -2239,13 +2259,15 @@ loop: /* A flush is urgent: we have to do a synchronous preflush */ sync = TRUE; - advance = 2 * (age - log->max_modified_age_sync); + advance = age - log->max_modified_age_sync; } else if (age > log_max_modified_age_async()) { /* A flush is not urgent: we do an asynchronous preflush */ advance = age - log_max_modified_age_async(); + log->check_flush_or_checkpoint = FALSE; } else { advance = 0; + log->check_flush_or_checkpoint = FALSE; } checkpoint_age = log->lsn - log->last_checkpoint_lsn; @@ -2262,9 +2284,9 @@ loop: do_checkpoint = TRUE; - log->check_flush_or_checkpoint = FALSE; + //log->check_flush_or_checkpoint = FALSE; } else { - log->check_flush_or_checkpoint = FALSE; + //log->check_flush_or_checkpoint = FALSE; } mutex_exit(&(log->mutex)); @@ -2272,6 +2294,7 @@ loop: if (advance) { ib_uint64_t new_oldest = oldest_lsn + advance; +retry: success = log_preflush_pool_modified_pages(new_oldest, sync); /* If the flush succeeded, this thread has done its part @@ -2286,7 +2309,7 @@ loop: log->check_flush_or_checkpoint = TRUE; mutex_exit(&(log->mutex)); - goto loop; + goto retry; } } @@ -3164,7 +3187,11 @@ void log_check_margins(void) /*===================*/ { -loop: +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + return; +#endif + loop: log_flush_margin(); log_checkpoint_margin(); diff --git a/storage/xtradb/page/page0page.c b/storage/xtradb/page/page0page.c index 17f6c6bbc36..4858929082a 100644 --- a/storage/xtradb/page/page0page.c +++ b/storage/xtradb/page/page0page.c @@ -215,12 +215,6 @@ page_set_max_trx_id( { page_t* page = buf_block_get_frame(block); #ifndef UNIV_HOTBACKUP - const ibool is_hashed = block->is_hashed; - - if (is_hashed) { - rw_lock_x_lock(btr_search_get_latch(block->index->id)); - } - ut_ad(!mtr || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); #endif /* !UNIV_HOTBACKUP */ @@ -241,12 +235,6 @@ page_set_max_trx_id( } else { mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id); } - -#ifndef UNIV_HOTBACKUP - if (is_hashed) { - rw_lock_x_unlock(btr_search_get_latch(block->index->id)); - } -#endif /* !UNIV_HOTBACKUP */ } /************************************************************//** @@ -1603,13 +1591,14 @@ page_rec_print( " n_owned: %lu; heap_no: %lu; next rec: %lu\n", (ulong) rec_get_n_owned_old(rec), (ulong) rec_get_heap_no_old(rec), - (ulong) rec_get_next_offs(rec, TRUE)); + (ulong) rec_get_next_offs(rec, FALSE)); } page_rec_check(rec); rec_validate(rec, offsets); } +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -1770,6 +1759,7 @@ page_print( page_dir_print(page, dn); page_print_list(block, index, rn); } +# endif /* UNIV_BTR_PRINT */ #endif /* !UNIV_HOTBACKUP */ /***************************************************************//** diff --git a/storage/xtradb/page/page0zip.c b/storage/xtradb/page/page0zip.c index fc9f30ed94e..d4b0dd8339d 100644 --- a/storage/xtradb/page/page0zip.c +++ b/storage/xtradb/page/page0zip.c @@ -4456,7 +4456,7 @@ page_zip_reorganize( #ifndef UNIV_HOTBACKUP temp_block = buf_block_alloc(buf_pool); - btr_search_drop_page_hash_index(block, index); + btr_search_drop_page_hash_index(block); block->check_index_page_at_flush = TRUE; #else /* !UNIV_HOTBACKUP */ ut_ad(block == back_block1); diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index 9bda27e4b1f..adc75bd5760 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/row/row0ins.c @@ -437,11 +437,9 @@ row_ins_cascade_calc_update_vec( dict_table_t* table = foreign->foreign_table; dict_index_t* index = foreign->foreign_index; upd_t* update; - upd_field_t* ufield; dict_table_t* parent_table; dict_index_t* parent_index; upd_t* parent_update; - upd_field_t* parent_ufield; ulint n_fields_updated; ulint parent_field_no; ulint i; @@ -477,13 +475,15 @@ row_ins_cascade_calc_update_vec( dict_index_get_nth_col_no(parent_index, i)); for (j = 0; j < parent_update->n_fields; j++) { - parent_ufield = parent_update->fields + j; + const upd_field_t* parent_ufield + = &parent_update->fields[j]; if (parent_ufield->field_no == parent_field_no) { ulint min_size; const dict_col_t* col; ulint ufield_len; + upd_field_t* ufield; col = dict_index_get_nth_col(index, i); @@ -985,10 +985,9 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } - if ((node->is_delete - && (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)) - || (!node->is_delete - && (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) { + if (node->is_delete + ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) + : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { /* Build the appropriate update vector which sets foreign->n_fields first fields in rec to SQL NULL */ @@ -997,6 +996,8 @@ row_ins_foreign_check_on_constraint( update->info_bits = 0; update->n_fields = foreign->n_fields; + UNIV_MEM_INVALID(update->fields, + update->n_fields * sizeof *update->fields); for (i = 0; i < foreign->n_fields; i++) { upd_field_t* ufield = &update->fields[i]; @@ -1665,7 +1666,7 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; ulint err = DB_SUCCESS; - unsigned allow_duplicates; + ulint allow_duplicates; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -1696,7 +1697,7 @@ row_ins_scan_sec_index_for_duplicate( btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE; + allow_duplicates = thr_get_trx(thr)->duplicates; /* Scan index records and check if there is a duplicate */ @@ -1830,7 +1831,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -1874,7 +1875,7 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index ac424ded6cb..63252ed01b3 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -291,21 +291,21 @@ row_mysql_pad_col( /* space=0x0020 */ pad_end = pad + len; ut_a(!(len % 2)); - do { + while (pad < pad_end) { *pad++ = 0x00; *pad++ = 0x20; - } while (pad < pad_end); + }; break; case 4: /* space=0x00000020 */ pad_end = pad + len; ut_a(!(len % 4)); - do { + while (pad < pad_end) { *pad++ = 0x00; *pad++ = 0x00; *pad++ = 0x00; *pad++ = 0x20; - } while (pad < pad_end); + } break; } } @@ -2736,7 +2736,7 @@ row_import_tablespace_for_mysql( success = fil_open_single_table_tablespace( TRUE, table->space, table->flags == DICT_TF_COMPACT ? 0 : table->flags, - table->name); + table->name, trx); if (success) { table->ibd_file_missing = FALSE; table->tablespace_discarded = FALSE; @@ -4119,6 +4119,7 @@ end: trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; + err = DB_ERROR; goto funct_exit; } diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c index 0c07d75b39a..2a4fc183c92 100644 --- a/storage/xtradb/srv/srv0srv.c +++ b/storage/xtradb/srv/srv0srv.c @@ -446,7 +446,7 @@ UNIV_INTERN ulong srv_ibuf_accel_rate = 100; #define PCT_IBUF_IO(pct) ((ulint) (srv_io_capacity * srv_ibuf_accel_rate * ((double) pct / 10000.0))) UNIV_INTERN ulint srv_checkpoint_age_target = 0; -UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:enable */ +UNIV_INTERN ulint srv_flush_neighbor_pages = 1; /* 0:disable 1:area 2:contiguous */ UNIV_INTERN ulint srv_deprecated_enable_unsafe_group_commit = 0; UNIV_INTERN ulong srv_read_ahead = 3; /* 1: random 2: linear 3: Both */ @@ -471,6 +471,9 @@ UNIV_INTERN ibool srv_print_lock_waits = FALSE; UNIV_INTERN ibool srv_print_buf_io = FALSE; UNIV_INTERN ibool srv_print_log_io = FALSE; UNIV_INTERN ibool srv_print_latch_waits = FALSE; + +UNIV_INTERN ulong srv_flush_checkpoint_debug = 0; + #endif /* UNIV_DEBUG */ UNIV_INTERN ulint srv_n_rows_inserted = 0; @@ -1253,7 +1256,7 @@ retry: static void srv_conc_exit_innodb_timer_based(trx_t* trx) { - (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); + (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); trx->declared_to_be_inside_innodb = FALSE; trx->n_tickets_to_enter_innodb = 0; return; @@ -1475,7 +1478,7 @@ srv_conc_force_enter_innodb( ut_ad(srv_conc_n_threads >= 0); #ifdef HAVE_ATOMIC_BUILTINS if (srv_thread_concurrency_timer_based) { - (void) os_atomic_increment_lint(&srv_conc_n_threads, 1); + (void) os_atomic_increment_lint(&srv_conc_n_threads, 1); trx->declared_to_be_inside_innodb = TRUE; trx->n_tickets_to_enter_innodb = 1; return; @@ -3625,11 +3628,18 @@ retry_flush_batch: PCT_IO(10), IB_ULONGLONG_MAX); } - srv_main_thread_op_info = "making checkpoint"; +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug != 1) { +#endif - /* Make a new checkpoint about once in 10 seconds */ + srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(TRUE, FALSE, TRUE); + /* Make a new checkpoint about once in 10 seconds */ + + log_checkpoint(TRUE, FALSE, TRUE); +#ifdef UNIV_DEBUG + } +#endif srv_main_thread_op_info = "reserving kernel mutex"; @@ -3708,6 +3718,10 @@ background_loop: } mutex_exit(&kernel_mutex); +#ifdef UNIV_DEBUG + if (srv_flush_checkpoint_debug == 1) + goto skip_flush; +#endif flush_loop: srv_main_thread_op_info = "flushing buffer pool pages"; srv_main_flush_loops++; @@ -3748,6 +3762,9 @@ flush_loop: goto flush_loop; } +#ifdef UNIV_DEBUG +skip_flush: +#endif srv_main_thread_op_info = "reserving kernel mutex"; mutex_enter(&kernel_mutex); diff --git a/storage/xtradb/srv/srv0start.c b/storage/xtradb/srv/srv0start.c index 4083eb75b83..99916610c21 100644 --- a/storage/xtradb/srv/srv0start.c +++ b/storage/xtradb/srv/srv0start.c @@ -735,6 +735,7 @@ open_or_create_data_files( ibool one_created = FALSE; ulint size; ulint size_high; + ulint flags; ulint rounded_size_pages; char name[10000]; @@ -917,12 +918,31 @@ open_or_create_data_files( return(DB_ERROR); } skip_size_check: - fil_read_flushed_lsn_and_arch_log_no( - files[i], one_opened, + fil_read_first_page( + files[i], one_opened, &flags, #ifdef UNIV_LOG_ARCHIVE min_arch_log_no, max_arch_log_no, #endif /* UNIV_LOG_ARCHIVE */ min_flushed_lsn, max_flushed_lsn); + + if (UNIV_PAGE_SIZE + != fsp_flags_get_page_size(flags)) { + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: data file %s" + " uses page size %lu,\n", + name, + fsp_flags_get_page_size(flags)); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: but the only supported" + " page size in this release is=%lu\n", + (ulong) UNIV_PAGE_SIZE); + + return(DB_ERROR); + } + one_opened = TRUE; } else { /* We created the data file and now write it full of @@ -1060,8 +1080,8 @@ skip_size_check: (ulong) TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 9); } - fil_read_flushed_lsn_and_arch_log_no( - files[i], one_opened, + fil_read_first_page( + files[i], one_opened, &flags, #ifdef UNIV_LOG_ARCHIVE min_arch_log_no, max_arch_log_no, #endif /* UNIV_LOG_ARCHIVE */ diff --git a/storage/xtradb/sync/sync0rw.c b/storage/xtradb/sync/sync0rw.c index e561ae319a5..8884812d84d 100644 --- a/storage/xtradb/sync/sync0rw.c +++ b/storage/xtradb/sync/sync0rw.c @@ -623,6 +623,9 @@ rw_lock_x_lock_func( ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ i = 0; @@ -710,7 +713,7 @@ mutex. */ UNIV_INTERN void rw_lock_debug_mutex_enter(void) -/*==========================*/ +/*===========================*/ { loop: if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) { @@ -937,11 +940,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_exit(&(lock->mutex)); @@ -985,11 +990,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } diff --git a/storage/xtradb/sync/sync0sync.c b/storage/xtradb/sync/sync0sync.c index b38e2183b0f..d2c4617d65c 100644 --- a/storage/xtradb/sync/sync0sync.c +++ b/storage/xtradb/sync/sync0sync.c @@ -1222,7 +1222,6 @@ sync_thread_add_level( case SYNC_OUTER_ANY_LATCH: case SYNC_FILE_FORMAT_TAG: case SYNC_DOUBLEWRITE: - case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: case SYNC_KERNEL: case SYNC_IBUF_BITMAP_MUTEX: |