Commit dacd97b4 authored by Vasil Dimov's avatar Vasil Dimov

Merge mysql-5.1-innodb -> mysql-5.1-bugteam

parents c3246242 4bb4eb80
This diff is collapsed.
...@@ -83,8 +83,6 @@ test t8 Compact ...@@ -83,8 +83,6 @@ test t8 Compact
test t9 Compact test t9 Compact
drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14; drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14;
alter table t1 key_block_size=0; alter table t1 key_block_size=0;
Warnings:
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
alter table t1 row_format=dynamic; alter table t1 row_format=dynamic;
SELECT table_schema, table_name, row_format SELECT table_schema, table_name, row_format
FROM information_schema.tables WHERE engine='innodb'; FROM information_schema.tables WHERE engine='innodb';
...@@ -190,16 +188,9 @@ set global innodb_file_per_table = on; ...@@ -190,16 +188,9 @@ set global innodb_file_per_table = on;
set global innodb_file_format = `1`; set global innodb_file_format = `1`;
set innodb_strict_mode = off; set innodb_strict_mode = off;
create table t1 (id int primary key) engine = innodb key_block_size = 0; create table t1 (id int primary key) engine = innodb key_block_size = 0;
Warnings:
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
drop table t1; drop table t1;
set innodb_strict_mode = on; set innodb_strict_mode = on;
create table t1 (id int primary key) engine = innodb key_block_size = 0; create table t1 (id int primary key) engine = innodb key_block_size = 0;
ERROR HY000: Can't create table 'test.t1' (errno: 1478)
show warnings;
Level Code Message
Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16]
Error 1005 Can't create table 'test.t1' (errno: 1478)
create table t2 (id int primary key) engine = innodb key_block_size = 9; create table t2 (id int primary key) engine = innodb key_block_size = 9;
ERROR HY000: Can't create table 'test.t2' (errno: 1478) ERROR HY000: Can't create table 'test.t2' (errno: 1478)
show warnings; show warnings;
...@@ -218,6 +209,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant; ...@@ -218,6 +209,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant;
SELECT table_schema, table_name, row_format SELECT table_schema, table_name, row_format
FROM information_schema.tables WHERE engine='innodb'; FROM information_schema.tables WHERE engine='innodb';
table_schema table_name row_format table_schema table_name row_format
test t1 Compact
test t10 Compact test t10 Compact
test t11 Redundant test t11 Redundant
test t3 Compressed test t3 Compressed
...@@ -227,7 +219,7 @@ test t6 Compressed ...@@ -227,7 +219,7 @@ test t6 Compressed
test t7 Compressed test t7 Compressed
test t8 Compressed test t8 Compressed
test t9 Dynamic test t9 Dynamic
drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; drop table t1, t3, t4, t5, t6, t7, t8, t9, t10, t11;
create table t1 (id int primary key) engine = innodb create table t1 (id int primary key) engine = innodb
key_block_size = 8 row_format = compressed; key_block_size = 8 row_format = compressed;
create table t2 (id int primary key) engine = innodb create table t2 (id int primary key) engine = innodb
...@@ -253,16 +245,12 @@ Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. ...@@ -253,16 +245,12 @@ Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
Error 1005 Can't create table 'test.t4' (errno: 1478) Error 1005 Can't create table 'test.t4' (errno: 1478)
create table t5 (id int primary key) engine = innodb create table t5 (id int primary key) engine = innodb
key_block_size = 8 row_format = default; key_block_size = 8 row_format = default;
ERROR HY000: Can't create table 'test.t5' (errno: 1478)
show warnings;
Level Code Message
Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
Error 1005 Can't create table 'test.t5' (errno: 1478)
SELECT table_schema, table_name, row_format SELECT table_schema, table_name, row_format
FROM information_schema.tables WHERE engine='innodb'; FROM information_schema.tables WHERE engine='innodb';
table_schema table_name row_format table_schema table_name row_format
test t1 Compressed test t1 Compressed
drop table t1; test t5 Compressed
drop table t1, t5;
create table t1 (id int primary key) engine = innodb create table t1 (id int primary key) engine = innodb
key_block_size = 9 row_format = redundant; key_block_size = 9 row_format = redundant;
ERROR HY000: Can't create table 'test.t1' (errno: 1478) ERROR HY000: Can't create table 'test.t1' (errno: 1478)
......
CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY,
FOREIGN KEY (c2) REFERENCES bug53046_1(c1)
ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;
INSERT INTO bug53046_1 VALUES (1);
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
INSERT INTO bug53046_2 VALUES (1), (2);
ANALYZE TABLE bug53046_1;
Table Op Msg_type Msg_text
test.bug53046_1 analyze status OK
SHOW TABLE STATUS LIKE 'bug53046_1';
UPDATE bug53046_1 SET c1 = c1 - 1;
DELETE FROM bug53046_1;
INSERT INTO bug53046_1 VALUES (1);
INSERT INTO bug53046_2 VALUES (1);
TRUNCATE TABLE bug53046_2;
DROP TABLE bug53046_2;
DROP TABLE bug53046_1;
SET GLOBAL innodb_file_format='Barracuda';
SET GLOBAL innodb_file_per_table=ON;
SET innodb_strict_mode=ON;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Compressed row_format=COMPRESSED
ALTER TABLE bug54679 ADD COLUMN b INT;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Compressed row_format=COMPRESSED
DROP TABLE bug54679;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Compact
ALTER TABLE bug54679 KEY_BLOCK_SIZE=1;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Compressed KEY_BLOCK_SIZE=1
ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT;
ERROR HY000: Can't create table '#sql-temporary' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE.
Error 1005 Can't create table '#sql-temporary' (errno: 1478)
DROP TABLE bug54679;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Redundant row_format=REDUNDANT
ALTER TABLE bug54679 KEY_BLOCK_SIZE=2;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
TABLE_NAME ROW_FORMAT CREATE_OPTIONS
bug54679 Compressed row_format=REDUNDANT KEY_BLOCK_SIZE=2
SET GLOBAL innodb_file_format=Antelope;
ALTER TABLE bug54679 KEY_BLOCK_SIZE=4;
ERROR HY000: Can't create table '#sql-temporary' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
Error 1005 Can't create table '#sql-temporary' (errno: 1478)
ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC;
ERROR HY000: Can't create table '#sql-temporary' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.
Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
Error 1005 Can't create table '#sql-temporary' (errno: 1478)
DROP TABLE bug54679;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
ERROR HY000: Can't create table 'test.bug54679' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.
Error 1005 Can't create table 'test.bug54679' (errno: 1478)
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB;
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=OFF;
ALTER TABLE bug54679 KEY_BLOCK_SIZE=4;
ERROR HY000: Can't create table '#sql-temporary' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
Error 1005 Can't create table '#sql-temporary' (errno: 1478)
ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC;
ERROR HY000: Can't create table '#sql-temporary' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
Error 1005 Can't create table '#sql-temporary' (errno: 1478)
DROP TABLE bug54679;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
ERROR HY000: Can't create table 'test.bug54679' (errno: 1478)
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
Error 1005 Can't create table 'test.bug54679' (errno: 1478)
SET GLOBAL innodb_file_per_table=ON;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
DROP TABLE bug54679;
SET GLOBAL innodb_file_format=Antelope;
SET GLOBAL innodb_file_format_check=Antelope;
SET GLOBAL innodb_file_per_table=0;
This diff is collapsed.
...@@ -173,9 +173,7 @@ set innodb_strict_mode = on; ...@@ -173,9 +173,7 @@ set innodb_strict_mode = on;
#Test different values of KEY_BLOCK_SIZE #Test different values of KEY_BLOCK_SIZE
--error ER_CANT_CREATE_TABLE
create table t1 (id int primary key) engine = innodb key_block_size = 0; create table t1 (id int primary key) engine = innodb key_block_size = 0;
show warnings;
--error ER_CANT_CREATE_TABLE --error ER_CANT_CREATE_TABLE
create table t2 (id int primary key) engine = innodb key_block_size = 9; create table t2 (id int primary key) engine = innodb key_block_size = 9;
...@@ -196,7 +194,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant; ...@@ -196,7 +194,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant;
SELECT table_schema, table_name, row_format SELECT table_schema, table_name, row_format
FROM information_schema.tables WHERE engine='innodb'; FROM information_schema.tables WHERE engine='innodb';
drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; drop table t1, t3, t4, t5, t6, t7, t8, t9, t10, t11;
#test different values of ROW_FORMAT with KEY_BLOCK_SIZE #test different values of ROW_FORMAT with KEY_BLOCK_SIZE
create table t1 (id int primary key) engine = innodb create table t1 (id int primary key) engine = innodb
...@@ -217,14 +215,12 @@ create table t4 (id int primary key) engine = innodb ...@@ -217,14 +215,12 @@ create table t4 (id int primary key) engine = innodb
key_block_size = 8 row_format = dynamic; key_block_size = 8 row_format = dynamic;
show warnings; show warnings;
--error ER_CANT_CREATE_TABLE
create table t5 (id int primary key) engine = innodb create table t5 (id int primary key) engine = innodb
key_block_size = 8 row_format = default; key_block_size = 8 row_format = default;
show warnings;
SELECT table_schema, table_name, row_format SELECT table_schema, table_name, row_format
FROM information_schema.tables WHERE engine='innodb'; FROM information_schema.tables WHERE engine='innodb';
drop table t1; drop table t1, t5;
#test multiple errors #test multiple errors
--error ER_CANT_CREATE_TABLE --error ER_CANT_CREATE_TABLE
......
#
# http://bugs.mysql.com/53046
# dict_update_statistics_low can still be run concurrently on same table
#
# This is a symbolic test, it would not fail if the bug is present.
# Rather those SQL commands have been used during manual testing under
# UNIV_DEBUG & UNIV_SYNC_DEBUG to test all changed codepaths for locking
# correctness.
#
-- source include/have_innodb_plugin.inc
CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY,
FOREIGN KEY (c2) REFERENCES bug53046_1(c1)
ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;
INSERT INTO bug53046_1 VALUES (1);
let $i = 5;
while ($i) {
eval INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
FROM bug53046_1;
dec $i;
}
INSERT INTO bug53046_2 VALUES (1), (2);
# CREATE TABLE innodb_table_monitor (a int) ENGINE=INNODB;
# wait more than 1 minute and observe the mysqld output
# DROP TABLE innodb_table_monitor;
ANALYZE TABLE bug53046_1;
# this prints create time and other nondeterministic data
-- disable_result_log
SHOW TABLE STATUS LIKE 'bug53046_1';
-- enable_result_log
UPDATE bug53046_1 SET c1 = c1 - 1;
DELETE FROM bug53046_1;
INSERT INTO bug53046_1 VALUES (1);
INSERT INTO bug53046_2 VALUES (1);
TRUNCATE TABLE bug53046_2;
DROP TABLE bug53046_2;
DROP TABLE bug53046_1;
# Test Bug #54679 alter table causes compressed row_format to revert to compact
--source include/have_innodb_plugin.inc
let $file_format=`select @@innodb_file_format`;
let $file_format_check=`select @@innodb_file_format_check`;
let $file_per_table=`select @@innodb_file_per_table`;
SET GLOBAL innodb_file_format='Barracuda';
SET GLOBAL innodb_file_per_table=ON;
SET innodb_strict_mode=ON;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
# The ROW_FORMAT of the table should be preserved when it is not specified
# in ALTER TABLE.
ALTER TABLE bug54679 ADD COLUMN b INT;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
DROP TABLE bug54679;
# Check that the ROW_FORMAT conversion to/from COMPRESSED works.
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
# KEY_BLOCK_SIZE implies COMPRESSED.
ALTER TABLE bug54679 KEY_BLOCK_SIZE=1;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
DROP TABLE bug54679;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
ALTER TABLE bug54679 KEY_BLOCK_SIZE=2;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables
WHERE TABLE_NAME='bug54679';
# This prevents other than REDUNDANT or COMPACT ROW_FORMAT for new tables.
SET GLOBAL innodb_file_format=Antelope;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug54679 KEY_BLOCK_SIZE=4;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
DROP TABLE bug54679;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB;
SET GLOBAL innodb_file_format=Barracuda;
# This will prevent ROW_FORMAT=COMPRESSED, because the system tablespace
# cannot be compressed.
SET GLOBAL innodb_file_per_table=OFF;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug54679 KEY_BLOCK_SIZE=4;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
DROP TABLE bug54679;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_CANT_CREATE_TABLE
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
SHOW WARNINGS;
SET GLOBAL innodb_file_per_table=ON;
CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
DROP TABLE bug54679;
EVAL SET GLOBAL innodb_file_format=$file_format;
EVAL SET GLOBAL innodb_file_format_check=$file_format_check;
EVAL SET GLOBAL innodb_file_per_table=$file_per_table;
#
# Bug#56632: ALTER TABLE implicitly changes ROW_FORMAT to COMPRESSED
# http://bugs.mysql.com/56632
#
# Innodb automatically uses compressed mode when the KEY_BLOCK_SIZE
# parameter is used, except if the ROW_FORMAT is also specified, in
# which case the KEY_BLOCK_SIZE is ignored and a warning is shown.
# But Innodb was getting confused when neither of those parameters
# was used on the ALTER statement after they were both used on the
# CREATE.
#
# This will test the results of all 4 combinations of these two
# parameters of the CREATE and ALTER.
#
# Tests 1-5 use INNODB_STRICT_MODE=1 which returns an error
# if there is anything wrong with the statement.
#
# 1) CREATE with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1, ALTER with neither.
# Result; CREATE; fails with error ER_CANT_CREATE_TABLE
# 2) CREATE with ROW_FORMAT=COMPACT, ALTER with KEY_BLOCK_SIZE=1
# Result; CREATE succeeds,
# ALTER quietly converts ROW_FORMAT to compressed.
# 3) CREATE with KEY_BLOCK_SIZE=1, ALTER with ROW_FORMAT=COMPACT
# Result; CREATE quietly converts ROW_FORMAT to compressed,
# ALTER fails with error ER_CANT_CREATE_TABLE.
# 4) CREATE with neither, ALTER with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1
# Result; CREATE succeeds,
# ALTER; fails with error ER_CANT_CREATE_TABLE
# 5) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither.
# Result; CREATE; fails with error ER_CANT_CREATE_TABLE
#
# Tests 6-11 use INNODB_STRICT_MODE=0 which automatically makes
# adjustments if the prameters are incompatible.
#
# 6) CREATE with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1, ALTER with neither.
# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE is ignored.
# ALTER succeeds, no warnings.
# 7) CREATE with ROW_FORMAT=COMPACT, ALTER with KEY_BLOCK_SIZE=1
# Result; CREATE succeeds,
# ALTER quietly converts ROW_FORMAT to compressed.
# 8) CREATE with KEY_BLOCK_SIZE=1, ALTER with ROW_FORMAT=COMPACT
# Result; CREATE quietly converts ROW_FORMAT to compressed,
# ALTER succeeds, warns that KEY_BLOCK_SIZE is ignored.
# 9) CREATE with neither, ALTER with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1
# Result; CREATE succeeds,
# ALTER succeeds, warns that KEY_BLOCK_SIZE is ignored.
# 10) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither.
# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored.
# ALTER succeeds, warns that KEY_BLOCK_SIZE=3 is ignored.
# 11) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with ROW_FORMAT=COMPACT.
# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored.
# ALTER succeeds, warns that KEY_BLOCK_SIZE=3 is ignored.
# 12) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with KEY_BLOCK_SIZE=1.
# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored.
# ALTER succeeds, quietly converts ROW_FORMAT to compressed.
-- source include/have_innodb_plugin.inc
SET storage_engine=InnoDB;
--disable_query_log
# These values can change during the test
LET $innodb_file_format_orig=`select @@innodb_file_format`;
LET $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`;
LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`;
--enable_query_log
SET GLOBAL innodb_file_format=`Barracuda`;
SET GLOBAL innodb_file_per_table=ON;
# Innodb strict mode will cause an error on the CREATE or ALTER when;
# 1. both ROW_FORMAT=COMPACT and KEY_BLOCK_SIZE=1,
# 2. KEY_BLOCK_SIZE is not a valid number (0,1,2,4,8,16).
# With innodb_strict_mode = OFF, These errors are corrected
# and just a warning is returned.
SET SESSION innodb_strict_mode = ON;
--echo # Test 1) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither
DROP TABLE IF EXISTS bug56632;
--error ER_CANT_CREATE_TABLE
CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
--echo # Test 2) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 3) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--disable_result_log
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug56632 ROW_FORMAT=COMPACT;
--enable_result_log
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 4) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT );
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--disable_result_log
--error ER_CANT_CREATE_TABLE
ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1;
--enable_result_log
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 5) CREATE with KEY_BLOCK_SIZE=3 (invalid).
DROP TABLE IF EXISTS bug56632;
--error ER_CANT_CREATE_TABLE
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3;
SHOW WARNINGS;
SET SESSION innodb_strict_mode = OFF;
--echo # Test 6) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 ADD COLUMN f1 INT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 7) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 8) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 ROW_FORMAT=COMPACT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 9) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT );
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 10) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither.
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 ADD COLUMN f1 INT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 11) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with ROW_FORMAT=COMPACT.
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 ROW_FORMAT=COMPACT;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Test 12) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with KEY_BLOCK_SIZE=1.
DROP TABLE IF EXISTS bug56632;
CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
ALTER TABLE bug56632 KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
SHOW CREATE TABLE bug56632;
SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632';
--echo # Cleanup
DROP TABLE IF EXISTS bug56632;
--disable_query_log
EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig;
EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig;
EVAL SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig;
EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig;
--enable_query_log
...@@ -1247,6 +1247,23 @@ innobase_start_or_create_for_mysql(void) ...@@ -1247,6 +1247,23 @@ innobase_start_or_create_for_mysql(void)
fil_init(srv_max_n_open_files); fil_init(srv_max_n_open_files);
/* Print time to initialize the buffer pool */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Initializing buffer pool, size =");
if (srv_pool_size * UNIV_PAGE_SIZE >= 1024 * 1024 * 1024) {
fprintf(stderr,
" %.1fG\n",
((double) (srv_pool_size * UNIV_PAGE_SIZE))
/ (1024 * 1024 * 1024));
} else {
fprintf(stderr,
" %.1fM\n",
((double) (srv_pool_size * UNIV_PAGE_SIZE))
/ (1024 * 1024));
}
if (srv_use_awe) { if (srv_use_awe) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Using AWE: Memory window is %lu MB" "InnoDB: Using AWE: Memory window is %lu MB"
...@@ -1267,6 +1284,8 @@ innobase_start_or_create_for_mysql(void) ...@@ -1267,6 +1284,8 @@ innobase_start_or_create_for_mysql(void)
srv_pool_size); srv_pool_size);
} }
ut_print_timestamp(stderr);
if (ret == NULL) { if (ret == NULL) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Fatal error: cannot allocate the memory" "InnoDB: Fatal error: cannot allocate the memory"
...@@ -1275,6 +1294,9 @@ innobase_start_or_create_for_mysql(void) ...@@ -1275,6 +1294,9 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR); return(DB_ERROR);
} }
fprintf(stderr,
" InnoDB: Completed initialization of buffer pool\n");
fsp_init(); fsp_init();
log_init(); log_init();
......
...@@ -888,7 +888,7 @@ rw_lock_debug_print( ...@@ -888,7 +888,7 @@ rw_lock_debug_print(
rwt = info->lock_type; rwt = info->lock_type;
fprintf(stderr, "Locked: thread %ld file %s line %ld ", fprintf(stderr, "Locked: thread %lu file %s line %lu ",
(ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) os_thread_pf(info->thread_id), info->file_name,
(ulong) info->line); (ulong) info->line);
if (rwt == RW_LOCK_SHARED) { if (rwt == RW_LOCK_SHARED) {
......
2010-11-11 The InnoDB Team
* thr/thr0loc.c, trx/trx0i_s.c:
Fix Bug#57802 Empty ASSERTION parameter passed to the HASH_SEARCH macro
2010-11-10 The InnoDB Team
* dict/dict0dict.c, handler/handler0alter.cc, include/dict0dict.h
row/row0merge.c:
Fix Bug#55084 InnoDB crash and corruption after ALTER TABLE
2010-11-10 The InnoDB Team
* srv/srv0start.c:
Fix Bug#48026 Log start and end of InnoDB buffer pool
initialization to the error log
2010-11-03 The InnoDB Team
* include/btr0btr.h, include/btr0btr.ic, dict/dict0crea.c:
Fix Bug#57947 InnoDB diagnostics shows btr_block_get calls
instead of real callers
2010-11-03 The InnoDB Team
* fil/fil0fil.c, fsp/fsp0fsp.c, handler/ha_innodb.cc,
include/fil0fil.h, include/univ.i:
Fix Bug #54538 - use of exclusive innodb dictionary lock limits
performance.
2010-11-02 The InnoDB Team
* btr/btr0cur.c, dict/dict0dict.c, dict/dict0load.c,
handler/ha_innodb.cc, include/dict0dict.h, row/row0mysql.c,
innodb_bug53046.result, innodb_bug53046.test:
Fix Bug#53046 dict_update_statistics_low can still be run
concurrently on same table
2010-11-02 The InnoDB Team
* row/row0sel.c:
Fix Bug#57799 READ UNCOMMITTED access failure of off-page
DYNAMIC or COMPRESSED columns again
2010-10-24 The InnoDB Team 2010-10-24 The InnoDB Team
* row/row0mysql.c * row/row0mysql.c
Fix Bug #57700 Latching order violation in Fix Bug#57700 Latching order violation in
row_truncate_table_for_mysql() row_truncate_table_for_mysql()
2010-10-20 The InnoDB Team 2010-10-20 The InnoDB Team
* dict/dict0load.c * dict/dict0load.c
Fix Bug #57616 Sig 11 in dict_load_table() when failed to load Fix Bug#57616 Sig 11 in dict_load_table() when failed to load
index or foreign key index or foreign key
2010-10-19 The InnoDB Team 2010-10-19 The InnoDB Team
...@@ -17,7 +60,7 @@ ...@@ -17,7 +60,7 @@
include/ibuf0ibuf.h, include/row0mysql.h, include/ibuf0ibuf.h, include/row0mysql.h,
row/row0mysql.c, row/row0sel.c, row/row0mysql.c, row/row0sel.c,
innodb_bug56680.test, innodb_bug56680.result: innodb_bug56680.test, innodb_bug56680.result:
Fix Bug #56680 InnoDB may return wrong results from a Fix Bug#56680 InnoDB may return wrong results from a
case-insensitive covering index case-insensitive covering index
2010-10-18 The InnoDB Team 2010-10-18 The InnoDB Team
...@@ -65,7 +108,7 @@ ...@@ -65,7 +108,7 @@
2010-08-03 The InnoDB Team 2010-08-03 The InnoDB Team
* include/dict0dict.h, include/dict0dict.ic, row/row0mysql.c: * include/dict0dict.h, include/dict0dict.ic, row/row0mysql.c:
Fix bug #54678, InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock Fix Bug#54678 InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
2010-08-03 The InnoDB Team 2010-08-03 The InnoDB Team
...@@ -139,7 +182,7 @@ ...@@ -139,7 +182,7 @@
* dict/dict0load.c, fil/fil0fil.c: * dict/dict0load.c, fil/fil0fil.c:
Fix Bug#54658: InnoDB: Warning: allocated tablespace %lu, Fix Bug#54658: InnoDB: Warning: allocated tablespace %lu,
old maximum was 0 (introduced in Bug #53578 fix) old maximum was 0 (introduced in Bug#53578 fix)
2010-06-16 The InnoDB Team 2010-06-16 The InnoDB Team
......
...@@ -953,7 +953,7 @@ btr_cur_ins_lock_and_undo( ...@@ -953,7 +953,7 @@ btr_cur_ins_lock_and_undo(
not zero, the parameters index and thr not zero, the parameters index and thr
should be specified */ should be specified */
btr_cur_t* cursor, /*!< in: cursor on page after which to insert */ btr_cur_t* cursor, /*!< in: cursor on page after which to insert */
const dtuple_t* entry, /*!< in: entry to insert */ dtuple_t* entry, /*!< in/out: entry to insert */
que_thr_t* thr, /*!< in: query thread or NULL */ que_thr_t* thr, /*!< in: query thread or NULL */
mtr_t* mtr, /*!< in/out: mini-transaction */ mtr_t* mtr, /*!< in/out: mini-transaction */
ibool* inherit)/*!< out: TRUE if the inserted new record maybe ibool* inherit)/*!< out: TRUE if the inserted new record maybe
...@@ -3355,8 +3355,6 @@ btr_estimate_number_of_different_key_vals( ...@@ -3355,8 +3355,6 @@ btr_estimate_number_of_different_key_vals(
also the pages used for external storage of fields (those pages are also the pages used for external storage of fields (those pages are
included in index->stat_n_leaf_pages) */ included in index->stat_n_leaf_pages) */
dict_index_stat_mutex_enter(index);
for (j = 0; j <= n_cols; j++) { for (j = 0; j <= n_cols; j++) {
index->stat_n_diff_key_vals[j] index->stat_n_diff_key_vals[j]
= ((n_diff[j] = ((n_diff[j]
...@@ -3386,8 +3384,6 @@ btr_estimate_number_of_different_key_vals( ...@@ -3386,8 +3384,6 @@ btr_estimate_number_of_different_key_vals(
index->stat_n_diff_key_vals[j] += add_on; index->stat_n_diff_key_vals[j] += add_on;
} }
dict_index_stat_mutex_exit(index);
mem_free(n_diff); mem_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
...@@ -3794,7 +3790,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to ...@@ -3794,7 +3790,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand. them in rec. The extern flags in rec will have to be set beforehand.
The fields are stored on pages allocated from leaf node The fields are stored on pages allocated from leaf node
file segment of the index tree. file segment of the index tree.
@return DB_SUCCESS or error */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN UNIV_INTERN
ulint ulint
btr_store_big_rec_extern_fields( btr_store_big_rec_extern_fields(
......
...@@ -1710,9 +1710,9 @@ buf_flush_validate_low(void) ...@@ -1710,9 +1710,9 @@ buf_flush_validate_low(void)
ut_a(om > 0); ut_a(om > 0);
if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) {
buf_page_t* rpage;
ut_a(rnode); ut_a(rnode);
buf_page_t* rpage = *rbt_value(buf_page_t*, rpage = *rbt_value(buf_page_t*, rnode);
rnode);
ut_a(rpage); ut_a(rpage);
ut_a(rpage == bpage); ut_a(rpage == bpage);
rnode = rbt_next(buf_pool->flush_rbt, rnode); rnode = rbt_next(buf_pool->flush_rbt, rnode);
......
...@@ -828,7 +828,7 @@ dict_truncate_index_tree( ...@@ -828,7 +828,7 @@ dict_truncate_index_tree(
appropriate field in the SYS_INDEXES record: this mini-transaction appropriate field in the SYS_INDEXES record: this mini-transaction
marks the B-tree totally truncated */ marks the B-tree totally truncated */
btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
btr_free_root(space, zip_size, root_page_no, mtr); btr_free_root(space, zip_size, root_page_no, mtr);
create: create:
......
...@@ -80,9 +80,18 @@ UNIV_INTERN rw_lock_t dict_operation_lock; ...@@ -80,9 +80,18 @@ UNIV_INTERN rw_lock_t dict_operation_lock;
/** Identifies generated InnoDB foreign key names */ /** Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_"; static char dict_ibfk[] = "_ibfk_";
/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */ /** array of rw locks protecting
#define DICT_INDEX_STAT_MUTEX_SIZE 32 dict_table_t::stat_initialized
static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE]; dict_table_t::stat_n_rows (*)
dict_table_t::stat_clustered_index_size
dict_table_t::stat_sum_of_other_index_sizes
dict_table_t::stat_modified_counter (*)
dict_table_t::indexes*::stat_n_diff_key_vals[]
dict_table_t::indexes*::stat_index_size
dict_table_t::indexes*::stat_n_leaf_pages
(*) those are not always protected for performance reasons */
#define DICT_TABLE_STATS_LATCHES_SIZE 64
static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
/*******************************************************************//** /*******************************************************************//**
Tries to find column names for the index and sets the col field of the Tries to find column names for the index and sets the col field of the
...@@ -243,43 +252,65 @@ dict_mutex_exit_for_mysql(void) ...@@ -243,43 +252,65 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
} }
/** Get the mutex that protects index->stat_n_diff_key_vals[] */ /** Get the latch that protects the stats of a given table */
#define GET_INDEX_STAT_MUTEX(index) \ #define GET_TABLE_STATS_LATCH(table) \
(&dict_index_stat_mutex[ut_fold_dulint(index->id) \ (&dict_table_stats_latches[ut_fold_dulint(table->id) \
% DICT_INDEX_STAT_MUTEX_SIZE]) % DICT_TABLE_STATS_LATCHES_SIZE])
/**********************************************************************//** /**********************************************************************//**
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. Lock the appropriate latch to protect a given table's statistics.
index->id is used to pick the right mutex and it should not change table->id is used to pick the corresponding latch from a global array of
before dict_index_stat_mutex_exit() is called on this index. */ latches. */
UNIV_INTERN UNIV_INTERN
void void
dict_index_stat_mutex_enter( dict_table_stats_lock(
/*========================*/ /*==================*/
const dict_index_t* index) /*!< in: index */ const dict_table_t* table, /*!< in: table */
ulint latch_mode) /*!< in: RW_S_LATCH or
RW_X_LATCH */
{ {
ut_ad(index != NULL); ut_ad(table != NULL);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->cached);
ut_ad(!index->to_be_dropped);
mutex_enter(GET_INDEX_STAT_MUTEX(index)); switch (latch_mode) {
case RW_S_LATCH:
rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
break;
case RW_X_LATCH:
rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
break;
case RW_NO_LATCH:
/* fall through */
default:
ut_error;
}
} }
/**********************************************************************//** /**********************************************************************//**
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ Unlock the latch that has been locked by dict_table_stats_lock() */
UNIV_INTERN UNIV_INTERN
void void
dict_index_stat_mutex_exit( dict_table_stats_unlock(
/*=======================*/ /*====================*/
const dict_index_t* index) /*!< in: index */ const dict_table_t* table, /*!< in: table */
ulint latch_mode) /*!< in: RW_S_LATCH or
RW_X_LATCH */
{ {
ut_ad(index != NULL); ut_ad(table != NULL);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(index->cached);
ut_ad(!index->to_be_dropped);
mutex_exit(GET_INDEX_STAT_MUTEX(index)); switch (latch_mode) {
case RW_S_LATCH:
rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
break;
case RW_X_LATCH:
rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
break;
case RW_NO_LATCH:
/* fall through */
default:
ut_error;
}
} }
/********************************************************************//** /********************************************************************//**
...@@ -668,8 +699,8 @@ dict_init(void) ...@@ -668,8 +699,8 @@ dict_init(void)
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH); mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE); rw_lock_create(&dict_table_stats_latches[i], SYNC_INDEX_TREE);
} }
} }
...@@ -700,12 +731,11 @@ dict_table_get( ...@@ -700,12 +731,11 @@ dict_table_get(
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
if (table != NULL) { if (table != NULL) {
if (!table->stat_initialized) { /* If table->ibd_file_missing == TRUE, this will
/* If table->ibd_file_missing == TRUE, this will print an error message and return without doing
print an error message and return without doing anything. */
anything. */ dict_update_statistics(table, TRUE /* only update stats
dict_update_statistics(table); if they have not been initialized */);
}
} }
return(table); return(table);
...@@ -4183,12 +4213,13 @@ Calculates new estimates for table and index statistics. The statistics ...@@ -4183,12 +4213,13 @@ Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
UNIV_INTERN UNIV_INTERN
void void
dict_update_statistics_low( dict_update_statistics(
/*=======================*/ /*===================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool has_dict_mutex __attribute__((unused))) ibool only_calc_if_missing_stats)/*!< in: only
/*!< in: TRUE if the caller has the update/recalc the stats if they have
dictionary mutex */ not been initialized yet, otherwise
do nothing */
{ {
dict_index_t* index; dict_index_t* index;
ulint sum_of_index_sizes = 0; ulint sum_of_index_sizes = 0;
...@@ -4216,6 +4247,12 @@ dict_update_statistics_low( ...@@ -4216,6 +4247,12 @@ dict_update_statistics_low(
return; return;
} }
dict_table_stats_lock(table, RW_X_LATCH);
if (only_calc_if_missing_stats && table->stat_initialized) {
dict_table_stats_unlock(table, RW_X_LATCH);
return;
}
do { do {
if (UNIV_LIKELY if (UNIV_LIKELY
...@@ -4261,13 +4298,9 @@ dict_update_statistics_low( ...@@ -4261,13 +4298,9 @@ dict_update_statistics_low(
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
dict_index_stat_mutex_enter(index);
table->stat_n_rows = index->stat_n_diff_key_vals[ table->stat_n_rows = index->stat_n_diff_key_vals[
dict_index_get_n_unique(index)]; dict_index_get_n_unique(index)];
dict_index_stat_mutex_exit(index);
table->stat_clustered_index_size = index->stat_index_size; table->stat_clustered_index_size = index->stat_index_size;
table->stat_sum_of_other_index_sizes = sum_of_index_sizes table->stat_sum_of_other_index_sizes = sum_of_index_sizes
...@@ -4276,18 +4309,8 @@ dict_update_statistics_low( ...@@ -4276,18 +4309,8 @@ dict_update_statistics_low(
table->stat_initialized = TRUE; table->stat_initialized = TRUE;
table->stat_modified_counter = 0; table->stat_modified_counter = 0;
}
/*********************************************************************//** dict_table_stats_unlock(table, RW_X_LATCH);
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
UNIV_INTERN
void
dict_update_statistics(
/*===================*/
dict_table_t* table) /*!< in/out: table */
{
dict_update_statistics_low(table, FALSE);
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -4367,7 +4390,9 @@ dict_table_print_low( ...@@ -4367,7 +4390,9 @@ dict_table_print_low(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
dict_update_statistics_low(table, TRUE); dict_update_statistics(table, FALSE /* update even if initialized */);
dict_table_stats_lock(table, RW_S_LATCH);
fprintf(stderr, fprintf(stderr,
"--------------------------------------\n" "--------------------------------------\n"
...@@ -4396,6 +4421,8 @@ dict_table_print_low( ...@@ -4396,6 +4421,8 @@ dict_table_print_low(
index = UT_LIST_GET_NEXT(indexes, index); index = UT_LIST_GET_NEXT(indexes, index);
} }
dict_table_stats_unlock(table, RW_S_LATCH);
foreign = UT_LIST_GET_FIRST(table->foreign_list); foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) { while (foreign != NULL) {
...@@ -4444,8 +4471,6 @@ dict_index_print_low( ...@@ -4444,8 +4471,6 @@ dict_index_print_low(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
dict_index_stat_mutex_enter(index);
if (index->n_user_defined_cols > 0) { if (index->n_user_defined_cols > 0) {
n_vals = index->stat_n_diff_key_vals[ n_vals = index->stat_n_diff_key_vals[
index->n_user_defined_cols]; index->n_user_defined_cols];
...@@ -4453,8 +4478,6 @@ dict_index_print_low( ...@@ -4453,8 +4478,6 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1]; n_vals = index->stat_n_diff_key_vals[1];
} }
dict_index_stat_mutex_exit(index);
fprintf(stderr, fprintf(stderr,
" INDEX: name %s, id %lu %lu, fields %lu/%lu," " INDEX: name %s, id %lu %lu, fields %lu/%lu,"
" uniq %lu, type %lu\n" " uniq %lu, type %lu\n"
...@@ -4798,7 +4821,8 @@ void ...@@ -4798,7 +4821,8 @@ void
dict_table_replace_index_in_foreign_list( dict_table_replace_index_in_foreign_list(
/*=====================================*/ /*=====================================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
dict_index_t* index) /*!< in: index to be replaced */ dict_index_t* index, /*!< in: index to be replaced */
const trx_t* trx) /*!< in: transaction handle */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
...@@ -4809,7 +4833,13 @@ dict_table_replace_index_in_foreign_list( ...@@ -4809,7 +4833,13 @@ dict_table_replace_index_in_foreign_list(
if (foreign->foreign_index == index) { if (foreign->foreign_index == index) {
dict_index_t* new_index dict_index_t* new_index
= dict_foreign_find_equiv_index(foreign); = dict_foreign_find_equiv_index(foreign);
ut_a(new_index);
/* There must exist an alternative index if
check_foreigns (FOREIGN_KEY_CHECKS) is on,
since ha_innobase::prepare_drop_index had done
the check before we reach here. */
ut_a(new_index || !trx->check_foreigns);
foreign->foreign_index = new_index; foreign->foreign_index = new_index;
} }
...@@ -4943,8 +4973,8 @@ dict_close(void) ...@@ -4943,8 +4973,8 @@ dict_close(void)
mem_free(dict_sys); mem_free(dict_sys);
dict_sys = NULL; dict_sys = NULL;
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
mutex_free(&dict_index_stat_mutex[i]); rw_lock_free(&dict_table_stats_latches[i]);
} }
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
...@@ -222,7 +222,8 @@ dict_print(void) ...@@ -222,7 +222,8 @@ dict_print(void)
is no index */ is no index */
if (dict_table_get_first_index(table)) { if (dict_table_get_first_index(table)) {
dict_update_statistics_low(table, TRUE); dict_update_statistics(table, FALSE /* update
even if initialized */);
} }
dict_table_print_low(table); dict_table_print_low(table);
......
...@@ -329,14 +329,15 @@ fil_get_space_id_for_table( ...@@ -329,14 +329,15 @@ fil_get_space_id_for_table(
/*******************************************************************//** /*******************************************************************//**
Frees a space object from the tablespace memory cache. Closes the files in Frees a space object from the tablespace memory cache. Closes the files in
the chain but does not delete them. There must not be any pending i/o's or the chain but does not delete them. There must not be any pending i/o's or
flushes on the files. */ flushes on the files.
@return TRUE on success */
static static
ibool ibool
fil_space_free( fil_space_free(
/*===========*/ /*===========*/
/* out: TRUE if success */ ulint id, /* in: space id */
ulint id, /* in: space id */ ibool x_latched); /* in: TRUE if caller has space->latch
ibool own_mutex);/* in: TRUE if own system->mutex */ in X mode */
/********************************************************************//** /********************************************************************//**
Reads data from a space to a buffer. Remember that the possible incomplete Reads data from a space to a buffer. Remember that the possible incomplete
blocks at the end of file are ignored: they are not taken into account when blocks at the end of file are ignored: they are not taken into account when
...@@ -1123,6 +1124,7 @@ fil_space_create( ...@@ -1123,6 +1124,7 @@ fil_space_create(
space = fil_space_get_by_name(name); space = fil_space_get_by_name(name);
if (UNIV_LIKELY_NULL(space)) { if (UNIV_LIKELY_NULL(space)) {
ibool success;
ulint namesake_id; ulint namesake_id;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -1161,9 +1163,10 @@ fil_space_create( ...@@ -1161,9 +1163,10 @@ fil_space_create(
namesake_id = space->id; namesake_id = space->id;
mutex_exit(&fil_system->mutex); success = fil_space_free(namesake_id, FALSE);
ut_a(success);
fil_space_free(namesake_id, FALSE); mutex_exit(&fil_system->mutex);
goto try_again; goto try_again;
} }
...@@ -1314,15 +1317,14 @@ fil_space_free( ...@@ -1314,15 +1317,14 @@ fil_space_free(
/*===========*/ /*===========*/
/* out: TRUE if success */ /* out: TRUE if success */
ulint id, /* in: space id */ ulint id, /* in: space id */
ibool own_mutex) /* in: TRUE if own system->mutex */ ibool x_latched) /* in: TRUE if caller has space->latch
in X mode */
{ {
fil_space_t* space; fil_space_t* space;
fil_space_t* namespace; fil_space_t* namespace;
fil_node_t* fil_node; fil_node_t* fil_node;
if (!own_mutex) { ut_ad(mutex_own(&fil_system->mutex));
mutex_enter(&fil_system->mutex);
}
space = fil_space_get_by_id(id); space = fil_space_get_by_id(id);
...@@ -1333,8 +1335,6 @@ fil_space_free( ...@@ -1333,8 +1335,6 @@ fil_space_free(
" from the cache but\n" " from the cache but\n"
"InnoDB: it is not there.\n", (ulong) id); "InnoDB: it is not there.\n", (ulong) id);
mutex_exit(&fil_system->mutex);
return(FALSE); return(FALSE);
} }
...@@ -1369,8 +1369,8 @@ fil_space_free( ...@@ -1369,8 +1369,8 @@ fil_space_free(
ut_a(0 == UT_LIST_GET_LEN(space->chain)); ut_a(0 == UT_LIST_GET_LEN(space->chain));
if (!own_mutex) { if (x_latched) {
mutex_exit(&fil_system->mutex); rw_lock_x_unlock(&space->latch);
} }
rw_lock_free(&(space->latch)); rw_lock_free(&(space->latch));
...@@ -1615,25 +1615,27 @@ fil_close_all_files(void) ...@@ -1615,25 +1615,27 @@ fil_close_all_files(void)
/*=====================*/ /*=====================*/
{ {
fil_space_t* space; fil_space_t* space;
fil_node_t* node;
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_FIRST(fil_system->space_list); space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) { while (space != NULL) {
fil_node_t* node;
fil_space_t* prev_space = space; fil_space_t* prev_space = space;
node = UT_LIST_GET_FIRST(space->chain); for (node = UT_LIST_GET_FIRST(space->chain);
node != NULL;
node = UT_LIST_GET_NEXT(chain, node)) {
while (node != NULL) {
if (node->open) { if (node->open) {
fil_node_close_file(node, fil_system); fil_node_close_file(node, fil_system);
} }
node = UT_LIST_GET_NEXT(chain, node);
} }
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
fil_space_free(prev_space->id, TRUE);
fil_space_free(prev_space->id, FALSE);
} }
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
...@@ -2253,6 +2255,19 @@ fil_delete_tablespace( ...@@ -2253,6 +2255,19 @@ fil_delete_tablespace(
path = mem_strdup(space->name); path = mem_strdup(space->name);
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
/* Important: We rely on the data dictionary mutex to ensure
that a race is not possible here. It should serialize the tablespace
drop/free. We acquire an X latch only to avoid a race condition
when accessing the tablespace instance via:
fsp_get_available_space_in_free_extents().
There our main motivation is to reduce the contention on the
dictionary mutex. */
rw_lock_x_lock(&space->latch);
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/* Invalidate in the buffer pool all pages belonging to the /* Invalidate in the buffer pool all pages belonging to the
tablespace. Since we have set space->is_being_deleted = TRUE, readahead tablespace. Since we have set space->is_being_deleted = TRUE, readahead
...@@ -2265,7 +2280,11 @@ fil_delete_tablespace( ...@@ -2265,7 +2280,11 @@ fil_delete_tablespace(
#endif #endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */ /* printf("Deleting tablespace %s id %lu\n", space->name, id); */
success = fil_space_free(id, FALSE); mutex_enter(&fil_system->mutex);
success = fil_space_free(id, TRUE);
mutex_exit(&fil_system->mutex);
if (success) { if (success) {
success = os_file_delete(path); success = os_file_delete(path);
...@@ -2273,6 +2292,8 @@ fil_delete_tablespace( ...@@ -2273,6 +2292,8 @@ fil_delete_tablespace(
if (!success) { if (!success) {
success = os_file_delete_if_exists(path); success = os_file_delete_if_exists(path);
} }
} else {
rw_lock_x_unlock(&space->latch);
} }
if (success) { if (success) {
...@@ -2300,6 +2321,31 @@ fil_delete_tablespace( ...@@ -2300,6 +2321,31 @@ fil_delete_tablespace(
return(FALSE); return(FALSE);
} }
/*******************************************************************//**
Returns TRUE if a single-table tablespace is being deleted.
@return TRUE if being deleted */
UNIV_INTERN
ibool
fil_tablespace_is_being_deleted(
/*============================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
ibool is_being_deleted;
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
ut_a(space != NULL);
is_being_deleted = space->is_being_deleted;
mutex_exit(&fil_system->mutex);
return(is_being_deleted);
}
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/*******************************************************************//** /*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the Discards a single-table tablespace. The tablespace must be cached in the
...@@ -4763,7 +4809,7 @@ fil_page_get_type( ...@@ -4763,7 +4809,7 @@ fil_page_get_type(
return(mach_read_from_2(page + FIL_PAGE_TYPE)); return(mach_read_from_2(page + FIL_PAGE_TYPE));
} }
/******************************************************************** /****************************************************************//**
Initializes the tablespace memory cache. */ Initializes the tablespace memory cache. */
UNIV_INTERN UNIV_INTERN
void void
......
...@@ -3102,13 +3102,63 @@ fsp_get_available_space_in_free_extents( ...@@ -3102,13 +3102,63 @@ fsp_get_available_space_in_free_extents(
ut_ad(!mutex_own(&kernel_mutex)); ut_ad(!mutex_own(&kernel_mutex));
/* The convoluted mutex acquire is to overcome latching order
issues: The problem is that the fil_mutex is at a lower level
than the tablespace latch and the buffer pool mutex. We have to
first prevent any operations on the file system by acquiring the
dictionary mutex. Then acquire the tablespace latch to obey the
latching order and then release the dictionary mutex. That way we
ensure that the tablespace instance can't be freed while we are
examining its contents (see fil_space_free()).
However, there is one further complication, we release the fil_mutex
when we need to invalidate the the pages in the buffer pool and we
reacquire the fil_mutex when deleting and freeing the tablespace
instance in fil0fil.c. Here we need to account for that situation
too. */
mutex_enter(&dict_sys->mutex);
/* At this stage there is no guarantee that the tablespace even
exists in the cache. */
if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) {
mutex_exit(&dict_sys->mutex);
return(ULLINT_UNDEFINED);
}
mtr_start(&mtr); mtr_start(&mtr);
latch = fil_space_get_latch(space, &flags); latch = fil_space_get_latch(space, &flags);
/* This should ensure that the tablespace instance can't be freed
by another thread. However, the tablespace pages can still be freed
from the buffer pool. We need to check for that again. */
zip_size = dict_table_flags_to_zip_size(flags); zip_size = dict_table_flags_to_zip_size(flags);
mtr_x_lock(latch, &mtr); mtr_x_lock(latch, &mtr);
mutex_exit(&dict_sys->mutex);
/* At this point it is possible for the tablespace to be deleted and
its pages removed from the buffer pool. We need to check for that
situation. However, the tablespace instance can't be deleted because
our latching above should ensure that. */
if (fil_tablespace_is_being_deleted(space)) {
mtr_commit(&mtr);
return(ULLINT_UNDEFINED);
}
/* From here on even if the user has dropped the tablespace, the
pages _must_ still exist in the buffer pool and the tablespace
instance _must_ be in the file system hash table. */
space_header = fsp_get_space_header(space, zip_size, &mtr); space_header = fsp_get_space_header(space, zip_size, &mtr);
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr); size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
......
This diff is collapsed.
...@@ -1012,12 +1012,13 @@ ha_innobase::prepare_drop_index( ...@@ -1012,12 +1012,13 @@ ha_innobase::prepare_drop_index(
index->to_be_dropped = TRUE; index->to_be_dropped = TRUE;
} }
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined /* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
for a foreign key constraint because InnoDB requires that both for a foreign key constraint because InnoDB requires that both
tables contain indexes for the constraint. Note that CREATE tables contain indexes for the constraint. Such index can
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we be dropped only if FOREIGN_KEY_CHECKS is set to 0.
can ignore here foreign keys because a new index for the Note that CREATE INDEX id ON table does a CREATE INDEX and
foreign key has already been created. DROP INDEX, and we can ignore here foreign keys because a
new index for the foreign key has already been created.
We check for the foreign key constraints after marking the We check for the foreign key constraints after marking the
candidate indexes for deletion, because when we check for an candidate indexes for deletion, because when we check for an
......
...@@ -94,26 +94,35 @@ btr_root_get( ...@@ -94,26 +94,35 @@ btr_root_get(
Gets a buffer page and declares its latching order level. */ Gets a buffer page and declares its latching order level. */
UNIV_INLINE UNIV_INLINE
buf_block_t* buf_block_t*
btr_block_get( btr_block_get_func(
/*==========*/ /*===============*/
ulint space, /*!< in: space id */ ulint space, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */ or 0 for uncompressed pages */
ulint page_no, /*!< in: page number */ ulint page_no, /*!< in: page number */
ulint mode, /*!< in: latch mode */ ulint mode, /*!< in: latch mode */
mtr_t* mtr); /*!< in: mtr */ const char* file, /*!< in: file name */
/**************************************************************//** ulint line, /*!< in: line where called */
Gets a buffer page and declares its latching order level. */ mtr_t* mtr) /*!< in/out: mtr */
UNIV_INLINE __attribute__((nonnull));
page_t* /** Gets a buffer page and declares its latching order level.
btr_page_get( @param space tablespace identifier
/*=========*/ @param zip_size compressed page size in bytes or 0 for uncompressed pages
ulint space, /*!< in: space id */ @param page_no page number
ulint zip_size, /*!< in: compressed page size in bytes @param mode latch mode
or 0 for uncompressed pages */ @param mtr mini-transaction handle
ulint page_no, /*!< in: page number */ @return the block descriptor */
ulint mode, /*!< in: latch mode */ # define btr_block_get(space,zip_size,page_no,mode,mtr) \
mtr_t* mtr); /*!< in: mtr */ btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr)
/** Gets a buffer page and declares its latching order level.
@param space tablespace identifier
@param zip_size compressed page size in bytes or 0 for uncompressed pages
@param page_no page number
@param mode latch mode
@param mtr mini-transaction handle
@return the uncompressed page frame */
# define btr_page_get(space,zip_size,page_no,mode,mtr) \
buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr))
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/**************************************************************//** /**************************************************************//**
Gets the index id field of a page. Gets the index id field of a page.
......
...@@ -39,18 +39,21 @@ Created 6/2/1994 Heikki Tuuri ...@@ -39,18 +39,21 @@ Created 6/2/1994 Heikki Tuuri
Gets a buffer page and declares its latching order level. */ Gets a buffer page and declares its latching order level. */
UNIV_INLINE UNIV_INLINE
buf_block_t* buf_block_t*
btr_block_get( btr_block_get_func(
/*==========*/ /*===============*/
ulint space, /*!< in: space id */ ulint space, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */ or 0 for uncompressed pages */
ulint page_no, /*!< in: page number */ ulint page_no, /*!< in: page number */
ulint mode, /*!< in: latch mode */ ulint mode, /*!< in: latch mode */
mtr_t* mtr) /*!< in: mtr */ const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in/out: mtr */
{ {
buf_block_t* block; buf_block_t* block;
block = buf_page_get(space, zip_size, page_no, mode, mtr); block = buf_page_get_gen(space, zip_size, page_no, mode,
NULL, BUF_GET, file, line, mtr);
if (mode != RW_NO_LATCH) { if (mode != RW_NO_LATCH) {
...@@ -60,23 +63,6 @@ btr_block_get( ...@@ -60,23 +63,6 @@ btr_block_get(
return(block); return(block);
} }
/**************************************************************//**
Gets a buffer page and declares its latching order level. */
UNIV_INLINE
page_t*
btr_page_get(
/*=========*/
ulint space, /*!< in: space id */
ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint page_no, /*!< in: page number */
ulint mode, /*!< in: latch mode */
mtr_t* mtr) /*!< in: mtr */
{
return(buf_block_get_frame(btr_block_get(space, zip_size, page_no,
mode, mtr)));
}
/**************************************************************//** /**************************************************************//**
Sets the index id field of a page. */ Sets the index id field of a page. */
UNIV_INLINE UNIV_INLINE
......
...@@ -520,7 +520,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to ...@@ -520,7 +520,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand. them in rec. The extern flags in rec will have to be set beforehand.
The fields are stored on pages allocated from leaf node The fields are stored on pages allocated from leaf node
file segment of the index tree. file segment of the index tree.
@return DB_SUCCESS or error */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN UNIV_INTERN
ulint ulint
btr_store_big_rec_extern_fields( btr_store_big_rec_extern_fields(
......
...@@ -318,7 +318,8 @@ void ...@@ -318,7 +318,8 @@ void
dict_table_replace_index_in_foreign_list( dict_table_replace_index_in_foreign_list(
/*=====================================*/ /*=====================================*/
dict_table_t* table, /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
dict_index_t* index); /*!< in: index to be replaced */ dict_index_t* index, /*!< in: index to be replaced */
const trx_t* trx); /*!< in: transaction handle */
/*********************************************************************//** /*********************************************************************//**
Checks if a index is defined for a foreign key constraint. Index is a part Checks if a index is defined for a foreign key constraint. Index is a part
of a foreign key constraint if the index is referenced by foreign key of a foreign key constraint if the index is referenced by foreign key
...@@ -1053,19 +1054,13 @@ Calculates new estimates for table and index statistics. The statistics ...@@ -1053,19 +1054,13 @@ Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */ are used in query optimization. */
UNIV_INTERN UNIV_INTERN
void void
dict_update_statistics_low(
/*=======================*/
dict_table_t* table, /*!< in/out: table */
ibool has_dict_mutex);/*!< in: TRUE if the caller has the
dictionary mutex */
/*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
UNIV_INTERN
void
dict_update_statistics( dict_update_statistics(
/*===================*/ /*===================*/
dict_table_t* table); /*!< in/out: table */ dict_table_t* table, /*!< in/out: table */
ibool only_calc_if_missing_stats);/*!< in: only
update/recalc the stats if they have
not been initialized yet, otherwise
do nothing */
/********************************************************************//** /********************************************************************//**
Reserves the dictionary system mutex for MySQL. */ Reserves the dictionary system mutex for MySQL. */
UNIV_INTERN UNIV_INTERN
...@@ -1079,21 +1074,25 @@ void ...@@ -1079,21 +1074,25 @@ void
dict_mutex_exit_for_mysql(void); dict_mutex_exit_for_mysql(void);
/*===========================*/ /*===========================*/
/**********************************************************************//** /**********************************************************************//**
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. Lock the appropriate latch to protect a given table's statistics.
index->id is used to pick the right mutex and it should not change table->id is used to pick the corresponding latch from a global array of
before dict_index_stat_mutex_exit() is called on this index. */ latches. */
UNIV_INTERN UNIV_INTERN
void void
dict_index_stat_mutex_enter( dict_table_stats_lock(
/*========================*/ /*==================*/
const dict_index_t* index); /*!< in: index */ const dict_table_t* table, /*!< in: table */
ulint latch_mode); /*!< in: RW_S_LATCH or
RW_X_LATCH */
/**********************************************************************//** /**********************************************************************//**
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ Unlock the latch that has been locked by dict_table_stats_lock() */
UNIV_INTERN UNIV_INTERN
void void
dict_index_stat_mutex_exit( dict_table_stats_unlock(
/*=======================*/ /*====================*/
const dict_index_t* index); /*!< in: index */ const dict_table_t* table, /*!< in: table */
ulint latch_mode); /*!< in: RW_S_LATCH or
RW_X_LATCH */
/********************************************************************//** /********************************************************************//**
Checks if the database name in two table names is the same. Checks if the database name in two table names is the same.
@return TRUE if same db name */ @return TRUE if same db name */
......
...@@ -716,6 +716,14 @@ fil_page_get_type( ...@@ -716,6 +716,14 @@ fil_page_get_type(
/*==============*/ /*==============*/
const byte* page); /*!< in: file page */ const byte* page); /*!< in: file page */
/*******************************************************************//**
Returns TRUE if a single-table tablespace is being deleted.
@return TRUE if being deleted */
UNIV_INTERN
ibool
fil_tablespace_is_being_deleted(
/*============================*/
ulint id); /*!< in: space id */
typedef struct fil_space_struct fil_space_t; typedef struct fil_space_struct fil_space_t;
......
...@@ -84,9 +84,10 @@ ulint ...@@ -84,9 +84,10 @@ ulint
row_ins_index_entry( row_ins_index_entry(
/*================*/ /*================*/
dict_index_t* index, /*!< in: index */ dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry to insert */ dtuple_t* entry, /*!< in/out: index entry to insert */
ulint n_ext, /*!< in: number of externally stored columns */ ulint n_ext, /*!< in: number of externally stored columns */
ibool foreign,/*!< in: TRUE=check foreign key constraints */ ibool foreign,/*!< in: TRUE=check foreign key constraints
(foreign=FALSE only during CREATE INDEX) */
que_thr_t* thr); /*!< in: query thread */ que_thr_t* thr); /*!< in: query thread */
/***********************************************************//** /***********************************************************//**
Inserts a row to a table. This is a high-level function used in Inserts a row to a table. This is a high-level function used in
......
...@@ -126,8 +126,8 @@ UNIV_INTERN ...@@ -126,8 +126,8 @@ UNIV_INTERN
void void
row_upd_index_entry_sys_field( row_upd_index_entry_sys_field(
/*==========================*/ /*==========================*/
const dtuple_t* entry, /*!< in: index entry, where the memory buffers dtuple_t* entry, /*!< in/out: index entry, where the memory
for sys fields are already allocated: buffers for sys fields are already allocated:
the function just copies the new values to the function just copies the new values to
them */ them */
dict_index_t* index, /*!< in: clustered index */ dict_index_t* index, /*!< in: clustered index */
......
...@@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri ...@@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0 #define INNODB_VERSION_MINOR 0
#define INNODB_VERSION_BUGFIX 13 #define INNODB_VERSION_BUGFIX 14
/* The following is the InnoDB version as shown in /* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins; SELECT plugin_version FROM information_schema.plugins;
...@@ -360,6 +360,9 @@ typedef unsigned long long int ullint; ...@@ -360,6 +360,9 @@ typedef unsigned long long int ullint;
/* Maximum value for ib_uint64_t */ /* Maximum value for ib_uint64_t */
#define IB_ULONGLONG_MAX ((ib_uint64_t) (~0ULL)) #define IB_ULONGLONG_MAX ((ib_uint64_t) (~0ULL))
/* THe 'undefined' value for ullint */
#define ULLINT_UNDEFINED ((ullint)(-1))
/* This 'ibool' type is used within Innobase. Remember that different included /* This 'ibool' type is used within Innobase. Remember that different included
headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */
#define ibool ulint #define ibool ulint
......
...@@ -1781,7 +1781,7 @@ ulint ...@@ -1781,7 +1781,7 @@ ulint
row_ins_duplicate_error_in_clust( row_ins_duplicate_error_in_clust(
/*=============================*/ /*=============================*/
btr_cur_t* cursor, /*!< in: B-tree cursor */ btr_cur_t* cursor, /*!< in: B-tree cursor */
dtuple_t* entry, /*!< in: entry to insert */ const dtuple_t* entry, /*!< in: entry to insert */
que_thr_t* thr, /*!< in: query thread */ que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
...@@ -1977,7 +1977,7 @@ row_ins_index_entry_low( ...@@ -1977,7 +1977,7 @@ row_ins_index_entry_low(
depending on whether we wish optimistic or depending on whether we wish optimistic or
pessimistic descent down the index tree */ pessimistic descent down the index tree */
dict_index_t* index, /*!< in: index */ dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry to insert */ dtuple_t* entry, /*!< in/out: index entry to insert */
ulint n_ext, /*!< in: number of externally stored columns */ ulint n_ext, /*!< in: number of externally stored columns */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
...@@ -2158,9 +2158,10 @@ ulint ...@@ -2158,9 +2158,10 @@ ulint
row_ins_index_entry( row_ins_index_entry(
/*================*/ /*================*/
dict_index_t* index, /*!< in: index */ dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry to insert */ dtuple_t* entry, /*!< in/out: index entry to insert */
ulint n_ext, /*!< in: number of externally stored columns */ ulint n_ext, /*!< in: number of externally stored columns */
ibool foreign,/*!< in: TRUE=check foreign key constraints */ ibool foreign,/*!< in: TRUE=check foreign key constraints
(foreign=FALSE only during CREATE INDEX) */
que_thr_t* thr) /*!< in: query thread */ que_thr_t* thr) /*!< in: query thread */
{ {
ulint err; ulint err;
......
...@@ -2043,7 +2043,7 @@ row_merge_drop_index( ...@@ -2043,7 +2043,7 @@ row_merge_drop_index(
/* Replace this index with another equivalent index for all /* Replace this index with another equivalent index for all
foreign key constraints on this table where this index is used */ foreign key constraints on this table where this index is used */
dict_table_replace_index_in_foreign_list(table, index); dict_table_replace_index_in_foreign_list(table, index, trx);
dict_index_remove_from_cache(table, index); dict_index_remove_from_cache(table, index);
trx->op_info = ""; trx->op_info = "";
......
...@@ -871,7 +871,8 @@ row_update_statistics_if_needed( ...@@ -871,7 +871,8 @@ row_update_statistics_if_needed(
if (counter > 2000000000 if (counter > 2000000000
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) { || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
dict_update_statistics(table); dict_update_statistics(table, FALSE /* update even if stats
are initialized */);
} }
} }
...@@ -2962,7 +2963,8 @@ row_truncate_table_for_mysql( ...@@ -2962,7 +2963,8 @@ row_truncate_table_for_mysql(
dict_table_autoinc_lock(table); dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, 1); dict_table_autoinc_initialize(table, 1);
dict_table_autoinc_unlock(table); dict_table_autoinc_unlock(table);
dict_update_statistics(table); dict_update_statistics(table, FALSE /* update even if stats are
initialized */);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
......
...@@ -106,6 +106,18 @@ row_sel_sec_rec_is_for_blob( ...@@ -106,6 +106,18 @@ row_sel_sec_rec_is_for_blob(
ulint len; ulint len;
byte buf[DICT_MAX_INDEX_COL_LEN]; byte buf[DICT_MAX_INDEX_COL_LEN];
ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE);
if (UNIV_UNLIKELY
(!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE,
field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) {
/* The externally stored field was not written yet.
This record should only be seen by
recv_recovery_rollback_active() or any
TRX_ISO_READ_UNCOMMITTED transactions. */
return(FALSE);
}
len = btr_copy_externally_stored_field_prefix(buf, sizeof buf, len = btr_copy_externally_stored_field_prefix(buf, sizeof buf,
zip_size, zip_size,
clust_field, clust_len); clust_field, clust_len);
......
...@@ -371,8 +371,8 @@ UNIV_INTERN ...@@ -371,8 +371,8 @@ UNIV_INTERN
void void
row_upd_index_entry_sys_field( row_upd_index_entry_sys_field(
/*==========================*/ /*==========================*/
const dtuple_t* entry, /*!< in: index entry, where the memory buffers dtuple_t* entry, /*!< in/out: index entry, where the memory
for sys fields are already allocated: buffers for sys fields are already allocated:
the function just copies the new values to the function just copies the new values to
them */ them */
dict_index_t* index, /*!< in: clustered index */ dict_index_t* index, /*!< in: clustered index */
...@@ -1587,12 +1587,12 @@ static ...@@ -1587,12 +1587,12 @@ static
ulint ulint
row_upd_clust_rec_by_insert( row_upd_clust_rec_by_insert(
/*========================*/ /*========================*/
upd_node_t* node, /*!< in: row update node */ upd_node_t* node, /*!< in/out: row update node */
dict_index_t* index, /*!< in: clustered index of the record */ dict_index_t* index, /*!< in: clustered index of the record */
que_thr_t* thr, /*!< in: query thread */ que_thr_t* thr, /*!< in: query thread */
ibool check_ref,/*!< in: TRUE if index may be referenced in ibool check_ref,/*!< in: TRUE if index may be referenced in
a foreign key constraint */ a foreign key constraint */
mtr_t* mtr) /*!< in: mtr; gets committed here */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */
{ {
mem_heap_t* heap = NULL; mem_heap_t* heap = NULL;
btr_pcur_t* pcur; btr_pcur_t* pcur;
......
...@@ -1286,8 +1286,25 @@ innobase_start_or_create_for_mysql(void) ...@@ -1286,8 +1286,25 @@ innobase_start_or_create_for_mysql(void)
fil_init(srv_file_per_table ? 50000 : 5000, fil_init(srv_file_per_table ? 50000 : 5000,
srv_max_n_open_files); srv_max_n_open_files);
/* Print time to initialize the buffer pool */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Initializing buffer pool, size =");
if (srv_buf_pool_size >= 1024 * 1024 * 1024) {
fprintf(stderr,
" %.1fG\n",
((double) srv_buf_pool_size) / (1024 * 1024 * 1024));
} else {
fprintf(stderr,
" %.1fM\n",
((double) srv_buf_pool_size) / (1024 * 1024));
}
ret = buf_pool_init(); ret = buf_pool_init();
ut_print_timestamp(stderr);
if (ret == NULL) { if (ret == NULL) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Fatal error: cannot allocate the memory" "InnoDB: Fatal error: cannot allocate the memory"
...@@ -1296,6 +1313,9 @@ innobase_start_or_create_for_mysql(void) ...@@ -1296,6 +1313,9 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR); return(DB_ERROR);
} }
fprintf(stderr,
" InnoDB: Completed initialization of buffer pool\n");
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/* We have observed deadlocks with a 5MB buffer pool but /* We have observed deadlocks with a 5MB buffer pool but
the actual lower limit could very well be a little higher. */ the actual lower limit could very well be a little higher. */
......
...@@ -335,10 +335,13 @@ rw_lock_validate( ...@@ -335,10 +335,13 @@ rw_lock_validate(
/*=============*/ /*=============*/
rw_lock_t* lock) /*!< in: rw-lock */ rw_lock_t* lock) /*!< in: rw-lock */
{ {
ulint waiters;
lint lock_word;
ut_a(lock); ut_a(lock);
ulint waiters = rw_lock_get_waiters(lock); waiters = rw_lock_get_waiters(lock);
lint lock_word = lock->lock_word; lock_word = lock->lock_word;
ut_ad(lock->magic_n == RW_LOCK_MAGIC_N); ut_ad(lock->magic_n == RW_LOCK_MAGIC_N);
ut_a(waiters == 0 || waiters == 1); ut_a(waiters == 0 || waiters == 1);
...@@ -988,7 +991,7 @@ rw_lock_debug_print( ...@@ -988,7 +991,7 @@ rw_lock_debug_print(
rwt = info->lock_type; rwt = info->lock_type;
fprintf(stderr, "Locked: thread %ld file %s line %ld ", fprintf(stderr, "Locked: thread %lu file %s line %lu ",
(ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) os_thread_pf(info->thread_id), info->file_name,
(ulong) info->line); (ulong) info->line);
if (rwt == RW_LOCK_SHARED) { if (rwt == RW_LOCK_SHARED) {
......
...@@ -71,6 +71,24 @@ struct thr_local_struct{ ...@@ -71,6 +71,24 @@ struct thr_local_struct{
/** The value of thr_local_struct::magic_n */ /** The value of thr_local_struct::magic_n */
#define THR_LOCAL_MAGIC_N 1231234 #define THR_LOCAL_MAGIC_N 1231234
#ifdef UNIV_DEBUG
/*******************************************************************//**
Validates thread local data.
@return TRUE if valid */
static
ibool
thr_local_validate(
/*===============*/
const thr_local_t* local) /*!< in: data to validate */
{
ut_ad(local->magic_n == THR_LOCAL_MAGIC_N);
ut_ad(local->slot_no == ULINT_UNDEFINED
|| local->slot_no < OS_THREAD_MAX_N);
ut_ad(local->in_ibuf == FALSE || local->in_ibuf == TRUE);
return(TRUE);
}
#endif /* UNIV_DEBUG */
/*******************************************************************//** /*******************************************************************//**
Returns the local storage struct for a thread. Returns the local storage struct for a thread.
@return local storage */ @return local storage */
...@@ -91,7 +109,8 @@ thr_local_get( ...@@ -91,7 +109,8 @@ thr_local_get(
local = NULL; local = NULL;
HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id),
thr_local_t*, local,, os_thread_eq(local->id, id)); thr_local_t*, local, ut_ad(thr_local_validate(local)),
os_thread_eq(local->id, id));
if (local == NULL) { if (local == NULL) {
mutex_exit(&thr_local_mutex); mutex_exit(&thr_local_mutex);
...@@ -102,7 +121,7 @@ thr_local_get( ...@@ -102,7 +121,7 @@ thr_local_get(
goto try_again; goto try_again;
} }
ut_ad(local->magic_n == THR_LOCAL_MAGIC_N); ut_ad(thr_local_validate(local));
return(local); return(local);
} }
...@@ -188,7 +207,7 @@ thr_local_create(void) ...@@ -188,7 +207,7 @@ thr_local_create(void)
local->id = os_thread_get_curr_id(); local->id = os_thread_get_curr_id();
local->handle = os_thread_get_curr(); local->handle = os_thread_get_curr();
local->magic_n = THR_LOCAL_MAGIC_N; local->magic_n = THR_LOCAL_MAGIC_N;
local->slot_no = ULINT_UNDEFINED;
local->in_ibuf = FALSE; local->in_ibuf = FALSE;
mutex_enter(&thr_local_mutex); mutex_enter(&thr_local_mutex);
...@@ -215,7 +234,8 @@ thr_local_free( ...@@ -215,7 +234,8 @@ thr_local_free(
/* Look for the local struct in the hash table */ /* Look for the local struct in the hash table */
HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id),
thr_local_t*, local,, os_thread_eq(local->id, id)); thr_local_t*, local, ut_ad(thr_local_validate(local)),
os_thread_eq(local->id, id));
if (local == NULL) { if (local == NULL) {
mutex_exit(&thr_local_mutex); mutex_exit(&thr_local_mutex);
...@@ -228,6 +248,7 @@ thr_local_free( ...@@ -228,6 +248,7 @@ thr_local_free(
mutex_exit(&thr_local_mutex); mutex_exit(&thr_local_mutex);
ut_a(local->magic_n == THR_LOCAL_MAGIC_N); ut_a(local->magic_n == THR_LOCAL_MAGIC_N);
ut_ad(thr_local_validate(local));
mem_free(local); mem_free(local);
} }
...@@ -270,6 +291,7 @@ thr_local_close(void) ...@@ -270,6 +291,7 @@ thr_local_close(void)
local = HASH_GET_NEXT(hash, prev_local); local = HASH_GET_NEXT(hash, prev_local);
ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N); ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N);
ut_ad(thr_local_validate(prev_local));
mem_free(prev_local); mem_free(prev_local);
} }
} }
......
...@@ -408,6 +408,42 @@ table_cache_create_empty_row( ...@@ -408,6 +408,42 @@ table_cache_create_empty_row(
return(row); return(row);
} }
#ifdef UNIV_DEBUG
/*******************************************************************//**
Validates a row in the locks cache.
@return TRUE if valid */
static
ibool
i_s_locks_row_validate(
/*===================*/
const i_s_locks_row_t* row) /*!< in: row to validate */
{
ut_ad(row->lock_trx_id != 0);
ut_ad(row->lock_mode != NULL);
ut_ad(row->lock_type != NULL);
ut_ad(row->lock_table != NULL);
ut_ad(row->lock_table_id != 0);
if (row->lock_space == ULINT_UNDEFINED) {
/* table lock */
ut_ad(!strcmp("TABLE", row->lock_type));
ut_ad(row->lock_index == NULL);
ut_ad(row->lock_data == NULL);
ut_ad(row->lock_page == ULINT_UNDEFINED);
ut_ad(row->lock_rec == ULINT_UNDEFINED);
} else {
/* record lock */
ut_ad(!strcmp("RECORD", row->lock_type));
ut_ad(row->lock_index != NULL);
ut_ad(row->lock_data != NULL);
ut_ad(row->lock_page != ULINT_UNDEFINED);
ut_ad(row->lock_rec != ULINT_UNDEFINED);
}
return(TRUE);
}
#endif /* UNIV_DEBUG */
/*******************************************************************//** /*******************************************************************//**
Fills i_s_trx_row_t object. Fills i_s_trx_row_t object.
If memory can not be allocated then FALSE is returned. If memory can not be allocated then FALSE is returned.
...@@ -435,18 +471,15 @@ fill_trx_row( ...@@ -435,18 +471,15 @@ fill_trx_row(
row->trx_id = trx_get_id(trx); row->trx_id = trx_get_id(trx);
row->trx_started = (ib_time_t) trx->start_time; row->trx_started = (ib_time_t) trx->start_time;
row->trx_state = trx_get_que_state_str(trx); row->trx_state = trx_get_que_state_str(trx);
row->requested_lock_row = requested_lock_row;
ut_ad(requested_lock_row == NULL
|| i_s_locks_row_validate(requested_lock_row));
if (trx->wait_lock != NULL) { if (trx->wait_lock != NULL) {
ut_a(requested_lock_row != NULL); ut_a(requested_lock_row != NULL);
row->requested_lock_row = requested_lock_row;
row->trx_wait_started = (ib_time_t) trx->wait_started; row->trx_wait_started = (ib_time_t) trx->wait_started;
} else { } else {
ut_a(requested_lock_row == NULL); ut_a(requested_lock_row == NULL);
row->requested_lock_row = NULL;
row->trx_wait_started = 0; row->trx_wait_started = 0;
} }
...@@ -729,6 +762,7 @@ fill_locks_row( ...@@ -729,6 +762,7 @@ fill_locks_row(
row->lock_table_id = lock_get_table_id(lock); row->lock_table_id = lock_get_table_id(lock);
row->hash_chain.value = row; row->hash_chain.value = row;
ut_ad(i_s_locks_row_validate(row));
return(TRUE); return(TRUE);
} }
...@@ -749,6 +783,9 @@ fill_lock_waits_row( ...@@ -749,6 +783,9 @@ fill_lock_waits_row(
relevant blocking lock relevant blocking lock
row in innodb_locks */ row in innodb_locks */
{ {
ut_ad(i_s_locks_row_validate(requested_lock_row));
ut_ad(i_s_locks_row_validate(blocking_lock_row));
row->requested_lock_row = requested_lock_row; row->requested_lock_row = requested_lock_row;
row->blocking_lock_row = blocking_lock_row; row->blocking_lock_row = blocking_lock_row;
...@@ -820,6 +857,7 @@ locks_row_eq_lock( ...@@ -820,6 +857,7 @@ locks_row_eq_lock(
or ULINT_UNDEFINED if the lock or ULINT_UNDEFINED if the lock
is a table lock */ is a table lock */
{ {
ut_ad(i_s_locks_row_validate(row));
#ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T #ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T
return(0); return(0);
#else #else
...@@ -877,7 +915,7 @@ search_innodb_locks( ...@@ -877,7 +915,7 @@ search_innodb_locks(
/* auxiliary variable */ /* auxiliary variable */
hash_chain, hash_chain,
/* assertion on every traversed item */ /* assertion on every traversed item */
, ut_ad(i_s_locks_row_validate(hash_chain->value)),
/* this determines if we have found the lock */ /* this determines if we have found the lock */
locks_row_eq_lock(hash_chain->value, lock, heap_no)); locks_row_eq_lock(hash_chain->value, lock, heap_no));
...@@ -917,6 +955,7 @@ add_lock_to_cache( ...@@ -917,6 +955,7 @@ add_lock_to_cache(
dst_row = search_innodb_locks(cache, lock, heap_no); dst_row = search_innodb_locks(cache, lock, heap_no);
if (dst_row != NULL) { if (dst_row != NULL) {
ut_ad(i_s_locks_row_validate(dst_row));
return(dst_row); return(dst_row);
} }
#endif #endif
...@@ -954,6 +993,7 @@ add_lock_to_cache( ...@@ -954,6 +993,7 @@ add_lock_to_cache(
} /* for()-loop */ } /* for()-loop */
#endif #endif
ut_ad(i_s_locks_row_validate(dst_row));
return(dst_row); return(dst_row);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment