diff --git a/include/my_base.h b/include/my_base.h index f6afc891281..cc02b0080d9 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -446,8 +446,9 @@ enum ha_base_keytype { #define HA_ERR_FILE_TOO_SHORT 175 /* File too short */ #define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */ #define HA_ERR_TOO_MANY_CONCURRENT_TRXS 177 /*Too many active concurrent transactions */ -#define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */ -#define HA_ERR_LAST 178 /* Copy of last error nr */ +#define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */ +#define HA_ERR_INDEX_CORRUPT 179 /* Index corrupted */ +#define HA_ERR_LAST 179 /* Copy of last error nr */ /* Number of different errors */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/innodb/r/innodb_bug59733.result b/mysql-test/suite/innodb/r/innodb_bug59733.result new file mode 100644 index 00000000000..c962cdfd677 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug59733.result @@ -0,0 +1,18 @@ +CREATE TABLE bug59733(a INT AUTO_INCREMENT PRIMARY KEY,b CHAR(1))ENGINE=InnoDB; +INSERT INTO bug59733 VALUES(0,'x'); +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +CREATE INDEX b ON bug59733 (b); +DELETE FROM bug59733 WHERE (a%100)=0; +DROP INDEX b ON bug59733; +CREATE INDEX b ON bug59733 (b); +DROP TABLE bug59733; diff --git a/mysql-test/suite/innodb/r/innodb_corrupt_bit.result b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result new file mode 100644 index 00000000000..c88e1ed2504 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_corrupt_bit.result @@ -0,0 +1,81 @@ +set names utf8; +CREATE TABLE corrupt_bit_test_ā( +a INT AUTO_INCREMENT PRIMARY KEY, +b CHAR(100), +c INT, +z INT, +INDEX(b)) +ENGINE=InnoDB; +INSERT INTO corrupt_bit_test_ā VALUES(0,'x',1, 1); +CREATE UNIQUE INDEX idxā ON corrupt_bit_test_ā(c, b); +CREATE UNIQUE INDEX idxē ON corrupt_bit_test_ā(z, b); +SELECT * FROM corrupt_bit_test_ā; +a b c z +1 x 1 1 +select @@unique_checks; +@@unique_checks +0 +select @@innodb_change_buffering_debug; +@@innodb_change_buffering_debug +1 +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1,z+1 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+10,z+10 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+20,z+20 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+50,z+50 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+100,z+100 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+200,z+200 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+400,z+400 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+800,z+800 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1600,z+1600 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+4000,z+4000 FROM corrupt_bit_test_ā; +select count(*) from corrupt_bit_test_ā; +count(*) +1024 +CREATE INDEX idx3 ON corrupt_bit_test_ā(b, c); +INSERT INTO corrupt_bit_test_ā VALUES(13000,'x',1,1); +CREATE INDEX idx4 ON corrupt_bit_test_ā(b, z); +check table corrupt_bit_test_ā; +Table Op Msg_type Msg_text +test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxā" is corrupted. +test.corrupt_bit_test_ā check Warning InnoDB: The B-tree of index "idxē" is corrupted. +test.corrupt_bit_test_ā check error Corrupt +select c from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +select z from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +show warnings; +Level Code Message +Warning 179 InnoDB: Index "idxē" for table "test"."corrupt_bit_test_ā" is marked as corrupted +Error 1034 Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +select * from corrupt_bit_test_ā use index(primary) where a = 10001; +a b c z +10001 a 20001 20001 +begin; +insert into corrupt_bit_test_ā values (10002, "a", 20002, 20002); +delete from corrupt_bit_test_ā where a = 10001; +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +rollback; +drop index idxā on corrupt_bit_test_ā; +check table corrupt_bit_test_ā; +Table Op Msg_type Msg_text +test.corrupt_bit_test_ā check Warning InnoDB: Index "idxē" is marked as corrupted +test.corrupt_bit_test_ā check error Corrupt +set names utf8; +select z from corrupt_bit_test_ā; +ERROR HY000: Incorrect key file for table 'corrupt_bit_test_ā'; try to repair it +drop index idxē on corrupt_bit_test_ā; +select z from corrupt_bit_test_ā limit 10; +z +20001 +1 +1 +2 +11 +12 +21 +22 +31 +32 +drop table corrupt_bit_test_ā; +SET GLOBAL innodb_change_buffering_debug = 0; diff --git a/mysql-test/suite/innodb/t/innodb_bug59733.test b/mysql-test/suite/innodb/t/innodb_bug59733.test new file mode 100644 index 00000000000..0b1bff51932 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug59733.test @@ -0,0 +1,53 @@ +# +# Bug #59733 Possible deadlock when buffered changes are to be discarded +# in buf_page_create +# +-- source include/have_innodb.inc + +-- disable_query_log +# The flag innodb_change_buffering_debug is only available in debug builds. +# It instructs InnoDB to try to evict pages from the buffer pool when +# change buffering is possible, so that the change buffer will be used +# whenever possible. +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET @innodb_change_buffering_debug_orig = @@innodb_change_buffering_debug; +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = 1; +-- enable_query_log + +CREATE TABLE bug59733(a INT AUTO_INCREMENT PRIMARY KEY,b CHAR(1))ENGINE=InnoDB; + +# Create enough rows for the table, so that the insert buffer will be +# used. There must be multiple index pages, because changes to the +# root page are never buffered. + +INSERT INTO bug59733 VALUES(0,'x'); +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; +INSERT INTO bug59733 SELECT 0,b FROM bug59733; + +# Create the secondary index for which changes will be buffered. +CREATE INDEX b ON bug59733 (b); + +# This should be buffered, if innodb_change_buffering_debug = 1 is in effect. +DELETE FROM bug59733 WHERE (a%100)=0; + +# Drop the index in order to get free pages with orphaned buffered changes. +DROP INDEX b ON bug59733; + +# Create the index and attempt to reuse pages for which buffered changes exist. +CREATE INDEX b ON bug59733 (b); + +DROP TABLE bug59733; + +-- disable_query_log +-- error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = @innodb_change_buffering_debug_orig; diff --git a/mysql-test/suite/innodb/t/innodb_corrupt_bit.test b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test new file mode 100644 index 00000000000..34991362f98 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_corrupt_bit.test @@ -0,0 +1,120 @@ +# +# Test for persistent corrupt bit for corrupted index and table +# +-- source include/have_innodb.inc + +# This test needs debug server +--source include/have_debug.inc + +-- disable_query_log +# This test setup is extracted from bug56680.test: +# The flag innodb_change_buffering_debug is only available in debug builds. +# It instructs InnoDB to try to evict pages from the buffer pool when +# change buffering is possible, so that the change buffer will be used +# whenever possible. +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET @innodb_change_buffering_debug_orig = @@innodb_change_buffering_debug; +-- error 0,ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = 1; + +# Turn off Unique Check to create corrupted index with dup key +SET UNIQUE_CHECKS=0; + +-- enable_query_log + +set names utf8; + +CREATE TABLE corrupt_bit_test_ā( + a INT AUTO_INCREMENT PRIMARY KEY, + b CHAR(100), + c INT, + z INT, + INDEX(b)) +ENGINE=InnoDB; + +INSERT INTO corrupt_bit_test_ā VALUES(0,'x',1, 1); + +# This is the first unique index we intend to corrupt +CREATE UNIQUE INDEX idxā ON corrupt_bit_test_ā(c, b); + +# This is the second unique index we intend to corrupt +CREATE UNIQUE INDEX idxē ON corrupt_bit_test_ā(z, b); + +SELECT * FROM corrupt_bit_test_ā; + +select @@unique_checks; +select @@innodb_change_buffering_debug; + +# Create enough rows for the table, so that the insert buffer will be +# used for modifying the secondary index page. There must be multiple +# index pages, because changes to the root page are never buffered. + +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1,z+1 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+10,z+10 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+20,z+20 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+50,z+50 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+100,z+100 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+200,z+200 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+400,z+400 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+800,z+800 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+1600,z+1600 FROM corrupt_bit_test_ā; +INSERT INTO corrupt_bit_test_ā SELECT 0,b,c+4000,z+4000 FROM corrupt_bit_test_ā; + +select count(*) from corrupt_bit_test_ā; + +CREATE INDEX idx3 ON corrupt_bit_test_ā(b, c); + +# Create a dup key error on index "idxē" and "idxā" by inserting a dup value +INSERT INTO corrupt_bit_test_ā VALUES(13000,'x',1,1); + +# creating an index should succeed even if other secondary indexes are corrupted +CREATE INDEX idx4 ON corrupt_bit_test_ā(b, z); + +# Check table will find the unique indexes corrupted +# with dup key +check table corrupt_bit_test_ā; + +# This selection intend to use the corrupted index. Expect to fail +-- error ER_NOT_KEYFILE +select c from corrupt_bit_test_ā; + +-- error ER_NOT_KEYFILE +select z from corrupt_bit_test_ā; + +show warnings; + +# Since corrupted index is a secondary index, we only disable such +# index and allow other DML to proceed +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); + +# This does not use the corrupted index, expect to succeed +select * from corrupt_bit_test_ā use index(primary) where a = 10001; + +# Some more DMLs +begin; +insert into corrupt_bit_test_ā values (10002, "a", 20002, 20002); +delete from corrupt_bit_test_ā where a = 10001; +insert into corrupt_bit_test_ā values (10001, "a", 20001, 20001); +rollback; + +# Drop one corrupted index before reboot +drop index idxā on corrupt_bit_test_ā; + +check table corrupt_bit_test_ā; + +set names utf8; + +-- error ER_NOT_KEYFILE +select z from corrupt_bit_test_ā; + +# Drop the corrupted index +drop index idxē on corrupt_bit_test_ā; + +# Now select back to normal +select z from corrupt_bit_test_ā limit 10; + +# Drop table +drop table corrupt_bit_test_ā; + +-- error 0, ER_UNKNOWN_SYSTEM_VARIABLE +SET GLOBAL innodb_change_buffering_debug = 0; diff --git a/mysql-test/suite/sys_vars/r/all_vars.result b/mysql-test/suite/sys_vars/r/all_vars.result index 715ad9e2c15..af05e3bc393 100644 --- a/mysql-test/suite/sys_vars/r/all_vars.result +++ b/mysql-test/suite/sys_vars/r/all_vars.result @@ -11,7 +11,5 @@ There should be *no* long test name listed below: select variable_name as `There should be *no* variables listed below:` from t2 left join t1 on variable_name=test_name where test_name is null; There should be *no* variables listed below: -INNODB_LARGE_PREFIX -INNODB_LARGE_PREFIX drop table t1; drop table t2; diff --git a/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result b/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result index 163eb31f686..ecf11351cd9 100644 --- a/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result @@ -1,13 +1,29 @@ +SET @start_global_value = @@global.innodb_file_per_table; +SELECT @start_global_value; +@start_global_value +0 '#---------------------BS_STVARS_028_01----------------------#' SELECT COUNT(@@GLOBAL.innodb_file_per_table); COUNT(@@GLOBAL.innodb_file_per_table) 1 1 Expected '#---------------------BS_STVARS_028_02----------------------#' -SELECT COUNT(@@GLOBAL.innodb_file_per_table); -COUNT(@@GLOBAL.innodb_file_per_table) +SET @@global.innodb_file_per_table = 0; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 +SET @@global.innodb_file_per_table ='On' ; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +1 +SET @@global.innodb_file_per_table ='Off' ; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 +SET @@global.innodb_file_per_table = 1; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table 1 -1 Expected '#---------------------BS_STVARS_028_03----------------------#' SELECT IF(@@GLOBAL.innodb_file_per_table,'ON','OFF') = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -47,4 +63,7 @@ COUNT(@@GLOBAL.innodb_file_per_table) 1 Expected SELECT innodb_file_per_table = @@SESSION.innodb_file_per_table; ERROR 42S22: Unknown column 'innodb_file_per_table' in 'field list' -Expected error 'Readonly variable' +SET @@global.innodb_file_per_table = @start_global_value; +SELECT @@global.innodb_file_per_table; +@@global.innodb_file_per_table +0 diff --git a/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result b/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result new file mode 100644 index 00000000000..bc9b7019eb8 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_force_load_corrupted_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_031_01----------------------#' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +'#---------------------BS_STVARS_031_02----------------------#' +SET @@GLOBAL.innodb_force_load_corrupted=1; +ERROR HY000: Variable 'innodb_force_load_corrupted' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +'#---------------------BS_STVARS_031_03----------------------#' +SELECT IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_031_04----------------------#' +SELECT @@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted; +@@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted +1 +1 Expected +'#---------------------BS_STVARS_031_05----------------------#' +SELECT COUNT(@@innodb_force_load_corrupted); +COUNT(@@innodb_force_load_corrupted) +1 +1 Expected +SELECT COUNT(@@local.innodb_force_load_corrupted); +ERROR HY000: Variable 'innodb_force_load_corrupted' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_force_load_corrupted); +ERROR HY000: Variable 'innodb_force_load_corrupted' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +COUNT(@@GLOBAL.innodb_force_load_corrupted) +1 +1 Expected +SELECT innodb_force_load_corrupted = @@SESSION.innodb_force_load_corrupted; +ERROR 42S22: Unknown column 'innodb_force_load_corrupted' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result b/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result new file mode 100644 index 00000000000..adb56b347cd --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_large_prefix_basic.result @@ -0,0 +1,92 @@ +SET @start_global_value = @@global.innodb_large_prefix; +SELECT @start_global_value; +@start_global_value +0 +Valid values are 'ON' and 'OFF' +select @@global.innodb_large_prefix in (0, 1); +@@global.innodb_large_prefix in (0, 1) +1 +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select @@session.innodb_large_prefix; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable +show global variables like 'innodb_large_prefix'; +Variable_name Value +innodb_large_prefix OFF +show session variables like 'innodb_large_prefix'; +Variable_name Value +innodb_large_prefix OFF +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set global innodb_large_prefix='OFF'; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set @@global.innodb_large_prefix=1; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set global innodb_large_prefix=0; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX OFF +set @@global.innodb_large_prefix='ON'; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set session innodb_large_prefix='OFF'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +set @@session.innodb_large_prefix='ON'; +ERROR HY000: Variable 'innodb_large_prefix' is a GLOBAL variable and should be set with SET GLOBAL +set global innodb_large_prefix=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_large_prefix' +set global innodb_large_prefix=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_large_prefix' +set global innodb_large_prefix=2; +ERROR 42000: Variable 'innodb_large_prefix' can't be set to the value of '2' +NOTE: The following should fail with ER_WRONG_VALUE_FOR_VAR (BUG#50643) +set global innodb_large_prefix=-3; +select @@global.innodb_large_prefix; +@@global.innodb_large_prefix +1 +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_LARGE_PREFIX ON +set global innodb_large_prefix='AUTO'; +ERROR 42000: Variable 'innodb_large_prefix' can't be set to the value of 'AUTO' +SET @@global.innodb_large_prefix = @start_global_value; +SELECT @@global.innodb_large_prefix; +@@global.innodb_large_prefix +0 diff --git a/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result b/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result index 89960e5860f..1dcc2d554ce 100644 --- a/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result @@ -1,13 +1,21 @@ +SET @start_global_value=@@global.innodb_lock_wait_timeout; +SELECT @start_global_value; +@start_global_value +50 '#---------------------BS_STVARS_032_01----------------------#' SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); COUNT(@@GLOBAL.innodb_lock_wait_timeout) 1 1 Expected '#---------------------BS_STVARS_032_02----------------------#' -SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); -COUNT(@@GLOBAL.innodb_lock_wait_timeout) -1 -1 Expected +SET global innodb_lock_wait_timeout=60; +SELECT @@global.innodb_lock_wait_timeout; +@@global.innodb_lock_wait_timeout +60 +SET session innodb_lock_wait_timeout=60; +SELECT @@session.innodb_lock_wait_timeout; +@@session.innodb_lock_wait_timeout +60 '#---------------------BS_STVARS_032_03----------------------#' SELECT @@GLOBAL.innodb_lock_wait_timeout = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -47,4 +55,7 @@ COUNT(@@GLOBAL.innodb_lock_wait_timeout) 1 Expected SELECT innodb_lock_wait_timeout = @@SESSION.innodb_lock_wait_timeout; ERROR 42S22: Unknown column 'innodb_lock_wait_timeout' in 'field list' -Expected error 'Readonly variable' +SET @@global.innodb_lock_wait_timeout = @start_global_value; +SELECT @@global.innodb_lock_wait_timeout; +@@global.innodb_lock_wait_timeout +50 diff --git a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test index 5b6fa943bbe..e07234a9152 100644 --- a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_basic.test @@ -1,8 +1,7 @@ ################# mysql-test\t\innodb_autoinc_lock_mode_basic.test ############ # # # Variable Name: innodb_autoinc_lock_mode # -# Scope: GLOBAL # -# Access Type: Dynamic # +# Access Type: Static # # Data Type: Numeric # # Default Value: 1 # # Range: 0,1,2 # diff --git a/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test b/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test index 636309a3088..e1b62046313 100644 --- a/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_fast_shutdown_basic.test @@ -3,9 +3,9 @@ # Variable Name: innodb_fast_shutdown # # Scope: GLOBAL # # Access Type: Dynamic # -# Data Type: boolean # +# Data Type: numeric # # Default Value: 1 # -# Valid Values: 0,1 # +# Valid Values: 0,1,2 # # # # # # Creation Date: 2008-02-20 # diff --git a/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test b/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test index 76a50df8879..1478d6df2e9 100644 --- a/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test @@ -4,7 +4,7 @@ # # # Variable Name: innodb_file_per_table # # Scope: Global # -# Access Type: Static # +# Access Type: Dynamic # # Data Type: boolean # # # # # @@ -24,6 +24,10 @@ --source include/have_innodb.inc +SET @start_global_value = @@global.innodb_file_per_table; +SELECT @start_global_value; + + --echo '#---------------------BS_STVARS_028_01----------------------#' #################################################################### # Displaying default value # @@ -37,11 +41,17 @@ SELECT COUNT(@@GLOBAL.innodb_file_per_table); # Check if Value can set # #################################################################### -SELECT COUNT(@@GLOBAL.innodb_file_per_table); ---echo 1 Expected +SET @@global.innodb_file_per_table = 0; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table ='On' ; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table ='Off' ; +SELECT @@global.innodb_file_per_table; +SET @@global.innodb_file_per_table = 1; +SELECT @@global.innodb_file_per_table; --echo '#---------------------BS_STVARS_028_03----------------------#' ################################################################# @@ -93,6 +103,10 @@ SELECT COUNT(@@GLOBAL.innodb_file_per_table); --Error ER_BAD_FIELD_ERROR SELECT innodb_file_per_table = @@SESSION.innodb_file_per_table; ---echo Expected error 'Readonly variable' +# +# Cleanup +# +SET @@global.innodb_file_per_table = @start_global_value; +SELECT @@global.innodb_file_per_table; diff --git a/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test b/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test new file mode 100644 index 00000000000..1726b320f47 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_force_load_corrupted_basic.test @@ -0,0 +1,102 @@ + + +################## mysql-test\t\innodb_force_load_corrupted_basic.test ##### +# # +# Variable Name: innodb_force_load_corrupted # +# Scope: Global # +# Access Type: Static # +# Data Type: boolean # +# # +# # +# Creation Date: 2008-02-07 # +# Author : Sharique Abdullah # +# # +# # +# Description:Test Cases of Dynamic System Variable innodb_force_load_corrupted# +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc + +--echo '#---------------------BS_STVARS_031_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_031_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_force_load_corrupted=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_031_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT IF(@@GLOBAL.innodb_force_load_corrupted, "ON", "OFF") = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_force_load_corrupted'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_031_04----------------------#' +################################################################################ +# Check if accessing variable with and without GLOBAL point to same variable # +################################################################################ +SELECT @@innodb_force_load_corrupted = @@GLOBAL.innodb_force_load_corrupted; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_031_05----------------------#' +################################################################################ +# Check if innodb_force_load_corrupted can be accessed with and without @@ sign # +################################################################################ + +SELECT COUNT(@@innodb_force_load_corrupted); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_force_load_corrupted); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_force_load_corrupted); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_force_load_corrupted); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_force_load_corrupted = @@SESSION.innodb_force_load_corrupted; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test b/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test index 3f00b50cf08..0ced5800d4b 100644 --- a/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_io_capacity_basic.test @@ -54,5 +54,9 @@ select * from information_schema.global_variables where variable_name='innodb_io set global innodb_io_capacity=100; select @@global.innodb_io_capacity; +# +# cleanup +# + SET @@global.innodb_io_capacity = @start_global_value; SELECT @@global.innodb_io_capacity; diff --git a/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test b/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test new file mode 100644 index 00000000000..582e9ffbee8 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_large_prefix_basic.test @@ -0,0 +1,70 @@ + + +# 2010-01-25 - Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_large_prefix; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are 'ON' and 'OFF' +select @@global.innodb_large_prefix in (0, 1); +select @@global.innodb_large_prefix; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.innodb_large_prefix; +show global variables like 'innodb_large_prefix'; +show session variables like 'innodb_large_prefix'; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; + +# +# show that it's writable +# +set global innodb_large_prefix='OFF'; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set @@global.innodb_large_prefix=1; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set global innodb_large_prefix=0; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +set @@global.innodb_large_prefix='ON'; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +--error ER_GLOBAL_VARIABLE +set session innodb_large_prefix='OFF'; +--error ER_GLOBAL_VARIABLE +set @@session.innodb_large_prefix='ON'; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_large_prefix=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_large_prefix=1e1; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_large_prefix=2; +--echo NOTE: The following should fail with ER_WRONG_VALUE_FOR_VAR (BUG#50643) +set global innodb_large_prefix=-3; +select @@global.innodb_large_prefix; +select * from information_schema.global_variables where variable_name='innodb_large_prefix'; +select * from information_schema.session_variables where variable_name='innodb_large_prefix'; +--error ER_WRONG_VALUE_FOR_VAR +set global innodb_large_prefix='AUTO'; + +# +# Cleanup +# + +SET @@global.innodb_large_prefix = @start_global_value; +SELECT @@global.innodb_large_prefix; diff --git a/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test b/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test index 8cfd23fd6e7..f80b8e48736 100644 --- a/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test @@ -3,13 +3,13 @@ ################## mysql-test\t\innodb_lock_wait_timeout_basic.test ########### # # # Variable Name: innodb_lock_wait_timeout # -# Scope: Global # -# Access Type: Static # +# Scope: Global , Session # +# Access Type: Dynamic # # Data Type: numeric # # # # # # Creation Date: 2008-02-07 # -# Author : Sharique Abdullah # +# Author : Sharique Abdullah # # # # # # Description:Test Cases of Dynamic System Variable innodb_lock_wait_timeout # @@ -24,6 +24,9 @@ --source include/have_innodb.inc +SET @start_global_value=@@global.innodb_lock_wait_timeout; +SELECT @start_global_value; + --echo '#---------------------BS_STVARS_032_01----------------------#' #################################################################### # Displaying default value # @@ -37,11 +40,10 @@ SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); # Check if Value can set # #################################################################### -SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); ---echo 1 Expected - - - +SET global innodb_lock_wait_timeout=60; +SELECT @@global.innodb_lock_wait_timeout; +SET session innodb_lock_wait_timeout=60; +SELECT @@session.innodb_lock_wait_timeout; --echo '#---------------------BS_STVARS_032_03----------------------#' ################################################################# @@ -89,6 +91,10 @@ SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); --Error ER_BAD_FIELD_ERROR SELECT innodb_lock_wait_timeout = @@SESSION.innodb_lock_wait_timeout; ---echo Expected error 'Readonly variable' +# +# Cleanup +# +SET @@global.innodb_lock_wait_timeout = @start_global_value; +SELECT @@global.innodb_lock_wait_timeout; diff --git a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test index 38c3acd92a2..7e70ed11351 100644 --- a/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_max_dirty_pages_pct_basic.test @@ -4,8 +4,8 @@ # Scope: GLOBAL # # Access Type: Dynamic # # Data Type: Numeric # -# Default Value: 90 # -# Range: 0-1000 # +# Default Value: 75 # +# Range: 0-99 # # # # # # Creation Date: 2008-02-07 # diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h index 3bd83398e81..428a58b0767 100644 --- a/mysys/my_handler_errors.h +++ b/mysys/my_handler_errors.h @@ -81,7 +81,8 @@ static const char *handler_error_messages[]= "File to short; Expected more data in file", "Read page with wrong checksum", "Too many active concurrent transactions", - "Index column length exceeds limit" + "Index column length exceeds limit", + "Index corrupted" }; extern void my_handler_error_register(void); diff --git a/sql/handler.cc b/sql/handler.cc index 580677242bd..db1eea6484b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -358,6 +358,7 @@ int ha_init_errors(void) SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE)); SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS)); SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG)); + SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT)); /* Register the error messages for use with my_error(). */ return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST); @@ -2865,6 +2866,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_INDEX_COL_TOO_LONG: textno= ER_INDEX_COLUMN_TOO_LONG; break; + case HA_ERR_INDEX_CORRUPT: + textno= ER_INDEX_CORRUPT; + break; default: { /* The error was "unknown" to this function. diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index b8f46f090ab..519d693f96d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6415,3 +6415,5 @@ ER_ERROR_IN_TRIGGER_BODY ER_ERROR_IN_UNKNOWN_TRIGGER_BODY eng "Unknown trigger has an error in its body: '%-.256s'" +ER_INDEX_CORRUPT + eng "Index %s is corrupted" diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 97a227c8bb5..0b1de2c47fa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -655,8 +655,8 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, const char *proc_info= thd->proc_info; len= my_snprintf(header, sizeof(header), - "MySQL thread id %lu, query id %lu", - thd->thread_id, (ulong) thd->query_id); + "MySQL thread id %lu, OS thread handle 0x%lx, query id %lu", + thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id); str.length(0); str.append(header, len); diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 3d8fadeaf92..4ce94854f7a 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -690,7 +690,8 @@ btr_root_block_get( zip_size = dict_table_zip_size(index->table); root_page_no = dict_index_get_page(index); - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + index, mtr); ut_a((ibool)!!page_is_comp(buf_block_get_frame(block)) == dict_table_is_comp(index->table)); #ifdef UNIV_BTR_DEBUG @@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf( dict_table_zip_size(index->table), node_addr.page, RW_X_LATCH, mtr); new_page = buf_block_get_frame(new_block); - buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level(new_block, SYNC_IBUF_TREE_NODE_NEW); flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, @@ -1139,7 +1140,7 @@ btr_node_ptr_get_child( page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); return(btr_block_get(space, dict_table_zip_size(index->table), - page_no, RW_X_LATCH, mtr)); + page_no, RW_X_LATCH, index, mtr)); } /************************************************************//** @@ -1312,7 +1313,8 @@ btr_create( space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); - buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level( + ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(buf_block_get_page_no(ibuf_hdr_block) == IBUF_HEADER_PAGE_NO); @@ -1350,10 +1352,9 @@ btr_create( page_no = buf_block_get_page_no(block); frame = buf_block_get_frame(block); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - if (type & DICT_IBUF) { /* It is an insert buffer tree: initialize the free list */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); @@ -1361,6 +1362,8 @@ btr_create( } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ + buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + if (!fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { /* Not enough space for new segment, free root @@ -1432,7 +1435,8 @@ btr_free_but_not_root( leaf_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + root, space)); @@ -1454,7 +1458,8 @@ leaf_loop: top_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + root, space)); @@ -1480,13 +1485,13 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr) /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; fseg_header_t* header; - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, mtr); btr_search_drop_page_hash_index(block); @@ -2365,9 +2370,8 @@ btr_attach_half_pages( /* Update page links of the level */ if (prev_page_no != FIL_NULL) { - buf_block_t* prev_block = btr_block_get(space, zip_size, - prev_page_no, - RW_X_LATCH, mtr); + buf_block_t* prev_block = btr_block_get( + space, zip_size, prev_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(prev_block->frame) == page_is_comp(page)); ut_a(btr_page_get_next(prev_block->frame, mtr) @@ -2380,9 +2384,8 @@ btr_attach_half_pages( } if (next_page_no != FIL_NULL) { - buf_block_t* next_block = btr_block_get(space, zip_size, - next_page_no, - RW_X_LATCH, mtr); + buf_block_t* next_block = btr_block_get( + space, zip_size, next_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_block->frame) == page_is_comp(page)); ut_a(btr_page_get_prev(next_block->frame, mtr) @@ -2804,17 +2807,42 @@ func_exit: return(rec); } +#ifdef UNIV_SYNC_DEBUG +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,index,mtr) +#else /* UNIV_SYNC_DEBUG */ +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,mtr) +#endif /* UNIV_SYNC_DEBUG */ + /*************************************************************//** Removes a page from the level list of pages. */ -static +static __attribute__((nonnull)) void -btr_level_list_remove( -/*==================*/ - ulint space, /*!< in: space where removed */ - ulint zip_size,/*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - page_t* page, /*!< in: page to remove */ - mtr_t* mtr) /*!< in: mtr */ +btr_level_list_remove_func( +/*=======================*/ + ulint space, /*!< in: space where removed */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + page_t* page, /*!< in/out: page to remove */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree */ +#endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint prev_page_no; ulint next_page_no; @@ -2832,7 +2860,7 @@ btr_level_list_remove( if (prev_page_no != FIL_NULL) { buf_block_t* prev_block = btr_block_get(space, zip_size, prev_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* prev_page = buf_block_get_frame(prev_block); #ifdef UNIV_BTR_DEBUG @@ -2849,7 +2877,7 @@ btr_level_list_remove( if (next_page_no != FIL_NULL) { buf_block_t* next_block = btr_block_get(space, zip_size, next_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG @@ -3175,7 +3203,7 @@ btr_compress( if (is_left) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3184,7 +3212,7 @@ btr_compress( } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3273,7 +3301,7 @@ err_exit: btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); @@ -3330,7 +3358,7 @@ err_exit: #endif /* UNIV_BTR_DEBUG */ /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); /* Replace the address of the old child node (= page) with the address of the merge page to the right */ @@ -3522,7 +3550,7 @@ btr_discard_page( if (left_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3530,7 +3558,7 @@ btr_discard_page( #endif /* UNIV_BTR_DEBUG */ } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3565,7 +3593,7 @@ btr_discard_page( btr_node_ptr_delete(index, block, mtr); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); #ifdef UNIV_ZIP_DEBUG { page_zip_des_t* merge_page_zip @@ -4083,7 +4111,7 @@ loop: if (right_page_no != FIL_NULL) { const rec_t* right_rec; right_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); right_page = buf_block_get_frame(right_block); if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr) != page_get_page_no(page))) { @@ -4309,7 +4337,7 @@ node_ptr_fails: mtr_start(&mtr); block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); page = buf_block_get_frame(block); goto loop; diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 46a52b549af..133b40e2d7b 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -249,7 +249,8 @@ btr_cur_latch_leaves( case BTR_SEARCH_LEAF: case BTR_MODIFY_LEAF: mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH; - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -260,9 +261,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, left_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -272,8 +273,9 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -282,9 +284,9 @@ btr_cur_latch_leaves( right_page_no = btr_page_get_next(page, mtr); if (right_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - right_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, right_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -303,8 +305,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, + left_page_no, mode, cursor->index, mtr); cursor->left_block = get_block; #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) @@ -315,7 +318,8 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -669,7 +673,9 @@ retry_page_get: ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } ut_ad(index->id == btr_page_get_index_id(page)); @@ -767,7 +773,7 @@ retry_page_get: if (level != 0) { /* x-latch the page */ page = btr_page_get( - space, zip_size, page_no, RW_X_LATCH, mtr); + space, zip_size, page_no, RW_X_LATCH, index, mtr); ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table)); diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index 056896c7927..3bd2e9fd7d6 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -266,8 +266,10 @@ btr_pcur_restore_position_func( file, line, mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; - buf_block_dbg_add_level(btr_pcur_get_block(cursor), - SYNC_TREE_NODE); + buf_block_dbg_add_level( + btr_pcur_get_block(cursor), + dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); if (cursor->rel_pos == BTR_PCUR_ON) { #ifdef UNIV_DEBUG @@ -417,7 +419,8 @@ btr_pcur_move_to_next_page( ut_ad(next_page_no != FIL_NULL); next_block = btr_block_get(space, zip_size, next_page_no, - cursor->latch_mode, mtr); + cursor->latch_mode, + btr_pcur_get_btr_cur(cursor)->index, mtr); next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_page) == page_is_comp(page)); diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index 93573a300e4..7070420425c 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -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. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -845,6 +845,7 @@ btr_search_guess_on_hash( btr_pcur_t pcur; #endif ut_ad(index && info && tuple && cursor && mtr); + ut_ad(!dict_index_is_ibuf(index)); ut_ad((latch_mode == BTR_SEARCH_LEAF) || (latch_mode == BTR_MODIFY_LEAF)); diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 648e53ac4a6..7bbe4f3b0c6 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -3473,6 +3473,53 @@ buf_page_create( return(block); } +/********************************************************************//** +Mark a table with the specified space pointed by bpage->space corrupted. +Also remove the bpage from LRU list. +@return TRUE if successful */ +static +ibool +buf_mark_space_corrupt( +/*===================*/ + buf_page_t* bpage) /*!< in: pointer to the block in question */ +{ + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + const ibool uncompressed = (buf_page_get_state(bpage) + == BUF_BLOCK_FILE_PAGE); + ulint space = bpage->space; + ibool ret = TRUE; + + /* First unfix and release lock on the bpage */ + buf_pool_mutex_enter(buf_pool); + mutex_enter(buf_page_get_mutex(bpage)); + ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ); + ut_ad(bpage->buf_fix_count == 0); + + /* Set BUF_IO_NONE before we remove the block from LRU list */ + buf_page_set_io_fix(bpage, BUF_IO_NONE); + + if (uncompressed) { + rw_lock_x_unlock_gen( + &((buf_block_t*) bpage)->lock, + BUF_IO_READ); + } + + /* Find the table with specified space id, and mark it corrupted */ + if (dict_set_corrupted_by_space(space)) { + buf_LRU_free_one_page(bpage); + } else { + ret = FALSE; + } + + ut_ad(buf_pool->n_pend_reads > 0); + buf_pool->n_pend_reads--; + + mutex_exit(buf_page_get_mutex(bpage)); + buf_pool_mutex_exit(buf_pool); + + return(ret); +} + /********************************************************************//** Completes an asynchronous read or write request of a file page to or from the buffer pool. */ @@ -3598,10 +3645,19 @@ corrupt: "InnoDB: about forcing recovery.\n", stderr); if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { - fputs("InnoDB: Ending processing because of" - " a corrupt database page.\n", - stderr); - exit(1); + /* If page space id is larger than TRX_SYS_SPACE + (0), we will attempt to mark the corresponding + table as corrupted instead of crashing server */ + if (bpage->space > TRX_SYS_SPACE + && buf_mark_space_corrupt(bpage)) { + return; + } else { + fputs("InnoDB: Ending processing" + " because of" + " a corrupt database page.\n", + stderr); + ut_error; + } } } diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 93c98719e29..b5ca21e14a6 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -1885,6 +1885,22 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +/******************************************************************//** +Remove one page from LRU list and put it to free list */ +UNIV_INTERN +void +buf_LRU_free_one_page( +/*==================*/ + buf_page_t* bpage) /*!< in/out: block, must contain a file page and + be in a state where it can be freed; there + may or may not be a hash index to the page */ +{ + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) + != BUF_BLOCK_ZIP_FREE) { + buf_LRU_block_free_hashed_page((buf_block_t*) bpage); + } +} + /**********************************************************************//** Updates buf_pool->LRU_old_ratio for one buffer pool instance. @return updated old_pct */ diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 9a528d679a7..d7373a4b8ef 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -827,7 +827,7 @@ dict_truncate_index_tree( appropriate field in the SYS_INDEXES record: this mini-transaction marks the B-tree totally truncated */ - btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, NULL, mtr); btr_free_root(space, zip_size, root_page_no, mtr); create: diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 1e3aed92cf7..dfb733cb36c 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, 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 @@ -54,6 +54,7 @@ UNIV_INTERN dict_index_t* dict_ind_compact; #include "row0merge.h" #include "m_ctype.h" /* my_isspace() */ #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/ +#include "row0upd.h" #include @@ -611,8 +612,7 @@ dict_table_get_on_id( { dict_table_t* table; - if (table_id <= DICT_FIELDS_ID - || trx->dict_operation_lock_mode == RW_X_LATCH) { + if (trx->dict_operation_lock_mode == RW_X_LATCH) { /* Note: An X latch implies that the transaction already owns the dictionary mutex. */ @@ -1714,7 +1714,8 @@ undo_size_ok: new_index->page = page_no; rw_lock_create(index_tree_rw_lock_key, &new_index->lock, - SYNC_INDEX_TREE); + dict_index_is_ibuf(index) + ? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE); if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { @@ -5045,4 +5046,179 @@ dict_close(void) rw_lock_free(&dict_table_stats_latches[i]); } } + +/**********************************************************************//** +Find a table in dict_sys->table_LRU list with specified space id +@return table if found, NULL if not */ +static +dict_table_t* +dict_find_table_by_space( +/*=====================*/ + ulint space_id) /*!< in: space ID */ +{ + dict_table_t* table; + ulint num_item; + ulint count = 0; + + ut_ad(space_id > 0); + + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + num_item = UT_LIST_GET_LEN(dict_sys->table_LRU); + + /* This function intentionally does not acquire mutex as it is used + by error handling code in deep call stack as last means to avoid + killing the server, so it worth to risk some consequencies for + the action. */ + while (table && count < num_item) { + if (table->space == space_id) { + return(table); + } + + table = UT_LIST_GET_NEXT(table_LRU, table); + count++; + } + + return(NULL); +} + +/**********************************************************************//** +Flags a table with specified space_id corrupted in the data dictionary +cache +@return TRUE if successful */ +UNIV_INTERN +ibool +dict_set_corrupted_by_space( +/*========================*/ + ulint space_id) /*!< in: space ID */ +{ + dict_table_t* table; + + table = dict_find_table_by_space(space_id); + + if (!table) { + return(FALSE); + } + + /* mark the table->corrupted bit only, since the caller + could be too deep in the stack for SYS_INDEXES update */ + table->corrupted = TRUE; + + return(TRUE); +} + +/**********************************************************************//** +Flags an index corrupted both in the data dictionary cache +and in the SYS_INDEXES */ +UNIV_INTERN +void +dict_set_corrupted( +/*===============*/ + dict_index_t* index) /*!< in/out: index */ +{ + mem_heap_t* heap; + mtr_t mtr; + dict_index_t* sys_index; + dtuple_t* tuple; + dfield_t* dfield; + byte* buf; + const char* status; + btr_cur_t cursor; + + ut_ad(index); + ut_ad(mutex_own(&dict_sys->mutex)); + ut_ad(!dict_table_is_comp(dict_sys->sys_tables)); + ut_ad(!dict_table_is_comp(dict_sys->sys_indexes)); + +#ifdef UNIV_SYNC_DEBUG + ut_ad(sync_thread_levels_empty_except_dict()); +#endif + + /* Mark the table as corrupted only if the clustered index + is corrupted */ + if (dict_index_is_clust(index)) { + index->table->corrupted = TRUE; + } + + if (UNIV_UNLIKELY(dict_index_is_corrupted(index))) { + /* The index was already flagged corrupted. */ + ut_ad(index->table->corrupted); + return; + } + + heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t) + + sizeof(que_fork_t) + sizeof(upd_node_t) + + sizeof(upd_t) + 12)); + mtr_start(&mtr); + index->type |= DICT_CORRUPT; + + sys_index = UT_LIST_GET_FIRST(dict_sys->sys_indexes->indexes); + + /* Find the index row in SYS_INDEXES */ + tuple = dtuple_create(heap, 2); + + dfield = dtuple_get_nth_field(tuple, 0); + buf = mem_heap_alloc(heap, 8); + mach_write_to_8(buf, index->table->id); + dfield_set_data(dfield, buf, 8); + + dfield = dtuple_get_nth_field(tuple, 1); + buf = mem_heap_alloc(heap, 8); + mach_write_to_8(buf, index->id); + dfield_set_data(dfield, buf, 8); + + dict_index_copy_types(tuple, sys_index, 2); + + btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE, + BTR_MODIFY_LEAF, + &cursor, 0, __FILE__, __LINE__, &mtr); + + if (cursor.up_match == dtuple_get_n_fields(tuple)) { + /* UPDATE SYS_INDEXES SET TYPE=index->type + WHERE TABLE_ID=index->table->id AND INDEX_ID=index->id */ + ulint len; + byte* field = rec_get_nth_field_old( + btr_cur_get_rec(&cursor), + DICT_SYS_INDEXES_TYPE_FIELD, &len); + if (len != 4) { + goto fail; + } + mlog_write_ulint(field, index->type, MLOG_4BYTES, &mtr); + status = " InnoDB: Flagged corruption of "; + } else { +fail: + status = " InnoDB: Unable to flag corruption of "; + } + + mtr_commit(&mtr); + mem_heap_free(heap); + + ut_print_timestamp(stderr); + fputs(status, stderr); + dict_index_name_print(stderr, NULL, index); + putc('\n', stderr); +} + +/**********************************************************************//** +Flags an index corrupted in the data dictionary cache only. This +is used mostly to mark a corrupted index when index's own dictionary +is corrupted, and we force to load such index for repair purpose */ +UNIV_INTERN +void +dict_set_corrupted_index_cache_only( +/*================================*/ + dict_index_t* index) /*!< in/out: index */ +{ + ut_ad(index); + ut_ad(mutex_own(&dict_sys->mutex)); + ut_ad(!dict_table_is_comp(dict_sys->sys_tables)); + ut_ad(!dict_table_is_comp(dict_sys->sys_indexes)); + + /* Mark the table as corrupted only if the clustered index + is corrupted */ + if (dict_index_is_clust(index)) { + index->table->corrupted = TRUE; + } + + index->type |= DICT_CORRUPT; +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index ab1fb16361e..60590aa6638 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -52,6 +52,11 @@ static const char* SYSTEM_TABLE_NAME[] = { "SYS_FOREIGN", "SYS_FOREIGN_COLS" }; + +/* If this flag is TRUE, then we will load the cluster index's (and tables') +metadata even if it is marked as "corrupted". */ +UNIV_INTERN my_bool srv_load_corrupted = FALSE; + /****************************************************************//** Compare the name of an index column. @return TRUE if the i'th column of index is 'name'. */ @@ -1324,6 +1329,9 @@ err_len: goto err_len; } type = mach_read_from_4(field); + if (UNIV_UNLIKELY(type & (~0 << DICT_IT_BITS))) { + return("unknown SYS_INDEXES.TYPE bits"); + } field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len); if (UNIV_UNLIKELY(len != 4)) { @@ -1423,16 +1431,47 @@ dict_load_indexes( goto next_rec; } else if (err_msg) { fprintf(stderr, "InnoDB: %s\n", err_msg); + if (ignore_err & DICT_ERR_IGNORE_CORRUPT) { + goto next_rec; + } error = DB_CORRUPTION; goto func_exit; } ut_ad(index); + /* Check whether the index is corrupted */ + if (dict_index_is_corrupted(index)) { + ut_print_timestamp(stderr); + fputs(" InnoDB: ", stderr); + dict_index_name_print(stderr, NULL, index); + fputs(" is corrupted\n", stderr); + + if (!srv_load_corrupted + && !(ignore_err & DICT_ERR_IGNORE_CORRUPT) + && dict_index_is_clust(index)) { + dict_mem_index_free(index); + + error = DB_INDEX_CORRUPT; + goto func_exit; + } else { + /* We will load the index if + 1) srv_load_corrupted is TRUE + 2) ignore_err is set with + DICT_ERR_IGNORE_CORRUPT + 3) if the index corrupted is a secondary + index */ + ut_print_timestamp(stderr); + fputs(" InnoDB: load corrupted index ", stderr); + dict_index_name_print(stderr, NULL, index); + putc('\n', stderr); + } + } + /* We check for unsupported types first, so that the subsequent checks are relevant for the supported types. */ - if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { - + if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE + | DICT_CORRUPT)) { fprintf(stderr, "InnoDB: Error: unknown type %lu" " of index %s of table %s\n", @@ -1453,9 +1492,13 @@ dict_load_indexes( /* If caller can tolerate this error, we will continue to load the index and let caller deal with this error. However - mark the index and table corrupted */ - index->corrupted = TRUE; - table->corrupted = TRUE; + mark the index and table corrupted. We + only need to mark such in the index + dictionary cache for such metadata corruption, + since we would always be able to set it + when loading the dictionary cache */ + dict_set_corrupted_index_cache_only(index); + fprintf(stderr, "InnoDB: Index is corrupt but forcing" " load into data dictionary\n"); @@ -1495,9 +1538,10 @@ corrupted: index->name, table->name); /* If the force recovery flag is set, and - if the failed index is not the primary index, we - will continue and open other indexes */ - if (srv_force_recovery + if the failed index is not the clustered index, + we will continue and open other indexes */ + if ((srv_force_recovery + || srv_load_corrupted) && !dict_index_is_clust(index)) { error = DB_SUCCESS; goto next_rec; @@ -1812,6 +1856,30 @@ err_exit: err = dict_load_indexes(table, heap, ignore_err); + if (err == DB_INDEX_CORRUPT) { + /* Refuse to load the table if the table has a corrupted + cluster index */ + if (!srv_load_corrupted) { + fprintf(stderr, "InnoDB: Error: Load table "); + ut_print_name(stderr, NULL, TRUE, table->name); + fprintf(stderr, " failed, the table has corrupted" + " clustered indexes. Turn on" + " 'innodb_force_load_corrupted'" + " to drop it\n"); + + dict_table_remove_from_cache(table); + table = NULL; + goto func_exit; + } else { + dict_index_t* clust_index; + clust_index = dict_table_get_first_index(table); + + if (dict_index_is_corrupted(clust_index)) { + table->corrupted = TRUE; + } + } + } + /* Initialize table foreign_child value. Its value could be changed when dict_load_foreigns() is called below */ table->fk_max_recusive_level = 0; @@ -1838,9 +1906,15 @@ err_exit: index = dict_table_get_first_index(table); if (!srv_force_recovery || !index - || !dict_index_is_clust(index)) { + || !dict_index_is_clust(index)) { dict_table_remove_from_cache(table); table = NULL; + } else if (dict_index_is_corrupted(index)) { + + /* It is possible we force to load a corrupted + clustered index if srv_load_corrupted is set. + Mark the table as corrupted in this case */ + table->corrupted = TRUE; } } #if 0 @@ -1867,6 +1941,7 @@ err_exit: mutex_exit(&dict_foreign_err_mutex); } #endif /* 0 */ +func_exit: mem_heap_free(heap); return(table); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f8e96d5fa60..c4283d65a2a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1043,6 +1043,8 @@ convert_error_code_to_mysql( #endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ case DB_UNSUPPORTED: return(HA_ERR_UNSUPPORTED); + case DB_INDEX_CORRUPT: + return(HA_ERR_INDEX_CORRUPT); } } @@ -2078,6 +2080,29 @@ no_db_name: } +/*****************************************************************//** +A wrapper function of innobase_convert_name(), convert a table or +index name to the MySQL system_charset_info (UTF-8) and quote it if needed. +@return pointer to the end of buf */ +static inline +void +innobase_format_name( +/*==================*/ + char* buf, /*!< out: buffer for converted identifier */ + ulint buflen, /*!< in: length of buf, in bytes */ + const char* name, /*!< in: index or table name to format */ + ibool is_index_name) /*!< in: index name */ +{ + const char* bufend; + + bufend = innobase_convert_name(buf, buflen, name, strlen(name), + NULL, !is_index_name); + + ut_ad((ulint) (bufend - buf) < buflen); + + buf[bufend - buf] = '\0'; +} + /**********************************************************************//** Determines if the currently running transaction has been interrupted. @return TRUE if interrupted */ @@ -5664,12 +5689,14 @@ ha_innobase::index_read( index = prebuilt->index; - if (UNIV_UNLIKELY(index == NULL)) { + if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) { prebuilt->index_usable = FALSE; DBUG_RETURN(HA_ERR_CRASHED); } if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + DBUG_RETURN(dict_index_is_corrupted(index) + ? HA_ERR_INDEX_CORRUPT + : HA_ERR_TABLE_DEF_CHANGED); } /* Note that if the index for which the search template is built is not @@ -5855,10 +5882,33 @@ ha_innobase::change_active_index( prebuilt->index); if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - push_warning_printf(user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - HA_ERR_TABLE_DEF_CHANGED, - "InnoDB: insufficient history for index %u", - keynr); + if (dict_index_is_corrupted(prebuilt->index)) { + char index_name[MAX_FULL_NAME_LEN + 1]; + char table_name[MAX_FULL_NAME_LEN + 1]; + + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + + innobase_format_name( + table_name, sizeof table_name, + prebuilt->index->table->name, FALSE); + + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_INDEX_CORRUPT, + "InnoDB: Index %s for table %s is" + " marked as corrupted", + index_name, table_name); + DBUG_RETURN(1); + } else { + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: insufficient history for index %u", + keynr); + } + /* The caller seems to ignore this. Thus, we must check this again in row_search_for_mysql(). */ DBUG_RETURN(2); @@ -7518,6 +7568,10 @@ ha_innobase::records_in_range( n_rows = HA_POS_ERROR; goto func_exit; } + if (dict_index_is_corrupted(index)) { + n_rows = HA_ERR_INDEX_CORRUPT; + goto func_exit; + } if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) { n_rows = HA_ERR_TABLE_DEF_CHANGED; goto func_exit; @@ -8184,6 +8238,7 @@ ha_innobase::check( ulint n_rows_in_table = ULINT_UNDEFINED; ibool is_ok = TRUE; ulint old_isolation_level; + ibool table_corrupted; DBUG_ENTER("ha_innobase::check"); DBUG_ASSERT(thd == ha_thd()); @@ -8225,6 +8280,14 @@ ha_innobase::check( prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ; + /* Check whether the table is already marked as corrupted + before running the check table */ + table_corrupted = prebuilt->table->corrupted; + + /* Reset table->corrupted bit so that check table can proceed to + do additional check */ + prebuilt->table->corrupted = FALSE; + /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ mutex_enter(&kernel_mutex); srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ @@ -8233,6 +8296,7 @@ ha_innobase::check( for (index = dict_table_get_first_index(prebuilt->table); index != NULL; index = dict_table_get_next_index(index)) { + char index_name[MAX_FULL_NAME_LEN + 1]; #if 0 fputs("Validating index ", stderr); ut_print_name(stderr, trx, FALSE, index->name); @@ -8241,11 +8305,16 @@ ha_innobase::check( if (!btr_validate_index(index, prebuilt->trx)) { is_ok = FALSE; + + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NOT_KEYFILE, "InnoDB: The B-tree of" - " index '%-.200s' is corrupted.", - index->name); + " index %s is corrupted.", + index_name); continue; } @@ -8258,11 +8327,26 @@ ha_innobase::check( prebuilt->trx, prebuilt->index); if (UNIV_UNLIKELY(!prebuilt->index_usable)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - HA_ERR_TABLE_DEF_CHANGED, - "InnoDB: Insufficient history for" - " index '%-.200s'", - index->name); + innobase_format_name( + index_name, sizeof index_name, + prebuilt->index->name, TRUE); + + if (dict_index_is_corrupted(prebuilt->index)) { + push_warning_printf( + user_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_INDEX_CORRUPT, + "InnoDB: Index %s is marked as" + " corrupted", + index_name); + is_ok = FALSE; + } else { + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: Insufficient history for" + " index %s", + index_name); + } continue; } @@ -8276,12 +8360,19 @@ ha_innobase::check( prebuilt->select_lock_type = LOCK_NONE; if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) { + innobase_format_name( + index_name, sizeof index_name, + index->name, TRUE); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NOT_KEYFILE, "InnoDB: The B-tree of" - " index '%-.200s' is corrupted.", - index->name); + " index %s is corrupted.", + index_name); is_ok = FALSE; + row_mysql_lock_data_dictionary(prebuilt->trx); + dict_set_corrupted(index); + row_mysql_unlock_data_dictionary(prebuilt->trx); } if (thd_killed(user_thd)) { @@ -8308,6 +8399,20 @@ ha_innobase::check( } } + if (table_corrupted) { + /* If some previous operation has marked the table as + corrupted in memory, and has not propagated such to + clustered index, we will do so here */ + index = dict_table_get_first_index(prebuilt->table); + + if (!dict_index_is_corrupted(index)) { + mutex_enter(&dict_sys->mutex); + dict_set_corrupted(index); + mutex_exit(&dict_sys->mutex); + } + prebuilt->table->corrupted = TRUE; + } + /* Restore the original isolation level */ prebuilt->trx->isolation_level = old_isolation_level; @@ -11101,6 +11206,11 @@ static MYSQL_SYSVAR_BOOL(large_prefix, innobase_large_prefix, "Support large index prefix length of REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes.", NULL, NULL, FALSE); +static MYSQL_SYSVAR_BOOL(force_load_corrupted, srv_load_corrupted, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Force InnoDB to load metadata of corrupted table.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, "Force InnoDB to not use next-key locking, to use only row-level locking.", @@ -11360,6 +11470,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(flush_method), MYSQL_SYSVAR(force_recovery), MYSQL_SYSVAR(large_prefix), + MYSQL_SYSVAR(force_load_corrupted), MYSQL_SYSVAR(locks_unsafe_for_binlog), MYSQL_SYSVAR(lock_wait_timeout), #ifdef UNIV_LOG_ARCHIVE diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 7d94ebc6438..718f2082ce9 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 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 @@ -402,7 +402,7 @@ ibuf_tree_root_get( block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); root = buf_block_get_frame(block); @@ -549,7 +549,7 @@ ibuf_init_at_db_start(void) block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); root = buf_block_get_frame(block); } @@ -2209,7 +2209,8 @@ ibuf_add_free_page(void) } else { buf_block_t* block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); } @@ -2332,8 +2333,7 @@ ibuf_remove_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); - + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); page = buf_block_get_frame(block); } @@ -3022,7 +3022,7 @@ ibuf_get_volume_buffered( IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); prev_page = buf_block_get_frame(block); @@ -3095,7 +3095,7 @@ count_later: IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); next_page = buf_block_get_frame(block); @@ -3333,7 +3333,7 @@ ibuf_set_entry_counter( IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); prev_page = buf_block_get_frame(block); @@ -4419,6 +4419,7 @@ ibuf_merge_or_delete_for_page( ut_ad(!block || buf_block_get_space(block) == space); ut_ad(!block || buf_block_get_page_no(block) == page_no); ut_ad(!block || buf_block_get_zip_size(block) == zip_size); + ut_ad(!block || buf_block_get_io_fix(block) == BUF_IO_READ); if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE || trx_sys_hdr_page(space, page_no)) { @@ -4571,7 +4572,13 @@ loop: ut_a(success); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + /* This is a user page (secondary index leaf page), + but we pretend that it is a change buffer page in + order to obey the latching order. This should be OK, + because buffered changes are applied immediately while + the block is io-fixed. Other threads must not try to + latch an io-fixed block. */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); } /* Position pcur in the insert buffer at the first entry for this @@ -4675,7 +4682,12 @@ loop: __FILE__, __LINE__, &mtr); ut_a(success); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + /* This is a user page (secondary + index leaf page), but it should be OK + to use too low latching order for it, + as the block is io-fixed. */ + buf_block_dbg_add_level( + block, SYNC_IBUF_TREE_NODE); if (!ibuf_restore_pos(space, page_no, search_tuple, diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 24f3801c7f8..699f201fe15 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -199,26 +199,45 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ - mtr_t* mtr) /*!< in/out: mtr */ - __attribute__((nonnull)); +# ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +# endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr); /*!< in/out: mini-transaction */ +# ifdef UNIV_SYNC_DEBUG /** 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 index index tree, may be NULL if not the insert buffer tree @param mtr mini-transaction handle @return the block descriptor */ -# define btr_block_get(space,zip_size,page_no,mode,mtr) \ - btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# define btr_block_get(space,zip_size,page_no,mode,index,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode, \ + __FILE__,__LINE__,index,mtr) +# else /* UNIV_SYNC_DEBUG */ /** 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 idx index tree, may be NULL if not the insert buffer tree +@param mtr mini-transaction handle +@return the block descriptor */ +# define btr_block_get(space,zip_size,page_no,mode,idx,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# endif /* UNIV_SYNC_DEBUG */ +/** 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 idx index tree, may be NULL if not the insert buffer tree @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)) +# define btr_page_get(space,zip_size,page_no,mode,idx,mtr) \ + buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr)) #endif /* !UNIV_HOTBACKUP */ /**************************************************************//** Gets the index id field of a page. @@ -344,8 +363,7 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr); /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr); /*!< in/out: mini-transaction */ /*************************************************************//** Makes tree one level higher by splitting the root, and inserts the tuple. It is assumed that mtr contains an x-latch on the tree. diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic index ccf41904fd0..1bd22a0ebc6 100644 --- a/storage/innobase/include/btr0btr.ic +++ b/storage/innobase/include/btr0btr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, 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 @@ -48,6 +48,10 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +#endif /* UNIV_SYNC_DEBUG */ mtr_t* mtr) /*!< in/out: mtr */ { buf_block_t* block; @@ -57,7 +61,9 @@ btr_block_get_func( if (mode != RW_NO_LATCH) { - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, index != NULL && dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } return(block); diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 74ef2d2dab7..eb40621abbe 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -203,6 +203,17 @@ void buf_LRU_stat_update(void); /*=====================*/ +/******************************************************************//** +Remove one page from LRU list and put it to free list */ +UNIV_INTERN +void +buf_LRU_free_one_page( +/*==================*/ + buf_page_t* bpage) /*!< in/out: block, must contain a file page and + be in a state where it can be freed; there + may or may not be a hash index to the page */ + __attribute__((nonnull)); + #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /**********************************************************************//** Validates the LRU list. diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 28ef64500cc..415470b61b4 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -110,6 +110,7 @@ enum db_err { foreign keys as its prefix columns */ DB_TOO_BIG_INDEX_COL, /* index column size exceeds maximum limit */ + DB_INDEX_CORRUPT, /* we have corrupted index */ /* The following are partial failure codes */ DB_FAIL = 1000, diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 22df826da65..5d136862bc6 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -137,8 +137,10 @@ dict_create(void); header is created */ /*-------------------------------------------------------------*/ -/* The field number of the page number field in the sys_indexes table -clustered index */ +/* The field numbers in the SYS_TABLES clustered index */ +#define DICT_SYS_TABLES_TYPE_FIELD 5 + +/* The field numbers in the SYS_INDEXES clustered index */ #define DICT_SYS_INDEXES_PAGE_NO_FIELD 8 #define DICT_SYS_INDEXES_SPACE_NO_FIELD 7 #define DICT_SYS_INDEXES_TYPE_FIELD 6 diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index f979d0fcc96..93e9162dc87 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -585,6 +585,20 @@ dict_table_get_next_index( # define dict_table_get_next_index(index) UT_LIST_GET_NEXT(indexes, index) #endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ + +/* Skip corrupted index */ +#define dict_table_skip_corrupt_index(index) \ + while (index && dict_index_is_corrupted(index)) { \ + index = dict_table_get_next_index(index); \ + } + +/* Get the next non-corrupt index */ +#define dict_table_next_uncorrupted_index(index) \ +do { \ + index = dict_table_get_next_index(index); \ + dict_table_skip_corrupt_index(index); \ +} while (0) + /********************************************************************//** Check whether the index is the clustered index. @return nonzero for clustered index, zero for other indexes */ @@ -593,7 +607,7 @@ ulint dict_index_is_clust( /*================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is unique. @return nonzero for unique index, zero for other indexes */ @@ -602,7 +616,7 @@ ulint dict_index_is_unique( /*=================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ @@ -611,7 +625,7 @@ ulint dict_index_is_ibuf( /*===============*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Check whether the index is a secondary index or the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ @@ -620,7 +634,7 @@ ulint dict_index_is_sec_or_ibuf( /*======================*/ const dict_index_t* index) /*!< in: index */ - __attribute__((pure)); + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of user-defined columns in a table in the dictionary @@ -630,7 +644,8 @@ UNIV_INLINE ulint dict_table_get_n_user_cols( /*=======================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of system columns in a table in the dictionary cache. @return number of system (e.g., ROW_ID) columns of a table */ @@ -638,7 +653,8 @@ UNIV_INLINE ulint dict_table_get_n_sys_cols( /*======================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); /********************************************************************//** Gets the number of all columns (also system) in a table in the dictionary cache. @@ -647,7 +663,8 @@ UNIV_INLINE ulint dict_table_get_n_cols( /*==================*/ - const dict_table_t* table); /*!< in: table */ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); #ifdef UNIV_DEBUG /********************************************************************//** Gets the nth column of a table. @@ -1243,6 +1260,56 @@ void dict_close(void); /*============*/ +/**********************************************************************//** +Check whether the table is corrupted. +@return nonzero for corrupted table, zero for valid tables */ +UNIV_INLINE +ulint +dict_table_is_corrupted( +/*====================*/ + const dict_table_t* table) /*!< in: table */ + __attribute__((nonnull, pure, warn_unused_result)); + +/**********************************************************************//** +Check whether the index is corrupted. +@return nonzero for corrupted index, zero for valid indexes */ +UNIV_INLINE +ulint +dict_index_is_corrupted( +/*====================*/ + const dict_index_t* index) /*!< in: index */ + __attribute__((nonnull, pure, warn_unused_result)); + +/**********************************************************************//** +Flags an index and table corrupted both in the data dictionary cache +and in the system table SYS_INDEXES. */ +UNIV_INTERN +void +dict_set_corrupted( +/*===============*/ + dict_index_t* index) /*!< in/out: index */ + UNIV_COLD __attribute__((nonnull)); + +/**********************************************************************//** +Flags an index corrupted in the data dictionary cache only. This +is used mostly to mark a corrupted index when index's own dictionary +is corrupted, and we force to load such index for repair purpose */ +UNIV_INTERN +void +dict_set_corrupted_index_cache_only( +/*================================*/ + dict_index_t* index); /*!< in/out: index */ + +/**********************************************************************//** +Flags a table with specified space_id corrupted in the table dictionary +cache. +@return TRUE if successful */ +UNIV_INTERN +ibool +dict_set_corrupted_by_space( +/*========================*/ + ulint space_id); /*!< in: space ID */ + #ifndef UNIV_NONINL #include "dict0dict.ic" #endif diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 59811568556..ade9e627e29 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -27,6 +27,7 @@ Created 1/8/1996 Heikki Tuuri #ifndef UNIV_HOTBACKUP #include "dict0load.h" #include "rem0types.h" +#include "srv0srv.h" /*********************************************************************//** Gets the minimum number of bytes per character. @@ -828,7 +829,7 @@ dict_table_check_if_in_cache_low( } /**********************************************************************//** -load a table into dictionary cache, ignore any error specified during load; +load a table into dictionary cache, ignore any error specified during load; @return table, NULL if not found */ UNIV_INLINE dict_table_t* @@ -872,6 +873,18 @@ dict_table_get_low( table = dict_table_check_if_in_cache_low(table_name); + if (table && table->corrupted) { + fprintf(stderr, "InnoDB: table"); + ut_print_name(stderr, NULL, TRUE, table->name); + if (srv_load_corrupted) { + fputs(" is corrupted, but" + " innodb_force_load_corrupted is set\n", stderr); + } else { + fputs(" is corrupted\n", stderr); + return(NULL); + } + } + if (table == NULL) { table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE); } @@ -937,4 +950,35 @@ dict_max_field_len_store_undo( return(prefix_len); } +/********************************************************************//** +Check whether the table is corrupted. +@return nonzero for corrupted table, zero for valid tables */ +UNIV_INLINE +ulint +dict_table_is_corrupted( +/*====================*/ + const dict_table_t* table) /*!< in: table */ +{ + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + return(UNIV_UNLIKELY(table->corrupted)); +} + +/********************************************************************//** +Check whether the index is corrupted. +@return nonzero for corrupted index, zero for valid indexes */ +UNIV_INLINE +ulint +dict_index_is_corrupted( +/*====================*/ + const dict_index_t* index) /*!< in: index */ +{ + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + + return(UNIV_UNLIKELY((index->type & DICT_CORRUPT) + || (index->table && index->table->corrupted))); +} + #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 3a475fa85fc..9ded0dba39b 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -51,7 +51,12 @@ combination of types */ #define DICT_UNIQUE 2 /*!< unique index */ #define DICT_UNIVERSAL 4 /*!< index which can contain records from any other index */ -#define DICT_IBUF 8 /*!< insert buffer tree */ +#define DICT_IBUF 8 /*!< insert buffer tree */ +#define DICT_CORRUPT 16 /*!< bit to store the corrupted flag + in SYS_INDEXES.TYPE */ + +#define DICT_IT_BITS 5 /*!< number of bits used for + SYS_INDEXES.TYPE */ /* @} */ /** Types for a table object */ @@ -369,8 +374,9 @@ struct dict_index_struct{ /*!< space where the index tree is placed */ unsigned page:32;/*!< index tree root page number */ #endif /* !UNIV_HOTBACKUP */ - unsigned type:4; /*!< index type (DICT_CLUSTERED, DICT_UNIQUE, - DICT_UNIVERSAL, DICT_IBUF) */ + unsigned type:DICT_IT_BITS; + /*!< index type (DICT_CLUSTERED, DICT_UNIQUE, + DICT_UNIVERSAL, DICT_IBUF, DICT_CORRUPT) */ unsigned trx_id_offset:10;/*!< position of the trx id column in a clustered index record, if the fields before it are known to be of a fixed size, @@ -391,8 +397,6 @@ struct dict_index_struct{ /*!< TRUE if this index is marked to be dropped in ha_innobase::prepare_drop_index(), otherwise FALSE */ - unsigned corrupted:1; - /*!< TRUE if the index object is corrupted */ dict_field_t* fields; /*!< array of field descriptions */ #ifndef UNIV_HOTBACKUP UT_LIST_NODE_T(dict_index_t) diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 8cbd7cd5783..f0a05a38070 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -51,7 +51,8 @@ be or-ed together */ enum dict_err_ignore { DICT_ERR_IGNORE_NONE = 0, /*!< no error to ignore */ DICT_ERR_IGNORE_INDEX_ROOT = 1, /*!< ignore error if index root - page is FIL_NUL or incorrect value */ + page is FIL_NULL or incorrect value */ + DICT_ERR_IGNORE_CORRUPT = 2, /*!< skip corrupted indexes */ DICT_ERR_IGNORE_ALL = 0xFFFF /*!< ignore all errors */ }; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 7a93548cb03..dfe7397d189 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -141,6 +141,10 @@ extern ulint srv_log_buffer_size; extern ulong srv_flush_log_at_trx_commit; extern char srv_adaptive_flushing; +/* If this flag is TRUE, then we will load the indexes' (and tables') metadata +even if they are marked as "corrupted". Mostly it is for DBA to process +corrupted index and table */ +extern my_bool srv_load_corrupted; /* The sort order table of the MySQL latin1_swedish_ci character set collation */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index dd74ccee523..9c0d5e3c302 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -638,10 +638,6 @@ or row lock! */ #define SYNC_DICT_HEADER 995 #define SYNC_IBUF_HEADER 914 #define SYNC_IBUF_PESS_INSERT_MUTEX 912 -#define SYNC_IBUF_MUTEX 910 /* ibuf mutex is really below - SYNC_FSP_PAGE: we assign a value this - high only to make the program to pass - the debug checks */ /*-------------------------------*/ #define SYNC_INDEX_TREE 900 #define SYNC_TREE_NODE_NEW 892 @@ -657,8 +653,11 @@ or row lock! */ #define SYNC_FSP 400 #define SYNC_FSP_PAGE 395 /*------------------------------------- Insert buffer headers */ -/*------------------------------------- ibuf_mutex */ +#define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */ /*------------------------------------- Insert buffer tree */ +#define SYNC_IBUF_INDEX_TREE 360 +#define SYNC_IBUF_TREE_NODE_NEW 359 +#define SYNC_IBUF_TREE_NODE 358 #define SYNC_IBUF_BITMAP_MUTEX 351 #define SYNC_IBUF_BITMAP 350 /*------------------------------------- MySQL query cache mutex */ diff --git a/storage/innobase/pars/pars0opt.c b/storage/innobase/pars/pars0opt.c index 2e392ba4836..d992805d9ef 100644 --- a/storage/innobase/pars/pars0opt.c +++ b/storage/innobase/pars/pars0opt.c @@ -568,7 +568,7 @@ opt_search_plan_for_table( best_last_op = last_op; } - index = dict_table_get_next_index(index); + dict_table_next_uncorrupted_index(index); } plan->index = best_index; diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 715e376f8f9..62146a95f11 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -118,6 +118,9 @@ ins_node_create_entry_list( node->entry_sys_heap); UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry); + /* We will include all indexes (include those corrupted + secondary indexes) in the entry list. Filteration of + these corrupted index will be done in row_ins() */ index = dict_table_get_next_index(index); } } @@ -2046,7 +2049,6 @@ row_ins_index_entry_low( mtr_start(&mtr); if (err != DB_SUCCESS) { - goto function_exit; } @@ -2431,6 +2433,13 @@ row_ins( node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); + + /* Skip corrupted secondar index and its entry */ + while (node->index && dict_index_is_corrupted(node->index)) { + + node->index = dict_table_get_next_index(node->index); + node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); + } } ut_ad(node->entry == NULL); diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 5be437add5a..d42f21241ca 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -2554,8 +2554,9 @@ row_merge_is_index_usable( const trx_t* trx, /*!< in: transaction */ const dict_index_t* index) /*!< in: index to check */ { - return(!trx->read_view - || read_view_sees_trx_id(trx->read_view, index->trx_id)); + return(!dict_index_is_corrupted(index) + && (!trx->read_view + || read_view_sees_trx_id(trx->read_view, index->trx_id))); } /*********************************************************************//** diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index a56d419d1f0..d98d47a5da6 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -3098,7 +3098,8 @@ row_drop_table_for_mysql( ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - table = dict_table_get_low_ignore_err(name, DICT_ERR_IGNORE_INDEX_ROOT); + table = dict_table_get_low_ignore_err( + name, DICT_ERR_IGNORE_INDEX_ROOT | DICT_ERR_IGNORE_CORRUPT); if (!table) { err = DB_TABLE_NOT_FOUND; diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index 83e7c9e4857..c008c2d1c31 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -469,6 +469,13 @@ row_purge_del_mark( heap = mem_heap_create(1024); while (node->index != NULL) { + /* skip corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; /* Build the index entry */ @@ -516,6 +523,12 @@ row_purge_upd_exist_or_extern_func( heap = mem_heap_create(1024); while (node->index != NULL) { + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; if (row_upd_changes_ord_field_binary(node->index, node->update, diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 36da621e077..a1039010d00 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -3441,6 +3441,13 @@ row_search_for_mysql( return(DB_MISSING_HISTORY); } + if (dict_index_is_corrupted(index)) { +#ifdef UNIV_SYNC_DEBUG + ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); +#endif /* UNIV_SYNC_DEBUG */ + return(DB_CORRUPTION); + } + if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" diff --git a/storage/innobase/row/row0uins.c b/storage/innobase/row/row0uins.c index d25afed3840..4fa97c9355d 100644 --- a/storage/innobase/row/row0uins.c +++ b/storage/innobase/row/row0uins.c @@ -328,6 +328,8 @@ row_undo_ins( node->index = dict_table_get_next_index( dict_table_get_first_index(node->table)); + dict_table_skip_corrupt_index(node->index); + while (node->index != NULL) { dtuple_t* entry; ulint err; @@ -355,7 +357,7 @@ row_undo_ins( } } - node->index = dict_table_get_next_index(node->index); + dict_table_next_uncorrupted_index(node->index); } log_free_check(); diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 2188fdeff49..b86ce9eeabd 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -573,6 +573,14 @@ row_undo_mod_upd_del_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; entry = row_build_index_entry(node->row, node->ext, @@ -626,6 +634,13 @@ row_undo_mod_del_mark_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; entry = row_build_index_entry(node->row, node->ext, @@ -677,6 +692,13 @@ row_undo_mod_upd_exist_sec( heap = mem_heap_create(1024); while (node->index != NULL) { + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + index = node->index; if (row_upd_changes_ord_field_binary(node->index, node->update, @@ -859,6 +881,9 @@ row_undo_mod( node->index = dict_table_get_next_index( dict_table_get_first_index(node->table)); + /* Skip all corrupted secondary index */ + dict_table_skip_corrupt_index(node->index); + if (node->rec_type == TRX_UNDO_UPD_EXIST_REC) { err = row_undo_mod_upd_exist_sec(node, thr); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index a2f6c17413f..6559c529117 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -2320,6 +2320,13 @@ row_upd( while (node->index != NULL) { + /* Skip corrupted index */ + dict_table_skip_corrupt_index(node->index); + + if (!node->index) { + break; + } + log_free_check(); err = row_upd_sec_step(node, thr); diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 251a392a02c..3888fe4c657 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1232,6 +1232,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: + case SYNC_IBUF_MUTEX: if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" @@ -1317,21 +1318,27 @@ sync_thread_add_level( || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: - ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) - || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)); break; case SYNC_INDEX_TREE: - if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP)) { - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, - TRUE)); - } else { - ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, - TRUE)); - } + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; - case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); + case SYNC_IBUF_TREE_NODE: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_INDEX_TREE) + || sync_thread_levels_g(array, SYNC_IBUF_TREE_NODE - 1, + TRUE)); + break; + case SYNC_IBUF_TREE_NODE_NEW: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + break; + case SYNC_IBUF_INDEX_TREE: + if (sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g( + array, SYNC_FSP_PAGE - 1, TRUE)); + } else { + ut_a(sync_thread_levels_g( + array, SYNC_IBUF_TREE_NODE - 1, TRUE)); + } break; case SYNC_IBUF_PESS_INSERT_MUTEX: ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 1ef1a082bb2..bd009f1fd32 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -712,6 +712,8 @@ ut_strerr( return("No index on referencing keys in referencing table"); case DB_PARENT_NO_INDEX: return("No index on referenced keys in referenced table"); + case DB_INDEX_CORRUPT: + return("Index corrupted"); case DB_END_OF_INDEX: return("End of index"); /* do not add default: in order to produce a warning if new code diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 92f055e269a..d492e8fc6b7 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -421,7 +421,7 @@ mkdir debug # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \ -DCMAKE_BUILD_TYPE=Debug \ - -DMYSQL_UNIX_ADDR="/var/lib/mysql/mysql.sock" \ + -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_debug}" \ -DMYSQL_SERVER_SUFFIX="%{server_suffix}" @@ -436,7 +436,7 @@ mkdir release # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DMYSQL_UNIX_ADDR="/var/lib/mysql/mysql.sock" \ + -DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \ -DFEATURE_SET="%{feature_set}" \ -DCOMPILATION_COMMENT="%{compilation_comment_release}" \ -DMYSQL_SERVER_SUFFIX="%{server_suffix}" @@ -1133,6 +1133,11 @@ echo "=====" >> $STATUS_HISTORY # merging BK trees) ############################################################################## %changelog +* Fri Aug 19 2011 Joerg Bruehe + +- Null-upmerge the fix of bug#37165: This spec file is not affected. +- Replace "/var/lib/mysql" by the spec file variable "%{mysqldatadir}". + * Mon Jul 25 2011 Chuck Bell - Added the mysql_plugin client - enables or disables plugins.